/* GENCAD (LAY) -- Generate GENCAD 1.4 Layout Data Output */ /* GENCAD (LAY) -- GENCAD 1.4 Layout Datenausgabe */ /* // Copyright (c) 1999-2012 Oliver Bartels F+E, Muenchen // Author: Roman Ludwig // Changes History: // rl (120427) RELEASED FOR BAE V7.8. // rl (110627) ENHANCEMENT: // Added output unit control bae.ini parameter. // rl (101019) RELEASED FOR BAE V7.6. // rl (091130) ENHANCEMENT: // Output of constructive parts to MECH section. // Autodetection of pure drill hole parts. // rl (091119) ENHANCEMENT: // Added complete placement output call option. // rl (091021) RELEASED FOR BAE V7.4. // rl (081014) RELEASED FOR BAE V7.2. // rl (080304) ENHANCEMENT: // Added optional part text placement side scan. // rl (071029) RELEASED FOR BAE V7.0. // rl (060829) RELEASED FOR BAE V6.8. // rl (060821) ENHANCEMENT: // Added variant support. // rl (060111) ENHANCEMENT: // Added optional output folder support. // rl (050906) RELEASED FOR BAE V6.6. // rl (040811) RELEASED FOR BAE V6.4. // rl (040721) ENHANCEMENT: // Added full batch call support. // rl (040227) BUGFIX: // Fixed problem with negative rectangle size output. // Fixed problem with pad documentary layer offset. // rl (031030) ENHANCMENT: // Added top side silk screen graphic to shape definition. // rl (030904) RELEASED FOR BAE V6.2. // rl (030703) ENHANCMENT: // Added bae.ini parameter settings. // Released for general BAE distribution. // rl (030121) ADAPTED TO VERSION 6.0 // rl (011015) ENHANCMENT: // Added standard line width to trace width table. // Changed artwork output accordingly. // rl (010112) ADAPTED TO VERSION 4.6 // rl (990222) ORIGINAL CODING // // DESCRIPTION // // The gencad User Language program generates a GENCAD 1.4 DAT layout // data file for the currently loaded layout. */ // Includes #include "pop.ulh" // User Language popup utilities #include "sql.ulh" // User Language SQL utilities #include "lay.ulh" // User Language layout utilities // Disable undo state request #pragma ULCALLERNOUNDO // Messages string REPPROCWR = M("Layoutdaten schreiben...", "Writing layout data..."); string REPDONE = M("Layoutdaten ausgegeben auf Datei '%s'.", "Layout Data written to file '%s'."); string REPFILE = M(" Gencad 1.4 Datei ....................: '%s'", " Gencad 1.4 Data File ....................: '%s'"); string REPLOGHD = M("GENCAD-AUSGABE :","GENCAD DATA OUTPUT :"); string REPLOGFILE = M(" Bearbeitete Datei ...............: '%s'", " File processed ............: '%s'"); string REPLOGELEM = M(" Bearbeitetes Layout .............: '%s'", " Layout processed ..........: '%s'"); string REPLOGOUTF = M(" Ausgabedatei ....................: '%s'", " Output file ...............: '%s'"); string REPLOGVAR = M(" Variante ........................: '%s'", " Variant ...................: '%s'"); string REPBASEVAR = M("Basisvariante","Base Variant"); string ERRPADOFF = M(" Warnung: Padstack '%s' Pads nicht zentriert!", " Warning: Padstack '%s' pads not centered!"); string ERRPINMOVE = M(" Warnung: Pinverschiebung nicht unterstuetzt ('%s'/'%s')!", " Warning: Pin movement not supported '%s'/'%s'!"); string ERRFOPEN = M("Fehler beim Oeffnen der Ausgabedatei '%s'!", "Error opening output file '%s'!"); string ERRNOSAVE = M("Aktuell geladenes Element nicht gesichert!", "Currently loaded element has not been saved!"); // INI file parameter name definitions #define PAR_DATEXT "GENCADEXT_LAY" // Gencad file extension #define PAR_STDLINEW "GENCADSTDW_LAY"// Gencad standard line width #define PAR_SILKSCREEN "GENCADSS_LAY" // Silk screen base layer #define PAR_SOLDERMASK "GENCADSM_LAY" // Solder mask base layer #define PAR_SOLDERPASTE "GENCADSP_LAY" // Solder paste base layer #define PAR_ATTRATTR "GENCADAATTR_LAY"// Gencad attribute attribute name #define PAR_ATTRDESC "GENCADADESC_LAY"// Gencad description attribute name #define PAR_ATTRTOL "GENCADATOL_LAY"// Gencad tolerance attribute name #define PAR_ATTRTYPE "GENCADATYPE_LAY"// Gencad type attribute name #define PAR_ATTRVALUE "GENCADAVAL_LAY"// Gencad value attribute name #define PAR_ATTRVOLTS "GENCADAVOLT_LAY"// Gencad volts attribute name #define PAR_OUTDIR "GENCADOUTDIR_LAY"// Data output directory #define PAR_VARFNAME "GENCADVARFN_LAY"// Variant specific output file name #define PAR_FNAMEMAC "GENCADFNMAC_LAY"// File name spec. reference name #define PAR_FNAMEATTR "GENCADFNATTR_LAY"// File name spec. attribute name #define PAR_SIDESCAN "GENCADSSCAN_LAY"// Gencad placement side scan flag #define PAR_DRILLMAC "GENCADDRMAC_LAY"// Gencad drill macro name pattern #define PAR_MECHSEC "GENCADMECH_LAY"// Gencad mechanical section output #define PAR_UNITS "GENCADUNITS_LAY"// Gencad output units // Constant definitions #define SMALLVAL 0.000001 // Small value #define GV_BATCALL "BAT_CALL" // Remote control operation flag #define GV_BATREPCNT "BAT_REPCNT" // Remote control op. report count #define GV_BATREPLINE "BAT_REPL_" // Remote control op. report line // Globals string DATEXT = bae_inistrval(PAR_DATEXT,".cad") /* Data output file name ext. */; int SILKSCREEN = bae_iniintval(PAR_SILKSCREEN,0x400) /* Silk screen lay.base doc.layer 1 */; int SOLDERMASK = bae_iniintval(PAR_SOLDERMASK,0x410) /* Solder mask lay.base doc.layer 2 */; int SOLDERPASTE = bae_iniintval(PAR_SOLDERPASTE,0x470) /* Solder paste lay.base doc.layer 8 */; int SIDESCAN = bae_iniintval(PAR_SIDESCAN,0) /* Placement side scan flag */; string DRILLMAC = bae_inistrval(PAR_DRILLMAC,"hole*") /* Drill macro name pattern */; double STDLINEWIDTH = bae_inidblval(PAR_STDLINEW,0.0001) /* Standard line width */; int MECHSEC = bae_iniintval(PAR_MECHSEC,1) /* Mechanical section output flag */; int UNITS = bae_iniintval(PAR_UNITS,1) /* Output units */; string ATTRTYPE = bae_inistrval(PAR_ATTRTYPE,"$type") /* Type attribute name */; string ATTRVALUE = bae_inistrval(PAR_ATTRVALUE,"$val") /* Value attribute name */; string ATTRVOLTS = bae_inistrval(PAR_ATTRVOLTS,"$volts") /* Volts attribute name */; string ATTRDESC = bae_inistrval(PAR_ATTRDESC,"$pchr") /* Description attribute name */; string ATTRTOL = bae_inistrval(PAR_ATTRTOL,"$tol") /* Tolerance attribute name */; string ATTRATTR = bae_inistrval(PAR_ATTRATTR,"$attribute") /* Attribute attribute name */; string OUTDIR = bae_inistrval(PAR_OUTDIR,"") /* Data output directory */; int VARFNAME = bae_iniintval(PAR_VARFNAME,0) /* Variant specific file name flag */; string FNAMEMAC = bae_inistrval(PAR_FNAMEMAC,"") /* File name spec. macro name */; string FNAMEATTR = bae_inistrval(PAR_FNAMEATTR,"") /* File name spec. attribute name */; int ALLOUT = 0 /* All part output flag */; // Layer table definitions struct laydes { // Layer table descriptor int layer /* Layer code */; string name /* Layer name */; }; struct laydes layfield[] = { // Layer output field { SILKSCREEN,"SILKSCREEN"}, // Doc. 1 { SOLDERMASK,"SOLDERMASK"}, // Doc. 2 { SOLDERPASTE,"SOLDERPASTE"} // Doc. 8 }; int layfieldn = arylength(layfield) /* Layer output field length */; // Test point list declarations struct pointdes { // Polygon point descriptor double x,y /* Point coordinates */; int t /* Point type */; } polypl[] /* Polygon point list */; int polypn /* Polygon point count */; int polyfound /* Polygon polyon found flag */; int vian = 0 /* Via count */; double trcwl[] /* Track width list */; int trcwn = 0 /* Track width count */; int mindidx = (-1) /* Min. distance track index */; int planeidx = 0 /* Current plane index */; int curtrcw /* Current trace width */; struct paddes { // Pad descriptor string name /* Pad name */; int layn /* Pad layer count */; int layl[] /* Pad layer list */; } padl[]; int padn = 0 /* Pad count */; string curpadname = "" /* Current pad name */; string curpart /* Current part name */; string curstkname /* Current padstack name */; string curnetname /* Current net name */; int curtree /* Current tree number */; int netout /* Current net output status */; int fh /* Data output file handle */; int fillstate = 0 /* Fill status */; int toplayskip = 0 /* Top layer skip flag */; int curlayer1,curlayer2 /* Current layer codes */; int plcside /* Placement side */; double wsnx,wsny /* Workspace origin */; double convfac /* Output conversion factor */; double drillsize = 0.0 /* Current drill size */; STRINGS msgl /* Message list */; int msgn = 0 /* Message count */; STRINGS hl /* Popup menu header list */; int hn /* Popup menu header count */; double PI = cvtangle(180.0,1,2) /* PI value */; struct nelemdes { // Net elements descriptor index L_CNET net /* Net index */; index L_FIGURE el[] /* Net element list */; int en /* Net element count */; } neleml[] /* Net list */; int nelemn = 0 /* Net element count */; index L_FIGURE curfig /* Current figure list element */; int varnum /* Variant number */; // SQL command definitions #define V_SELECTN "select name from varinfo where variant=%d;" string sqlcommand /* SQL command string */; string varname = "" /* Variant name */; // Main program void main() { index L_CPART cpart /* Connection part index */; string fn = "" /* Data output file name */; string outdir /* Output directory base */; string fname /* Output file name */; string fnamedir /* Job name directory */; string dirsep="/" /* Directory separator */; string msg /* Message string */; int i /* Loop control variable */; // Test if a valid element is loaded if (bae_planddbclass()!=DDBCLLAY) // Invalid element error_class(); // Check if complete placement call if (bae_peekiact()) { if ((fn=askstr("",MAXTEXTLEN))=="all") { ALLOUT=1; VARFNAME=0; if (bae_peekiact()) fn=askstr("",MAXTEXTLEN); else fn=""; } } // Abort if plan not saved if (bae_plannotsaved()) error(ERRNOSAVE); // Query the current active variant if (ALLOUT==1 || lay_rulequery(RS_OCPLAN,0,RS_PCBSUBJ,RS_VARIANT,"?d",varnum)<1) // Use base variant varnum=0; if (FNAMEMAC!="") forall (cpart where strmatch(cpart.MACRO.NAME,FNAMEMAC)) if ((varname=getlayattribval(cpart,FNAMEATTR))!="") break; if (varname=="") { // Select variant table entry sprintf(sqlcommand,V_SELECTN,varnum); // Build the variant number string sqlcmd(bae_planfname(),sqlcommand,ndatafunc); if (varname=="") sprintf(varname,"variant%d",varnum); } // Get file name bases fname=bae_planfname(); fname=convstring(fname,0); fnamedir=""; for (i=strlen(fname)-1;i>=0;i--) if (fname[i]=='/' || fname[i]=='\\' || fname[i]==':') { if (fname[i]!=':') dirsep[0]=fname[i]; // Delimiter found fnamedir=fname; fnamedir[i+1]='\0'; break; } if (OUTDIR!="") { if (OUTDIR[0]=='*') OUTDIR=convstring(bae_planfname(),2)+ strextract(OUTDIR,1,strlen(OUTDIR)-1); // Build the output data file names outdir=fnamedir+OUTDIR; if (filetype(outdir)!=0) bae_createdir(outdir); if (fn=="") { if (VARFNAME) fn=outdir+dirsep+varname+DATEXT; else fn=outdir+dirsep+ convstring(bae_planfname(),2)+DATEXT; } } else { if (fn=="") { // Build the test data file name if (VARFNAME) fn=fnamedir+varname+DATEXT; else fn=convstring(bae_planfname(),0)+DATEXT; } } // Set the cached figure list access lay_setfigcache(); // Write the layout data write_layout(fn); // Check if message display required if (msgn>0) { // Display data output report header sprintf(hl[0],REPLOGHD); sprintf(hl[2],REPLOGFILE,bae_planfname()); sprintf(hl[3],REPLOGOUTF,strgetvarfilename(fn)); sprintf(hl[4],REPLOGELEM,bae_planename()); sprintf(hl[5],REPLOGVAR,varnum==0 ? REPBASEVAR : itoa(varnum)); hl[1]=hl[6]=""; hn=7; // Display log with popup menu bae_setintpar(16,4026); popupmenu(0,"",hl,hn,msgl,msgn, UINPOPABORT,0,-1,-1,hn+msgn+2,100,0,UINPOPABORT); } // Check if remote control operation if (varget(GV_BATCALL,0)==0) { vardelete(GV_BATCALL); // Print messages sprintf(msg,REPFILE,strgetvarfilename(fn)); varset(GV_BATREPLINE+itoa(0),msg); varset(GV_BATREPCNT,1); } else { // Print the done message sprintf(msg,REPDONE,strgetvarfilename(fn)); bae_prtdialog(msg); } } int padmacrofunc(index L_MACRO macro,index L_POOL pool,int macinws, string refname,index L_LEVEL level) /* // Pad macro scan function // Returns : (-1) on scan error, 0 on scan stop, 1 on scan continue // Parameters : // index L_MACRO macro : Macro index // index L_POOL pool : Macro pool element (internal) // int macinws : Macro in workspace flag // string refname : Macro reference name // index L_LEVEL level : Macro level */ { double x,y /* Pad coordinates */; double ang /* Pad angle */; int mirr /* Pad mirror flag */; int layer /* Pad layer offset */; int tlayer /* Pad transformed layer offset */; int layoff /* Pad layer offset */; int padidx /* Pad index */; int i /* Loop control variable */; // Check class switch (macro.CLASS) { case DDBCLLSTK : // Continue scan return(1); case DDBCLLPAD : // Get pad placement data lay_maccoords(x,y,ang,mirr,layer); if (!chklay(layer)) break; // Check for pad offset if (x!=0.0 || y!=0.0) { sprintf(msgl[msgn],ERRPADOFF,curstkname); msgn++; } // Search the pad defintion for (padidx=0;padidx=padn) break; for (i=0;i=DOCLAYBASE ? layer : layoff ; if (tlayer>=DOCLAYBASE) tlayer=tlayer; else if (layoff>=0) { if (layer<0) tlayer=layer; else if (layer==0) tlayer=layoff; else tlayer=layer+layoff; } else tlayer=layoff; // Check if both side documentary layer if (tlayer>=DOCLAYBASE && (tlayer&0x02)!=0) { // Write the bottom pad fprintf(fh,"PAD \"%s\" %s",padlname( pool.MACRO.NAME,padl[padidx].layl[i]), glayname(tlayer&0xff0)); writeangle(ang); fprintf(fh," %s\n",mirr ? "MIRRORX" : "0"); // Write the top pad fprintf(fh,"PAD \"%s\" %s",padlname( pool.MACRO.NAME,padl[padidx].layl[i]), glayname((tlayer&0xff0)|0x01)); writeangle(ang); fprintf(fh," %s\n",mirr ? "MIRRORX" : "0"); } else { // Write the pad fprintf(fh,"PAD \"%s\" %s",padlname( pool.MACRO.NAME,padl[padidx].layl[i]), glayname(tlayer)); writeangle(ang); fprintf(fh," %s\n",mirr ? "MIRRORX" : "0"); } } break; default : ; } // Abort scan return(0); } int pinmacrofunc(index L_MACRO macro,index L_POOL pool,int macinws, string refname,index L_LEVEL level) /* // Pin macro scan function // Returns : (-1) on scan error, 0 on scan stop, 1 on scan continue // Parameters : // index L_MACRO macro : Macro index // index L_POOL pool : Macro pool element (internal) // int macinws : Macro in workspace flag // string refname : Macro reference name // index L_LEVEL level : Macro level */ { double x,y /* Pad coordinates */; double ang /* Pad angle */; int mirr /* Pad mirror flag */; // Check class switch (macro.CLASS) { case DDBCLLPRT : // Continue scan return(1); case DDBCLLSTK : // Check if via if (refname=="") break; // Get padstack placement data lay_maccoords(x,y,ang,mirr,0); // Write the pin placement fprintf(fh,"PIN \"%s\" \"%s\"",refname,macro.NAME); writexy(x,y); fprintf(fh," %s",mirr ? "BOTTOM" : "TOP"); writeangle(ang); fprintf(fh," %s\n",mirr ? "MIRRORX" : "0"); /* fprintf(fh,"PIN \"%s\" \"%s\"",refname,macro.NAME); writexy(x,y); fprintf(fh," %s",mirr ? "TOP" : "BOTTOM"); writeangle(ang); fprintf(fh," %s\n",mirr ? "0" : "MIRRORX"); */ break; default : ; } // Abort scan return(0); } int viamacrofunc(index L_MACRO macro,index L_POOL pool,int macinws, string refname,index L_LEVEL level) /* // Pad macro scan function // Returns : (-1) on scan error, 0 on scan stop, 1 on scan continue // Parameters : // index L_MACRO macro : Macro index // index L_POOL pool : Macro pool element (internal) // int macinws : Macro in workspace flag // string refname : Macro reference name // index L_LEVEL level : Macro level */ { index L_CNET net /* Net list index */; double x,y /* Pad coordinates */; // Check class switch (macro.CLASS) { case DDBCLLPRT : // Continue scan return(1); case DDBCLLSTK : // Check if pin padstack if (refname!="") break; // Check the tree number if (lay_gettreeidx(level.LEVVAL,net) || net.NUMBER!=curtree) // Tree not of interest break; // Check if net name output required if (!netout) { fprintf(fh,"ROUTE \"%s\"\n",curnetname); netout=1; } // Get via placement data lay_maccoords(x,y,0.0,0,0); // Write the via fprintf(fh,"VIA \"%s\"",macro.NAME); writexy(x,y); vian++; fprintf(fh," ALL -2 via%d\n",vian); break; default : ; } // Abort scan return(0); } int vialfunc(index L_MACRO macro,index L_POOL pool,int macinws, string refname,index L_LEVEL level) /* // Pad macro scan function // Returns : (-1) on scan error, 0 on scan stop, 1 on scan continue // Parameters : // index L_MACRO macro : Macro index // index L_POOL pool : Macro pool element (internal) // int macinws : Macro in workspace flag // string refname : Macro reference name // index L_LEVEL level : Macro level */ { index L_CNET net /* Net list index */; int slb = 0 /* Search lower boundary */; int sub = nelemn-1 /* Search upper boundary */; int sidx /* Search index */; // Check class switch (macro.CLASS) { case DDBCLLPRT : // Continue scan return(1); case DDBCLLSTK : // Check if pin padstack if (refname!="") break; // Check the tree number if (lay_gettreeidx(level.LEVVAL,net)) // Tree not of interest break; // Loop until search area empty while (slb<=sub) { // Get the search index sidx=(slb+sub)>>1; // Test if pin found if (net==neleml[sidx].net) { // Net found neleml[sidx].el[neleml[sidx].en]=curfig; neleml[sidx].en++; // Return without errors return(0); } // Update the search area if (netp4.x ? p4.x : p2.x, p2.y>p4.y ? p4.y : p2.y); writelen(fabs(p3.x-p2.x)); writelen(fabs(p1.y-p2.y)); fprintf(fh,"\n"); // Return without errors return(0); } // Check the other orientation else if (fabs(p2.y-p1.y)<=SMALLVAL && fabs(p4.y-p3.y)<=SMALLVAL && fabs(p4.x-p1.x)<=SMALLVAL && fabs(p3.x-p2.x)<=SMALLVAL && fabs((p2.x-p1.x)-(p3.x-p4.x))<=SMALLVAL && fabs((p3.y-p2.y)-(p4.y-p1.y))<=SMALLVAL) { // Write the rectangle if (curpadname!="") { fprintf(fh, "PAD \"%s\" RECTANGULAR -1\n", padlname(curpadname,poly.LAYER)); padl[padn].name=curpadname; padl[padn].layl[padl[padn].layn]= poly.LAYER; padl[padn].layn++; } fprintf(fh,"RECTANGLE"); writexy( p1.x>p3.x ? p3.x : p1.x, p1.y>p3.y ? p3.y : p1.y); writelen(fabs(p2.x-p1.x)); writelen(fabs(p4.y-p1.y)); fprintf(fh,"\n"); // Return without errors return(0); } } } if (curpadname!="") { fprintf(fh,"PAD \"%s\" POLYGON -1\n", padlname(curpadname,poly.LAYER)); padl[padn].name=curpadname; padl[padn].layl[padl[padn].layn]=poly.LAYER; padl[padn].layn++; } // Get the scan end lastidx= closeflag ? polypn-1 : polypn-2 ; // Write all polygon lines/arcs for (i=0;i<=lastidx;i++) { // Get the next point index nextidx= (i==polypn-1) ? 0 : i+1 ; // Check for arcs if (polypl[i].t!=0) { // Get start and end point for counter clockwise arc if (polypl[i].t==1) { start= i==0 ? polypn-1 : i-1; end=nextidx; } else { end= i==0 ? polypn-1 : i-1; start=nextidx; } // Write the arc writearc(polypl[start].x,polypl[start].y, polypl[end].x,polypl[end].y,polypl[i].x,polypl[i].y); } else if (polypl[nextidx].t==0) { // Write the segment writeline(polypl[i].x,polypl[i].y, polypl[nextidx].x,polypl[nextidx].y); } } // Return without errors return(0); } int pathwfunc(index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Output an already transformed path data block to the data file // Return value : // zero if done or (-1) on file error // Parameters : // index L_LINE path : Path // int layer : Path layer // int pathinws : Path in workspace flag // index L_LEVEL level : Path level */ { int i /* Loop control variable */; // Search the path width for (i=0;i=0 && layer0) { fprintf(fh,"FILLED 0\n"); fillstate=0; } // Write the text line writeline(x1,y1,x2,y2); // Return without errors return(0); } // Test data scan routines int pathfunc(index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Perform routing output for traces on lower hierarchy levels // Return value : // zero if done or (-1) on error // Parameters : // index L_LINE path : Path // int layer : Path layer // int pathinws : Path in workspace flag // index L_LEVEL level : Path level */ { index L_CNET net /* Net list index */; index L_POINT point /* Polygon point index */; int nextidx /* Next polygon point index */; int lastidx /* Last polygon point index */; int start /* Arc start point index */; int end /* Arc end point index */; int tidx /* Track index */; int i /* Loop control variable */; // Check the tree number if (lay_gettreeidx(level.LEVVAL,net) || net.NUMBER!=curtree) // Tree not of interest return(0); // Check if net name output required if (!netout) { fprintf(fh,"ROUTE \"%s\"\n",curnetname); netout=1; } // Search the track width for (tidx=0;tidx>1; // Test if pin found if (net==neleml[sidx].net) { // Net found neleml[sidx].el[neleml[sidx].en]=curfig; neleml[sidx].en++; // Return without errors return(0); } // Update the search area if (net>1; // Test if pin found if (net==neleml[sidx].net) { // Net found neleml[sidx].el[neleml[sidx].en]=curfig; neleml[sidx].en++; // Return without errors return(0); } // Update the search area if (net1) { // Set the top layer skip flag toplayskip=1; break; } // Write header data fprintf(fh,"$HEADER\nGENCAD 1.4\n"); fprintf(fh,"USER \"BAE\"\n"); fprintf(fh,"DRAWING \"%s/%s\"\n",bae_planfname(),bae_planename()); fprintf(fh,"REVISION \"1\"\nUNITS "); switch (UNITS) { case 2 : convfac=cvtlength(1.0,0,2); fprintf(fh,"MM"); break; case 3 : convfac=cvtlength(1.0,0,3); fprintf(fh,"THOU"); // Inch case 1 : default : convfac=cvtlength(1.0,0,1); fprintf(fh,"INCH"); } fprintf(fh,"\nORIGIN 0.0 0.0\n"); fprintf(fh,"INTERTRACK 0\nCADID \"Bartels AutoEngineer %s\"\n", bae_swversion(0)); fprintf(fh,"$ENDHEADER\n"); // Write board data fprintf(fh,"$BOARD\n"); // Write board outline curlayer1=curlayer2=LAYERBRD; wsnx=bae_planwsnx(); wsny=bae_planwsny(); if (lay_scanall(0.0,0.0,0.0,0,0, macrostopfunc,polyfunc,NULL,NULL,NULL,laychk,NULL)!=0) // Scan error error_scan(); // Write the artwork sections fillstate=0; for (i=0;i=DOCLAYBASE) { curlayer2=curlayer1|0x02; fprintf(fh,"ARTWORK \"%s\" %s\n", layername(curlayer1),glayname(curlayer1)); fprintf(fh,"TRACK 1\n"); if (lay_scanall(0.0,0.0,0.0,0,0,macrostopfunc2, polyfunc,NULL,textfunc,NULL,laychk,NULL)!=0) // Scan error error_scan(); fillstate=0; curlayer1|=0x01; fprintf(fh,"ARTWORK \"%s\" %s\n", layername(curlayer1),glayname(curlayer1)); fprintf(fh,"TRACK 1\n"); if (lay_scanall(0.0,0.0,0.0,0,0,macrostopfunc2, polyfunc,NULL,textfunc,NULL,laychk,NULL)!=0) // Scan error error_scan(); fillstate=0; } else { curlayer2=curlayer1; fprintf(fh,"ARTWORK \"%s\" %s\n", layername(curlayer1),glayname(curlayer1)); fprintf(fh,"TRACK 1\n"); if (lay_scanall(0.0,0.0,0.0,0,0,macrostopfunc2, polyfunc,NULL,textfunc,NULL,laychk,NULL)!=0) // Scan error error_scan(); fillstate=0; } } fprintf(fh,"$ENDBOARD\n"); // Write pad data fprintf(fh,"$PADS\n"); fillstate=(-1); curlayer1=curlayer2=0; // Scan all pad macro pool elements wsnx=wsny=0.0; forall (pool where pool.TYP==1 && pool.MACRO.CLASS==DDBCLLPAD) { // Write the pad description curpadname=pool.MACRO.NAME; padl[padn].name=curpadname; padl[padn].layn=0; // Scan pad macros if (lay_scanpool(pool,0.0,0.0,0.0,0,0, NULL,polyfunc,NULL,NULL,NULL,NULL,NULL)!=0) // Scan error error_scan(); // Check if pads found if (padl[padn].layn>0) padn++; } fprintf(fh,"$ENDPADS\n"); curpadname=""; // Write padstack data fprintf(fh,"$PADSTACKS\n"); fillstate=(-1); // Scan all padstack macro pool elements forall (pool where pool.TYP==1 && pool.MACRO.CLASS==DDBCLLSTK) { // Write the padstack description curstkname=pool.MACRO.NAME; fprintf(fh,"PADSTACK \"%s\"",curstkname); // Scan drills drillsize=0.0; if (lay_scanpool(pool,0.0,0.0,0.0,0,0, NULL,NULL,NULL,NULL,drillfunc,NULL,NULL)!=0) // Scan error error_scan(); writelen(drillsize); fprintf(fh,"\n"); // Scan pad macros if (lay_scanpool(pool,0.0,0.0,0.0,0,0, padmacrofunc,NULL,NULL,NULL,NULL,NULL,NULL)!=0) // Scan error error_scan(); } fprintf(fh,"$ENDPADSTACKS\n"); fprintf(fh,"$ARTWORKS\n$ENDARTWORKS\n"); fprintf(fh,"$SHAPES\n"); curlayer1=curlayer2=0; // Scan all part macros forall (pool where pool.TYP==1 && pool.MACRO.CLASS==DDBCLLPRT) { // Write the part description curpart=pool.MACRO.NAME; fprintf(fh,"SHAPE \"%s\"\n",curpart); // Write the part artwork curpart=pool.MACRO.NAME; curlayer1=curlayer2=SILKSCREEN|1; polyfound=0; // Scan macro if (lay_scanpool(pool,0.0,0.0,0.0,0,0, macrostopfunc2,polyfunc,NULL,NULL,NULL,laychk,NULL)!=0) // Scan error error_scan(); if (!polyfound) { fprintf(fh,"RECTANGLE"); writexy(pool.MACRO.MLX-pool.MACRO.MNX, pool.MACRO.MLY-pool.MACRO.MNY); writelen(pool.MACRO.MUX-pool.MACRO.MLX); writelen(pool.MACRO.MUY-pool.MACRO.MLY); fprintf(fh,"\n"); } // Scan pin macros if (lay_scanpool(pool,0.0,0.0,0.0,0,0, pinmacrofunc,NULL,NULL,NULL,NULL,NULL,NULL)!=0) // Scan error error_scan(); } fprintf(fh,"$ENDSHAPES\n"); // Write the component list fprintf(fh,"$COMPONENTS\n"); wsnx=bae_planwsnx(); wsny=bae_planwsny(); curlayer1=SILKSCREEN; curlayer2=SILKSCREEN|1; forall (fig where fig.TYP==L_FIGNREF) { nref=fig.NREF; // Check if connection part if (lay_findconpart(nref.NAME,cpart)!=0) continue; fprintf(fh,"COMPONENT \"%s\"\n",nref.NAME); fprintf(fh,"DEVICE \"%s\"\n",nref.NAME); fprintf(fh,"PLACE"); writexy(nref.X,nref.Y); plcside=2; if (SIDESCAN) if (lay_scanfelem(fig,0.0,0.0,0.0,0,0, NULL,NULL,NULL,textfunc,NULL,playchk,NULL)!=0) // Scan error error_scan(); fprintf(fh,"\nLAYER %s\n",plcside==0 ? "BOTTOM" : plcside==1 ? "TOP" : nref.MIRROR ? "BOTTOM" : "TOP"); fprintf(fh,"ROTATION"); writeangle(nref.ANGLE); fprintf(fh,"\nSHAPE \"%s\" %s %s\n",nref.MACRO.NAME, nref.MIRROR ? "MIRRORX" : "0",nref.MIRROR ? "FLIP" : "0"); } fprintf(fh,"$ENDCOMPONENTS\n"); fprintf(fh,"$DEVICES\n"); // Scan all part macros forall (nref) { // Scan the attributes if (lay_findconpart(nref.NAME,cpart)!=0) continue; atype=getlayattribval(cpart,ATTRTYPE); if (ALLOUT || getlayattribval(cpart,"$noplc")=="") { avalue=getlayattribval(cpart,ATTRVALUE); avolts=getlayattribval(cpart,ATTRVOLTS); adesc=getlayattribval(cpart,ATTRDESC); atol=getlayattribval(cpart,ATTRTOL); aattr=getlayattribval(cpart,ATTRATTR); } else { avalue=""; atol=""; avolts=""; adesc=""; aattr=""; } // Write the part device description fprintf(fh,"DEVICE \"%s\"\n",nref.NAME); fprintf(fh,"TYPE %s\n",atype=="" ? "UNKOWN" : atype); fprintf(fh,"PACKAGE \"%s\"\n",nref.MACRO.NAME); if (avalue!="") fprintf(fh,"VALUE \"%s\"\n",avalue); if (atol!="") fprintf(fh,"TOL \"%s\"\n",atol); if (avolts!="") fprintf(fh,"VOLTS %s\n",avolts); if (adesc!="") fprintf(fh,"DESC \"%s\"\n",adesc); if (aattr!="") fprintf(fh,"ATTRIBUTE %s\n",aattr); forall (rmod of nref where rmod.LAYER==LAYERALL) { sprintf(msgl[msgn],ERRPINMOVE,nref.NAME,rmod.STR); msgn++; } } fprintf(fh,"$ENDDEVICES\n"); fprintf(fh,"$SIGNALS\n"); forall (net) { fprintf(fh,"SIGNAL \"%s\"\n",net.NAME); forall (pin of net) { // Check if part placed if (ALLOUT==0 && getlayattribval(pin.CPART,"$noplc")!="") continue; fprintf(fh,"NODE \"%s\" \"%s\"\n", pin.CPART.NAME,pin.NAME); } nelemn++; } fprintf(fh,"$ENDSIGNALS\n"); neleml[nelemn].en=0; nelemn=0; forall (net) { neleml[nelemn].net=net; neleml[nelemn].en=0; nelemn++; } // Scan figure list to get the trace data forall (curfig where curfig.TYP==L_FIGPATH || curfig.TYP==L_FIGUREF) if (lay_scanfelem(curfig,0.0,0.0,0.0,0,0, vialfunc,NULL,pathlfunc,NULL,NULL,NULL,NULL)!=0) // Scan error error_scan(); // Scan figure list to get the polygon data forall (curfig where curfig.TYP==L_FIGPOLY) { poly=curfig.POLY; switch (poly.TYP) { case L_POLYCOPPASS : case L_POLYCOPACT : break; default : continue; } if (lay_scanfelem(curfig,0.0,0.0,0.0,0,0, NULL,polylfunc,NULL,NULL,NULL,NULL,NULL)!=0) // Scan error error_scan(); } fprintf(fh,"$TRACKS\n"); // Add the standard line width trcwl[trcwn++]=STDLINEWIDTH; // Search the path width lay_getplanchkparam(0.0,0.0,mindist,0,"",-1,0); for (i=0;i0.0) { fprintf(fh,"HOLE"); writexy(nref.X,nref.Y); writelen(drillsize); fprintf(fh,"\n"); continue; } if (DRILLMAC!="" && strmatch(nref.MACRO.NAME,DRILLMAC)) { drillsize=0.0; if (lay_scanfelem(fig,0.0,0.0,0.0,0,0, NULL,NULL,NULL,NULL,mdrillfunc,NULL,NULL)!=0) // Scan error error_scan(); if (drillsize>0.0) { fprintf(fh,"HOLE"); writexy(nref.X,nref.Y); writelen(drillsize); fprintf(fh,"\n"); continue; } } fprintf(fh,"MECHANICAL \"%s\"\n",nref.NAME); fprintf(fh,"PLACE"); writexy(nref.X,nref.Y); plcside=2; if (SIDESCAN) if (lay_scanfelem(fig,0.0,0.0,0.0,0,0, NULL,NULL,NULL,textfunc,NULL,playchk,NULL)!=0) // Scan error error_scan(); fprintf(fh,"\nLAYER %s\n",plcside==0 ? "BOTTOM" : plcside==1 ? "TOP" : nref.MIRROR ? "BOTTOM" : "TOP"); fprintf(fh,"ROTATION"); writeangle(nref.ANGLE); fprintf(fh,"\nSHAPE \"%s\" %s %s\n",nref.MACRO.NAME, nref.MIRROR ? "MIRRORX" : "0",nref.MIRROR ? "FLIP" : "0"); } fprintf(fh,"$ENDMECH\n"); } // Close the output file fclose(fh); } void writexy(double x,double y) /* // Write a x coordinate to the output file // Parameter : // double x : X coordinate value // double y : Y coordinate value */ { fprintf(fh," %.6f %.6f",(x-wsnx)*convfac,(y-wsny)*convfac); } void writeline(double x1,double y1,double x2,double y2) /* // Write a line to the output file // Parameter : // double x1,y1 : Segment start coordinate values // double x2,y2 : Segment end coordinate values */ { // Write the segment fprintf(fh,"LINE"); writexy(x1,y1); writexy(x2,y2); fprintf(fh,"\n"); } void writearc(double x1,double y1,double x2,double y2,double xc,double yc) /* // Write a segment to the output file // Parameter : // double x1,y1 : Arc start coordinate values // double x2,y2 : Arc end coordinate values // double xc,yc : Arc center coordinate values // double r : Arc radius */ { // Write the arc fprintf(fh,"ARC"); writexy(x1,y1); writexy(x2,y2); writexy(xc,yc); fprintf(fh,"\n"); } void writelen(double len) /* // Write a length to the output file // Parameter : // double len : Length value */ { if (len==0.0) fprintf(fh," 0"); else fprintf(fh," %.6f",len*convfac); } void writeangle(double ang) /* // Write a angle to the output file // Parameter : // double ang : Angle value */ { double outang /* Output angle */; // Adjust angle to [0.0,2*PI[ outang=ang; while (outang<0.0) outang+=2.0*PI; while (outang>=2.0*PI) outang-=2.0*PI; // Write the angle if (outang==0.0) fprintf(fh," 0"); else fprintf(fh," %.1f",cvtangle(outang,2,1)); } string padlname(string padname, int layer) /* // Get a layer based pad name // Return value : // Pad name // Parameter : // string padname : Pad base name // int layer : Layer number */ { string res /* Result string */; if (layer==0) res="pad_"+padname; else sprintf(res,"pad_%s_%x",padname,layer&0xffff); // Return the pad name return(res); } string glayname(int lay) /* // Get the GENCAD layer name for a BAE layer code // Return value : // Layer name // Parameter : // int lay : Layer number */ { string layname /* Layer name */; int i /* Loop control variable */; if (lay==0) return("BOTTOM"); if (lay==LAYERALL) return("ALL"); if (lay==lay_plantoplay() || lay==LAYERTOP) return("TOP"); if (lay>0 && lay=POWLAYBASE && lay=layfieldn) layname="UNKNOWN"; } return(layname); } int chklay(int lay) /* // Check a layer number for output // Return value : // 1 if layer out else zero // Parameter : // int lay : Layer number */ { int i /* Loop control variable */; // Check if signal layer if ((lay>=0 && lay=POWLAYBASE && lay=DOCLAYBASE) for (i=0;i