kicad-source/eeschema/sch_eagle_plugin.cpp

644 lines
18 KiB
C++
Raw Normal View History

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 CERN
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <properties.h>
#include <wx/filename.h>
2017-03-09 13:49:24 +01:00
#include <memory>
2017-05-08 16:10:23 +02:00
#include <string>
#include <unordered_map>
2017-03-09 13:49:24 +01:00
#include <sch_sheet.h>
#include <sch_eagle_plugin.h>
2017-05-08 16:10:23 +02:00
#include <eagle_parser.h>
2017-03-09 13:49:24 +01:00
using namespace std;
2017-05-08 16:27:11 +02:00
NODE_MAP mapChildren( wxXmlNode* aCurrentNode )
2017-05-08 16:10:23 +02:00
{
// Map node_name -> node_pointer
2017-05-08 16:27:11 +02:00
NODE_MAP nodesMap;
2017-05-08 16:10:23 +02:00
// Loop through all children mapping them in nodesMap
2017-05-08 16:27:11 +02:00
aCurrentNode = aCurrentNode->GetChildren();
while( aCurrentNode )
2017-05-08 16:10:23 +02:00
{
// Create a new pair in the map
// key: current node name
// value: current node pointer
2017-05-08 16:27:11 +02:00
nodesMap[aCurrentNode->GetName().ToStdString()] = aCurrentNode;
2017-05-08 16:10:23 +02:00
// Get next child
2017-05-08 16:27:11 +02:00
aCurrentNode = aCurrentNode->GetNext();
2017-05-08 16:10:23 +02:00
}
return nodesMap;
}
void kicadLayer( int aEagleLayer )
{
/**
* Layers in Kicad schematics are not actually layers, but abstract groups mainly used to
* decide item colours.
*
* <layers>
* <layer number="90" name="Modules" color="5" fill="1" visible="yes" active="yes"/>
* <layer number="91" name="Nets" color="2" fill="1" visible="yes" active="yes"/>
* <layer number="92" name="Busses" color="1" fill="1" visible="yes" active="yes"/>
* <layer number="93" name="Pins" color="2" fill="1" visible="no" active="yes"/>
* <layer number="94" name="Symbols" color="4" fill="1" visible="yes" active="yes"/>
* <layer number="95" name="Names" color="7" fill="1" visible="yes" active="yes"/>
* <layer number="96" name="Values" color="7" fill="1" visible="yes" active="yes"/>
* <layer number="97" name="Info" color="7" fill="1" visible="yes" active="yes"/>
* <layer number="98" name="Guide" color="6" fill="1" visible="yes" active="yes"/>
* </layers>
*/
switch( aEagleLayer )
{
case 90: break;
case 91: break;
case 92: break;
case 93: break;
case 94: break;
case 95: break;
case 96: break;
case 97: break;
case 98: break;
}
}
SCH_EAGLE_PLUGIN::SCH_EAGLE_PLUGIN()
{
2017-03-09 13:49:24 +01:00
m_rootSheet = nullptr;
}
2017-05-08 16:10:23 +02:00
SCH_EAGLE_PLUGIN::~SCH_EAGLE_PLUGIN()
{
}
2017-03-09 13:49:24 +01:00
const wxString SCH_EAGLE_PLUGIN::GetName() const
{
return wxT( "EAGLE" );
}
const wxString SCH_EAGLE_PLUGIN::GetFileExtension() const
{
return wxT( "sch" );
}
int SCH_EAGLE_PLUGIN::GetModifyHash() const
{
return 0;
}
void SCH_EAGLE_PLUGIN::SaveLibrary( const wxString& aFileName, const PROPERTIES* aProperties )
{
}
SCH_SHEET* SCH_EAGLE_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway,
SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties )
{
2017-05-08 16:10:23 +02:00
// TODO: Handle Kiway and uncomment next line.
2017-03-09 13:49:24 +01:00
// wxASSERT( !aFileName || aKiway != NULL );
2017-03-09 13:49:24 +01:00
// Load the document
wxXmlDocument xmlDocument;
wxFileName fn = aFileName;
2017-03-09 13:49:24 +01:00
if( !xmlDocument.Load( fn.GetFullPath() ) )
2017-03-01 23:57:12 +01:00
THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'" ), fn.GetFullPath() ) );
2017-03-09 13:49:24 +01:00
// Delete on exception, if I own m_rootSheet, according to aAppendToMe
unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
if( aAppendToMe )
{
m_rootSheet = aAppendToMe->GetRootSheet();
}
else
{
m_rootSheet = new SCH_SHEET();
m_rootSheet->SetFileName( aFileName );
}
// Retrieve the root as current node
wxXmlNode* currentNode = xmlDocument.GetRoot();
// If the attribute is found, store the Eagle version;
// otherwise, store the dummy "0.0" version.
2017-05-08 16:10:23 +02:00
m_version = currentNode->GetAttribute( "version", "0.0" );
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
// Map all children into a readable dictionary
2017-05-08 16:27:11 +02:00
NODE_MAP children = mapChildren( currentNode );
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
// TODO: handle compatibility nodes
// wxXmlNode* compatibility = children["compatibility"];
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
// Load drawing
loadDrawing( children["drawing"] );
2017-03-09 13:49:24 +01:00
deleter.release();
return m_rootSheet;
}
2017-05-08 16:10:23 +02:00
void SCH_EAGLE_PLUGIN::loadDrawing( wxXmlNode* aDrawingNode )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
// Map all children into a readable dictionary
2017-05-08 16:27:11 +02:00
NODE_MAP drawingChildren = mapChildren( aDrawingNode );
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
// Board nodes should not appear in .sch files
// wxXmlNode* board = drawingChildren["board"]
// TODO: handle grid nodes
// wxXmlNode* grid = drawingChildren["grid"]
// TODO: handle layers nodes
// wxXmlNode* layers = drawingChildren["layers"]
// TODO: handle library nodes
// wxXmlNode* library = drawingChildren["library"]
// TODO: handle settings nodes
// wxXmlNode* settings = drawingChildren["settings"]
// Load schematic
loadSchematic( drawingChildren["schematic"] );
}
void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
{
// Map all children into a readable dictionary
2017-05-08 16:27:11 +02:00
NODE_MAP schematicChildren = mapChildren( aSchematicNode );
2017-05-08 16:10:23 +02:00
// TODO : handle classes nodes
2017-05-08 16:27:11 +02:00
//wxXmlNode* classes = schematicChildren["classes"];
2017-05-08 16:10:23 +02:00
// TODO : handle description nodes
// wxXmlNode* description = schematicChildren["description"];
// TODO : handle errors nodes
// wxXmlNode* errors = schematicChildren["errors"];
// TODO : handle modules nodes
// wxXmlNode* modules = schematicChildren["modules"];
// TODO : handle parts nodes
// wxXmlNode* parts = schematicChildren["parts"];
// TODO : handle variantdefs nodes
// wxXmlNode* variantdefs = schematicChildren["variantdefs"];
// TODO: handle attributes node
// wxXmlNode* attributes = schematicChildren["attributes"];
// Possible children: constant, display, font, layer, name, ratio, rot, size, value, x, y
// Loop through all the libraries
wxXmlNode* libraryNode = schematicChildren["libraries"]->GetChildren();
2017-05-08 16:27:11 +02:00
2017-05-08 16:10:23 +02:00
while( libraryNode )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
loadLibrary( libraryNode );
libraryNode = libraryNode->GetNext();
}
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
// Loop through all the sheets
wxXmlNode* sheetNode = schematicChildren["sheets"]->GetChildren();
2017-05-08 16:27:11 +02:00
2017-05-08 16:10:23 +02:00
while( sheetNode )
{
loadSheet( sheetNode );
sheetNode = sheetNode->GetNext();
}
}
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode )
{
// Map all children into a readable dictionary
2017-05-08 16:27:11 +02:00
NODE_MAP sheetChildren = mapChildren( aSheetNode );
2017-05-08 16:10:23 +02:00
// Loop through all busses
// From the DTD: "Buses receive names which determine which signals they include.
// A bus is a drawing object. It does not create any electrical connections.
// These are always created by means of the nets and their names."
wxXmlNode* busNode = sheetChildren["busses"]->GetChildren();
2017-05-08 16:27:11 +02:00
2017-05-08 16:10:23 +02:00
while( busNode )
{
// Get the bus name
wxString busName = busNode->GetAttribute( "name" );
// Load segments of this bus
loadSegments( busNode );
// Get next bus
busNode = busNode->GetNext();
}
// Loop through all nets
// From the DTD: "Net is an electrical connection in a schematic."
wxXmlNode* netNode = sheetChildren["nets"]->GetChildren();
2017-05-08 16:27:11 +02:00
2017-05-08 16:10:23 +02:00
while( netNode )
{
// Get the net name and class
wxString netName = netNode->GetAttribute( "name" );
wxString netClass = netNode->GetAttribute( "class" );
// Load segments of this net
loadSegments( netNode );
// Get next net
netNode = netNode->GetNext();
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
// Loop through all instances
wxXmlNode* instanceNode = sheetChildren["instances"]->GetChildren();
2017-05-08 16:27:11 +02:00
2017-05-08 16:10:23 +02:00
while( instanceNode )
{
loadInstance( instanceNode );
instanceNode = instanceNode->GetNext();
}
// Loop through all moduleinsts
wxXmlNode* moduleinstNode = sheetChildren["moduleinsts"]->GetChildren();
2017-05-08 16:27:11 +02:00
2017-05-08 16:10:23 +02:00
while( moduleinstNode )
{
loadModuleinst( moduleinstNode );
moduleinstNode = moduleinstNode->GetNext();
}
// TODO: do something with the description
// wxXmlNode* description = sheetChildren["description"];
// wxString language = description->GetAttribute( "language", "en" ); // Defaults to "en"
// wxString description = description->GetNodeContent();
// TODO: do something with the plain
// wxXmlNode* plain = sheetChildren["plain"];
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
void SCH_EAGLE_PLUGIN::loadSegments( wxXmlNode* aSegmentsNode )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
// Loop through all segments
wxXmlNode* currentSegment = aSegmentsNode->GetChildren();
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
while( currentSegment )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
// Loop through all segment children
wxXmlNode* segmentAttribute = currentSegment->GetChildren();
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
while( segmentAttribute )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
wxString nodeName = segmentAttribute->GetName();
if( nodeName == "junction" )
{
// TODO: handle junctions attributes
segmentAttribute->GetAttribute( "x" );
segmentAttribute->GetAttribute( "y" );
}
else if( nodeName == "label" )
{
// TODO: handle labels attributes
segmentAttribute->GetAttribute( "x" ); // REQUIRED
segmentAttribute->GetAttribute( "y" ); // REQUIRED
segmentAttribute->GetAttribute( "size" ); // REQUIRED
segmentAttribute->GetAttribute( "layer" ); // REQUIRED
segmentAttribute->GetAttribute( "font" ); // Defaults to "proportional"
segmentAttribute->GetAttribute( "ratio" ); // Defaults to "8"
segmentAttribute->GetAttribute( "rot" ); // Defaults to "R0"
segmentAttribute->GetAttribute( "xref" ); // Defaults to "no"
}
else if( nodeName == "pinref" )
{
// TODO: handle pinref attributes
segmentAttribute->GetAttribute( "gate" ); // REQUIRED
segmentAttribute->GetAttribute( "part" ); // REQUIRED
segmentAttribute->GetAttribute( "pin" ); // REQUIRED
}
else if( nodeName == "portref" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
// TODO: handle portref attributes
segmentAttribute->GetAttribute( "moduleinst" ); // REQUIRED
segmentAttribute->GetAttribute( "port" ); // REQUIRED
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "wire" )
{
loadWire( segmentAttribute );
}
else // DEFAULT
{
THROW_IO_ERROR( wxString::Format( _( "XML node '%s' unknown" ), nodeName ) );
}
// Get next segment attribute
segmentAttribute = segmentAttribute->GetNext();
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
currentSegment = currentSegment->GetNext();
}
}
SCH_LINE* SCH_EAGLE_PLUGIN::loadWire( wxXmlNode* aWireNode )
{
std::unique_ptr< SCH_LINE > wire( new SCH_LINE );
wxString layer = aWireNode->GetAttribute( "layer" ); // REQUIRED
wxString width = aWireNode->GetAttribute( "width" ); // REQUIRED
wxString x1 = aWireNode->GetAttribute( "x1" ); // REQUIRED
wxString x2 = aWireNode->GetAttribute( "x2" ); // REQUIRED
wxString y1 = aWireNode->GetAttribute( "y1" ); // REQUIRED
wxString y2 = aWireNode->GetAttribute( "y2" ); // REQUIRED
wxString cap = aWireNode->GetAttribute( "cap", "round" ); // Defaults to "round"
wxString curve = aWireNode->GetAttribute( "curve", "0" ); // Defaults to "0"
wxString style = aWireNode->GetAttribute( "style", "continuous" ); // Defaults to "continuous"
// wxString extent = aWireNode->GetAttribute( "extent" ); // Non-required, defaults to NOTHING
// TODO: layer map?
// wire->SetLayer( layerMap( layer ) );
// if( strCompare( "Wire", line, &line ) )
// wire->SetLayer( LAYER_WIRE );
// else if( strCompare( "Bus", line, &line ) )
// wire->SetLayer( LAYER_BUS );
// else if( strCompare( "Notes", line, &line ) )
// wire->SetLayer( LAYER_NOTES );
// else
// SCH_PARSE_ERROR( "invalid line type", aReader, line );
wxPoint begin, end;
begin.x = wxAtoi( x1 );
begin.y = wxAtoi( y1 );
end.x = wxAtoi( x2 );
end.y = wxAtoi( y2 );
wire->SetStartPoint( begin );
wire->SetEndPoint( end );
return wire.release();
}
void SCH_EAGLE_PLUGIN::loadInstance( wxXmlNode* aInstanceNode )
{
}
void SCH_EAGLE_PLUGIN::loadModuleinst( wxXmlNode* aModuleinstNode )
{
}
void SCH_EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLibraryNode )
{
// Read the library name
wxString libName = aLibraryNode->GetAttribute( "name" );
// Query all children and map them into a readable dictionary
2017-05-08 16:27:11 +02:00
NODE_MAP libraryChildren = mapChildren( aLibraryNode );
2017-05-08 16:10:23 +02:00
// TODO: Do something with the description
// wxXmlNode* libraryChildren["description"];
// Loop through the devicesets and load each of them
2017-05-08 16:27:11 +02:00
// wxXmlNode* devicesetNode = libraryChildren["devicesets"]->GetChildren();
2017-05-08 16:10:23 +02:00
// while( devicesetNode )
// {
// loadDeviceset( devicesetNode );
// devicesetNode = devicesetNode->GetNext();
// }
// Loop through the packages and load each of them
2017-05-08 16:27:11 +02:00
// wxXmlNode* packageNode = libraryChildren["packages"]->GetChildren();
2017-05-08 16:10:23 +02:00
// while( packageNode )
// {
// loadPackage( packageNode );
// packageNode = packageNode->GetNext();
// }
// Loop through the symbols and load each of them
wxXmlNode* symbolNode = libraryChildren["symbols"]->GetChildren();
2017-05-08 16:27:11 +02:00
2017-05-08 16:10:23 +02:00
while( symbolNode )
{
loadSymbol( symbolNode );
symbolNode = symbolNode->GetNext();
}
}
LIB_PART* SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode )
{
// Create a new part with the symbol name
wxString symbolName = aSymbolNode->GetAttribute( "name" );
2017-05-08 16:27:11 +02:00
std::unique_ptr<LIB_PART> part( new LIB_PART( symbolName ) );
2017-05-08 16:10:23 +02:00
wxXmlNode* currentNode = aSymbolNode->GetChildren();
while( currentNode )
{
wxString nodeName = currentNode->GetName();
if( nodeName == "description" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:27:11 +02:00
// TODO
wxASSERT_MSG( false, "'description' nodes are not implemented yet" );
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "dimension" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:27:11 +02:00
// TODO
wxASSERT_MSG( false, "'description' nodes are not implemented yet" );
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "frame" )
2017-03-09 13:49:24 +01:00
{
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "circle" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
part->AddDrawItem( loadCircle( part, currentNode ) );
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "pin" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
part->AddDrawItem( loadPin( part, currentNode ) );
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "polygon" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
part->AddDrawItem( loadPolyline( part, currentNode ) );
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "rectangle" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
part->AddDrawItem( loadRectangle( part, currentNode ) );
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "text" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
part->AddDrawItem( loadText( part, currentNode ) );
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
else if( nodeName == "wire" )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
part->AddDrawItem( loadPolyline( part, currentNode ) );
2017-03-09 13:49:24 +01:00
}
currentNode = currentNode->GetNext();
}
2017-05-08 16:10:23 +02:00
return part.release();
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:27:11 +02:00
2017-05-08 16:10:23 +02:00
LIB_CIRCLE* SCH_EAGLE_PLUGIN::loadCircle( LIB_PART* aPart, wxXmlNode* aCircleNode )
2017-03-09 13:49:24 +01:00
{
2017-05-08 16:10:23 +02:00
unique_ptr< LIB_CIRCLE > circle( new LIB_CIRCLE( aPart.get() ) );
int layer = wxAtoi( aCircleNode->GetAttribute( "layer" ) );
int x;
int y;
int radius;
int width;
aCircleNode->GetAttribute( "x" ).ToDouble( &x );
aCircleNode->GetAttribute( "y" ).ToDouble( &y );
aCircleNode->GetAttribute( "radius" ).ToDouble( &radius );
aCircleNode->GetAttribute( "width" ).ToDouble( &width );
2017-03-09 13:49:24 +01:00
2017-05-08 16:10:23 +02:00
circle->SetPosition( wxPoint( x, y ) );
circle->SetRadius( radius );
circle->SetWidth( width ;
return circle.release();
2017-03-09 13:49:24 +01:00
}
2017-05-08 16:10:23 +02:00
void SCH_EAGLE_PLUGIN::Save( const wxString& aFileName, SCH_SCREEN* aSchematic, KIWAY* aKiway,
const PROPERTIES* aProperties )
{
}
size_t SCH_EAGLE_PLUGIN::GetSymbolLibCount( const wxString& aLibraryPath,
const PROPERTIES* aProperties )
{
return 0;
}
void SCH_EAGLE_PLUGIN::EnumerateSymbolLib( wxArrayString& aAliasNameList,
const wxString& aLibraryPath,
const PROPERTIES* aProperties )
{
}
LIB_ALIAS* SCH_EAGLE_PLUGIN::LoadSymbol( const wxString& aLibraryPath, const wxString& aSymbolName,
const PROPERTIES* aProperties )
{
return nullptr;
}
void SCH_EAGLE_PLUGIN::SaveSymbol( const wxString& aLibraryPath, const LIB_PART* aSymbol,
const PROPERTIES* aProperties )
{
}
void SCH_EAGLE_PLUGIN::DeleteAlias( const wxString& aLibraryPath, const wxString& aAliasName,
const PROPERTIES* aProperties )
{
}
void SCH_EAGLE_PLUGIN::DeleteSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
const PROPERTIES* aProperties )
{
}
void SCH_EAGLE_PLUGIN::CreateSymbolLib( const wxString& aLibraryPath,
const PROPERTIES* aProperties )
{
}
bool SCH_EAGLE_PLUGIN::DeleteSymbolLib( const wxString& aLibraryPath,
const PROPERTIES* aProperties )
{
return false;
}
bool SCH_EAGLE_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath )
{
return false;
}
2017-05-08 16:10:23 +02:00
void SCH_EAGLE_PLUGIN::SymbolLibOptions( PROPERTIES* aListToAppendTo ) const
{
}
2017-05-08 16:10:23 +02:00
// approved
// attribute
// circle
// clearance
// connect
// contactref
// description
// dimension
// frame
// gate
// grid
// hole
// junction
// label
// layer
// note
// pad
// param
// pin
// pinref
// port
// portref
// rectangle
// setting
// smd
// textvariant
// variantdef
// vertex
// via
// wire