/********************************************************/ /* Routine de lecture d'un fichier GERBER format RS274X */ /********************************************************/ #include "fctsys.h" #include "common.h" #include "gerbview.h" #include "pcbplot.h" #include "protos.h" #define IsNumber(x) ( ( ((x) >= '0') && ((x) <='9') ) ||\ ((x) == '-') || ((x) == '+') || ((x) == '.') || ((x) == ',')) #define CODE(x,y) ((x<<8) + (y)) enum rs274x_parameters { FORMAT_STATEMENT_COMMAND = CODE('F','S'), AXIS_SELECT = CODE('A','S'), MIRROR_IMAGE = CODE('M','I'), MODE_OF_UNITS = CODE('M','O'), INCH = CODE('I','N'), MILLIMETER = CODE('M','M'), OFFSET = CODE('O','F'), SCALE_FACTOR = CODE('S','F'), IMAGE_NAME = CODE('I','N'), IMAGE_JUSTIFY = CODE('I','J'), IMAGE_OFFSET = CODE('I','O'), IMAGE_POLARITY = CODE('I','P'), IMAGE_ROTATION = CODE('I','R'), PLOTTER_FILM = CODE('P','M'), INCLUDE_FILE = CODE('I','F'), APERTURE_DESCR = CODE('A','D'), APERTURE_MACRO = CODE('A','M'), LAYER_NAME = CODE('L','N'), LAYER_POLARITY = CODE('L','P'), KNOCKOUT = CODE('K','O'), STEP_AND_REPEAT = CODE('S','P'), ROTATE = CODE('R','O') }; /* Variables locales : */ /* Routines Locales */ static bool ReadApertureMacro( char * buff, char * &text, FILE *gerber_file); /* Lit 2 codes ascii du texte pointé par text retourne le code correspondant ou -1 si erreur */ static int ReadXCommand(char * &text) { int result; if ( text && *text ) { result = (*text) << 8; text ++; } else return -1; if ( text && *text ) { result += (*text) & 255; text ++; } else return -1; return result; } /********************************/ static int ReadInt(char * &text) /********************************/ { int nb = 0; while ( text && *text == ' ' ) text++; // Skip blanks before number while ( text && *text) { if ( (*text >= '0') && (*text <='9') ) { nb *= 10; nb += *text & 0x0F; text++; } else break; } return nb; } /************************************/ static double ReadDouble(char * &text) /************************************/ { double nb = 0.0; char buf[256], * ptchar; ptchar = buf; while ( text && *text == ' ' ) text++; // Skip blanks before number while ( text && *text) { if ( IsNumber(*text) ) { * ptchar = * text; text++; ptchar ++; } else break; } *ptchar = 0; nb = atof(buf); return nb; } /****************************************************************************/ bool GERBER_Descr::ReadRS274XCommand(WinEDA_GerberFrame * frame, wxDC * DC, char * buff, char * &text) /****************************************************************************/ /* Lit toutes les commandes RS274X jusqu'a trouver de code de fin % appelle ExecuteRS274XCommand() pour chaque commande trouvée */ { int code_command; bool eof = FALSE; text++; do { while ( *text ) { switch( *text ) { case '%': // End commande text ++; m_CommandState = CMD_IDLE; return TRUE; case ' ': case '\r': case '\n': text++; break; case '*': text++; break; default: code_command = ReadXCommand ( text ); ExecuteRS274XCommand(code_command, buff, text); break; } } // End of current line if ( fgets(buff,255,m_Current_File) == NULL ) eof = TRUE; text = buff; } while( !eof ); return FALSE; } /*******************************************************************************/ bool GERBER_Descr::ExecuteRS274XCommand(int command, char * buff, char * &text) /*******************************************************************************/ /* Execute 1 commande RS274X */ { int code; int xy_seq_len, xy_seq_char; char ctmp; bool ok = TRUE; D_CODE * dcode; char Line[1024]; wxString msg; double fcoord; double conv_scale = m_GerbMetric ? PCB_INTERNAL_UNIT/25.4 : PCB_INTERNAL_UNIT; switch( command ) { case FORMAT_STATEMENT_COMMAND: xy_seq_len = 2; while ( *text != '*' ) { switch ( *text ) { case ' ': text++; break; case'L': // No Leading 0 m_NoTrailingZeros = FALSE; text ++; break; case'T': // No trailing 0 m_NoTrailingZeros = TRUE; text ++; break; case 'A': // Absolute coord m_Relative = FALSE; text++; break; case 'I': // Absolute coord m_Relative = TRUE; text++; break; case 'N': // Sequence code (followed by the number of digits for the X,Y command text++; xy_seq_char = * text; text++; if ( (xy_seq_char >= '0') && (xy_seq_char <= '9') ) xy_seq_len = - '0'; break; case 'X': case 'Y': // Valeurs transmises :2 (really xy_seq_len : FIX ME) digits code = *(text ++); ctmp = *(text++) - '0'; if ( code == 'X' ) { m_FmtScale.x = * text - '0'; // = nb chiffres apres la virgule m_FmtLen.x = ctmp + m_FmtScale.x; // = nb total de chiffres } else { m_FmtScale.y = * text - '0'; m_FmtLen.y = ctmp + m_FmtScale.y; } text++; break; case'*': break; default: GetEndOfBlock( buff, text, m_Current_File ); ok = FALSE; break; } } break; case AXIS_SELECT: case MIRROR_IMAGE: ok = FALSE; break; case MODE_OF_UNITS: code = ReadXCommand ( text ); if ( code == INCH ) m_GerbMetric = FALSE; else if ( code == MILLIMETER ) m_GerbMetric = TRUE; conv_scale = m_GerbMetric ? PCB_INTERNAL_UNIT/25.4 : PCB_INTERNAL_UNIT; break; case OFFSET: // command: OFAnnBnn (nn = float number) m_Offset.x = m_Offset.y = 0; while ( *text != '*' ) { switch ( *text ) { case'A': // A axis offset in current unit (inch ou mm) text ++; fcoord = ReadDouble(text); m_Offset.x = (int) round(fcoord * conv_scale); break; case'B': // B axis offset in current unit (inch ou mm) text ++; fcoord = ReadDouble(text); m_Offset.y = (int) round(fcoord * conv_scale); break; } } break; case SCALE_FACTOR: case IMAGE_JUSTIFY: case IMAGE_ROTATION : case IMAGE_OFFSET: case PLOTTER_FILM: case LAYER_NAME: case KNOCKOUT: case STEP_AND_REPEAT: case ROTATE: msg.Printf(_("Command <%c%c> ignored by Gerbview"), (command>>8) & 0xFF, command & 0xFF); if ( g_DebugLevel > 0 )wxMessageBox(msg); break; case IMAGE_NAME: m_Name.Empty(); while ( *text != '*' ) { m_Name.Append(*text); text++; } break; case IMAGE_POLARITY: if ( strnicmp(text, "NEG", 3 ) == 0 ) m_ImageNegative = TRUE; else m_ImageNegative = FALSE; break; case LAYER_POLARITY: if ( * text == 'C' ) m_LayerNegative = TRUE; else m_LayerNegative = FALSE; break; case APERTURE_MACRO: ReadApertureMacro( buff, text, m_Current_File ); break; case INCLUDE_FILE: if ( m_FilesPtr >= 10 ) { ok = FALSE; DisplayError(NULL, _("Too many include files!!") ); break; } strcpy(Line, text); strtok(Line,"*%%\n\r"); m_FilesList[m_FilesPtr] = m_Current_File; m_Current_File = fopen(Line,"rt"); if (m_Current_File == 0) { wxString msg; msg.Printf( wxT("fichier <%s> non trouve"),Line); DisplayError(NULL, msg, 10); ok = FALSE; m_Current_File = m_FilesList[m_FilesPtr]; break; } m_FilesPtr ++; break; case APERTURE_DESCR: if ( *text != 'D' ) { ok = FALSE; break; } m_As_DCode = TRUE; text++; code = ReadInt(text); ctmp = *text; dcode = ReturnToolDescr(m_Layer, code); if ( dcode == NULL ) break; if ( text[1] == ',' ) // Tool usuel (C,R,O,P) { text += 2; // text pointe size ( 1er modifier) dcode->m_Size.x = dcode->m_Size.y = (int) round(ReadDouble(text) * conv_scale); switch (ctmp ) { case 'C': // Circle dcode->m_Shape = GERB_CIRCLE; while ( * text == ' ' ) text++; if ( * text == 'X' ) { text++; dcode->m_Drill.x = dcode->m_Drill.y = (int) round(ReadDouble(text) * conv_scale); dcode->m_DrillShape = 1; } while ( * text == ' ' ) text++; if ( * text == 'X' ) { text++; dcode->m_Drill.y = (int) round(ReadDouble(text) * conv_scale); dcode->m_DrillShape = 2; } dcode->m_Defined = TRUE; break; case 'O': // ovale case 'R': // rect dcode->m_Shape = (ctmp == 'O') ? GERB_OVALE : GERB_RECT; while ( * text == ' ' ) text++; if ( * text == 'X' ) { text++; dcode->m_Size.y = (int) round(ReadDouble(text) * conv_scale); } while ( * text == ' ' ) text++; if ( * text == 'X' ) { text++; dcode->m_Drill.x = dcode->m_Drill.y = (int) round(ReadDouble(text) * conv_scale); dcode->m_DrillShape = 1; } while ( * text == ' ' ) text++; if ( * text == 'Y' ) { text++; dcode->m_Drill.y = (int) round(ReadDouble(text) * conv_scale); dcode->m_DrillShape = 2; } dcode->m_Defined = TRUE; break; case 'P': // Polygone // A modifier: temporairement la forme ronde est utilisée dcode->m_Shape = GERB_CIRCLE; dcode->m_Defined = TRUE; break; } } break; default: ok = FALSE; break; } GetEndOfBlock( buff, text, m_Current_File ); return ok; } /*****************************************************************/ bool GetEndOfBlock( char * buff, char * &text, FILE *gerber_file) /*****************************************************************/ { bool eof = FALSE; do { while ( (text < buff+255) && *text ) { if ( *text == '*' ) return TRUE; if ( *text == '%' ) return TRUE; text ++; } if ( fgets(buff,255,gerber_file) == NULL ) eof = TRUE; text = buff; } while( ! eof); return FALSE; } /*******************************************************************/ bool ReadApertureMacro( char * buff, char * &text, FILE *gerber_file) /*******************************************************************/ { wxString macro_name; int macro_type = 0; // Read macro name while ( (text < buff+255) && *text ) { if ( *text == '*' ) break; macro_name.Append(*text); text ++; } if ( g_DebugLevel > 0 ) wxMessageBox(macro_name, wxT("macro name")); text = buff; fgets(buff,255,gerber_file); // Read parameters macro_type = ReadInt(text); while ( (text < buff+255) && *text ) { if ( *text == '*' ) return TRUE; text ++; } return FALSE; }