Footprint Wizards Update
This commit is contained in:
parent
d1278a48b6
commit
66ee44cb1f
|
@ -151,11 +151,17 @@ static void InitKiCadAboutNew( AboutAppInfo& info )
|
|||
<< HtmlHyperlink( wxT( "https://launchpad.net/kicad" ),
|
||||
_( "Developer's website on Launchpad" ) )
|
||||
<< wxT("</li>" );
|
||||
|
||||
description << wxT( "<li>" )
|
||||
<< HtmlHyperlink( wxT( "https://github.com/KiCad/" ),
|
||||
_( "Our official Repository for component and footprint libraries" ) )
|
||||
<< wxT( "</li>" );
|
||||
|
||||
description << wxT( "<li>" )
|
||||
<< HtmlHyperlink( wxT( "https://github.com/KiCad/Footprint_Wizards" ),
|
||||
_( "Footprint wizards info on our official repository " ) )
|
||||
<< wxT( "</li>" );
|
||||
|
||||
description << wxT( "<p><u>" )
|
||||
<< _( "Non official repositories" )
|
||||
<< wxT( "</u>" );
|
||||
|
|
|
@ -33,6 +33,17 @@
|
|||
#include <vector>
|
||||
#include <wxPcbStruct.h>
|
||||
|
||||
// Allowable parameter types for PCB wizards
|
||||
const wxString WIZARD_PARAM_UNITS_MM = "mm"; // Millimetres
|
||||
const wxString WIZARD_PARAM_UNITS_MILS = "mils"; // Mils / thou
|
||||
const wxString WIZARD_PARAM_UNITS_FLOAT = "float"; // Floating point (dimensionless)
|
||||
const wxString WIZARD_PARAM_UNITS_INTEGER = "integer"; // Integer (dimensionless)
|
||||
const wxString WIZARD_PARAM_UNITS_BOOL = "bool"; // Boolean option
|
||||
const wxString WIZARD_PARAM_UNITS_RADIANS = "radians"; // Angle (radians)
|
||||
const wxString WIZARD_PARAM_UNITS_DEGREES = "degrees"; // Angle (degrees)
|
||||
const wxString WIZARD_PARAM_UNITS_PERCENT = "%"; // Percent (0% -> 100%)
|
||||
const wxString WIZARD_PARAM_UNITS_STRING = "string"; // String
|
||||
|
||||
/**
|
||||
* Class FOOTPRINT_WIZARD
|
||||
* This is the parent class from where any footprint wizard class must
|
||||
|
@ -104,6 +115,20 @@ public:
|
|||
*/
|
||||
virtual wxArrayString GetParameterErrors( int aPage ) = 0;
|
||||
|
||||
/**
|
||||
* Function GetParameterHints
|
||||
* @param aPage is the page we want to know the hints of
|
||||
* @return an array of hints (if any) for the parameters, empty string for no hints
|
||||
*/
|
||||
virtual wxArrayString GetParameterHints( int aPage ) = 0;
|
||||
|
||||
/**
|
||||
* Function GetParamaterDesignators
|
||||
* @param aPage is the page we want to know the designators of
|
||||
* @return an array of designators (blank strings for no designators
|
||||
*/
|
||||
virtual wxArrayString GetParameterDesignators( int aPage ) = 0;
|
||||
|
||||
/**
|
||||
* Function SetParameterValues
|
||||
* @param aPage is the page we want to set the parameters in
|
||||
|
@ -112,6 +137,12 @@ public:
|
|||
*/
|
||||
virtual wxString SetParameterValues( int aPage, wxArrayString& aValues ) = 0;
|
||||
|
||||
/**
|
||||
* Function ResetParameters
|
||||
* Reset all wizard parameters to default values
|
||||
*/
|
||||
virtual void ResetParameters() = 0;
|
||||
|
||||
/**
|
||||
* Function GetModule
|
||||
* This method builds the module itself and returns it to the caller function
|
||||
|
|
|
@ -203,6 +203,22 @@ void FOOTPRINT_WIZARD_FRAME::SelectCurrentWizard( wxCommandEvent& event )
|
|||
SelectFootprintWizard();
|
||||
}
|
||||
|
||||
void FOOTPRINT_WIZARD_FRAME::DefaultParameters( wxCommandEvent& event )
|
||||
{
|
||||
FOOTPRINT_WIZARD* footprintWizard = GetMyWizard();
|
||||
|
||||
if ( footprintWizard == NULL )
|
||||
return;
|
||||
|
||||
footprintWizard->ResetParameters();
|
||||
|
||||
// Reload
|
||||
ReCreateParameterList();
|
||||
ReloadFootprint();
|
||||
DisplayWizardInfos();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void FOOTPRINT_WIZARD_FRAME::ParametersUpdated( wxGridEvent& event )
|
||||
{
|
||||
|
@ -223,39 +239,12 @@ void FOOTPRINT_WIZARD_FRAME::ParametersUpdated( wxGridEvent& event )
|
|||
int count = m_parameterGrid->GetNumberRows();
|
||||
|
||||
// Skip extra event, useless
|
||||
if( event.GetString() == m_parameterGrid->GetCellValue( event.GetRow(), m_columnPrmValue ) )
|
||||
if( event.GetString() == m_parameterGrid->GetCellValue( event.GetRow(), WIZ_COL_VALUE ) )
|
||||
return;
|
||||
|
||||
for( int prm_id = 0; prm_id < count; ++prm_id )
|
||||
{
|
||||
wxString value = m_parameterGrid->GetCellValue( prm_id, m_columnPrmValue );
|
||||
|
||||
// if this parameter is expected to be an internal
|
||||
// unit convert it back from the user format
|
||||
if( ptList[prm_id]==wxT( "IU" ) )
|
||||
{
|
||||
// If our locale is set to use, for decimal point, just change it
|
||||
// to be scripting compatible
|
||||
LOCALE_IO toggle;
|
||||
double dValue;
|
||||
|
||||
value.ToDouble( &dValue );
|
||||
|
||||
// convert from mils to inches where it's needed
|
||||
if( g_UserUnit==INCHES )
|
||||
dValue = dValue / 1000.0;
|
||||
|
||||
dValue = From_User_Unit( g_UserUnit, dValue );
|
||||
|
||||
// Internal units are int. Print them as int.
|
||||
value.Printf( "%d", KiROUND( dValue ) );
|
||||
|
||||
if( prmValues[prm_id].EndsWith(".0") )
|
||||
{
|
||||
prmValues[prm_id].RemoveLast();
|
||||
prmValues[prm_id].RemoveLast();
|
||||
}
|
||||
}
|
||||
wxString value = m_parameterGrid->GetCellValue( prm_id, WIZ_COL_VALUE);
|
||||
|
||||
if( prmValues[prm_id] != value )
|
||||
{
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#include "footprint_wizard_frame.h"
|
||||
#include <footprint_info.h>
|
||||
#include <wx/grid.h>
|
||||
#include <wx/tokenzr.h>
|
||||
#include <wx/numformatter.h>
|
||||
|
||||
#include <hotkeys.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
|
@ -61,6 +63,9 @@ BEGIN_EVENT_TABLE( FOOTPRINT_WIZARD_FRAME, EDA_DRAW_FRAME )
|
|||
EVT_TOOL( ID_FOOTPRINT_WIZARD_SELECT_WIZARD,
|
||||
FOOTPRINT_WIZARD_FRAME::SelectCurrentWizard )
|
||||
|
||||
EVT_TOOL( ID_FOOTPRINT_WIZARD_RESET_TO_DEFAULT,
|
||||
FOOTPRINT_WIZARD_FRAME::DefaultParameters )
|
||||
|
||||
EVT_TOOL( ID_FOOTPRINT_WIZARD_NEXT,
|
||||
FOOTPRINT_WIZARD_FRAME::Process_Special_Functions )
|
||||
|
||||
|
@ -74,6 +79,7 @@ BEGIN_EVENT_TABLE( FOOTPRINT_WIZARD_FRAME, EDA_DRAW_FRAME )
|
|||
FOOTPRINT_WIZARD_FRAME::Show3D_Frame )
|
||||
|
||||
// listbox events
|
||||
|
||||
EVT_LISTBOX( ID_FOOTPRINT_WIZARD_PAGE_LIST, FOOTPRINT_WIZARD_FRAME::ClickOnPageList )
|
||||
EVT_GRID_CMD_CELL_CHANGED( ID_FOOTPRINT_WIZARD_PARAMETER_LIST,
|
||||
FOOTPRINT_WIZARD_FRAME::ParametersUpdated )
|
||||
|
@ -81,10 +87,6 @@ BEGIN_EVENT_TABLE( FOOTPRINT_WIZARD_FRAME, EDA_DRAW_FRAME )
|
|||
EVT_MENU( ID_SET_RELATIVE_OFFSET, FOOTPRINT_WIZARD_FRAME::OnSetRelativeOffset )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// Column index to display parameters in m_parameterGrid
|
||||
int FOOTPRINT_WIZARD_FRAME::m_columnPrmName = 0;
|
||||
int FOOTPRINT_WIZARD_FRAME::m_columnPrmValue = 1;
|
||||
int FOOTPRINT_WIZARD_FRAME::m_columnPrmUnit = 2;
|
||||
|
||||
#define FOOTPRINT_WIZARD_FRAME_NAME wxT( "FootprintWizard" )
|
||||
|
||||
|
@ -255,6 +257,13 @@ void FOOTPRINT_WIZARD_FRAME::ExportSelectedFootprint( wxCommandEvent& aEvent )
|
|||
Close();
|
||||
}
|
||||
|
||||
void FOOTPRINT_WIZARD_FRAME::OnGridSize( wxSizeEvent& aSizeEvent )
|
||||
{
|
||||
// Resize the parameter columns
|
||||
ResizeParamColumns();
|
||||
|
||||
aSizeEvent.Skip();
|
||||
}
|
||||
|
||||
void FOOTPRINT_WIZARD_FRAME::OnSize( wxSizeEvent& SizeEv )
|
||||
{
|
||||
|
@ -278,9 +287,10 @@ void FOOTPRINT_WIZARD_FRAME::initParameterGrid()
|
|||
m_parameterGrid->CreateGrid( 0, 3 );
|
||||
|
||||
// Columns
|
||||
m_parameterGrid->SetColLabelValue( m_columnPrmName, _( "Parameter" ) );
|
||||
m_parameterGrid->SetColLabelValue( m_columnPrmValue, _( "Value" ) );
|
||||
m_parameterGrid->SetColLabelValue( m_columnPrmUnit, _( "Units" ) );
|
||||
m_parameterGrid->SetColLabelValue( WIZ_COL_NAME, _( "Parameter" ) );
|
||||
m_parameterGrid->SetColLabelValue( WIZ_COL_VALUE, _( "Value" ) );
|
||||
m_parameterGrid->SetColLabelValue( WIZ_COL_UNITS, _( "Units" ) );
|
||||
|
||||
m_parameterGrid->SetColLabelAlignment( wxALIGN_LEFT, wxALIGN_CENTRE );
|
||||
m_parameterGrid->AutoSizeColumns();
|
||||
|
||||
|
@ -288,6 +298,11 @@ void FOOTPRINT_WIZARD_FRAME::initParameterGrid()
|
|||
m_parameterGrid->AutoSizeRows();
|
||||
m_parameterGrid->SetRowLabelSize( 25 );
|
||||
m_parameterGrid->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE );
|
||||
|
||||
m_parameterGrid->DisableDragGridSize();
|
||||
m_parameterGrid->DisableDragColSize();
|
||||
|
||||
m_parameterGrid->Connect( wxEVT_SIZE, wxSizeEventHandler(FOOTPRINT_WIZARD_FRAME::OnGridSize), NULL, this );
|
||||
}
|
||||
|
||||
|
||||
|
@ -336,63 +351,117 @@ void FOOTPRINT_WIZARD_FRAME::ReCreateParameterList()
|
|||
|
||||
m_parameterGrid->ClearGrid();
|
||||
|
||||
// Get the list of names, values, and types
|
||||
wxArrayString fpList = footprintWizard->GetParameterNames( page );
|
||||
wxArrayString fvList = footprintWizard->GetParameterValues( page );
|
||||
wxArrayString ptList = footprintWizard->GetParameterTypes( page );
|
||||
// Get the list of names, values, types, hints and designators
|
||||
wxArrayString designatorsList = footprintWizard->GetParameterDesignators( page );
|
||||
wxArrayString namesList = footprintWizard->GetParameterNames( page );
|
||||
wxArrayString valuesList = footprintWizard->GetParameterValues( page );
|
||||
wxArrayString typesList = footprintWizard->GetParameterTypes( page );
|
||||
wxArrayString hintsList = footprintWizard->GetParameterHints( page );
|
||||
|
||||
// Dimension the wxGrid
|
||||
if( m_parameterGrid->GetNumberRows() > 0 )
|
||||
m_parameterGrid->DeleteRows( 0, m_parameterGrid->GetNumberRows() );
|
||||
|
||||
m_parameterGrid->AppendRows( fpList.size() );
|
||||
m_parameterGrid->AppendRows( namesList.size() );
|
||||
|
||||
wxString value, units;
|
||||
for( unsigned int i = 0; i< fpList.size(); i++ )
|
||||
wxString designator, name, value, units, hint;
|
||||
|
||||
for( unsigned int i = 0; i< namesList.size(); i++ )
|
||||
{
|
||||
value = fvList[i];
|
||||
designator = designatorsList[i];
|
||||
name = namesList[i];
|
||||
value = valuesList[i];
|
||||
units = typesList[i];
|
||||
hint = hintsList[i];
|
||||
|
||||
m_parameterGrid->SetCellValue( i, m_columnPrmName, fpList[i] );
|
||||
m_parameterGrid->SetReadOnly( i, m_columnPrmName );
|
||||
m_parameterGrid->SetRowLabelValue( i, designator );
|
||||
|
||||
if( ptList[i]==wxT( "IU" ) )
|
||||
// Set the 'Name'
|
||||
m_parameterGrid->SetCellValue( i, WIZ_COL_NAME, name );
|
||||
m_parameterGrid->SetReadOnly( i, WIZ_COL_NAME );
|
||||
m_parameterGrid->SetCellAlignment( i, WIZ_COL_NAME, wxALIGN_LEFT, wxALIGN_CENTRE );
|
||||
|
||||
// Set the editor type of the
|
||||
|
||||
// Boolean parameters can be displayed using a checkbox
|
||||
if ( units == WIZARD_PARAM_UNITS_BOOL )
|
||||
{
|
||||
LOCALE_IO toggle;
|
||||
wxGridCellBoolEditor *boolEditor = new wxGridCellBoolEditor;
|
||||
boolEditor->UseStringValues("True","False");
|
||||
m_parameterGrid->SetCellEditor( i, WIZ_COL_VALUE, boolEditor );
|
||||
|
||||
// We are handling internal units, so convert them to the current
|
||||
// system selected units and store into value.
|
||||
double dValue;
|
||||
|
||||
value.ToDouble( &dValue );
|
||||
|
||||
dValue = To_User_Unit( g_UserUnit, dValue );
|
||||
|
||||
if( g_UserUnit==INCHES ) // we convert inches into mils for more detail
|
||||
{
|
||||
dValue = dValue * 1000.0;
|
||||
units = wxT( "mils" );
|
||||
}
|
||||
else if( g_UserUnit==MILLIMETRES )
|
||||
{
|
||||
units = wxT( "mm" );
|
||||
}
|
||||
|
||||
// Use Double2Str to build the string, because useless trailing 0
|
||||
// are removed. The %f format does not remove them
|
||||
std::string s = Double2Str( dValue );
|
||||
value = FROM_UTF8( s.c_str() );
|
||||
m_parameterGrid->SetCellRenderer( i, WIZ_COL_VALUE, new wxGridCellBoolRenderer );
|
||||
}
|
||||
else if( ptList[i]==wxT( "UNITS" ) ) // 1,2,3,4,5 ... N
|
||||
// Parameters that can be selected from a list of multiple options
|
||||
else if ( units.Contains( "," ) ) // Indicates list of available options
|
||||
{
|
||||
wxStringTokenizer tokenizer( units, "," );
|
||||
wxArrayString options;
|
||||
|
||||
while ( tokenizer.HasMoreTokens() )
|
||||
{
|
||||
options.Add( tokenizer.GetNextToken() );
|
||||
}
|
||||
|
||||
m_parameterGrid->SetCellEditor( i, WIZ_COL_VALUE, new wxGridCellChoiceEditor( options ) );
|
||||
|
||||
units = wxT( "" );
|
||||
}
|
||||
// Integer parameters
|
||||
else if ( units == WIZARD_PARAM_UNITS_INTEGER )
|
||||
{
|
||||
m_parameterGrid->SetCellEditor( i, WIZ_COL_VALUE, new wxGridCellNumberEditor );
|
||||
}
|
||||
// Non-integer numerical parameters
|
||||
else if ( ( units == WIZARD_PARAM_UNITS_MM ) ||
|
||||
( units == WIZARD_PARAM_UNITS_MILS ) ||
|
||||
( units == WIZARD_PARAM_UNITS_FLOAT ) ||
|
||||
( units == WIZARD_PARAM_UNITS_RADIANS ) ||
|
||||
( units == WIZARD_PARAM_UNITS_DEGREES ) ||
|
||||
( units == WIZARD_PARAM_UNITS_PERCENT ) )
|
||||
{
|
||||
m_parameterGrid->SetCellEditor( i, WIZ_COL_VALUE, new wxGridCellFloatEditor );
|
||||
|
||||
m_parameterGrid->SetCellValue( i, m_columnPrmValue, value );
|
||||
m_parameterGrid->SetCellValue( i, m_columnPrmUnit, units );
|
||||
m_parameterGrid->SetReadOnly( i, m_columnPrmUnit );
|
||||
// Convert separators to the locale-specific character
|
||||
value.Replace( ",", wxNumberFormatter::GetDecimalSeparator() );
|
||||
value.Replace( ".", wxNumberFormatter::GetDecimalSeparator() );
|
||||
}
|
||||
|
||||
|
||||
// Set the 'Units'
|
||||
m_parameterGrid->SetCellValue( i, WIZ_COL_UNITS, units );
|
||||
m_parameterGrid->SetReadOnly( i, WIZ_COL_UNITS );
|
||||
m_parameterGrid->SetCellAlignment( i, WIZ_COL_UNITS, wxALIGN_LEFT, wxALIGN_CENTRE );
|
||||
|
||||
// Set the 'Value'
|
||||
m_parameterGrid->SetCellValue( i, WIZ_COL_VALUE, value );
|
||||
m_parameterGrid->SetCellAlignment( i, WIZ_COL_VALUE, wxALIGN_CENTRE, wxALIGN_CENTRE );
|
||||
}
|
||||
|
||||
ResizeParamColumns();
|
||||
|
||||
}
|
||||
|
||||
void FOOTPRINT_WIZARD_FRAME::ResizeParamColumns()
|
||||
{
|
||||
|
||||
// Parameter grid is not yet configured
|
||||
if ( ( m_parameterGrid == NULL ) || ( m_parameterGrid->GetNumberCols() == 0 ) )
|
||||
return;
|
||||
|
||||
// first auto-size the columns to ensure enough space around text
|
||||
m_parameterGrid->AutoSizeColumns();
|
||||
|
||||
// Auto-size the value column
|
||||
int width = m_parameterGrid->GetClientSize().GetWidth() -
|
||||
m_parameterGrid->GetRowLabelSize() -
|
||||
m_parameterGrid->GetColSize( WIZ_COL_NAME ) -
|
||||
m_parameterGrid->GetColSize( WIZ_COL_UNITS );
|
||||
|
||||
if ( width > m_parameterGrid->GetColMinimalAcceptableWidth() )
|
||||
{
|
||||
m_parameterGrid->SetColSize( WIZ_COL_VALUE, width );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -593,6 +662,13 @@ void FOOTPRINT_WIZARD_FRAME::ReCreateHToolbar()
|
|||
_( "Select the wizard script to load and run" ) );
|
||||
|
||||
m_mainToolBar->AddSeparator();
|
||||
|
||||
m_mainToolBar->AddTool( ID_FOOTPRINT_WIZARD_RESET_TO_DEFAULT, wxEmptyString,
|
||||
KiBitmap( reload_xpm ),
|
||||
_( "Reset the wizard parameters to default values ") );
|
||||
|
||||
m_mainToolBar->AddSeparator();
|
||||
|
||||
m_mainToolBar->AddTool( ID_FOOTPRINT_WIZARD_PREVIOUS, wxEmptyString,
|
||||
KiBitmap( lib_previous_xpm ),
|
||||
_( "Select previous parameters page" ) );
|
||||
|
@ -655,13 +731,13 @@ FOOTPRINT_WIZARD_MESSAGES::FOOTPRINT_WIZARD_MESSAGES( FOOTPRINT_WIZARD_FRAME* aP
|
|||
wxCAPTION | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT )
|
||||
{
|
||||
m_canClose = false;
|
||||
wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
|
||||
SetSizer( bSizer );
|
||||
wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
|
||||
SetSizer( bSizer );
|
||||
|
||||
m_messageWindow = new wxTextCtrl( this, wxID_ANY, wxEmptyString,
|
||||
m_messageWindow = new wxTextCtrl( this, wxID_ANY, wxEmptyString,
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_MULTILINE|wxTE_READONLY );
|
||||
bSizer->Add( m_messageWindow, 1, wxEXPAND, 0 );
|
||||
bSizer->Add( m_messageWindow, 1, wxEXPAND, 0 );
|
||||
|
||||
m_config = aCfg;
|
||||
|
||||
|
@ -670,7 +746,7 @@ FOOTPRINT_WIZARD_MESSAGES::FOOTPRINT_WIZARD_MESSAGES( FOOTPRINT_WIZARD_FRAME* aP
|
|||
SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
|
||||
|
||||
m_messageWindow->SetMinSize( wxSize( 350, 250 ) );
|
||||
Layout();
|
||||
Layout();
|
||||
|
||||
bSizer->SetSizeHints( this );
|
||||
}
|
||||
|
|
|
@ -39,9 +39,16 @@ class wxGrid;
|
|||
class wxGridEvent;
|
||||
class FOOTPRINT_EDIT_FRAME;
|
||||
|
||||
// A helper class to display messages when building a footprin
|
||||
// A helper class to display messages when building a footprint
|
||||
class FOOTPRINT_WIZARD_MESSAGES;
|
||||
|
||||
enum WizardParameterColumnNames
|
||||
{
|
||||
WIZ_COL_NAME = 0,
|
||||
WIZ_COL_VALUE,
|
||||
WIZ_COL_UNITS
|
||||
};
|
||||
|
||||
/**
|
||||
* Class FOOTPRINT_WIZARD_FRAME
|
||||
*/
|
||||
|
@ -54,11 +61,6 @@ private:
|
|||
int m_parameterGridWidth; ///< size of the grid
|
||||
FOOTPRINT_WIZARD_MESSAGES* m_messagesFrame;
|
||||
|
||||
// Column index to display parameters in m_parameterGrid
|
||||
static int m_columnPrmName;
|
||||
static int m_columnPrmValue;
|
||||
static int m_columnPrmUnit;
|
||||
|
||||
protected:
|
||||
wxString m_wizardName; ///< name of the current wizard
|
||||
wxString m_wizardDescription; ///< description of the wizard
|
||||
|
@ -76,6 +78,8 @@ private:
|
|||
|
||||
void OnSize( wxSizeEvent& event ) override;
|
||||
|
||||
void OnGridSize( wxSizeEvent& aSizeEvent );
|
||||
|
||||
/**
|
||||
* Function ExportSelectedFootprint();
|
||||
* will let the caller exit from the wait loop, and get the built footprint
|
||||
|
@ -103,6 +107,11 @@ private:
|
|||
*/
|
||||
void ReCreateParameterList();
|
||||
|
||||
/**
|
||||
* Expand the 'Value' column to fill available
|
||||
*/
|
||||
void ResizeParamColumns();
|
||||
|
||||
/**
|
||||
* Function initParameterGrid
|
||||
* Prepare the grid where parameters are displayed
|
||||
|
@ -168,6 +177,8 @@ private:
|
|||
|
||||
void SelectCurrentWizard( wxCommandEvent& event );
|
||||
|
||||
void DefaultParameters( wxCommandEvent& event );
|
||||
|
||||
/**
|
||||
* Function ParametersUpdated
|
||||
* Update the footprint python parameters values from the values in grid
|
||||
|
|
|
@ -200,7 +200,6 @@ PGM_BASE& Pgm()
|
|||
#if defined( KICAD_SCRIPTING )
|
||||
static bool scriptingSetup()
|
||||
{
|
||||
wxString path_frag;
|
||||
|
||||
#if defined( __WINDOWS__ )
|
||||
// If our python.exe (in kicad/bin) exists, force our kicad python environment
|
||||
|
@ -227,14 +226,6 @@ static bool scriptingSetup()
|
|||
wxSetEnv( wxT( "PATH" ), kipython );
|
||||
}
|
||||
|
||||
// wizard plugins are stored in ../share/kicad/scripting/plugins.
|
||||
// so add the base scripting path to python scripting default search paths
|
||||
// which are ( [KICAD_PATH] is an environment variable to define)
|
||||
// [KICAD_PATH]/scripting
|
||||
// [KICAD_PATH]/scripting/plugins
|
||||
// Add this default search path:
|
||||
path_frag = Pgm().GetExecutablePath() + wxT( "../share/kicad/scripting" );
|
||||
|
||||
#elif defined( __WXMAC__ )
|
||||
|
||||
// This path is given to LoadPlugins() from kicadplugins.i, which
|
||||
|
@ -278,13 +269,9 @@ static bool scriptingSetup()
|
|||
|
||||
wxSetEnv( wxT( "PYTHONPATH" ), pypath );
|
||||
|
||||
// Add this default search path:
|
||||
path_frag = Pgm().GetExecutablePath() + wxT( "../share/kicad/scripting" );
|
||||
#endif
|
||||
|
||||
// path_frag is the path to the bundled scripts and plugins, all other paths are
|
||||
// determined by the python pcbnew.py initialisation code.
|
||||
if( !pcbnewInitPythonScripting( TO_UTF8( path_frag ) ) )
|
||||
if ( !pcbnewInitPythonScripting( TO_UTF8( PyScriptingPath() ) ) )
|
||||
{
|
||||
wxLogError( "pcbnewInitPythonScripting() failed." );
|
||||
return false;
|
||||
|
|
|
@ -392,6 +392,7 @@ enum pcbnew_ids
|
|||
ID_FOOTPRINT_WIZARD_PAGES_WINDOW,
|
||||
ID_FOOTPRINT_WIZARD_PARAMETERS_WINDOW,
|
||||
ID_FOOTPRINT_WIZARD_SELECT_WIZARD,
|
||||
ID_FOOTPRINT_WIZARD_RESET_TO_DEFAULT,
|
||||
ID_FOOTPRINT_WIZARD_EXPORT_TO_BOARD,
|
||||
|
||||
ID_UPDATE_PCB_FROM_SCH,
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
from __future__ import division
|
||||
import pcbnew
|
||||
|
||||
import HelpfulFootprintWizardPlugin as HFPW
|
||||
import FootprintWizardBase
|
||||
|
||||
|
||||
class FPC_FootprintWizard(HFPW.HelpfulFootprintWizardPlugin):
|
||||
class FPC_FootprintWizard(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GetName(self):
|
||||
return "FPC (SMT connector)"
|
||||
|
@ -29,11 +28,11 @@ class FPC_FootprintWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
return "FPC (SMT connector) Footprint Wizard"
|
||||
|
||||
def GetValue(self):
|
||||
pins = self.parameters["Pads"]["*n"]
|
||||
pins = self.parameters["Pads"]["n"]
|
||||
return "FPC_%d" % pins
|
||||
|
||||
def GenerateParameterList(self):
|
||||
self.AddParam( "Pads", "n", self.uNatural, 40 )
|
||||
self.AddParam( "Pads", "n", self.uInteger, 40 )
|
||||
self.AddParam( "Pads", "pitch", self.uMM, 0.5 )
|
||||
self.AddParam( "Pads", "width", self.uMM, 0.25 )
|
||||
self.AddParam( "Pads", "height", self.uMM, 1.6)
|
||||
|
@ -56,13 +55,12 @@ class FPC_FootprintWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
return pad
|
||||
|
||||
def CheckParameters(self):
|
||||
p = self.parameters
|
||||
self.CheckParamInt( "Pads", "*n" ) # not internal units preceded by "*"
|
||||
|
||||
#TODO implement custom parameter checking
|
||||
pass
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
p = self.parameters
|
||||
pad_count = int(p["Pads"]["*n"])
|
||||
pad_count = int(p["Pads"]["n"])
|
||||
pad_width = p["Pads"]["width"]
|
||||
pad_height = p["Pads"]["height"]
|
||||
pad_pitch = p["Pads"]["pitch"]
|
|
@ -15,10 +15,150 @@
|
|||
#
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import pcbnew
|
||||
import math
|
||||
|
||||
# Base class for creating footprint wizards
|
||||
# Inherit this class to make a new wizard
|
||||
class FootprintWizard(pcbnew.FootprintWizardPlugin):
|
||||
|
||||
# Copy units from pcbnew
|
||||
uMM = pcbnew.uMM
|
||||
uMils = pcbnew.uMils
|
||||
uFloat = pcbnew.uFloat
|
||||
uInteger = pcbnew.uInteger
|
||||
uBool = pcbnew.uBool
|
||||
uRadians = pcbnew.uRadians
|
||||
uDegrees = pcbnew.uDegrees
|
||||
uPercent = pcbnew.uPercent
|
||||
uString = pcbnew.uString
|
||||
|
||||
"""
|
||||
A class to simplify many aspects of footprint creation, leaving only
|
||||
the foot-print specific routines to the wizards themselves
|
||||
|
||||
Generally, you need to implement:
|
||||
GetValue()
|
||||
GenerateParameterList()
|
||||
CheckParameters()
|
||||
BuildThisFootprint()
|
||||
GetName()
|
||||
GetDescription()
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
pcbnew.FootprintWizardPlugin.__init__(self)
|
||||
self.GenerateParameterList()
|
||||
|
||||
def GetName(self):
|
||||
"""
|
||||
Retun the name of the footprint wizard
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def GetDescription(self):
|
||||
"""
|
||||
Return the footprint wizard description
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def GetValue(self):
|
||||
"""
|
||||
Return the value (name) of the generated footprint
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def GenerateParameterList(self):
|
||||
"""
|
||||
Footprint parameter specification is done here
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def CheckParameters(self):
|
||||
"""
|
||||
Any custom parameter checking should be performed here
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
"""
|
||||
Draw the footprint.
|
||||
|
||||
This is specific to each footprint class, you need to implment
|
||||
this to draw what you want
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
# Do not override this method!
|
||||
def BuildFootprint( self ):
|
||||
"""
|
||||
Actually make the footprint. We defer all but the setup to
|
||||
the implementing class
|
||||
"""
|
||||
|
||||
self.buildmessages = ""
|
||||
self.module = pcbnew.MODULE(None) # create a new module
|
||||
|
||||
# Perform default checks on all params
|
||||
for p in self.params:
|
||||
p.ClearErrors()
|
||||
p.Check() # use defaults
|
||||
|
||||
self.CheckParameters() # User error checks
|
||||
|
||||
|
||||
if self.AnyErrors(): # Errors were detected!
|
||||
|
||||
self.buildmessages = "Cannot build footprint: Parameters have errors:\n"
|
||||
|
||||
for p in self.params:
|
||||
if len(p.error_list) > 0:
|
||||
self.buildmessages +="['{page}']['{name}']:\n".format(page=p.page,name=p.name)
|
||||
|
||||
for error in p.error_list:
|
||||
self.buildmessages += "\t" + error + "\n"
|
||||
|
||||
return
|
||||
|
||||
self.buildmessages = ("Building new {name} footprint with the following parameters:\n".format(name=self.name))
|
||||
|
||||
self.buildmessages += self.Show()
|
||||
|
||||
self.draw = FootprintWizardDrawingAids(
|
||||
self.module)
|
||||
|
||||
self.module.SetValue(self.GetValue())
|
||||
self.module.SetReference("%s**" % self.GetReferencePrefix())
|
||||
|
||||
fpid = pcbnew.LIB_ID(self.module.GetValue()) # the name in library
|
||||
self.module.SetFPID(fpid)
|
||||
|
||||
self.SetModule3DModel() # add a 3d module if specified
|
||||
|
||||
thick = self.GetTextThickness()
|
||||
|
||||
self.module.Reference().SetThickness(thick)
|
||||
self.module.Value().SetThickness(thick)
|
||||
|
||||
self.BuildThisFootprint() # implementer's build function
|
||||
|
||||
return
|
||||
|
||||
def SetModule3DModel(self):
|
||||
pass
|
||||
|
||||
def GetTextSize(self):
|
||||
"""
|
||||
IPC nominal
|
||||
"""
|
||||
return pcbnew.FromMM(1.0)
|
||||
|
||||
def GetTextThickness(self):
|
||||
"""
|
||||
Thicker than IPC guidelines (10% of text height = 0.12mm)
|
||||
as 5 wires/mm is a common silk screen limitation
|
||||
"""
|
||||
return pcbnew.FromMM(0.15)
|
||||
|
||||
class FootprintWizardDrawingAids:
|
||||
"""
|
||||
|
@ -294,6 +434,7 @@ class FootprintWizardDrawingAids:
|
|||
If filled is true, the thickness and radius of the line will be set
|
||||
such that the circle appears filled
|
||||
"""
|
||||
|
||||
circle = pcbnew.EDGE_MODULE(self.module)
|
||||
start = self.TransformPoint(x, y)
|
||||
|
||||
|
@ -362,21 +503,22 @@ class FootprintWizardDrawingAids:
|
|||
|
||||
_PolyLineInternal(pts) # original
|
||||
|
||||
if mirrorX is not None:
|
||||
self.TransformFlip(mirrorX, 0, self.flipX)
|
||||
_PolyLineInternal(pts)
|
||||
self.PopTransform()
|
||||
|
||||
if mirrorY is not None:
|
||||
self.TransformFlipOrigin(0, mirrorY, self.flipY)
|
||||
_PolyLineInternal(pts)
|
||||
self.PopTransform()
|
||||
|
||||
if mirrorX is not None and mirrorY is not None:
|
||||
self.TransformFlip(mirrorX, mirrorY, self.flipBoth) # both
|
||||
_PolyLineInternal(pts)
|
||||
self.PopTransform()
|
||||
|
||||
elif mirrorX is not None:
|
||||
self.TransformFlip(mirrorX, 0, self.flipX)
|
||||
_PolyLineInternal(pts)
|
||||
self.PopTransform()
|
||||
|
||||
elif mirrorY is not None:
|
||||
self.TransformFlip(0, mirrorY, self.flipY)
|
||||
_PolyLineInternal(pts)
|
||||
self.PopTransform()
|
||||
|
||||
|
||||
def Reference(self, x, y, size, orientation_degree = 0):
|
||||
"""
|
||||
Draw the module's reference as the given point.
|
||||
|
@ -529,4 +671,4 @@ class FootprintWizardDrawingAids:
|
|||
[0, 0]]
|
||||
|
||||
self.Polyline(pts)
|
||||
self.PopTransform(2)
|
||||
self.PopTransform(2)
|
|
@ -1,348 +0,0 @@
|
|||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import pcbnew
|
||||
import math
|
||||
import FootprintWizardDrawingAids
|
||||
|
||||
|
||||
class FootprintWizardParameterManager:
|
||||
"""
|
||||
Functions for helpfully managing parameters to a KiCAD Footprint
|
||||
Wizard.
|
||||
|
||||
Abstracts away from whatever structure is used by pcbnew's footprint
|
||||
wizard class
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.parameters = {}
|
||||
self.GenerateParameterList()
|
||||
|
||||
def GenerateParameterList(self):
|
||||
"""
|
||||
Construct parameters here, or leave out to have no parameters
|
||||
"""
|
||||
pass
|
||||
|
||||
def CheckParameters(self):
|
||||
"""
|
||||
Implement this to make checks on parameter values, filling
|
||||
parameter_errors (or using the checker routines)
|
||||
|
||||
Subclasses can implment their own and override the parent
|
||||
defaults and add new ones
|
||||
"""
|
||||
pass
|
||||
|
||||
uMM = 1
|
||||
uMils = 2
|
||||
uNatural = 3
|
||||
uBool = 4
|
||||
uString = 5
|
||||
|
||||
def AddParam(self, section, param, unit, default, hint=''):
|
||||
"""
|
||||
Add a parameter with some properties.
|
||||
|
||||
TODO: Hints are not supported, as there is as yet nowhere to
|
||||
put them in the KiCAD interface
|
||||
"""
|
||||
error = ""
|
||||
val = None
|
||||
if unit == self.uMM:
|
||||
val = pcbnew.FromMM(default)
|
||||
elif unit == self.uMils:
|
||||
val = pcbnew.FromMils(default)
|
||||
elif unit == self.uNatural:
|
||||
val = default
|
||||
elif unit == self.uString:
|
||||
val = str(default)
|
||||
elif unit == self.uBool:
|
||||
val = "True" if default else "False" # ugly stringing
|
||||
else:
|
||||
error = "Warning: Unknown unit type: %s" % unit
|
||||
return error
|
||||
|
||||
if unit in [self.uNatural, self.uBool, self.uString]:
|
||||
param = "*%s" % param # star prefix for natural
|
||||
|
||||
if section not in self.parameters:
|
||||
if not hasattr(self, 'page_order'):
|
||||
self.page_order = []
|
||||
self.page_order.append(section)
|
||||
self.parameters[section] = {}
|
||||
if not hasattr(self, 'parameter_order'):
|
||||
self.parameter_order = {}
|
||||
self.parameter_order[section] = []
|
||||
|
||||
self.parameters[section][param] = val
|
||||
self.parameter_order[section].append(param)
|
||||
|
||||
return error
|
||||
|
||||
|
||||
def _PrintParameterTable(self):
|
||||
"""
|
||||
Pretty-print the parameters we have
|
||||
"""
|
||||
message = ""
|
||||
|
||||
for name, section in self.parameters.iteritems():
|
||||
message += " %s:\n" % name
|
||||
|
||||
for key, value in section.iteritems():
|
||||
unit = ""
|
||||
if ((type(value) is int or type(value) is float)
|
||||
and not "*" in key):
|
||||
unit = "mm"
|
||||
|
||||
if "*" in key:
|
||||
key = key[1:]
|
||||
else:
|
||||
value = pcbnew.ToMM(value)
|
||||
|
||||
message += " %s: %s%s\n" % (key, value, unit)
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def _ParametersHaveErrors(self):
|
||||
"""
|
||||
Return true if we discovered errors during parameter processing
|
||||
"""
|
||||
|
||||
for name, section in self.parameter_errors.iteritems():
|
||||
for k, v in section.iteritems():
|
||||
if v:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _PrintParameterErrors(self):
|
||||
"""
|
||||
Pretty-print parameters with errors
|
||||
"""
|
||||
errors = ""
|
||||
|
||||
for name, section in self.parameter_errors.iteritems():
|
||||
printed_section = False
|
||||
|
||||
for key, value in section.iteritems():
|
||||
if value:
|
||||
if not printed_section:
|
||||
errors += " %s:" % name
|
||||
|
||||
errors += " %s: %s (have %s)\n" % (
|
||||
key, value, self.parameters[name][key])
|
||||
|
||||
return errors
|
||||
|
||||
def ProcessParameters(self):
|
||||
"""
|
||||
Make sure the parameters we have meet whatever expectations the
|
||||
footprint wizard has of them
|
||||
"""
|
||||
|
||||
self.ClearErrors()
|
||||
self.CheckParameters()
|
||||
|
||||
if self._ParametersHaveErrors():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
#################################################################
|
||||
# PARAMETER CHECKERS
|
||||
#################################################################
|
||||
|
||||
def CheckParamInt(self, section, param, min_value=1,
|
||||
max_value=None, is_multiple_of=1):
|
||||
"""
|
||||
Make sure a parameter can be made into an int, and enforce
|
||||
limits if required
|
||||
"""
|
||||
|
||||
try:
|
||||
self.parameters[section][param] = (
|
||||
int(self.parameters[section][param]))
|
||||
except ValueError:
|
||||
self.parameter_errors[section][param] = (
|
||||
"Must be a valid integer")
|
||||
return
|
||||
|
||||
if min_value is not None and (
|
||||
self.parameters[section][param] < min_value):
|
||||
self.parameter_errors[section][param] = (
|
||||
"Must be greater than or equal to %d" % (min_value))
|
||||
return
|
||||
|
||||
if max_value is not None and (
|
||||
self.parameters[section][param] > max_value):
|
||||
self.parameter_errors[section][param] = (
|
||||
"Must be less than or equal to %d" % (max_value))
|
||||
return
|
||||
|
||||
if is_multiple_of > 1 and (
|
||||
self.parameters[section][param] % is_multiple_of) > 0:
|
||||
self.parameter_errors[section][param] = (
|
||||
"Must be a multiple of %d" % is_multiple_of)
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
def CheckParamBool(self, section, param):
|
||||
"""
|
||||
Make sure a parameter looks like a boolean, convert to native
|
||||
boolean type if so
|
||||
"""
|
||||
if str(self.parameters[section][param]).lower() in [
|
||||
"true", "t", "y", "yes", "on", "1", "1.0"]:
|
||||
self.parameters[section][param] = True
|
||||
return
|
||||
elif str(self.parameters[section][param]).lower() in [
|
||||
"false", "f", "n", "no", "off", "0", "0.0"]:
|
||||
self.parameters[section][param] = False
|
||||
return
|
||||
|
||||
self.parameter_errors[section][param] = "Must be boolean (true/false)"
|
||||
return
|
||||
|
||||
|
||||
class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
|
||||
FootprintWizardParameterManager):
|
||||
"""
|
||||
A class to simplify many aspects of footprint creation, leaving only
|
||||
the foot-print specific routines to the wizards themselves
|
||||
|
||||
Generally, you need to implement:
|
||||
GetReference()
|
||||
GetValue()
|
||||
GenerateParameterList()
|
||||
CheckParameters()
|
||||
BuildThisFootprint()
|
||||
GetName()
|
||||
GetDescription()
|
||||
"""
|
||||
def __init__(self):
|
||||
pcbnew.FootprintWizardPlugin.__init__(self)
|
||||
FootprintWizardParameterManager.__init__(self)
|
||||
|
||||
self.name = self.GetName()
|
||||
self.decription = self.GetDescription()
|
||||
self.image = self.GetImage()
|
||||
|
||||
def GetValue(self):
|
||||
raise NotImplementedError
|
||||
|
||||
# this value come from our KiCad Library Convention 1.0
|
||||
def GetReferencePrefix(self):
|
||||
return "REF"
|
||||
|
||||
def GetImage(self):
|
||||
return ""
|
||||
|
||||
def GetTextSize(self):
|
||||
"""
|
||||
IPC nominal
|
||||
"""
|
||||
return pcbnew.FromMM(1.0)
|
||||
|
||||
def GetTextThickness(self):
|
||||
"""
|
||||
Thicker than IPC guidelines (10% of text height = 0.12mm)
|
||||
as 5 wires/mm is a common silk screen limitation
|
||||
"""
|
||||
return pcbnew.FromMM(0.15)
|
||||
|
||||
def SetModule3DModel(self):
|
||||
"""
|
||||
Set a 3D model for the module
|
||||
|
||||
Default is to do nothing, you need to implement this if you have
|
||||
a model to set
|
||||
|
||||
FIXME: This doesn't seem to be enabled yet?
|
||||
"""
|
||||
pass
|
||||
|
||||
def PutOnGridMM(self, value, gridSizeMM=0.05):
|
||||
"""
|
||||
Round the value (in KiCAD internal units 1nm) according to the
|
||||
provided gridSize in mm.
|
||||
"""
|
||||
thresh = pcbnew.FromMM(gridSizeMM)
|
||||
res = round(value/thresh)*thresh
|
||||
return res
|
||||
|
||||
def PutOnGridMils(self, value, gridSizeMil=2):
|
||||
"""
|
||||
Round the value (in KiCAD internal units 1nm) according to the
|
||||
provided gridSize in mil.
|
||||
"""
|
||||
thresh = pcbnew.FromMils(gridSizeMil)
|
||||
res = round(value/thresh)*thresh
|
||||
return res
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
"""
|
||||
Draw the footprint.
|
||||
|
||||
This is specific to each footprint class, you need to implment
|
||||
this to draw what you want
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def BuildFootprint( self ):
|
||||
"""
|
||||
Actually make the footprint. We defer all but the setup to
|
||||
the implementing class
|
||||
"""
|
||||
|
||||
self.buildmessages = ""
|
||||
|
||||
self.module = pcbnew.MODULE(None) # create a new module
|
||||
# do it first, so if we return early, we don't segfault KiCad
|
||||
|
||||
if not self.ProcessParameters():
|
||||
self.buildmessages = "Cannot build footprint: Parameters have errors:\n"
|
||||
self.buildmessages += self._PrintParameterErrors()
|
||||
return
|
||||
|
||||
self.buildmessages = ("Building new %s footprint with the following parameters:\n"
|
||||
% self.name)
|
||||
|
||||
self.buildmessages += self._PrintParameterTable()
|
||||
|
||||
self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(
|
||||
self.module)
|
||||
|
||||
self.module.SetValue(self.GetValue())
|
||||
self.module.SetReference("%s**" % self.GetReferencePrefix())
|
||||
|
||||
fpid = pcbnew.LIB_ID(self.module.GetValue()) # the name in library
|
||||
self.module.SetFPID(fpid)
|
||||
|
||||
self.SetModule3DModel() # add a 3d module if specified
|
||||
|
||||
thick = self.GetTextThickness()
|
||||
|
||||
self.module.Reference().SetThickness(thick)
|
||||
self.module.Value().SetThickness(thick)
|
||||
|
||||
self.BuildThisFootprint() # implementer's build function
|
||||
|
||||
return
|
|
@ -17,7 +17,7 @@
|
|||
from __future__ import division
|
||||
import pcbnew
|
||||
|
||||
import HelpfulFootprintWizardPlugin as HFPW
|
||||
import FootprintWizardBase
|
||||
import PadArray as PA
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@ class BGAPadGridArray(PA.PadGridArray):
|
|||
n_x + 1)
|
||||
|
||||
|
||||
class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
|
||||
class BGAWizard(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GetName(self):
|
||||
return "BGA"
|
||||
|
@ -38,35 +38,48 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
return "Ball Grid Array Footprint Wizard"
|
||||
|
||||
def GenerateParameterList(self):
|
||||
self.AddParam("Pads", "pad pitch", self.uMM, 1)
|
||||
self.AddParam("Pads", "pad size", self.uMM, 0.5)
|
||||
self.AddParam("Pads", "row count", self.uNatural, 5)
|
||||
self.AddParam("Pads", "column count", self.uNatural, 5)
|
||||
self.AddParam("Pads", "outline x margin", self.uMM, 1)
|
||||
self.AddParam("Pads", "outline y margin", self.uMM, 1)
|
||||
self.AddParam("Pads", "pitch", self.uMM, 1, designator='p')
|
||||
self.AddParam("Pads", "size", self.uMM, 0.5)
|
||||
self.AddParam("Pads", "columns", self.uInteger, 5, designator="nx")
|
||||
self.AddParam("Pads", "rows", self.uInteger, 5, designator="ny")
|
||||
|
||||
self.AddParam("Package", "width", self.uMM, 6, designator='X')
|
||||
self.AddParam("Package", "length", self.uMM, 6, designator='Y')
|
||||
self.AddParam("Package", "margin", self.uMM, 0.25, min_value=0.2, hint="Courtyard margin")
|
||||
|
||||
def CheckParameters(self):
|
||||
self.CheckParamInt("Pads", "*row count")
|
||||
self.CheckParamInt("Pads", "*column count")
|
||||
|
||||
# check that the package is large enough
|
||||
width = pcbnew.ToMM(self.parameters['Pads']['pitch'] * self.parameters['Pads']['columns'])
|
||||
|
||||
length = pcbnew.ToMM(self.parameters['Pads']['pitch'] * self.parameters['Pads']['rows'])
|
||||
|
||||
self.CheckParam('Package','width',min_value=width,info="Package width is too small (< {w}mm)".format(w=width))
|
||||
self.CheckParam('Package','length',min_value=length,info="Package length is too small (< {l}mm".format(l=length))
|
||||
|
||||
def GetValue(self):
|
||||
pins = (self.parameters["Pads"]["*row count"]
|
||||
* self.parameters["Pads"]["*column count"])
|
||||
pins = (self.parameters["Pads"]["rows"] * self.parameters["Pads"]["columns"])
|
||||
|
||||
return "BGA_%d" % pins
|
||||
return "BGA-{n}_{a}x{b}_{x}x{y}mm".format(
|
||||
n = pins,
|
||||
a = self.parameters['Pads']['columns'],
|
||||
b = self.parameters['Pads']['rows'],
|
||||
x = pcbnew.ToMM(self.parameters['Package']['width']),
|
||||
y = pcbnew.ToMM(self.parameters['Package']['length'])
|
||||
)
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
|
||||
pads = self.parameters["Pads"]
|
||||
|
||||
rows = pads["*row count"]
|
||||
cols = pads["*column count"]
|
||||
pad_size = pads["pad size"]
|
||||
rows = pads["rows"]
|
||||
cols = pads["columns"]
|
||||
pad_size = pads["size"]
|
||||
pad_size = pcbnew.wxSize(pad_size, pad_size)
|
||||
pad_pitch = pads["pad pitch"]
|
||||
pad_pitch = pads["pitch"]
|
||||
|
||||
# add in the pads
|
||||
pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"])
|
||||
pad = PA.PadMaker(self.module).SMTRoundPad(pads["size"])
|
||||
|
||||
pin1_pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2,
|
||||
-((rows - 1) * pad_pitch) / 2)
|
||||
|
@ -74,21 +87,68 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch)
|
||||
array.AddPadsToModule(self.draw)
|
||||
|
||||
#box
|
||||
ssx = -pin1_pos.x + pads["outline x margin"]
|
||||
ssy = -pin1_pos.y + pads["outline y margin"]
|
||||
# Draw box outline on F.Fab layer
|
||||
self.draw.SetLayer(pcbnew.F_Fab)
|
||||
ssx = self.parameters['Package']['width'] / 2
|
||||
ssy = self.parameters['Package']['length'] / 2
|
||||
|
||||
self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2,
|
||||
pads["outline x margin"])
|
||||
# Bevel should be 1mm nominal but we'll allow smaller values
|
||||
if pcbnew.ToMM(ssx) < 1:
|
||||
bevel = ssx
|
||||
else:
|
||||
bevel = pcbnew.FromMM(1)
|
||||
|
||||
# Box with 1mm bevel as per IPC7351C
|
||||
self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2, bevel)
|
||||
|
||||
# Add IPC markings to F_Silk layer
|
||||
self.draw.SetLayer(pcbnew.F_SilkS)
|
||||
offset = pcbnew.FromMM(0.15)
|
||||
len_x = 0.5 * ssx
|
||||
len_y = 0.5 * ssy
|
||||
|
||||
edge = [
|
||||
[ ssx + offset - len_x, -ssy - offset],
|
||||
[ ssx + offset, -ssy - offset],
|
||||
[ ssx + offset, -ssy - offset + len_y],
|
||||
]
|
||||
|
||||
# Draw three square edges
|
||||
self.draw.Polyline(edge)
|
||||
self.draw.Polyline(edge, mirrorY=0)
|
||||
self.draw.Polyline(edge, mirrorX=0, mirrorY=0)
|
||||
|
||||
# Draw pin-1 marker
|
||||
bevel += offset
|
||||
pin1 = [
|
||||
[ -ssx - offset + len_x, -ssy - offset],
|
||||
[ -ssx - offset + bevel, -ssy - offset],
|
||||
[ -ssx - offset, -ssy - offset + bevel],
|
||||
[ -ssx - offset, -ssy - offset + len_y],
|
||||
]
|
||||
|
||||
# Remove lines if the package is too small
|
||||
if bevel > len_x:
|
||||
pin1 = pin1[1:]
|
||||
|
||||
if bevel > len_y:
|
||||
pin1 = pin1[:-1]
|
||||
|
||||
self.draw.Polyline(pin1)
|
||||
|
||||
# Draw a circle in the bevel void
|
||||
self.draw.Circle( -ssx, -ssy, pcbnew.FromMM(0.2), filled=True)
|
||||
|
||||
# Courtyard
|
||||
cmargin = self.draw.GetLineThickness()
|
||||
cmargin = self.parameters['Package']['margin']
|
||||
self.draw.SetLayer(pcbnew.F_CrtYd)
|
||||
sizex = (ssx + cmargin) * 2
|
||||
sizey = (ssy + cmargin) * 2
|
||||
|
||||
# round size to nearest 0.1mm, rectangle will thus land on a 0.05mm grid
|
||||
sizex = self.PutOnGridMM(sizex, 0.1)
|
||||
sizey = self.PutOnGridMM(sizey, 0.1)
|
||||
sizex = pcbnew.PutOnGridMM(sizex, 0.1)
|
||||
sizey = pcbnew.PutOnGridMM(sizey, 0.1)
|
||||
|
||||
# set courtyard line thickness to the one defined in KLC
|
||||
self.draw.SetLineThickness(pcbnew.FromMM(0.05))
|
||||
self.draw.Box(0, 0, sizex, sizey)
|
||||
|
|
|
@ -18,11 +18,11 @@ from __future__ import division
|
|||
import math
|
||||
|
||||
import pcbnew
|
||||
import HelpfulFootprintWizardPlugin as HFPW
|
||||
import FootprintWizardBase
|
||||
import PadArray as PA
|
||||
|
||||
|
||||
class circular_pad_array_wizard(HFPW.HelpfulFootprintWizardPlugin):
|
||||
class circular_pad_array_wizard(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GetName(self):
|
||||
return "Circular Pad Array"
|
||||
|
@ -32,52 +32,84 @@ class circular_pad_array_wizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
|
||||
def GenerateParameterList(self):
|
||||
|
||||
self.AddParam("Pads", "n", self.uNatural, 6)
|
||||
self.AddParam("Pads", "pad width", self.uMM, 1.5)
|
||||
self.AddParam("Pads", "drill", self.uMM, 1)
|
||||
self.AddParam("Pads", "circle diameter", self.uMM, 5)
|
||||
self.AddParam("Pads", "first pad angle", self.uNatural, 0)
|
||||
self.AddParam("Pads", "number clockwise", self.uBool, True)
|
||||
self.AddParam("Pads", "first pad number", self.uNatural, 1)
|
||||
self.AddParam("Pads", "count", self.uInteger, 6, min_value=1, designator='n')
|
||||
self.AddParam("Pads", "center diameter", self.uMM, 5, min_value=0, designator='r', hint="Centre distance between pads")
|
||||
self.AddParam("Pads", "diameter", self.uMM, 1.5)
|
||||
self.AddParam("Pads", "drill", self.uMM, 0.8)
|
||||
self.AddParam("Pads", "angle", self.uDegrees, 0, designator='a')
|
||||
|
||||
self.AddParam("Numbering", "initial", self.uInteger, 1, min_value=1)
|
||||
#self.AddParam("Numbering", "increment", self.uInteger, 1, min_value=1)
|
||||
self.AddParam("Numbering", "clockwise", self.uBool, True)
|
||||
|
||||
self.AddParam("Outline", "diameter", self.uMM, 7, designator='D')
|
||||
self.AddParam("Outline", "margin", self.uMM, 0.25, min_value=0.2)
|
||||
|
||||
def CheckParameters(self):
|
||||
|
||||
self.CheckParamInt("Pads", "*n")
|
||||
self.CheckParamInt("Pads", "*first pad number")
|
||||
self.CheckParamBool("Pads", "*number clockwise")
|
||||
pads = self.parameters['Pads']
|
||||
numbering = self.parameters['Numbering']
|
||||
outline = self.parameters['Outline']
|
||||
|
||||
# Check that pads do not overlap
|
||||
pad_dia = pcbnew.ToMM(pads['diameter'])
|
||||
centres = pcbnew.ToMM(pads['center diameter'])
|
||||
n_pads = pads['count']
|
||||
|
||||
self.CheckParam('Pads','diameter',max_value=centres*math.pi/n_pads,info="Pads overlap")
|
||||
|
||||
# Check that the pads fit inside the outline
|
||||
d_min = pad_dia + centres
|
||||
|
||||
self.CheckParam("Outline","diameter",min_value=d_min, info="Outline diameter is too small")
|
||||
|
||||
|
||||
def GetValue(self):
|
||||
pins = self.parameters["Pads"]["*n"]
|
||||
pins = self.parameters["Pads"]["count"]
|
||||
return "CPA_%d" % pins
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
|
||||
prm = self.parameters['Pads']
|
||||
pads = self.parameters['Pads']
|
||||
numbering = self.parameters['Numbering']
|
||||
outline = self.parameters['Outline']
|
||||
|
||||
pad_size = prm['pad width']
|
||||
pad_size = pads['diameter']
|
||||
|
||||
pad = PA.PadMaker(self.module).THPad(
|
||||
prm['pad width'], prm['pad width'], prm['drill'])
|
||||
pad = PA.PadMaker(self.module).THPad(pads['diameter'], pads['diameter'], pads['drill'])
|
||||
|
||||
array = PA.PadCircleArray(
|
||||
pad, prm['*n'], prm['circle diameter'] / 2,
|
||||
angle_offset=prm["*first pad angle"],
|
||||
pad, pads['count'], pads['center diameter'] / 2,
|
||||
angle_offset=pads["angle"],
|
||||
centre=pcbnew.wxPoint(0, 0),
|
||||
clockwise=prm["*number clockwise"])
|
||||
clockwise=numbering["clockwise"])
|
||||
|
||||
array.SetFirstPadInArray(prm["*first pad number"])
|
||||
array.SetFirstPadInArray(numbering["initial"])
|
||||
|
||||
array.AddPadsToModule(self.draw)
|
||||
|
||||
body_radius = (prm['circle diameter'] + prm['pad width'])/2 + self.draw.GetLineThickness()
|
||||
# Draw the outline
|
||||
body_radius = outline['diameter'] / 2
|
||||
self.draw.SetLayer(pcbnew.F_Fab)
|
||||
self.draw.GetLineThickness()
|
||||
self.draw.Circle(0, 0, body_radius)
|
||||
|
||||
#silkscreen
|
||||
body_radius += pcbnew.FromMM(0.15)
|
||||
self.draw.SetLayer(pcbnew.F_SilkS)
|
||||
self.draw.Circle(0, 0, body_radius)
|
||||
|
||||
# courtyard
|
||||
self.draw.SetLayer(pcbnew.F_CrtYd)
|
||||
self.draw.SetLineThickness(pcbnew.FromMM(0.05))
|
||||
self.draw.Circle(0, 0, body_radius + outline['margin'])
|
||||
|
||||
# Text size
|
||||
|
||||
text_size = self.GetTextSize() # IPC nominal
|
||||
thickness = self.GetTextThickness()
|
||||
textposy = body_radius + self.draw.GetLineThickness()/2 + self.GetTextSize()/2 + thickness
|
||||
textposy = body_radius + self.draw.GetLineThickness()/2 + self.GetTextSize()/2 + thickness + + outline['margin']
|
||||
self.draw.Value( 0, textposy, text_size )
|
||||
self.draw.Reference( 0, -textposy, text_size )
|
||||
|
||||
|
||||
|
||||
circular_pad_array_wizard().register()
|
||||
|
|
|
@ -17,55 +17,80 @@
|
|||
from __future__ import division
|
||||
import pcbnew
|
||||
|
||||
import HelpfulFootprintWizardPlugin as HFPW
|
||||
import pcbnew
|
||||
import FootprintWizardBase
|
||||
import PadArray as PA
|
||||
|
||||
class QFNWizard(HFPW.HelpfulFootprintWizardPlugin):
|
||||
class QFNWizard(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GetName(self):
|
||||
return "QFN"
|
||||
|
||||
def GetDescription(self):
|
||||
return "Quad Flat No-lead with Exposed Pad footprint wizard"
|
||||
return "Quad Flat No-lead (QFN) footprint wizard"
|
||||
|
||||
def GenerateParameterList(self):
|
||||
self.AddParam("Pads", "n", self.uNatural, 100)
|
||||
self.AddParam("Pads", "pad pitch", self.uMM, 0.5)
|
||||
self.AddParam("Pads", "pad width", self.uMM, 0.25)
|
||||
self.AddParam("Pads", "pad length", self.uMM, 1.5)
|
||||
self.AddParam("Pads", "oval", self.uBool, True)
|
||||
self.AddParam("Pads", "thermal vias", self.uBool, True)
|
||||
self.AddParam("Pads", "thermal vias drill", self.uMM, 0.3)
|
||||
self.AddParam("Pads", "epad subdiv x", self.uNatural, 2)
|
||||
self.AddParam("Pads", "epad subdiv y", self.uNatural, 2)
|
||||
|
||||
self.AddParam("Package", "package width", self.uMM, 14)
|
||||
self.AddParam("Package", "package height", self.uMM, 14)
|
||||
self.AddParam("Package", "courtyard margin", self.uMM, 1)
|
||||
#TODO - Allow different number of pads in x and y directions
|
||||
|
||||
self.AddParam("Pads", "n", self.uInteger, 100, multiple=4, min_value=4)
|
||||
self.AddParam("Pads", "pitch", self.uMM, 0.5, designator='e')
|
||||
self.AddParam("Pads", "width", self.uMM, 0.25, designator='X1')
|
||||
self.AddParam("Pads", "length", self.uMM, 1.5, designator='Y1')
|
||||
self.AddParam("Pads", "oval", self.uBool, True)
|
||||
|
||||
self.AddParam("EPad", "epad", self.uBool, True)
|
||||
self.AddParam("EPad", "width", self.uMM, 10, designator="E2")
|
||||
self.AddParam("EPad", "length", self.uMM, 10, designator="D2")
|
||||
self.AddParam("EPad", "thermal vias", self.uBool, False)
|
||||
self.AddParam("EPad", "thermal vias drill", self.uMM, 1, min_value=0.1)
|
||||
self.AddParam("EPad", "x divisions", self.uInteger, 2, min_value=1)
|
||||
self.AddParam("EPad", "y divisions", self.uInteger, 2, min_value=1)
|
||||
self.AddParam("EPad", "paste margin", self.uMM, 0.1)
|
||||
|
||||
self.AddParam("Package", "width", self.uMM, 14, designator='E')
|
||||
self.AddParam("Package", "height", self.uMM, 14, designator='D')
|
||||
self.AddParam("Package", "margin", self.uMM, 0.25, minValue=0.2)
|
||||
|
||||
@property
|
||||
def pads(self):
|
||||
return self.parameters['Pads']
|
||||
|
||||
@property
|
||||
def epad(self):
|
||||
return self.parameters['EPad']
|
||||
|
||||
@property
|
||||
def package(self):
|
||||
return self.parameters['Package']
|
||||
|
||||
def CheckParameters(self):
|
||||
self.CheckParamInt("Pads", "*n", is_multiple_of=4)
|
||||
self.CheckParamBool("Pads", "*oval")
|
||||
self.CheckParamBool("Pads", "*thermal vias")
|
||||
pass
|
||||
|
||||
def GetValue(self):
|
||||
return "QFN_%d" % self.parameters["Pads"]["*n"]
|
||||
|
||||
return "QFN-{n}_{ep}{x:g}x{y:g}_Pitch{p:g}mm".format(
|
||||
n = self.pads['n'],
|
||||
ep = "EP_" if self.epad['epad'] else '',
|
||||
x = pcbnew.ToMM(self.package['width']),
|
||||
y = pcbnew.ToMM(self.package['height']),
|
||||
p = pcbnew.ToMM(self.pads['pitch'])
|
||||
)
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
pads = self.parameters["Pads"]
|
||||
|
||||
pad_pitch = pads["pad pitch"]
|
||||
pad_length = pads["pad length"]
|
||||
pad_width = pads["pad width"]
|
||||
pad_pitch = self.pads["pitch"]
|
||||
pad_length = self.pads["length"]
|
||||
pad_width = self.pads["width"]
|
||||
|
||||
v_pitch = self.parameters["Package"]["package height"]
|
||||
h_pitch = self.parameters["Package"]["package width"]
|
||||
v_pitch = self.package["height"]
|
||||
h_pitch = self.package["width"]
|
||||
|
||||
pads_per_row = pads["*n"] // 4
|
||||
pads_per_row = int(self.pads["n"] // 4)
|
||||
|
||||
row_len = (pads_per_row - 1) * pad_pitch
|
||||
|
||||
pad_shape = pcbnew.PAD_SHAPE_OVAL if pads["*oval"] else pcbnew.PAD_SHAPE_RECT
|
||||
pad_shape = pcbnew.PAD_SHAPE_OVAL if self.pads["oval"] else pcbnew.PAD_SHAPE_RECT
|
||||
|
||||
h_pad = PA.PadMaker(self.module).SMDPad( pad_length, pad_width,
|
||||
shape=pad_shape, rot_degree=90.0)
|
||||
|
@ -97,79 +122,88 @@ class QFNWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
array.SetFirstPadInArray(3*pads_per_row + 1)
|
||||
array.AddPadsToModule(self.draw)
|
||||
|
||||
lim_x = self.parameters["Package"]["package width"] / 2
|
||||
lim_y = self.parameters["Package"]["package height"] / 2
|
||||
lim_x = self.package["width"] / 2
|
||||
lim_y = self.package["height"] / 2
|
||||
inner = (row_len / 2) + pad_pitch
|
||||
|
||||
# epad
|
||||
epad_width = self.parameters["Package"]["package height"] - (2*pad_length)
|
||||
epad_length = self.parameters["Package"]["package width"] - (2*pad_length)
|
||||
epad_subdv_x = pads["*epad subdiv x"]
|
||||
epad_subdv_y = pads["*epad subdiv y"]
|
||||
epad_via_drill = pads["thermal vias drill"]
|
||||
epad_width = self.epad["width"]
|
||||
epad_length = self.epad["length"]
|
||||
|
||||
if (epad_subdv_y != 0 and epad_subdv_x != 0) and (epad_subdv_y != 1 or epad_subdv_x != 1):
|
||||
# Create the master pad (one area) on front solder mask, and perhaps of front copper layer
|
||||
# at location 0,0
|
||||
emasterpad = PA.PadMaker(self.module).SMDPad( epad_length, epad_width,
|
||||
shape=pcbnew.PAD_SHAPE_RECT, rot_degree=0.0)
|
||||
emasterpad.SetLayerSet(pcbnew.LSET(pcbnew.F_Mask)) # currently, only on solder mask
|
||||
emasterpad.SetPadName(pads["*n"]+1)
|
||||
self.module.Add(emasterpad)
|
||||
epad_ny = self.epad["x divisions"]
|
||||
epad_nx = self.epad["y divisions"]
|
||||
|
||||
px = pcbnew.FromMM(0.1); py = pcbnew.FromMM(0.1)
|
||||
esubpad_size_x = epad_length / epad_subdv_x - px
|
||||
esubpad_size_y = epad_width / epad_subdv_y - py
|
||||
epad1_pos = pcbnew.wxPoint(-(esubpad_size_x*(epad_subdv_x-1)/2), -esubpad_size_y*(epad_subdv_y-1)/2)
|
||||
epad = PA.PadMaker(self.module).SMDPad( esubpad_size_y, esubpad_size_x,
|
||||
shape=pcbnew.PAD_SHAPE_RECT, rot_degree=0.0)
|
||||
array = PA.EPADGridArray(epad, epad_subdv_x, epad_subdv_y, esubpad_size_x + px, esubpad_size_y + py, pcbnew.wxPoint(0,0))
|
||||
array.SetFirstPadInArray(pads["*n"]+1)
|
||||
array.AddPadsToModule(self.draw)
|
||||
if pads["*thermal vias"]:
|
||||
via_diam = min(esubpad_size_y, esubpad_size_x)/3.
|
||||
thpad = PA.PadMaker(self.module).THRoundPad(via_diam, min(via_diam/2, epad_via_drill))
|
||||
layerset = pcbnew.LSET.AllCuMask()
|
||||
layerset.AddLayer(pcbnew.B_Mask)
|
||||
layerset.AddLayer(pcbnew.F_Mask)
|
||||
thpad.SetLayerSet(layerset)
|
||||
array2 = PA.EPADGridArray(thpad, epad_subdv_x, epad_subdv_y, esubpad_size_x + px, esubpad_size_y + py, pcbnew.wxPoint(0,0))
|
||||
array2.SetFirstPadInArray(pads["*n"]+1)
|
||||
array2.AddPadsToModule(self.draw)
|
||||
else:
|
||||
epad = PA.PadMaker(self.module).SMDPad(epad_length, epad_width)
|
||||
epad_pos = pcbnew.wxPoint(0,0)
|
||||
array = PA.PadLineArray(epad, 1, 1, False, epad_pos)
|
||||
array.SetFirstPadInArray(pads["*n"]+1)
|
||||
array.AddPadsToModule(self.draw)
|
||||
if pads["*thermal vias"]:
|
||||
via_diam = min(epad_length, epad_width)/3.
|
||||
thpad = PA.PadMaker(self.module).THRoundPad( via_diam, min(via_diam/2, epad_via_drill))
|
||||
layerset = pcbnew.LSET.AllCuMask()
|
||||
layerset.AddLayer(pcbnew.B_Mask)
|
||||
layerset.AddLayer(pcbnew.F_Mask)
|
||||
thpad.SetLayerSet(layerset)
|
||||
array2 = PA.PadLineArray(thpad, 1, 1, False, epad_pos)
|
||||
array2.SetFirstPadInArray(pads["*n"]+1)
|
||||
array2.AddPadsToModule(self.draw)
|
||||
epad_via_drill = self.epad["thermal vias drill"]
|
||||
|
||||
#top left - diagonal
|
||||
self.draw.Line(-lim_x, -inner, -inner, -lim_y)
|
||||
# top right
|
||||
self.draw.Polyline([(inner, -lim_y), (lim_x, -lim_y), (lim_x, -inner)])
|
||||
# bottom left
|
||||
self.draw.Polyline([(-inner, lim_y), (-lim_x, lim_y), (-lim_x, inner)])
|
||||
# bottom right
|
||||
self.draw.Polyline([(inner, lim_y), (lim_x, lim_y), (lim_x, inner)])
|
||||
# Create a central exposed pad?
|
||||
if self.epad['epad'] == True:
|
||||
|
||||
epad_num = self.pads['n'] + 1
|
||||
|
||||
epad_w = epad_length / epad_nx
|
||||
epad_l = epad_width / epad_ny
|
||||
|
||||
# Create the epad
|
||||
epad = PA.PadMaker(self.module).SMDPad( epad_w, epad_l, shape=pcbnew.PAD_SHAPE_RECT )
|
||||
epad.SetLocalSolderPasteMargin( -1 * self.epad['paste margin'] )
|
||||
# set pad layers
|
||||
layers = pcbnew.LSET(pcbnew.F_Mask)
|
||||
layers.AddLayer(pcbnew.F_Cu)
|
||||
layers.AddLayer(pcbnew.F_Paste)
|
||||
epad.SetPadName(epad_num)
|
||||
|
||||
array = PA.EPADGridArray( epad, epad_ny, epad_nx, epad_l, epad_w, pcbnew.wxPoint(0,0) )
|
||||
array.SetFirstPadInArray(epad_num)
|
||||
array.AddPadsToModule(self.draw)
|
||||
|
||||
if self.epad['thermal vias']:
|
||||
|
||||
# create the thermal via
|
||||
via_diam = min(epad_w, epad_l) / 2
|
||||
via_drill = min(via_diam / 2, epad_via_drill)
|
||||
via = PA.PadMaker(self.module).THRoundPad(via_diam, via_drill)
|
||||
layers = pcbnew.LSET.AllCuMask()
|
||||
layers.AddLayer(pcbnew.B_Mask)
|
||||
layers.AddLayer(pcbnew.F_Mask)
|
||||
via.SetLayerSet(layers)
|
||||
|
||||
via_array = PA.EPADGridArray(via, epad_ny, epad_nx, epad_l, epad_w, pcbnew.wxPoint(0,0) )
|
||||
via_array.SetFirstPadInArray(epad_num)
|
||||
via_array.AddPadsToModule(self.draw)
|
||||
|
||||
# Draw the package outline on the F.Fab layer
|
||||
bevel = min( pcbnew.FromMM(1.0), self.package['width']/2, self.package['height']/2 )
|
||||
|
||||
self.draw.SetLayer(pcbnew.F_Fab)
|
||||
|
||||
w = self.package['width']
|
||||
h = self.package['height']
|
||||
|
||||
self.draw.BoxWithDiagonalAtCorner(0, 0, w, h, bevel)
|
||||
|
||||
# Silkscreen
|
||||
self.draw.SetLayer(pcbnew.F_SilkS)
|
||||
|
||||
offset = self.draw.GetLineThickness()
|
||||
clip = row_len / 2 + self.pads['pitch']
|
||||
|
||||
self.draw.Polyline( [ [ clip, -h/2-offset], [ w/2+offset,-h/2-offset], [ w/2+offset, -clip] ] ) # top right
|
||||
self.draw.Polyline( [ [ clip, h/2+offset], [ w/2+offset, h/2+offset], [ w/2+offset, clip] ] ) # bottom right
|
||||
self.draw.Polyline( [ [-clip, h/2+offset], [-w/2-offset, h/2+offset], [-w/2-offset, clip] ] ) # bottom left
|
||||
|
||||
# Add pin-1 indication as per IPC-7351C
|
||||
self.draw.Line(-clip, -h/2-offset, -w/2-pad_length/2, -h/2-offset)
|
||||
|
||||
# Courtyard
|
||||
cmargin = self.parameters["Package"]["courtyard margin"]
|
||||
cmargin = self.package["margin"]
|
||||
self.draw.SetLayer(pcbnew.F_CrtYd)
|
||||
sizex = (lim_x + cmargin) * 2 + pad_length/2.
|
||||
sizey = (lim_y + cmargin) * 2 + pad_length/2.
|
||||
|
||||
sizex = (lim_x + cmargin) * 2 + pad_length
|
||||
sizey = (lim_y + cmargin) * 2 + pad_length
|
||||
|
||||
# round size to nearest 0.1mm, rectangle will thus land on a 0.05mm grid
|
||||
sizex = self.PutOnGridMM(sizex, 0.1)
|
||||
sizey = self.PutOnGridMM(sizey, 0.1)
|
||||
sizex = pcbnew.PutOnGridMM(sizex, 0.1)
|
||||
sizey = pcbnew.PutOnGridMM(sizey, 0.1)
|
||||
# set courtyard line thickness to the one defined in KLC
|
||||
thick = self.draw.GetLineThickness()
|
||||
self.draw.SetLineThickness(pcbnew.FromMM(0.05))
|
||||
|
|
|
@ -17,53 +17,64 @@
|
|||
from __future__ import division
|
||||
import pcbnew
|
||||
|
||||
import HelpfulFootprintWizardPlugin
|
||||
import FootprintWizardBase
|
||||
import PadArray as PA
|
||||
|
||||
|
||||
class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
||||
class QFPWizard(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GetName(self):
|
||||
return "QFP"
|
||||
|
||||
def GetDescription(self):
|
||||
return "Quad Flat Package footprint wizard"
|
||||
return "Quad Flat Package (QFP) footprint wizard"
|
||||
|
||||
def GenerateParameterList(self):
|
||||
self.AddParam("Pads", "n", self.uNatural, 100)
|
||||
self.AddParam("Pads", "pad pitch", self.uMM, 0.5)
|
||||
self.AddParam("Pads", "pad width", self.uMM, 0.25)
|
||||
self.AddParam("Pads", "pad length", self.uMM, 1.5)
|
||||
self.AddParam("Pads", "vertical pitch", self.uMM, 15)
|
||||
self.AddParam("Pads", "horizontal pitch", self.uMM, 15)
|
||||
self.AddParam("Pads", "n", self.uInteger, 100, multiple=4, min_value=4)
|
||||
self.AddParam("Pads", "pitch", self.uMM, 0.5, designator='e')
|
||||
self.AddParam("Pads", "width", self.uMM, 0.25, designator='X1')
|
||||
self.AddParam("Pads", "length", self.uMM, 1.5, designator='Y1')
|
||||
self.AddParam("Pads", "horizontal spacing", self.uMM, 15, designator='C1')
|
||||
self.AddParam("Pads", "vertical spacing", self.uMM, 15, designator='C2')
|
||||
self.AddParam("Pads", "oval", self.uBool, True)
|
||||
|
||||
self.AddParam("Package", "package width", self.uMM, 14)
|
||||
self.AddParam("Package", "package height", self.uMM, 14)
|
||||
self.AddParam("Package", "courtyard margin", self.uMM, 1)
|
||||
self.AddParam("Package", "width", self.uMM, 14, designator='D1')
|
||||
self.AddParam("Package", "height", self.uMM, 14, designator='E1')
|
||||
self.AddParam("Package", "courtyard margin", self.uMM, 0.25, min_value=0.2)
|
||||
|
||||
@property
|
||||
def pads(self):
|
||||
return self.parameters['Pads']
|
||||
|
||||
@property
|
||||
def package(self):
|
||||
return self.parameters['Package']
|
||||
|
||||
def CheckParameters(self):
|
||||
self.CheckParamInt("Pads", "*n", is_multiple_of=4)
|
||||
self.CheckParamBool("Pads", "*oval")
|
||||
# todo - custom checking
|
||||
pass
|
||||
|
||||
def GetValue(self):
|
||||
return "QFP_%d" % self.parameters["Pads"]["*n"]
|
||||
return "QFP-{n}_{x:g}x{y:g}_Pitch{p:g}mm".format(
|
||||
n = self.pads['n'],
|
||||
x = pcbnew.ToMM(self.package['width']),
|
||||
y = pcbnew.ToMM(self.package['height']),
|
||||
p = pcbnew.ToMM(self.pads['pitch'])
|
||||
)
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
pads = self.parameters["Pads"]
|
||||
|
||||
pad_pitch = pads["pad pitch"]
|
||||
pad_length = self.parameters["Pads"]["pad length"]
|
||||
pad_width = self.parameters["Pads"]["pad width"]
|
||||
pad_pitch = self.pads["pitch"]
|
||||
pad_length = self.pads["length"]
|
||||
pad_width = self.pads["width"]
|
||||
|
||||
v_pitch = pads["vertical pitch"]
|
||||
h_pitch = pads["horizontal pitch"]
|
||||
v_pitch = self.pads["vertical spacing"]
|
||||
h_pitch = self.pads["horizontal spacing"]
|
||||
|
||||
pads_per_row = pads["*n"] // 4
|
||||
pads_per_row = int(self.pads["n"] // 4)
|
||||
|
||||
row_len = (pads_per_row - 1) * pad_pitch
|
||||
|
||||
pad_shape = pcbnew.PAD_SHAPE_OVAL if pads["*oval"] else pcbnew.PAD_SHAPE_RECT
|
||||
pad_shape = pcbnew.PAD_SHAPE_OVAL if self.pads["oval"] else pcbnew.PAD_SHAPE_RECT
|
||||
|
||||
h_pad = PA.PadMaker(self.module).SMDPad( pad_length, pad_width,
|
||||
shape=pad_shape, rot_degree=90.0)
|
||||
|
@ -95,27 +106,49 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
|||
array.SetFirstPadInArray(3*pads_per_row + 1)
|
||||
array.AddPadsToModule(self.draw)
|
||||
|
||||
lim_x = self.parameters["Package"]["package width"] / 2
|
||||
lim_y = self.parameters["Package"]["package height"] / 2
|
||||
offset = pcbnew.FromMM(0.15)
|
||||
|
||||
x = self.parameters["Package"]["width"] / 2 + offset
|
||||
y = self.parameters["Package"]["height"] / 2 + offset
|
||||
inner = (row_len / 2) + pad_pitch
|
||||
|
||||
#top left - diagonal
|
||||
self.draw.Line(-lim_x, -inner, -inner, -lim_y)
|
||||
# Add outline to F_Fab layer
|
||||
self.draw.SetLayer(pcbnew.F_Fab)
|
||||
|
||||
bevel = min( pcbnew.FromMM(1.0), self.package['width']/2, self.package['height']/2 )
|
||||
|
||||
w = self.package['width']
|
||||
h = self.package['height']
|
||||
|
||||
# outermost limits of pins
|
||||
right_edge = (h_pitch + pad_length) / 2
|
||||
left_edge = -right_edge
|
||||
|
||||
bottom_edge = (v_pitch + pad_length) / 2
|
||||
top_edge = -bottom_edge
|
||||
|
||||
self.draw.BoxWithDiagonalAtCorner(0, 0, w, h, bevel)
|
||||
|
||||
# Draw silkscreen
|
||||
self.draw.SetLayer(pcbnew.F_SilkS)
|
||||
|
||||
#top left - as per IPC-7351C
|
||||
self.draw.Polyline([(-inner, -y), (-x, -y), (-x, -inner), (left_edge, -inner)])
|
||||
# top right
|
||||
self.draw.Polyline([(inner, -lim_y), (lim_x, -lim_y), (lim_x, -inner)])
|
||||
self.draw.Polyline([(inner, -y), (x, -y), (x, -inner)])
|
||||
# bottom left
|
||||
self.draw.Polyline([(-inner, lim_y), (-lim_x, lim_y), (-lim_x, inner)])
|
||||
self.draw.Polyline([(-inner, y), (-x, y), (-x, inner)])
|
||||
# bottom right
|
||||
self.draw.Polyline([(inner, lim_y), (lim_x, lim_y), (lim_x, inner)])
|
||||
self.draw.Polyline([(inner, y), (x, y), (x, inner)])
|
||||
|
||||
# Courtyard
|
||||
cmargin = self.parameters["Package"]["courtyard margin"]
|
||||
self.draw.SetLayer(pcbnew.F_CrtYd)
|
||||
sizex = (lim_x + cmargin) * 2 + pad_length
|
||||
sizey = (lim_y + cmargin) * 2 + pad_length
|
||||
sizex = (right_edge + cmargin) * 2
|
||||
sizey = (bottom_edge + cmargin) * 2
|
||||
# round size to nearest 0.1mm, rectangle will thus land on a 0.05mm grid
|
||||
sizex = self.PutOnGridMM(sizex, 0.1)
|
||||
sizey = self.PutOnGridMM(sizey, 0.1)
|
||||
sizex = pcbnew.PutOnGridMM(sizex, 0.1)
|
||||
sizey = pcbnew.PutOnGridMM(sizey, 0.1)
|
||||
# set courtyard line thickness to the one defined in KLC
|
||||
thick = self.draw.GetLineThickness()
|
||||
self.draw.SetLineThickness(pcbnew.FromMM(0.05))
|
||||
|
|
|
@ -0,0 +1,827 @@
|
|||
#
|
||||
# QR Code Generator for Python
|
||||
#
|
||||
# Copyright (c) 2012 Kazuhiko Arase
|
||||
#
|
||||
# URL: http://www.d-project.com/
|
||||
#
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license.php
|
||||
#
|
||||
# The word 'QR Code' is registered trademark of
|
||||
# DENSO WAVE INCORPORATED
|
||||
# http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
#
|
||||
|
||||
"""QR Code Generator for Python
|
||||
|
||||
from qrcode import QRCode, ErrorCorrectLevel
|
||||
|
||||
# generate with explicit type number
|
||||
qr = QRCode()
|
||||
qr.setTypeNumber(4)
|
||||
qr.setErrorCorrectLevel(ErrorCorrectLevel.M)
|
||||
qr.addData('here comes qr!')
|
||||
qr.make()
|
||||
|
||||
# generate with auto type number
|
||||
# qr = QRCode.getMinimumQRCode('here comes qr!', ErrorCorrectLevel.M)
|
||||
|
||||
# create an image
|
||||
for r in range(qr.getModuleCount() ):
|
||||
for c in range(qr.getModuleCount() ):
|
||||
color = black if qr.isDark(r, c) else white
|
||||
# set pixel ...
|
||||
|
||||
"""
|
||||
|
||||
class QRCode:
|
||||
|
||||
PAD0 = 0xEC
|
||||
PAD1 = 0x11
|
||||
|
||||
def __init__(self):
|
||||
self.typeNumber = 1
|
||||
self.errorCorrectLevel = ErrorCorrectLevel.H
|
||||
self.qrDataList = []
|
||||
self.modules = []
|
||||
self.moduleCount = 0
|
||||
|
||||
def getTypeNumber(self):
|
||||
return self.typeNumber
|
||||
|
||||
def setTypeNumber(self, typeNumber):
|
||||
self.typeNumber = typeNumber
|
||||
|
||||
def getErrorCorrectLevel(self):
|
||||
return self.errorCorrectLevel
|
||||
|
||||
def setErrorCorrectLevel(self, errorCorrectLevel):
|
||||
self.errorCorrectLevel = errorCorrectLevel
|
||||
|
||||
def clearData(self):
|
||||
self.qrDataList = []
|
||||
|
||||
def addData(self, data):
|
||||
self.qrDataList.append(QR8BitByte(data) )
|
||||
|
||||
def getDataCount(self):
|
||||
return len(self.qrDataList)
|
||||
|
||||
def getData(self, index):
|
||||
return self.qrDataList[index]
|
||||
|
||||
def isDark(self, row, col):
|
||||
return (self.modules[row][col] if self.modules[row][col] != None
|
||||
else False)
|
||||
|
||||
def getModuleCount(self):
|
||||
return self.moduleCount
|
||||
|
||||
def make(self):
|
||||
self._make(False, self._getBestMaskPattern() )
|
||||
|
||||
def _getBestMaskPattern(self):
|
||||
minLostPoint = 0
|
||||
pattern = 0
|
||||
for i in range(8):
|
||||
self._make(True, i)
|
||||
lostPoint = QRUtil.getLostPoint(self)
|
||||
if i == 0 or minLostPoint > lostPoint:
|
||||
minLostPoint = lostPoint
|
||||
pattern = i
|
||||
return pattern
|
||||
|
||||
def _make(self, test, maskPattern):
|
||||
|
||||
self.moduleCount = self.typeNumber * 4 + 17
|
||||
self.modules = [[None] * self.moduleCount
|
||||
for i in range(self.moduleCount)]
|
||||
|
||||
self._setupPositionProbePattern(0, 0)
|
||||
self._setupPositionProbePattern(self.moduleCount - 7, 0)
|
||||
self._setupPositionProbePattern(0, self.moduleCount - 7)
|
||||
|
||||
self._setupPositionAdjustPattern()
|
||||
self._setupTimingPattern()
|
||||
|
||||
self._setupTypeInfo(test, maskPattern)
|
||||
|
||||
if self.typeNumber >= 7:
|
||||
self._setupTypeNumber(test)
|
||||
|
||||
data = QRCode._createData(
|
||||
self.typeNumber,
|
||||
self.errorCorrectLevel,
|
||||
self.qrDataList)
|
||||
|
||||
self._mapData(data, maskPattern)
|
||||
|
||||
def _mapData(self, data, maskPattern):
|
||||
|
||||
rows = list(range(self.moduleCount) )
|
||||
cols = [col - 1 if col <= 6 else col
|
||||
for col in range(self.moduleCount - 1, 0, -2)]
|
||||
maskFunc = QRUtil.getMaskFunction(maskPattern)
|
||||
|
||||
byteIndex = 0
|
||||
bitIndex = 7
|
||||
|
||||
for col in cols:
|
||||
rows.reverse()
|
||||
for row in rows:
|
||||
for c in range(2):
|
||||
if self.modules[row][col - c] == None:
|
||||
|
||||
dark = False
|
||||
if byteIndex < len(data):
|
||||
dark = ( (data[byteIndex] >> bitIndex) & 1) == 1
|
||||
if maskFunc(row, col - c):
|
||||
dark = not dark
|
||||
self.modules[row][col - c] = dark
|
||||
|
||||
bitIndex -= 1
|
||||
if bitIndex == -1:
|
||||
byteIndex += 1
|
||||
bitIndex = 7
|
||||
|
||||
def _setupPositionAdjustPattern(self):
|
||||
pos = QRUtil.getPatternPosition(self.typeNumber)
|
||||
for row in pos:
|
||||
for col in pos:
|
||||
if self.modules[row][col] != None:
|
||||
continue
|
||||
for r in range(-2, 3):
|
||||
for c in range(-2, 3):
|
||||
self.modules[row + r][col + c] = (
|
||||
r == -2 or r == 2 or c == -2 or c == 2
|
||||
or (r == 0 and c == 0) )
|
||||
|
||||
def _setupPositionProbePattern(self, row, col):
|
||||
for r in range(-1, 8):
|
||||
for c in range(-1, 8):
|
||||
if (row + r <= -1 or self.moduleCount <= row + r
|
||||
or col + c <= -1 or self.moduleCount <= col + c):
|
||||
continue
|
||||
self.modules[row + r][col + c] = (
|
||||
(0 <= r and r <= 6 and (c == 0 or c == 6) )
|
||||
or (0 <= c and c <= 6 and (r == 0 or r == 6) )
|
||||
or (2 <= r and r <= 4 and 2 <= c and c <= 4) )
|
||||
|
||||
def _setupTimingPattern(self):
|
||||
for r in range(8, self.moduleCount - 8):
|
||||
if self.modules[r][6] != None:
|
||||
continue
|
||||
self.modules[r][6] = r % 2 == 0
|
||||
for c in range(8, self.moduleCount - 8):
|
||||
if self.modules[6][c] != None:
|
||||
continue
|
||||
self.modules[6][c] = c % 2 == 0
|
||||
|
||||
def _setupTypeNumber(self, test):
|
||||
bits = QRUtil.getBCHTypeNumber(self.typeNumber)
|
||||
for i in range(18):
|
||||
self.modules[i // 3][i % 3 + self.moduleCount - 8 - 3] = (
|
||||
not test and ( (bits >> i) & 1) == 1)
|
||||
for i in range(18):
|
||||
self.modules[i % 3 + self.moduleCount - 8 - 3][i // 3] = (
|
||||
not test and ( (bits >> i) & 1) == 1)
|
||||
|
||||
def _setupTypeInfo(self, test, maskPattern):
|
||||
|
||||
data = (self.errorCorrectLevel << 3) | maskPattern
|
||||
bits = QRUtil.getBCHTypeInfo(data)
|
||||
|
||||
# vertical
|
||||
for i in range(15):
|
||||
mod = not test and ( (bits >> i) & 1) == 1
|
||||
if i < 6:
|
||||
self.modules[i][8] = mod
|
||||
elif i < 8:
|
||||
self.modules[i + 1][8] = mod
|
||||
else:
|
||||
self.modules[self.moduleCount - 15 + i][8] = mod
|
||||
|
||||
# horizontal
|
||||
for i in range(15):
|
||||
mod = not test and ( (bits >> i) & 1) == 1
|
||||
if i < 8:
|
||||
self.modules[8][self.moduleCount - i - 1] = mod
|
||||
elif i < 9:
|
||||
self.modules[8][15 - i - 1 + 1] = mod
|
||||
else:
|
||||
self.modules[8][15 - i - 1] = mod
|
||||
|
||||
# fixed
|
||||
self.modules[self.moduleCount - 8][8] = not test
|
||||
|
||||
@staticmethod
|
||||
def _createData(typeNumber, errorCorrectLevel, dataArray):
|
||||
|
||||
rsBlocks = RSBlock.getRSBlocks(typeNumber, errorCorrectLevel)
|
||||
|
||||
buffer = BitBuffer()
|
||||
|
||||
for data in dataArray:
|
||||
buffer.put(data.getMode(), 4)
|
||||
buffer.put(data.getLength(), data.getLengthInBits(typeNumber) )
|
||||
data.write(buffer)
|
||||
|
||||
totalDataCount = sum(rsBlock.getDataCount()
|
||||
for rsBlock in rsBlocks)
|
||||
|
||||
if buffer.getLengthInBits() > totalDataCount * 8:
|
||||
raise Exception('code length overflow. (%s > %s)' %
|
||||
(buffer.getLengthInBits(), totalDataCount * 8) )
|
||||
|
||||
# end code
|
||||
if buffer.getLengthInBits() + 4 <= totalDataCount * 8:
|
||||
buffer.put(0, 4)
|
||||
|
||||
# padding
|
||||
while buffer.getLengthInBits() % 8 != 0:
|
||||
buffer.put(False)
|
||||
|
||||
# padding
|
||||
while True:
|
||||
if buffer.getLengthInBits() >= totalDataCount * 8:
|
||||
break
|
||||
buffer.put(QRCode.PAD0, 8)
|
||||
if buffer.getLengthInBits() >= totalDataCount * 8:
|
||||
break
|
||||
buffer.put(QRCode.PAD1, 8)
|
||||
|
||||
return QRCode._createBytes(buffer, rsBlocks)
|
||||
|
||||
@staticmethod
|
||||
def _createBytes(buffer, rsBlocks):
|
||||
|
||||
offset = 0
|
||||
|
||||
maxDcCount = 0
|
||||
maxEcCount = 0
|
||||
|
||||
dcdata = [None] * len(rsBlocks)
|
||||
ecdata = [None] * len(rsBlocks)
|
||||
|
||||
for r in range(len(rsBlocks) ):
|
||||
|
||||
dcCount = rsBlocks[r].getDataCount()
|
||||
ecCount = rsBlocks[r].getTotalCount() - dcCount
|
||||
|
||||
maxDcCount = max(maxDcCount, dcCount)
|
||||
maxEcCount = max(maxEcCount, ecCount)
|
||||
|
||||
dcdata[r] = [0] * dcCount
|
||||
for i in range(len(dcdata[r] ) ):
|
||||
dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]
|
||||
offset += dcCount
|
||||
|
||||
rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount)
|
||||
rawPoly = Polynomial(dcdata[r], rsPoly.getLength() - 1)
|
||||
|
||||
modPoly = rawPoly.mod(rsPoly)
|
||||
ecdata[r] = [0] * (rsPoly.getLength() - 1)
|
||||
for i in range(len(ecdata[r]) ):
|
||||
modIndex = i + modPoly.getLength() - len(ecdata[r])
|
||||
ecdata[r][i] = modPoly.get(modIndex) if modIndex >= 0 else 0
|
||||
|
||||
totalCodeCount = sum(rsBlock.getTotalCount()
|
||||
for rsBlock in rsBlocks)
|
||||
|
||||
data = [0] * totalCodeCount
|
||||
|
||||
index = 0
|
||||
|
||||
for i in range(maxDcCount):
|
||||
for r in range(len(rsBlocks) ):
|
||||
if i < len(dcdata[r] ):
|
||||
data[index] = dcdata[r][i]
|
||||
index += 1
|
||||
|
||||
for i in range(maxEcCount):
|
||||
for r in range(len(rsBlocks) ):
|
||||
if i < len(ecdata[r] ):
|
||||
data[index] = ecdata[r][i]
|
||||
index += 1
|
||||
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def getMinimumQRCode(data, errorCorrectLevel):
|
||||
mode = Mode.MODE_8BIT_BYTE # fixed to 8bit byte
|
||||
qr = QRCode()
|
||||
qr.setErrorCorrectLevel(errorCorrectLevel)
|
||||
qr.addData(data)
|
||||
length = qr.getData(0).getLength()
|
||||
for typeNumber in range(1, 11):
|
||||
if length <= QRUtil.getMaxLength(
|
||||
typeNumber, mode, errorCorrectLevel):
|
||||
qr.setTypeNumber(typeNumber)
|
||||
break
|
||||
qr.make()
|
||||
return qr
|
||||
|
||||
class Mode:
|
||||
MODE_NUMBER = 1 << 0
|
||||
MODE_ALPHA_NUM = 1 << 1
|
||||
MODE_8BIT_BYTE = 1 << 2
|
||||
MODE_KANJI = 1 << 3
|
||||
|
||||
class ErrorCorrectLevel:
|
||||
L = 1 # 7%
|
||||
M = 0 # 15%
|
||||
Q = 3 # 25%
|
||||
H = 2 # 30%
|
||||
|
||||
class MaskPattern:
|
||||
PATTERN000 = 0
|
||||
PATTERN001 = 1
|
||||
PATTERN010 = 2
|
||||
PATTERN011 = 3
|
||||
PATTERN100 = 4
|
||||
PATTERN101 = 5
|
||||
PATTERN110 = 6
|
||||
PATTERN111 = 7
|
||||
|
||||
class QRUtil:
|
||||
|
||||
@staticmethod
|
||||
def getPatternPosition(typeNumber):
|
||||
return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]
|
||||
|
||||
PATTERN_POSITION_TABLE = [
|
||||
[],
|
||||
[6, 18],
|
||||
[6, 22],
|
||||
[6, 26],
|
||||
[6, 30],
|
||||
[6, 34],
|
||||
[6, 22, 38],
|
||||
[6, 24, 42],
|
||||
[6, 26, 46],
|
||||
[6, 28, 50],
|
||||
[6, 30, 54],
|
||||
[6, 32, 58],
|
||||
[6, 34, 62],
|
||||
[6, 26, 46, 66],
|
||||
[6, 26, 48, 70],
|
||||
[6, 26, 50, 74],
|
||||
[6, 30, 54, 78],
|
||||
[6, 30, 56, 82],
|
||||
[6, 30, 58, 86],
|
||||
[6, 34, 62, 90],
|
||||
[6, 28, 50, 72, 94],
|
||||
[6, 26, 50, 74, 98],
|
||||
[6, 30, 54, 78, 102],
|
||||
[6, 28, 54, 80, 106],
|
||||
[6, 32, 58, 84, 110],
|
||||
[6, 30, 58, 86, 114],
|
||||
[6, 34, 62, 90, 118],
|
||||
[6, 26, 50, 74, 98, 122],
|
||||
[6, 30, 54, 78, 102, 126],
|
||||
[6, 26, 52, 78, 104, 130],
|
||||
[6, 30, 56, 82, 108, 134],
|
||||
[6, 34, 60, 86, 112, 138],
|
||||
[6, 30, 58, 86, 114, 142],
|
||||
[6, 34, 62, 90, 118, 146],
|
||||
[6, 30, 54, 78, 102, 126, 150],
|
||||
[6, 24, 50, 76, 102, 128, 154],
|
||||
[6, 28, 54, 80, 106, 132, 158],
|
||||
[6, 32, 58, 84, 110, 136, 162],
|
||||
[6, 26, 54, 82, 110, 138, 166],
|
||||
[6, 30, 58, 86, 114, 142, 170]
|
||||
]
|
||||
|
||||
MAX_LENGTH = [
|
||||
[ [41, 25, 17, 10], [34, 20, 14, 8], [27, 16, 11, 7], [17, 10, 7, 4] ],
|
||||
[ [77, 47, 32, 20], [63, 38, 26, 16], [48, 29, 20, 12], [34, 20, 14, 8] ],
|
||||
[ [127, 77, 53, 32], [101, 61, 42, 26], [77, 47, 32, 20], [58, 35, 24, 15] ],
|
||||
[ [187, 114, 78, 48], [149, 90, 62, 38], [111, 67, 46, 28], [82, 50, 34, 21] ],
|
||||
[ [255, 154, 106, 65], [202, 122, 84, 52], [144, 87, 60, 37], [106, 64, 44, 27] ],
|
||||
[ [322, 195, 134, 82], [255, 154, 106, 65], [178, 108, 74, 45], [139, 84, 58, 36] ],
|
||||
[ [370, 224, 154, 95], [293, 178, 122, 75], [207, 125, 86, 53], [154, 93, 64, 39] ],
|
||||
[ [461, 279, 192, 118], [365, 221, 152, 93], [259, 157, 108, 66], [202, 122, 84, 52] ],
|
||||
[ [552, 335, 230, 141], [432, 262, 180, 111], [312, 189, 130, 80], [235, 143, 98, 60] ],
|
||||
[ [652, 395, 271, 167], [513, 311, 213, 131], [364, 221, 151, 93], [288, 174, 119, 74] ]
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def getMaxLength(typeNumber, mode, errorCorrectLevel):
|
||||
t = typeNumber - 1
|
||||
e = {
|
||||
ErrorCorrectLevel.L: 0,
|
||||
ErrorCorrectLevel.M: 1,
|
||||
ErrorCorrectLevel.Q: 2,
|
||||
ErrorCorrectLevel.H: 3
|
||||
}[errorCorrectLevel]
|
||||
m = {
|
||||
Mode.MODE_NUMBER: 0,
|
||||
Mode.MODE_ALPHA_NUM: 1,
|
||||
Mode.MODE_8BIT_BYTE: 2,
|
||||
Mode.MODE_KANJI: 3
|
||||
}[mode]
|
||||
return QRUtil.MAX_LENGTH[t][e][m]
|
||||
|
||||
@staticmethod
|
||||
def getErrorCorrectPolynomial(errorCorrectLength):
|
||||
a = Polynomial([1])
|
||||
for i in range(errorCorrectLength):
|
||||
a = a.multiply(Polynomial([1, QRMath.gexp(i)]) )
|
||||
return a
|
||||
|
||||
@staticmethod
|
||||
def getMaskFunction(maskPattern):
|
||||
return {
|
||||
MaskPattern.PATTERN000:
|
||||
lambda i, j: (i + j) % 2 == 0,
|
||||
MaskPattern.PATTERN001:
|
||||
lambda i, j: i % 2 == 0,
|
||||
MaskPattern.PATTERN010:
|
||||
lambda i, j: j % 3 == 0,
|
||||
MaskPattern.PATTERN011:
|
||||
lambda i, j: (i + j) % 3 == 0,
|
||||
MaskPattern.PATTERN100:
|
||||
lambda i, j: (i // 2 + j // 3) % 2 == 0,
|
||||
MaskPattern.PATTERN101:
|
||||
lambda i, j: (i * j) % 2 + (i * j) % 3 == 0,
|
||||
MaskPattern.PATTERN110:
|
||||
lambda i, j: ( (i * j) % 2 + (i * j) % 3) % 2 == 0,
|
||||
MaskPattern.PATTERN111:
|
||||
lambda i, j: ( (i * j) % 3 + (i + j) % 2) % 2 == 0
|
||||
}[maskPattern]
|
||||
|
||||
@staticmethod
|
||||
def getLostPoint(qrcode):
|
||||
|
||||
moduleCount = qrcode.getModuleCount()
|
||||
lostPoint = 0
|
||||
|
||||
# LEVEL1
|
||||
for row in range(moduleCount):
|
||||
for col in range(moduleCount):
|
||||
sameCount = 0
|
||||
dark = qrcode.isDark(row, col)
|
||||
for r in range(-1, 2):
|
||||
if row + r < 0 or moduleCount <= row + r:
|
||||
continue
|
||||
for c in range(-1, 2):
|
||||
if col + c < 0 or moduleCount <= col + c:
|
||||
continue
|
||||
if r == 0 and c == 0:
|
||||
continue
|
||||
if dark == qrcode.isDark(row + r, col + c):
|
||||
sameCount += 1
|
||||
if sameCount > 5:
|
||||
lostPoint += (3 + sameCount - 5)
|
||||
|
||||
# LEVEL2
|
||||
for row in range(moduleCount - 1):
|
||||
for col in range(moduleCount - 1):
|
||||
count = 0
|
||||
if qrcode.isDark(row, col):
|
||||
count += 1
|
||||
if qrcode.isDark(row + 1, col):
|
||||
count += 1
|
||||
if qrcode.isDark(row, col + 1):
|
||||
count += 1
|
||||
if qrcode.isDark(row + 1, col + 1):
|
||||
count += 1
|
||||
if count == 0 or count == 4:
|
||||
lostPoint += 3
|
||||
|
||||
# LEVEL3
|
||||
for row in range(moduleCount):
|
||||
for col in range(moduleCount - 6):
|
||||
if (qrcode.isDark(row, col)
|
||||
and not qrcode.isDark(row, col + 1)
|
||||
and qrcode.isDark(row, col + 2)
|
||||
and qrcode.isDark(row, col + 3)
|
||||
and qrcode.isDark(row, col + 4)
|
||||
and not qrcode.isDark(row, col + 5)
|
||||
and qrcode.isDark(row, col + 6) ):
|
||||
lostPoint += 40
|
||||
|
||||
for col in range(moduleCount):
|
||||
for row in range(moduleCount - 6):
|
||||
if (qrcode.isDark(row, col)
|
||||
and not qrcode.isDark(row + 1, col)
|
||||
and qrcode.isDark(row + 2, col)
|
||||
and qrcode.isDark(row + 3, col)
|
||||
and qrcode.isDark(row + 4, col)
|
||||
and not qrcode.isDark(row + 5, col)
|
||||
and qrcode.isDark(row + 6, col) ):
|
||||
lostPoint += 40
|
||||
|
||||
# LEVEL4
|
||||
darkCount = 0
|
||||
for col in range(moduleCount):
|
||||
for row in range(moduleCount):
|
||||
if qrcode.isDark(row, col):
|
||||
darkCount += 1
|
||||
|
||||
ratio = abs(100 * darkCount // moduleCount // moduleCount - 50) // 5
|
||||
lostPoint += ratio * 10
|
||||
|
||||
return lostPoint
|
||||
|
||||
G15 = ( (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) |
|
||||
(1 << 2) | (1 << 1) | (1 << 0) )
|
||||
G18 = ( (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) |
|
||||
(1 << 8) | (1 << 5) | (1 << 2) | (1 << 0) )
|
||||
G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1)
|
||||
|
||||
@staticmethod
|
||||
def getBCHTypeInfo(data):
|
||||
d = data << 10
|
||||
while QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0:
|
||||
d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) -
|
||||
QRUtil.getBCHDigit(QRUtil.G15) ) )
|
||||
return ( (data << 10) | d) ^ QRUtil.G15_MASK
|
||||
|
||||
@staticmethod
|
||||
def getBCHTypeNumber(data):
|
||||
d = data << 12
|
||||
while QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0:
|
||||
d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) -
|
||||
QRUtil.getBCHDigit(QRUtil.G18) ) )
|
||||
return (data << 12) | d
|
||||
|
||||
@staticmethod
|
||||
def getBCHDigit(data):
|
||||
digit = 0
|
||||
while data != 0:
|
||||
digit += 1
|
||||
data >>= 1
|
||||
return digit
|
||||
|
||||
@staticmethod
|
||||
def stringToBytes(s):
|
||||
return [ord(c) & 0xff for c in s]
|
||||
|
||||
class QR8BitByte:
|
||||
|
||||
def __init__(self, data):
|
||||
self.mode = Mode.MODE_8BIT_BYTE
|
||||
self.data = data
|
||||
|
||||
def getMode(self):
|
||||
return self.mode
|
||||
|
||||
def getData(self):
|
||||
return self.data
|
||||
|
||||
'''
|
||||
def write(self, buffer): raise Exception('not implemented.')
|
||||
def getLength(self): raise Exception('not implemented.')
|
||||
'''
|
||||
|
||||
def write(self, buffer):
|
||||
data = QRUtil.stringToBytes(self.getData() )
|
||||
for d in data:
|
||||
buffer.put(d, 8)
|
||||
|
||||
def getLength(self):
|
||||
return len(QRUtil.stringToBytes(self.getData() ) )
|
||||
|
||||
def getLengthInBits(self, type):
|
||||
if 1 <= type and type < 10: # 1 - 9
|
||||
return {
|
||||
Mode.MODE_NUMBER: 10,
|
||||
Mode.MODE_ALPHA_NUM: 9,
|
||||
Mode.MODE_8BIT_BYTE: 8,
|
||||
Mode.MODE_KANJI: 8
|
||||
}[self.mode]
|
||||
|
||||
elif type < 27: # 10 - 26
|
||||
return {
|
||||
Mode.MODE_NUMBER: 12,
|
||||
Mode.MODE_ALPHA_NUM: 11,
|
||||
Mode.MODE_8BIT_BYTE: 16,
|
||||
Mode.MODE_KANJI: 10
|
||||
}[self.mode]
|
||||
|
||||
elif type < 41: # 27 - 40
|
||||
return {
|
||||
Mode.MODE_NUMBER: 14,
|
||||
Mode.MODE_ALPHA_NUM: 13,
|
||||
Mode.MODE_8BIT_BYTE: 16,
|
||||
Mode.MODE_KANJI: 12
|
||||
}[self.mode]
|
||||
|
||||
else:
|
||||
raise Exception('type:%s' % type)
|
||||
|
||||
class QRMath:
|
||||
|
||||
EXP_TABLE = None
|
||||
LOG_TABLE = None
|
||||
|
||||
@staticmethod
|
||||
def _init():
|
||||
|
||||
QRMath.EXP_TABLE = [0] * 256
|
||||
for i in range(256):
|
||||
QRMath.EXP_TABLE[i] = (1 << i if i < 8 else
|
||||
QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^
|
||||
QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8])
|
||||
|
||||
QRMath.LOG_TABLE = [0] * 256
|
||||
for i in range(255):
|
||||
QRMath.LOG_TABLE[QRMath.EXP_TABLE[i] ] = i
|
||||
|
||||
@staticmethod
|
||||
def glog(n):
|
||||
if n < 1:
|
||||
raise Exception('log(%s)' % n)
|
||||
return QRMath.LOG_TABLE[n]
|
||||
|
||||
@staticmethod
|
||||
def gexp(n):
|
||||
while n < 0:
|
||||
n += 255
|
||||
while n >= 256:
|
||||
n -= 255
|
||||
return QRMath.EXP_TABLE[n]
|
||||
|
||||
# initialize statics
|
||||
QRMath._init()
|
||||
|
||||
class Polynomial:
|
||||
|
||||
def __init__(self, num, shift=0):
|
||||
offset = 0
|
||||
length = len(num)
|
||||
while offset < length and num[offset] == 0:
|
||||
offset += 1
|
||||
self.num = num[offset:] + [0] * shift
|
||||
|
||||
def get(self, index):
|
||||
return self.num[index]
|
||||
|
||||
def getLength(self):
|
||||
return len(self.num)
|
||||
|
||||
def __repr__(self):
|
||||
return ','.join( [str(self.get(i) )
|
||||
for i in range(self.getLength() ) ] )
|
||||
|
||||
def toLogString(self):
|
||||
return ','.join( [str(QRMath.glog(self.get(i) ) )
|
||||
for i in range(self.getLength() ) ] )
|
||||
|
||||
def multiply(self, e):
|
||||
num = [0] * (self.getLength() + e.getLength() - 1)
|
||||
for i in range(self.getLength() ):
|
||||
for j in range(e.getLength() ):
|
||||
num[i + j] ^= QRMath.gexp(QRMath.glog(self.get(i) ) +
|
||||
QRMath.glog(e.get(j) ) )
|
||||
return Polynomial(num)
|
||||
|
||||
def mod(self, e):
|
||||
if self.getLength() - e.getLength() < 0:
|
||||
return self
|
||||
ratio = QRMath.glog(self.get(0) ) - QRMath.glog(e.get(0) )
|
||||
num = self.num[:]
|
||||
for i in range(e.getLength() ):
|
||||
num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio)
|
||||
return Polynomial(num).mod(e)
|
||||
|
||||
class RSBlock:
|
||||
|
||||
RS_BLOCK_TABLE = [
|
||||
|
||||
# L
|
||||
# M
|
||||
# Q
|
||||
# H
|
||||
|
||||
# 1
|
||||
[1, 26, 19],
|
||||
[1, 26, 16],
|
||||
[1, 26, 13],
|
||||
[1, 26, 9],
|
||||
|
||||
# 2
|
||||
[1, 44, 34],
|
||||
[1, 44, 28],
|
||||
[1, 44, 22],
|
||||
[1, 44, 16],
|
||||
|
||||
# 3
|
||||
[1, 70, 55],
|
||||
[1, 70, 44],
|
||||
[2, 35, 17],
|
||||
[2, 35, 13],
|
||||
|
||||
# 4
|
||||
[1, 100, 80],
|
||||
[2, 50, 32],
|
||||
[2, 50, 24],
|
||||
[4, 25, 9],
|
||||
|
||||
# 5
|
||||
[1, 134, 108],
|
||||
[2, 67, 43],
|
||||
[2, 33, 15, 2, 34, 16],
|
||||
[2, 33, 11, 2, 34, 12],
|
||||
|
||||
# 6
|
||||
[2, 86, 68],
|
||||
[4, 43, 27],
|
||||
[4, 43, 19],
|
||||
[4, 43, 15],
|
||||
|
||||
# 7
|
||||
[2, 98, 78],
|
||||
[4, 49, 31],
|
||||
[2, 32, 14, 4, 33, 15],
|
||||
[4, 39, 13, 1, 40, 14],
|
||||
|
||||
# 8
|
||||
[2, 121, 97],
|
||||
[2, 60, 38, 2, 61, 39],
|
||||
[4, 40, 18, 2, 41, 19],
|
||||
[4, 40, 14, 2, 41, 15],
|
||||
|
||||
# 9
|
||||
[2, 146, 116],
|
||||
[3, 58, 36, 2, 59, 37],
|
||||
[4, 36, 16, 4, 37, 17],
|
||||
[4, 36, 12, 4, 37, 13],
|
||||
|
||||
# 10
|
||||
[2, 86, 68, 2, 87, 69],
|
||||
[4, 69, 43, 1, 70, 44],
|
||||
[6, 43, 19, 2, 44, 20],
|
||||
[6, 43, 15, 2, 44, 16]
|
||||
]
|
||||
|
||||
def __init__(self, totalCount, dataCount):
|
||||
self.totalCount = totalCount
|
||||
self.dataCount = dataCount
|
||||
|
||||
def getDataCount(self):
|
||||
return self.dataCount
|
||||
|
||||
def getTotalCount(self):
|
||||
return self.totalCount
|
||||
|
||||
def __repr__(self):
|
||||
return ('(total=%s,data=%s)' % (self.totalCount, self.dataCount) )
|
||||
|
||||
@staticmethod
|
||||
def getRSBlocks(typeNumber, errorCorrectLevel):
|
||||
rsBlock = RSBlock.getRsBlockTable(typeNumber, errorCorrectLevel)
|
||||
length = len(rsBlock) // 3
|
||||
list = []
|
||||
for i in range(length):
|
||||
count = rsBlock[i * 3 + 0]
|
||||
totalCount = rsBlock[i * 3 + 1]
|
||||
dataCount = rsBlock[i * 3 + 2]
|
||||
list += [RSBlock(totalCount, dataCount)] * count
|
||||
return list
|
||||
|
||||
@staticmethod
|
||||
def getRsBlockTable(typeNumber, errorCorrectLevel):
|
||||
return {
|
||||
ErrorCorrectLevel.L:
|
||||
RSBlock.RS_BLOCK_TABLE[ (typeNumber - 1) * 4 + 0],
|
||||
ErrorCorrectLevel.M:
|
||||
RSBlock.RS_BLOCK_TABLE[ (typeNumber - 1) * 4 + 1],
|
||||
ErrorCorrectLevel.Q:
|
||||
RSBlock.RS_BLOCK_TABLE[ (typeNumber - 1) * 4 + 2],
|
||||
ErrorCorrectLevel.H:
|
||||
RSBlock.RS_BLOCK_TABLE[ (typeNumber - 1) * 4 + 3]
|
||||
}[errorCorrectLevel]
|
||||
|
||||
class BitBuffer:
|
||||
|
||||
def __init__(self, inclements=32):
|
||||
self.inclements = inclements
|
||||
self.buffer = [0] * self.inclements
|
||||
self.length = 0
|
||||
|
||||
def getBuffer(self):
|
||||
return self.buffer
|
||||
|
||||
def getLengthInBits(self):
|
||||
return self.length
|
||||
|
||||
def get(self, index):
|
||||
return ( (self.buffer[index // 8] >> (7 - index % 8) ) & 1) == 1
|
||||
|
||||
def putBit(self, bit):
|
||||
if self.length == len(self.buffer) * 8:
|
||||
self.buffer += [0] * self.inclements
|
||||
if bit:
|
||||
self.buffer[self.length // 8] |= (0x80 >> (self.length % 8) )
|
||||
self.length += 1
|
||||
|
||||
def put(self, num, length):
|
||||
for i in range(length):
|
||||
self.putBit( ( (num >> (length - i - 1) ) & 1) == 1)
|
||||
|
||||
def __repr__(self):
|
||||
return ''.join('1' if self.get(i) else '0'
|
||||
for i in range(self.getLengthInBits() ) )
|
|
@ -0,0 +1,120 @@
|
|||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
import pcbnew
|
||||
import FootprintWizardBase
|
||||
|
||||
# Additional import for QRCode
|
||||
# see https://github.com/kazuhikoarase/qrcode-generator/blob/master/python/qrcode.py
|
||||
import qrcode
|
||||
|
||||
class QRCodeWizard(FootprintWizardBase.FootprintWizard):
|
||||
GetName = lambda self: '2D Barcode QRCode'
|
||||
GetDescription = lambda self: 'QR Code'
|
||||
GetReferencePrefix = lambda self: 'QR***'
|
||||
GetValue = lambda self: self.module.Value().GetText()
|
||||
|
||||
def GenerateParameterList(self):
|
||||
self.AddParam("Barcode", "Pixel Width", self.uMM, 0.5, min_value=0.4)
|
||||
self.AddParam("Barcode", "Border", self.uInteger, 0)
|
||||
self.AddParam("Barcode", "Contents", self.uString, 'Example')
|
||||
self.AddParam("Barcode", "Negative", self.uBool, False)
|
||||
self.AddParam("Barcode", "Use SilkS layer", self.uBool, False)
|
||||
self.AddParam("Barcode", "Use Cu layer", self.uBool, True)
|
||||
self.AddParam("Caption", "Enabled", self.uBool, True)
|
||||
self.AddParam("Caption", "Height", self.uMM, 1.2)
|
||||
self.AddParam("Caption", "Thickness", self.uMM, 0.12)
|
||||
|
||||
|
||||
def CheckParameters(self):
|
||||
self.Barcode = str(self.parameters['Barcode']['Contents'])
|
||||
self.X = self.parameters['Barcode']['Pixel Width']
|
||||
self.negative = self.parameters['Barcode']['Negative']
|
||||
self.UseSilkS = self.parameters['Barcode']['Use SilkS layer']
|
||||
self.UseCu = self.parameters['Barcode']['Use Cu layer']
|
||||
self.border = int(self.parameters['Barcode']['Border'])
|
||||
self.textHeight = int(self.parameters['Caption']['Height'])
|
||||
self.module.Value().SetText(str(self.Barcode) )
|
||||
|
||||
# Build Qrcode
|
||||
self.qr = qrcode.QRCode()
|
||||
self.qr.setTypeNumber(4)
|
||||
# ErrorCorrectLevel: L = 7%, M = 15% Q = 25% H = 30%
|
||||
self.qr.setErrorCorrectLevel(qrcode.ErrorCorrectLevel.M)
|
||||
self.qr.addData(str(self.Barcode))
|
||||
self.qr.make()
|
||||
|
||||
def _drawPixel(self, xposition, yposition):
|
||||
# build a rectangular pad: as a dot
|
||||
pad = pcbnew.D_PAD(self.module)
|
||||
pad.SetSize(pcbnew.wxSize(self.X, self.X))
|
||||
pad.SetShape(pcbnew.PAD_SHAPE_RECT)
|
||||
pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)
|
||||
layerset = pcbnew.LSET()
|
||||
if self.UseCu:
|
||||
layerset.AddLayer(pcbnew.F_Cu)
|
||||
layerset.AddLayer(pcbnew.F_Mask)
|
||||
if self.UseSilkS:
|
||||
layerset.AddLayer(pcbnew.F_SilkS)
|
||||
pad.SetLayerSet( layerset )
|
||||
pad.SetPosition(pcbnew.wxPoint(xposition,yposition))
|
||||
pad.SetPadName("1")
|
||||
self.module.Add(pad)
|
||||
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
if self.border >= 0:
|
||||
# Adding border: Create a new array larger than the self.qr.modules
|
||||
sz = self.qr.modules.__len__() + (self.border * 2)
|
||||
arrayToDraw = [ [ 0 for a in range(sz) ] for b in range(sz) ]
|
||||
lineposition = self.border
|
||||
for i in self.qr.modules:
|
||||
columnposition = self.border
|
||||
for j in i:
|
||||
arrayToDraw[lineposition][columnposition] = j
|
||||
columnposition += 1
|
||||
lineposition += 1
|
||||
else:
|
||||
# No border: using array as is
|
||||
arrayToDraw = self.qr.modules
|
||||
|
||||
# used many times...
|
||||
half_number_of_elements = arrayToDraw.__len__() / 2
|
||||
|
||||
# Center position of QrCode
|
||||
yposition = - int(half_number_of_elements * self.X)
|
||||
for line in arrayToDraw:
|
||||
xposition = - int(half_number_of_elements * self.X)
|
||||
for pixel in line:
|
||||
# Trust table for drawing a pixel
|
||||
# Negative is a boolean;
|
||||
# each pixel is a boolean (need to draw of not)
|
||||
# Negative | Pixel | Result
|
||||
# 0 | 0 | 0
|
||||
# 0 | 1 | 1
|
||||
# 1 | 0 | 1
|
||||
# 1 | 1 | 0
|
||||
# => Draw as Xor
|
||||
if self.negative != pixel: # Xor...
|
||||
self._drawPixel(xposition, yposition)
|
||||
xposition += self.X
|
||||
yposition += self.X
|
||||
#int((5 + half_number_of_elements) * self.X))
|
||||
textPosition = int((self.textHeight) + ((1 + half_number_of_elements) * self.X))
|
||||
self.module.Value().SetPosition(pcbnew.wxPoint(0, - textPosition))
|
||||
self.module.Reference().SetPosition(pcbnew.wxPoint(0, textPosition))
|
||||
self.module.Value().SetLayer(pcbnew.F_SilkS)
|
||||
|
||||
QRCodeWizard().register()
|
|
@ -17,7 +17,7 @@
|
|||
from __future__ import division
|
||||
import pcbnew
|
||||
|
||||
import HelpfulFootprintWizardPlugin as HFPW
|
||||
import FootprintWizardBase
|
||||
import PadArray as PA
|
||||
|
||||
|
||||
|
@ -35,7 +35,7 @@ class RowedGridArray(PA.PadGridArray):
|
|||
return x+1
|
||||
|
||||
|
||||
class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
||||
class RowedFootprint(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
pad_count_key = 'pad count'
|
||||
row_count_key = 'row count'
|
||||
|
@ -50,31 +50,25 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
|||
|
||||
def GenerateParameterList(self):
|
||||
# defaults for a DIP package
|
||||
self.AddParam("Pads", self.pad_count_key, self.uNatural, 24)
|
||||
self.AddParam("Pads", self.row_count_key, self.uNatural, 2)
|
||||
self.AddParam("Pads", self.pad_count_key, self.uInteger, 24)
|
||||
self.AddParam("Pads", self.row_count_key, self.uInteger, 2, min_value=1, max_value=2)
|
||||
|
||||
self.AddParam("Body", self.silkscreen_inside_key, self.uBool, False)
|
||||
self.AddParam("Body", self.outline_x_margin_key, self.uMM, 0.5)
|
||||
self.AddParam("Body", self.outline_y_margin_key, self.uMM, 0.5)
|
||||
|
||||
def CheckParameters(self):
|
||||
self.CheckParamInt("Pads", '*' + self.row_count_key, min_value=1, max_value=2)
|
||||
self.CheckParamInt(
|
||||
"Pads", '*' + self.pad_count_key,
|
||||
is_multiple_of=self.parameters["Pads"]['*' + self.row_count_key])
|
||||
|
||||
# can do this internally to parameter manager?
|
||||
self.CheckParamBool("Body", '*' + self.silkscreen_inside_key)
|
||||
self.CheckParam("Pads", self.pad_count_key, multiple=self.parameters['Pads'][self.row_count_key], info='Pads must be multiple of row count')
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
pads = self.parameters["Pads"]
|
||||
body = self.parameters["Body"]
|
||||
num_pads = pads['*' + self.pad_count_key]
|
||||
num_pads = pads[self.pad_count_key]
|
||||
pad_length = pads[self.pad_length_key]
|
||||
pad_width = pads[self.pad_width_key]
|
||||
row_pitch = pads[self.row_spacing_key]
|
||||
pad_pitch = pads[self.pad_pitch_key]
|
||||
num_rows = pads['*' + self.row_count_key]
|
||||
num_rows = pads[self.row_count_key]
|
||||
|
||||
pads_per_row = num_pads // num_rows
|
||||
|
||||
|
@ -96,7 +90,7 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
|||
ssx_offset = -pad_width / 2 - body[self.outline_x_margin_key]
|
||||
ssy_offset = -pad_length / 2 - body[self.outline_y_margin_key]
|
||||
|
||||
if body['*' + self.silkscreen_inside_key]:
|
||||
if body[self.silkscreen_inside_key]:
|
||||
ssy_offset *= -1
|
||||
|
||||
ssx = -pin1_posX - ssx_offset
|
||||
|
@ -110,8 +104,8 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
|||
sizex = (ssx + cmargin) * 2
|
||||
sizey = (ssy + cmargin) * 2
|
||||
# round size to nearest 0.1mm, rectangle will thus land on a 0.05mm grid
|
||||
sizex = self.PutOnGridMM(sizex, 0.1)
|
||||
sizey = self.PutOnGridMM(sizey, 0.1)
|
||||
sizex = pcbnew.PutOnGridMM(sizex, 0.1)
|
||||
sizey = pcbnew.PutOnGridMM(sizey, 0.1)
|
||||
# set courtyard line thickness to the one defined in KLC
|
||||
self.draw.SetLineThickness(pcbnew.FromMM(0.05))
|
||||
self.draw.Box(0, 0, sizex, sizey)
|
||||
|
@ -156,8 +150,8 @@ class SDIPWizard(RowedFootprint):
|
|||
|
||||
def GetValue(self):
|
||||
pads = self.parameters["Pads"]
|
||||
rows = pads['*' + self.row_count_key]
|
||||
pad_count = pads['*' + self.pad_count_key]
|
||||
rows = pads[self.row_count_key]
|
||||
pad_count = pads[self.pad_count_key]
|
||||
row_dist_mil = pcbnew.Iu2Mils(int(self.parameters["Pads"][self.row_spacing_key])) #int(self.parameters["Pads"][self.row_spacing_key] / 2.54 * 100)
|
||||
pad_shape = ""
|
||||
|
||||
|
@ -185,7 +179,7 @@ class SDIPWizard(RowedFootprint):
|
|||
|
||||
def DrawBox(self, ssx, ssy):
|
||||
|
||||
if self.parameters["Pads"]['*' + self.row_count_key] == 2:
|
||||
if self.parameters["Pads"][self.row_count_key] == 2:
|
||||
|
||||
# ----------
|
||||
# |8 7 6 5 |
|
||||
|
@ -208,7 +202,7 @@ class SDIPWizard(RowedFootprint):
|
|||
|
||||
#line between pin1 and pin2
|
||||
pad_pitch = self.parameters["Pads"][self.pad_pitch_key]
|
||||
pad_cnt = self.parameters["Pads"]['*' + self.pad_count_key]
|
||||
pad_cnt = self.parameters["Pads"][self.pad_count_key]
|
||||
line_x = ( pad_cnt/2 - 1) * pad_pitch
|
||||
self.draw.VLine(-line_x, -ssy, ssy * 2)
|
||||
|
||||
|
@ -226,7 +220,7 @@ class SOICWizard(RowedFootprint):
|
|||
return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard"
|
||||
|
||||
def GetValue(self):
|
||||
pad_count = self.parameters["Pads"]['*' + self.pad_count_key]
|
||||
pad_count = self.parameters["Pads"][self.pad_count_key]
|
||||
return "%s-%d" % ("SOIC", pad_count)
|
||||
|
||||
def GenerateParameterList(self):
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
#
|
||||
|
||||
from pcbnew import *
|
||||
import HelpfulFootprintWizardPlugin as HFPW
|
||||
import FootprintWizardBase
|
||||
import pcbnew
|
||||
|
||||
|
||||
class TouchSliderWizard(HFPW.HelpfulFootprintWizardPlugin):
|
||||
class TouchSliderWizard(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GetName(self):
|
||||
"""
|
||||
|
@ -44,16 +44,23 @@ class TouchSliderWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
return 'Capacitive Touch Slider wizard'
|
||||
|
||||
def GetValue(self):
|
||||
steps = int(self.parameters["Pads"]["*steps"])
|
||||
return "TS"+str(steps)
|
||||
return "TouchSlider-{s}_{x:g}x{y:g}mm".format(
|
||||
s = self.pads['steps'],
|
||||
x = pcbnew.ToMM(self.pads['length']),
|
||||
y = pcbnew.ToMM(self.pads['width'])
|
||||
)
|
||||
|
||||
def GenerateParameterList(self):
|
||||
self.AddParam("Pads", "steps", self.uNatural, 4)
|
||||
self.AddParam("Pads", "bands", self.uNatural, 2)
|
||||
self.AddParam("Pads", "steps", self.uInteger, 4, min_value=2)
|
||||
self.AddParam("Pads", "bands", self.uInteger, 2, min_value=1)
|
||||
self.AddParam("Pads", "width", self.uMM, 10)
|
||||
self.AddParam("Pads", "length", self.uMM, 50)
|
||||
self.AddParam("Pads", "clearance", self.uMM, 1)
|
||||
|
||||
@property
|
||||
def pads(self):
|
||||
return self.parameters['Pads']
|
||||
|
||||
# build a rectangular pad
|
||||
def smdRectPad(self,module,size,pos,name):
|
||||
pad = D_PAD(module)
|
||||
|
@ -82,18 +89,8 @@ class TouchSliderWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
|
||||
# This method checks the parameters provided to wizard and set errors
|
||||
def CheckParameters(self):
|
||||
prms = self.parameters["Pads"]
|
||||
steps = prms["*steps"]
|
||||
bands = prms["*bands"]
|
||||
|
||||
if steps < 1:
|
||||
self.parameter_errors["Pads"]["*steps"]="steps must be positive"
|
||||
if bands < 1:
|
||||
self.parameter_errors["Pads"]["*bands"]="bands must be positive"
|
||||
|
||||
touch_width = prms["width"]
|
||||
touch_length = prms["length"]
|
||||
touch_clearance = prms["clearance"]
|
||||
#TODO - implement custom checks
|
||||
pass
|
||||
|
||||
# The start pad is made of a rectangular pad plus a couple of
|
||||
# triangular pads facing tips on the middle/right of the first
|
||||
|
@ -177,18 +174,18 @@ class TouchSliderWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
# build the footprint from parameters
|
||||
# FIX ME: the X and Y position of the footprint can be better.
|
||||
def BuildThisFootprint(self):
|
||||
prm = self.parameters["Pads"]
|
||||
steps = int(prm["*steps"])
|
||||
bands = int(prm["*bands"])
|
||||
touch_width = prm["width"]
|
||||
touch_length = prm["length"]
|
||||
touch_clearance = prm["clearance"]
|
||||
|
||||
steps = self.pads["steps"]
|
||||
bands = self.pads["bands"]
|
||||
touch_width = self.pads["width"]
|
||||
touch_length = self.pads["length"]
|
||||
touch_clearance = self.pads["clearance"]
|
||||
|
||||
step_length = float(touch_length) / float(steps)
|
||||
|
||||
t_size = self.GetTextSize()
|
||||
w_text = self.draw.GetLineThickness()
|
||||
ypos = touch_width/(bands*2) + t_size/2 + w_text
|
||||
ypos = touch_width/2 + t_size/2 + w_text
|
||||
self.draw.Value(0, -ypos, t_size)
|
||||
ypos += t_size + w_text*2
|
||||
self.draw.Reference(0, -ypos, t_size)
|
||||
|
@ -197,9 +194,13 @@ class TouchSliderWizard(HFPW.HelpfulFootprintWizardPlugin):
|
|||
self.module.SetAttributes(MOD_CMS)
|
||||
|
||||
# starting pad
|
||||
pos = wxPointMM(0,0)
|
||||
band_width = touch_width/bands
|
||||
|
||||
xpos = -0.5 * (steps - 1) * step_length
|
||||
ypos = -0.5 * (bands - 1) * band_width
|
||||
|
||||
pos = wxPointMM(pcbnew.ToMM(xpos), pcbnew.ToMM(ypos))
|
||||
|
||||
for b in range(bands):
|
||||
self.AddStrip(pos,steps,band_width,step_length,touch_clearance)
|
||||
pos += wxPoint(0,band_width)
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
from __future__ import division
|
||||
import pcbnew as B
|
||||
|
||||
import HelpfulFootprintWizardPlugin
|
||||
import FootprintWizardBase
|
||||
|
||||
'''
|
||||
Created on Jan 16, 2015
|
||||
|
@ -49,7 +48,7 @@ class Uss39:
|
|||
# Reformated text with start and end characters
|
||||
return reduce(lambda a1, a2: a1 + [0] + a2, [map(int, ptd[c]) for c in ("*%s*" % self.makePrintable(text))])
|
||||
|
||||
class Uss39Wizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
||||
class Uss39Wizard(FootprintWizardBase.FootprintWizard):
|
||||
GetName = lambda self: 'BARCODE USS-39'
|
||||
GetDescription = lambda self: 'USS-39 Barcode'
|
||||
GetReferencePrefix = lambda self: 'BARCODE'
|
||||
|
@ -61,18 +60,20 @@ class Uss39Wizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
|||
self.AddParam("Barcode", "Height", self.uMM, 3.0)
|
||||
self.AddParam("Barcode", "Margin", self.uMM, 2.0)
|
||||
self.AddParam("Barcode", "Contents", self.uString, 'BARCODE')
|
||||
|
||||
self.AddParam("Caption", "Enabled", self.uBool, True)
|
||||
self.AddParam("Caption", "Height", self.uMM, 1.2)
|
||||
self.AddParam("Caption", "Thickness", self.uMM, 0.12)
|
||||
|
||||
def CheckParameters(self):
|
||||
|
||||
# Reset constants
|
||||
self.CourtyardLineWidth = B.FromMM(0.05)
|
||||
# Set bar height to the greater of 6.35mm or 0.15*L
|
||||
# Set quiet width to 10*X
|
||||
# User-defined parameters
|
||||
# Create barcode object
|
||||
self.Barcode = Uss39('=' + str(self.parameters['Barcode']['*Contents']))
|
||||
self.Barcode = Uss39('=' + str(self.parameters['Barcode']['Contents']))
|
||||
self.X = int(self.parameters['Barcode']['Pixel Width'])
|
||||
self.module.Value().SetText( str(self.Barcode) )
|
||||
self.C = len(str(self.Barcode))
|
||||
|
@ -146,4 +147,4 @@ class Uss39Wizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
|||
self.draw.Circle(0, 0, B.FromMM(0.25))
|
||||
self.module.Value().SetLayer(B.F_Fab)
|
||||
|
||||
Uss39Wizard().register()
|
||||
Uss39Wizard().register()
|
|
@ -17,52 +17,41 @@
|
|||
from __future__ import division
|
||||
import pcbnew
|
||||
|
||||
import HelpfulFootprintWizardPlugin as HFPW
|
||||
import FootprintWizardBase
|
||||
import PadArray as PA
|
||||
|
||||
|
||||
class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
||||
|
||||
pad_count_key = '#pad count'
|
||||
line_count_key = '#line count'
|
||||
pad_vertical_size_key = 'pad vertical size'
|
||||
pad_horizontal_size_key = 'pad horizontal size'
|
||||
line_spacing_key = 'line spacing'
|
||||
pad_pitch_key = 'pad pitch'
|
||||
drill_size_key = 'drill size'
|
||||
|
||||
courtyard_x_margin_key = 'courtyard x margin'
|
||||
courtyard_y_margin_key = 'courtyard y margin'
|
||||
outline_x_margin_key = 'outline x margin'
|
||||
outline_y_margin_key = 'outline y margin'
|
||||
silkscreen_inside_key = 'silk screen inside'
|
||||
class RowedFootprint(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GenerateParameterList(self):
|
||||
|
||||
# defaults for a ZIP package
|
||||
self.AddParam("Pads", self.pad_count_key, self.uNatural, 24)
|
||||
self.AddParam("Pads", self.line_count_key, self.uNatural, 2)
|
||||
self.AddParam("Body", self.silkscreen_inside_key, self.uBool, False)
|
||||
self.AddParam("Body", self.courtyard_x_margin_key, self.uMM, 1)
|
||||
self.AddParam("Body", self.courtyard_y_margin_key, self.uMM, 1)
|
||||
self.AddParam("Pads", "pad count", self.uInteger, 24)
|
||||
self.AddParam("Pads", "line count", self.uInteger, 2)
|
||||
|
||||
self.AddParam("Body", "silkscreen inside", self.uBool, False)
|
||||
self.AddParam("Body", "courtyard margin", self.uMM, 0.5, min_value=0.2)
|
||||
|
||||
@property
|
||||
def pads(self):
|
||||
return self.parameters['Pads']
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self.parameters['Body']
|
||||
|
||||
def CheckParameters(self):
|
||||
self.CheckParamInt("Pads", '*' + self.pad_count_key)
|
||||
self.CheckParamInt("Pads", '*' + self.line_count_key)
|
||||
|
||||
# can do this internally to parameter manager?
|
||||
self.CheckParamBool("Body", '*' + self.silkscreen_inside_key)
|
||||
# TODO - implement custom checks
|
||||
pass
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
pads = self.parameters["Pads"]
|
||||
body = self.parameters["Body"]
|
||||
|
||||
pad_count = pads['*' + self.pad_count_key]
|
||||
pad_Vsize = pads[self.pad_vertical_size_key]
|
||||
pad_Hsize = pads[self.pad_horizontal_size_key]
|
||||
line_pitch = pads[self.line_spacing_key]
|
||||
pad_pitch = pads[self.pad_pitch_key]
|
||||
line_count = pads['*' + self.line_count_key]
|
||||
pad_count = self.pads['pad count']
|
||||
pad_Vsize = self.pads['pad height']
|
||||
pad_Hsize = self.pads['pad width']
|
||||
line_pitch = self.pads['line spacing']
|
||||
pad_pitch = self.pads['pitch']
|
||||
line_count = self.pads['line count']
|
||||
|
||||
if line_count == 1:
|
||||
singleline = True
|
||||
|
@ -74,12 +63,12 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
|||
|
||||
array = PA.PadZGridArray(pad, pad_count, line_count, line_pitch, pad_pitch)
|
||||
array.AddPadsToModule(self.draw)
|
||||
|
||||
|
||||
# draw the Silk Screen
|
||||
pads_per_line = pad_count // line_count
|
||||
row_length = pad_pitch * (pads_per_line - 1) # fenceposts
|
||||
ssx_offset = pad_Hsize / 2 + body[self.outline_x_margin_key]
|
||||
ssy_offset = pad_Vsize / 2 + body[self.outline_y_margin_key]
|
||||
ssx_offset = pad_Hsize / 2 + self.body['outline x margin']
|
||||
ssy_offset = pad_Vsize / 2 + self.body['outline y margin']
|
||||
|
||||
pin1posX = pad_pitch * (pad_count - 1) / 2
|
||||
pin1posY = line_pitch * (line_count - 1) / 2
|
||||
|
@ -91,7 +80,7 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
|||
# body inside pads is possible only for 2 rows.
|
||||
# for other values, there is no room
|
||||
linew = self.draw.GetLineThickness()
|
||||
if body['*'+self.silkscreen_inside_key] and line_count == 2:
|
||||
if self.body['silkscreen inside'] and line_count == 2:
|
||||
cornery = pin1posY - ssy_offset
|
||||
if cornery < linew:
|
||||
cornery = linew
|
||||
|
@ -99,15 +88,15 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
|||
self.DrawBox(leftx*2, cornery*2)
|
||||
|
||||
# Courtyard
|
||||
cmarginx = body[self.courtyard_x_margin_key]
|
||||
cmarginy = body[self.courtyard_y_margin_key]
|
||||
cmarginx = self.body['courtyard margin']
|
||||
cmarginy = cmarginx
|
||||
self.draw.SetLayer(pcbnew.F_CrtYd)
|
||||
thick = self.draw.GetLineThickness()
|
||||
sizex = (pin1posX + cmarginx) * 2 + pad_Hsize + thick
|
||||
sizey = (pin1posY + cmarginy) * 2 + pad_Vsize + thick
|
||||
# round size to nearest 0.1mm, rectangle will thus land on a 0.05mm grid
|
||||
sizex = self.PutOnGridMM(sizex, 0.1)
|
||||
sizey = self.PutOnGridMM(sizey, 0.1)
|
||||
sizex = pcbnew.PutOnGridMM(sizex, 0.1)
|
||||
sizey = pcbnew.PutOnGridMM(sizey, 0.1)
|
||||
# set courtyard line thickness to the one defined in KLC
|
||||
self.draw.SetLineThickness(pcbnew.FromMM(0.05))
|
||||
self.draw.Box(0, 0, sizex, sizey)
|
||||
|
@ -152,17 +141,17 @@ class ZIPWizard(RowedFootprint):
|
|||
def GenerateParameterList(self):
|
||||
RowedFootprint.GenerateParameterList(self)
|
||||
|
||||
self.AddParam("Pads", self.pad_pitch_key, self.uMM, 1.27)
|
||||
self.AddParam("Pads", self.pad_horizontal_size_key, self.uMM, 1.2)
|
||||
self.AddParam("Pads", self.pad_vertical_size_key, self.uMM, 2)
|
||||
self.AddParam("Pads", self.line_spacing_key, self.uMM, 2.54)
|
||||
self.AddParam("Pads", self.drill_size_key, self.uMM, 0.8)
|
||||
self.AddParam("Body", self.outline_x_margin_key, self.uMM, 1)
|
||||
self.AddParam("Body", self.outline_y_margin_key, self.uMM, 0.5)
|
||||
self.AddParam("Pads", "pitch", self.uMM, 1.27)
|
||||
self.AddParam("Pads", "pad width", self.uMM, 1.2)
|
||||
self.AddParam("Pads", "pad height", self.uMM, 2)
|
||||
self.AddParam("Pads", "line spacing", self.uMM, 2.54)
|
||||
self.AddParam("Pads", "drill size", self.uMM, 0.8)
|
||||
self.AddParam("Body", 'outline x margin', self.uMM, 1)
|
||||
self.AddParam("Body", 'outline y margin', self.uMM, 0.5)
|
||||
|
||||
def GetValue(self):
|
||||
rows = self.parameters["Pads"]['*' + self.line_count_key]
|
||||
pad_cnt = self.parameters["Pads"]['*' + self.pad_count_key]
|
||||
rows = self.pads['line count']
|
||||
pad_cnt = self.pads['pad count']
|
||||
|
||||
if rows == 1:
|
||||
name = "SIP"
|
||||
|
@ -174,9 +163,9 @@ class ZIPWizard(RowedFootprint):
|
|||
return "%s-%d" % (name, pad_cnt)
|
||||
|
||||
def GetPad(self):
|
||||
pad_Vsize = self.parameters["Pads"][self.pad_vertical_size_key]
|
||||
pad_Hsize = self.parameters["Pads"][self.pad_horizontal_size_key]
|
||||
drill = self.parameters["Pads"][self.drill_size_key]
|
||||
pad_Vsize = self.pads['pad height']
|
||||
pad_Hsize = self.pads['pad width']
|
||||
drill = self.pads['drill size']
|
||||
return PA.PadMaker(self.module).THPad(
|
||||
pad_Vsize, pad_Hsize, drill, shape=pcbnew.PAD_SHAPE_OVAL)
|
||||
|
||||
|
@ -192,23 +181,23 @@ class ZOICWizard(RowedFootprint):
|
|||
return "ZOIC, etc, Footprint Wizard"
|
||||
|
||||
def GetValue(self):
|
||||
return "%s-%d" % ("ZOIC", self.parameters["Pads"]['*' + self.pad_count_key])
|
||||
return "%s-%d" % ("ZOIC-", self.pads['pad count'])
|
||||
|
||||
def GenerateParameterList(self):
|
||||
RowedFootprint.GenerateParameterList(self)
|
||||
|
||||
#and override some of them
|
||||
self.AddParam("Pads", self.pad_pitch_key, self.uMM, 0.6)
|
||||
self.AddParam("Pads", self.pad_horizontal_size_key, self.uMM, 0.6)
|
||||
self.AddParam("Pads", self.pad_vertical_size_key, self.uMM, 1.8)
|
||||
self.AddParam("Pads", self.line_spacing_key, self.uMM, 5.2)
|
||||
self.AddParam("Pads", "pitch", self.uMM, 0.6)
|
||||
self.AddParam("Pads", "pad width", self.uMM, 0.6)
|
||||
self.AddParam("Pads", "pad height", self.uMM, 1.8)
|
||||
self.AddParam("Pads", "line spacing", self.uMM, 5.2)
|
||||
|
||||
self.AddParam("Body", self.outline_x_margin_key, self.uMM, 0.5)
|
||||
self.AddParam("Body", self.outline_y_margin_key, self.uMM, 1)
|
||||
self.AddParam("Body", "outline x margin", self.uMM, 0.5)
|
||||
self.AddParam("Body", "outline y margin", self.uMM, 1)
|
||||
|
||||
def GetPad(self):
|
||||
pad_Vsize = self.parameters["Pads"][self.pad_vertical_size_key]
|
||||
pad_Hsize = self.parameters["Pads"][self.pad_horizontal_size_key]
|
||||
pad_Vsize = self.pads['pad height']
|
||||
pad_Hsize = self.pads['pad width']
|
||||
return PA.PadMaker(self.module).SMDPad(
|
||||
pad_Vsize, pad_Hsize, shape=pcbnew.PAD_SHAPE_RECT)
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013 NBEE Embedded Systems SL, Miguel Angel Ajo <miguelangel@ajo.es>
|
||||
* Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
* Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -237,24 +237,9 @@ wxArrayString PYTHON_FOOTPRINT_WIZARD::GetParameterTypes( int aPage )
|
|||
|
||||
PyObject* arglist = Py_BuildValue( "(i)", aPage );
|
||||
|
||||
ret = CallRetArrayStrMethod( "GetParameterNames", arglist );
|
||||
ret = CallRetArrayStrMethod( "GetParameterTypes", arglist );
|
||||
Py_DECREF( arglist );
|
||||
|
||||
for( unsigned i = 0; i<ret.GetCount(); i++ )
|
||||
{
|
||||
wxString rest;
|
||||
wxString item = ret[i];
|
||||
|
||||
if( item.StartsWith( wxT( "*" ), &rest ) )
|
||||
{
|
||||
ret[i] = wxT( "UNITS" ); // units
|
||||
}
|
||||
else
|
||||
{
|
||||
ret[i] = wxT( "IU" ); // internal units
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -284,6 +269,29 @@ wxArrayString PYTHON_FOOTPRINT_WIZARD::GetParameterErrors( int aPage )
|
|||
return ret;
|
||||
}
|
||||
|
||||
wxArrayString PYTHON_FOOTPRINT_WIZARD::GetParameterHints( int aPage )
|
||||
{
|
||||
PyLOCK lock;
|
||||
|
||||
PyObject* arglist = Py_BuildValue( "(i)", aPage );
|
||||
wxArrayString ret = CallRetArrayStrMethod( "GetParameterHints", arglist );
|
||||
|
||||
Py_DECREF( arglist );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
wxArrayString PYTHON_FOOTPRINT_WIZARD::GetParameterDesignators( int aPage )
|
||||
{
|
||||
PyLOCK lock;
|
||||
|
||||
PyObject* arglist = Py_BuildValue( "(i)", aPage );
|
||||
wxArrayString ret = CallRetArrayStrMethod( "GetParameterDesignators", arglist );
|
||||
|
||||
Py_DECREF( arglist );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
wxString PYTHON_FOOTPRINT_WIZARD::SetParameterValues( int aPage, wxArrayString& aValues )
|
||||
{
|
||||
|
@ -309,6 +317,13 @@ wxString PYTHON_FOOTPRINT_WIZARD::SetParameterValues( int aPage, wxArrayString&
|
|||
return res;
|
||||
}
|
||||
|
||||
void PYTHON_FOOTPRINT_WIZARD::ResetParameters()
|
||||
{
|
||||
PyLOCK lock;
|
||||
|
||||
CallMethod( "ResetWizard", NULL );
|
||||
}
|
||||
|
||||
|
||||
// this is a SWIG function declaration -from module.i
|
||||
MODULE* PyModule_to_MODULE( PyObject* obj0 );
|
||||
|
|
|
@ -45,6 +45,7 @@ class PYTHON_FOOTPRINT_WIZARD : public FOOTPRINT_WIZARD
|
|||
public:
|
||||
PYTHON_FOOTPRINT_WIZARD( PyObject* wizard );
|
||||
~PYTHON_FOOTPRINT_WIZARD();
|
||||
|
||||
wxString GetName() override;
|
||||
wxString GetImage() override;
|
||||
wxString GetDescription() override;
|
||||
|
@ -58,6 +59,10 @@ public:
|
|||
wxString SetParameterValues( int aPage, wxArrayString& aValues ) override;
|
||||
MODULE* GetFootprint( wxString * aMessages ) override;
|
||||
void* GetObject() override;
|
||||
wxArrayString GetParameterHints( int aPage ) override;
|
||||
wxArrayString GetParameterDesignators( int aPage = 0) override;
|
||||
|
||||
void ResetParameters() override;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -119,23 +119,19 @@ def LoadPlugins(bundlepath=None):
|
|||
if bundlepath:
|
||||
plugin_directories.append(bundlepath)
|
||||
plugin_directories.append(os.path.join(bundlepath, 'plugins'))
|
||||
plugin_directories.append(os.path.join(bundlepath, 'plugins', 'wizards'))
|
||||
|
||||
if kicad_path:
|
||||
plugin_directories.append(os.path.join(kicad_path, 'scripting'))
|
||||
plugin_directories.append(os.path.join(kicad_path, 'scripting', 'plugins'))
|
||||
plugin_directories.append(os.path.join(kicad_path, 'scripting', 'plugins', 'wizards'))
|
||||
|
||||
if config_path:
|
||||
plugin_directories.append(os.path.join(config_path, 'scripting'))
|
||||
plugin_directories.append(os.path.join(config_path, 'scripting', 'plugins'))
|
||||
plugin_directories.append(os.path.join(config_path, 'scripting', 'plugins', 'wizards'))
|
||||
|
||||
if sys.platform.startswith('linux'):
|
||||
plugin_directories.append(os.environ['HOME']+'/.kicad_plugins/')
|
||||
plugin_directories.append(os.environ['HOME']+'/.kicad/scripting/')
|
||||
plugin_directories.append(os.environ['HOME']+'/.kicad/scripting/plugins/')
|
||||
plugin_directories.append(os.environ['HOME']+'/.kicad/scripting/plugins/wizards')
|
||||
|
||||
for plugins_dir in plugin_directories:
|
||||
if not os.path.isdir(plugins_dir):
|
||||
|
@ -164,7 +160,6 @@ def LoadPlugins(bundlepath=None):
|
|||
pass
|
||||
|
||||
|
||||
|
||||
class KiCadPlugin:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
@ -203,88 +198,295 @@ class FilePlugin(KiCadPlugin):
|
|||
|
||||
from math import ceil, floor, sqrt
|
||||
|
||||
class FootprintWizardPlugin(KiCadPlugin):
|
||||
uMM = "mm" # Millimetres
|
||||
uMils = "mils" # Mils
|
||||
uFloat = "float" # Natural number units (dimensionless)
|
||||
uInteger = "integer" # Integer (no decimals, numeric, dimensionless)
|
||||
uBool = "bool" # Boolean value
|
||||
uRadians = "radians" # Angular units (radians)
|
||||
uDegrees = "degrees" # Angular units (degrees)
|
||||
uPercent = "%" # Percent (0% -> 100%)
|
||||
uString = "string" # Raw string
|
||||
|
||||
uNumeric = [uMM, uMils, uFloat, uInteger, uDegrees, uRadians, uPercent] # List of numeric types
|
||||
uUnits = [uMM, uMils, uFloat, uInteger, uBool, uDegrees, uRadians, uPercent, uString] # List of allowable types
|
||||
|
||||
class FootprintWizardParameter(object):
|
||||
_true = ['true','t','y','yes','on','1',1,]
|
||||
_false = ['false','f','n','no','off','0',0,'',None]
|
||||
|
||||
_bools = _true + _false
|
||||
|
||||
def __init__(self, page, name, units, default, **kwarg):
|
||||
self.page = page
|
||||
self.name = name
|
||||
self.hint = kwarg.get('hint','') # Parameter hint (shown as mouse-over text)
|
||||
self.designator = kwarg.get('designator',' ') # Parameter designator such as "e, D, p" (etc)
|
||||
|
||||
if units.lower() in uUnits:
|
||||
self.units = units.lower()
|
||||
elif units.lower() == 'percent':
|
||||
self.units = uPercent
|
||||
elif type(units) in [list, tuple]: # Convert a list of options into a single string
|
||||
self.units = ",".join([str(el).strip() for el in units])
|
||||
else:
|
||||
self.units = units
|
||||
|
||||
self.multiple = int(kwarg.get('multiple',1)) # Check integer values are multiples of this number
|
||||
self.min_value = kwarg.get('min_value',None) # Check numeric values are above or equal to this number
|
||||
self.max_value = kwarg.get('max_value',None) # Check numeric values are below or equal to this number
|
||||
|
||||
self.SetValue(default)
|
||||
self.default = self.raw_value # Save value as default
|
||||
|
||||
def ClearErrors(self):
|
||||
self.error_list = []
|
||||
|
||||
def AddError(self, err, info=None):
|
||||
|
||||
if err in self.error_list: # prevent duplicate error messages
|
||||
return
|
||||
if info is not None:
|
||||
err = err + " (" + str(info) + ")"
|
||||
|
||||
self.error_list.append(err)
|
||||
|
||||
def Check(self, min_value=None, max_value=None, multiple=None, info=None):
|
||||
|
||||
if min_value is None:
|
||||
min_value = self.min_value
|
||||
if max_value is None:
|
||||
max_value = self.max_value
|
||||
if multiple is None:
|
||||
multiple = self.multiple
|
||||
|
||||
if self.units not in uUnits and ',' not in self.units: # Allow either valid units or a list of strings
|
||||
self.AddError("type '{t}' unknown".format(t=self.units),info)
|
||||
self.AddError("Allowable types: " + str(self.units),info)
|
||||
|
||||
if self.units in uNumeric:
|
||||
try:
|
||||
to_num = float(self.raw_value)
|
||||
|
||||
if min_value is not None: # Check minimum value if it is present
|
||||
if to_num < min_value:
|
||||
self.AddError("value '{v}' is below minimum ({m})".format(v=self.raw_value,m=min_value),info)
|
||||
|
||||
if max_value is not None: # Check maximum value if it is present
|
||||
if to_num > max_value:
|
||||
self.AddError("value '{v}' is above maximum ({m})".format(v=self.raw_value,m=max_value),info)
|
||||
|
||||
except:
|
||||
self.AddError("value '{v}' is not of type '{t}'".format(v = self.raw_value, t=self.units),info)
|
||||
|
||||
if self.units == uInteger: # Perform integer specific checks
|
||||
try:
|
||||
to_int = int(self.raw_value)
|
||||
|
||||
if multiple is not None and multiple > 1:
|
||||
if (to_int % multiple) > 0:
|
||||
self.AddError("value '{v}' is not a multiple of {m}".format(v=self.raw_value,m=multiple),info)
|
||||
except:
|
||||
self.AddError("value {'v}' is not an integer".format(v=self.raw_value),info)
|
||||
|
||||
if self.units == uBool: # Check that the value is of a correct boolean format
|
||||
if self.raw_value in [True,False] or str(self.raw_value).lower() in self._bools:
|
||||
pass
|
||||
else:
|
||||
self.AddError("value '{v}' is not a boolean value".format(v = self.raw_value),info)
|
||||
|
||||
@property
|
||||
def value(self): # Return the current value, converted to appropriate units (from string representation) if required
|
||||
v = str(self.raw_value) # Enforce string type for known starting point
|
||||
|
||||
if self.units == uInteger: # Integer values
|
||||
return int(v)
|
||||
elif self.units in uNumeric: # Any values that use floating points
|
||||
v = v.replace(",",".") # Replace "," separators with "."
|
||||
v = float(v)
|
||||
|
||||
if self.units == uMM: # Convert from millimetres to nanometres
|
||||
return FromMM(v)
|
||||
|
||||
elif self.units == uMils: # Convert from mils to nanometres
|
||||
return FromMils(v)
|
||||
|
||||
else: # Any other floating-point values
|
||||
return v
|
||||
|
||||
elif self.units == uBool:
|
||||
if v.lower() in self._true:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return v
|
||||
|
||||
def DefaultValue(self): # Reset the value of the parameter to its default
|
||||
self.raw_value = str(self.default)
|
||||
|
||||
def SetValue(self, new_value): # Update the value
|
||||
new_value = str(new_value)
|
||||
|
||||
if len(new_value.strip()) == 0:
|
||||
if not self.units in [uString, uBool]:
|
||||
return # Ignore empty values unless for strings or bools
|
||||
|
||||
if self.units == uBool: # Enforce the same boolean representation as is used in KiCad
|
||||
new_value = "1" if new_value.lower() in self._true else "0"
|
||||
elif self.units in uNumeric:
|
||||
new_value = new_value.replace(",", ".") # Enforce decimal point separators
|
||||
elif ',' in self.units: # Select from a list of values
|
||||
if new_value not in self.units.split(','):
|
||||
new_value = self.units.split(',')[0]
|
||||
|
||||
self.raw_value = new_value
|
||||
|
||||
def __str__(self): # pretty-print the parameter
|
||||
|
||||
s = self.name + ": " + str(self.raw_value)
|
||||
|
||||
if self.units in [uMM, uMils, uPercent, uRadians, uDegrees]:
|
||||
s += self.units
|
||||
elif self.units == uBool: # Special case for Boolean values
|
||||
s = self.name + ": {b}".format(b = "True" if self.value else "False")
|
||||
elif self.units == uString:
|
||||
s = self.name + ": '" + self.raw_value + "'"
|
||||
|
||||
return s
|
||||
|
||||
class FootprintWizardPlugin(KiCadPlugin, object):
|
||||
def __init__(self):
|
||||
KiCadPlugin.__init__(self)
|
||||
self.defaults()
|
||||
|
||||
def defaults(self):
|
||||
self.module = None
|
||||
self.parameters = {}
|
||||
self.parameter_errors={}
|
||||
self.name = "Undefined Footprint Wizard plugin"
|
||||
self.description = ""
|
||||
self.params = [] # List of added parameters that observes addition order
|
||||
|
||||
self.name = "KiCad FP Wizard"
|
||||
self.description = "Undefined Footprint Wizard plugin"
|
||||
self.image = ""
|
||||
self.buildmessages = ""
|
||||
|
||||
def GetName(self):
|
||||
def AddParam(self, page, name, unit, default, **kwarg):
|
||||
|
||||
if self.GetParam(page,name) is not None: # Param already exists!
|
||||
return
|
||||
|
||||
param = FootprintWizardParameter(page, name, unit, default, **kwarg) # Create a new parameter
|
||||
self.params.append(param)
|
||||
|
||||
@property
|
||||
def parameters(self): # This is a helper function that returns a nested (unordered) dict of the VALUES of parameters
|
||||
pages = {} # Page dict
|
||||
for p in self.params:
|
||||
if p.page not in pages:
|
||||
pages[p.page] = {}
|
||||
|
||||
pages[p.page][p.name] = p.value # Return the 'converted' value (convert from string to actual useful units)
|
||||
|
||||
return pages
|
||||
|
||||
@property
|
||||
def values(self): # Same as above
|
||||
return self.parameters
|
||||
|
||||
def ResetWizard(self): # Reset all parameters to default values
|
||||
for p in self.params:
|
||||
p.DefaultValue()
|
||||
|
||||
def GetName(self): # Return the name of this wizard
|
||||
return self.name
|
||||
|
||||
def GetImage(self):
|
||||
def GetImage(self): # Return the filename of the preview image associated with this wizard
|
||||
return self.image
|
||||
|
||||
def GetDescription(self):
|
||||
def GetDescription(self): # Return the description text
|
||||
return self.description
|
||||
|
||||
def GetValue(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def GetNumParameterPages(self):
|
||||
return len(self.parameters)
|
||||
def GetReferencePrefix(self):
|
||||
return "REF" # Default reference prefix for any footprint
|
||||
|
||||
def GetParameterPageName(self,page_n):
|
||||
return self.page_order[page_n]
|
||||
def GetParam(self, page, name): # Grab a parameter
|
||||
for p in self.params:
|
||||
if p.page == page and p.name == name:
|
||||
return p
|
||||
|
||||
def GetParameterNames(self,page_n):
|
||||
name = self.GetParameterPageName(page_n)
|
||||
return self.parameter_order[name]
|
||||
return None
|
||||
|
||||
def GetParameterValues(self,page_n):
|
||||
name = self.GetParameterPageName(page_n)
|
||||
names = self.GetParameterNames(page_n)
|
||||
values = [self.parameters[name][n] for n in names]
|
||||
return map(lambda x: str(x), values) # list elements as strings
|
||||
def CheckParam(self, page, name, **kwarg):
|
||||
self.GetParam(page,name).Check(**kwarg)
|
||||
|
||||
def GetParameterErrors(self,page_n):
|
||||
self.CheckParameters()
|
||||
name = self.GetParameterPageName(page_n)
|
||||
names = self.GetParameterNames(page_n)
|
||||
values = [self.parameter_errors[name][n] for n in names]
|
||||
return map(lambda x: str(x), values) # list elements as strings
|
||||
def AnyErrors(self):
|
||||
return any([len(p.error_list) > 0 for p in self.params])
|
||||
|
||||
def CheckParameters(self):
|
||||
return ""
|
||||
@property
|
||||
def pages(self): # Return an (ordered) list of the available page names
|
||||
page_list = []
|
||||
for p in self.params:
|
||||
if p.page not in page_list:
|
||||
page_list.append(p.page)
|
||||
|
||||
def ConvertValue(self,v):
|
||||
try:
|
||||
v = float(v)
|
||||
except:
|
||||
pass
|
||||
if type(v) is float:
|
||||
if ceil(v) == floor(v):
|
||||
v = int(v)
|
||||
return v
|
||||
return page_list
|
||||
|
||||
def GetNumParameterPages(self): # Return the number of parameter pages
|
||||
return len(self.pages)
|
||||
|
||||
def SetParameterValues(self,page_n,values):
|
||||
name = self.GetParameterPageName(page_n)
|
||||
keys = self.GetParameterNames(page_n)
|
||||
for n, key in enumerate(keys):
|
||||
val = self.ConvertValue(values[n])
|
||||
self.parameters[name][key] = val
|
||||
def GetParameterPageName(self,page_n): # Return the name of a page at a given index
|
||||
return self.pages[page_n]
|
||||
|
||||
def GetParametersByPageName(self, page_name): # Return a list of parameters on a given page
|
||||
params = []
|
||||
|
||||
def ClearErrors(self):
|
||||
errs={}
|
||||
for p in self.params:
|
||||
if p.page == page_name:
|
||||
params.append(p)
|
||||
|
||||
for page in self.parameters.keys():
|
||||
page_dict = self.parameters[page]
|
||||
page_params = {}
|
||||
for param in page_dict.keys():
|
||||
page_params[param]=""
|
||||
return params
|
||||
|
||||
errs[page]=page_params
|
||||
def GetParametersByPageIndex(self, page_index): # Return an ordered list of parameters on a given page
|
||||
return self.GetParametersByPageName(self.GetParameterPageName(page_index))
|
||||
|
||||
self.parameter_errors = errs
|
||||
def GetParameterDesignators(self, page_index): # Return a list of designators associated with a given page
|
||||
params = self.GetParametersByPageIndex(page_index)
|
||||
return [p.designator for p in params]
|
||||
|
||||
def GetParameterNames(self,page_index): # Return the list of names associated with a given page
|
||||
params = self.GetParametersByPageIndex(page_index)
|
||||
return [p.name for p in params]
|
||||
|
||||
def GetParameterValues(self,page_index): # Return the list of values associated with a given page
|
||||
params = self.GetParametersByPageIndex(page_index)
|
||||
return [str(p.raw_value) for p in params]
|
||||
|
||||
def GetParameterErrors(self,page_index): # Return list of errors associated with a given page
|
||||
params = self.GetParametersByPageIndex(page_index)
|
||||
return [str("\n".join(p.error_list)) for p in params]
|
||||
|
||||
def GetParameterTypes(self, page_index): # Return list of units associated with a given page
|
||||
params = self.GetParametersByPageIndex(page_index)
|
||||
return [str(p.units) for p in params]
|
||||
|
||||
def GetParameterHints(self, page_index): # Return a list of units associated with a given page
|
||||
params = self.GetParametersByPageIndex(page_index)
|
||||
return [str(p.hint) for p in params]
|
||||
|
||||
def GetParameterDesignators(self, page_index): # Return a list of designators associated with a given page
|
||||
params = self.GetParametersByPageIndex(page_index)
|
||||
return [str(p.designator) for p in params]
|
||||
|
||||
def SetParameterValues(self, page_index, list_of_values): # Update values on a given page
|
||||
|
||||
params = self.GetParametersByPageIndex(page_index)
|
||||
|
||||
for i, param in enumerate(params):
|
||||
if i >= len(list_of_values):
|
||||
break
|
||||
param.SetValue(list_of_values[i])
|
||||
|
||||
def GetFootprint( self ):
|
||||
self.BuildFootprint()
|
||||
|
@ -297,17 +499,30 @@ class FootprintWizardPlugin(KiCadPlugin):
|
|||
return self.buildmessages
|
||||
|
||||
def Show(self):
|
||||
print "Footprint Wizard Name: ",self.GetName()
|
||||
print "Footprint Wizard Description: ",self.GetDescription()
|
||||
text = "Footprint Wizard Name: {name}\n".format(name=self.GetName())
|
||||
text += "Footprint Wizard Description: {desc}\n".format(desc=self.GetDescription())
|
||||
|
||||
n_pages = self.GetNumParameterPages()
|
||||
print " setup pages: ",n_pages
|
||||
for page in range(0,n_pages):
|
||||
name = self.GetParameterPageName(page)
|
||||
values = self.GetParameterValues(page)
|
||||
names = self.GetParameterNames(page)
|
||||
print "page %d) %s"%(page,name)
|
||||
for n in range (0,len(values)):
|
||||
print "\t%s\t:\t%s"%(names[n],values[n])
|
||||
|
||||
text += "Pages: {n}\n".format(n=n_pages)
|
||||
|
||||
for i in range(n_pages):
|
||||
name = self.GetParameterPageName(i)
|
||||
|
||||
params = self.GetParametersByPageName(name)
|
||||
|
||||
text += "{name}\n".format(name=name)
|
||||
|
||||
for j in range(len(params)):
|
||||
text += ("\t{param}{err}\n".format(
|
||||
param = str(params[j]),
|
||||
err = ' *' if len(params[j].error_list) > 0 else ''
|
||||
))
|
||||
|
||||
if self.AnyErrors():
|
||||
text += " * Errors exist for these parameters"
|
||||
|
||||
return text
|
||||
|
||||
class ActionPlugin(KiCadPlugin):
|
||||
def __init__(self):
|
||||
|
|
Loading…
Reference in New Issue