/********************************************************/ /* 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 */ { bool ok = true; int code_command; text++; for(;;) { while( *text ) { switch( *text ) { case '%': // End commande text++; m_CommandState = CMD_IDLE; goto exit; // success completion case ' ': case '\r': case '\n': text++; break; case '*': text++; break; default: code_command = ReadXCommand( text ); ok = ExecuteRS274XCommand( code_command, buff, text ); if( !ok ) goto exit; break; } } // End of current line if( fgets( buff, 255, m_Current_File ) == NULL ) { ok = false; break; } text = buff; } exit: return ok; } /*******************************************************************************/ 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; } ok = GetEndOfBlock( buff, text, m_Current_File ); return ok; } /*****************************************************************/ bool GetEndOfBlock( char* buff, char*& text, FILE* gerber_file ) /*****************************************************************/ { for(;;) { while( (text < buff + 255) && *text ) { if( *text == '*' ) return TRUE; if( *text == '%' ) return TRUE; text++; } if( fgets( buff, 255, gerber_file ) == NULL ) break; text = buff; } 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; }