mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-13 02:32:09 +10:00
IC improvements
This commit is contained in:
+136
-39
@@ -30,16 +30,22 @@ import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.Arrays;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.Display;
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.Orientation;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
import org.diylc.components.AbstractLabeledComponent;
|
||||
import org.diylc.components.AbstractMakerBoard;
|
||||
import org.diylc.components.transform.DIL_ICTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDatasheetSupport;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
@@ -55,11 +61,15 @@ import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@AiNote("The first control point is the anchor; with 'Orientation' DEFAULT the first row of pins runs down from it 'Pin Spacing' apart, the second row sits 'Row Spacing' to the right and the notch is at the anchor's end. The other orientations rotate this around the anchor")
|
||||
@AiNote("'Pin Names' is a comma-separated list of pin names in pin-number order, starting with pin 1 next to the notch; a pin without a name is called by its number. Pins named alike up to a trailing '_1', '_2' are one net inside the package, e.g. GND_1 and GND_2, while 1IN- and 2IN- are inputs of two separate sections")
|
||||
@AiNote("A datasheet model is a part number such as TL072 or NE555 and sets 'Pins', 'Row Spacing', 'Pin Names' and 'Value'. Set 'Value' to the same part number together with the model")
|
||||
@ComponentDescriptor(name = "DIP IC", author = "Branislav Stojkovic", category = "Semiconductors",
|
||||
instanceNamePrefix = "IC", description = "Dual-in-line package IC",
|
||||
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE,
|
||||
transformer = DIL_ICTransformer.class, enableCache = true)
|
||||
public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberComponentSimple {
|
||||
transformer = DIL_ICTransformer.class, enableCache = true, enableDatasheet = true,
|
||||
datasheetCreationStepCount = 2, datasheetModelColumn = 1)
|
||||
public class DIL_IC extends AbstractLabeledComponent<String>
|
||||
implements IGerberComponentSimple, IDatasheetSupport {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -72,7 +82,9 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
public static int EDGE_RADIUS = 6;
|
||||
public static Size PIN_SIZE = new Size(0.04d, SizeUnit.in);
|
||||
public static Size INDENT_SIZE = new Size(0.07d, SizeUnit.in);
|
||||
public static DisplayNumbers DISPLAY_NUMBERS = DisplayNumbers.NO;
|
||||
public static DisplayNumbers DISPLAY_NUMBERS = DisplayNumbers.NAMES;
|
||||
// the smaller font lets names sit closer to their pins than on a maker board
|
||||
public static Size PIN_NAME_OFFSET = new Size(1.35d, SizeUnit.mm);
|
||||
|
||||
private String value = "";
|
||||
private Orientation orientation = Orientation.DEFAULT;
|
||||
@@ -86,6 +98,7 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
private Color labelColor = LABEL_COLOR;
|
||||
private Color indentColor = INDENT_COLOR;
|
||||
private DisplayNumbers displayNumbers = DISPLAY_NUMBERS;
|
||||
private String pinNames = null;
|
||||
// new Point(0, pinSpacing.convertToPixels()),
|
||||
// new Point(0, 2 * pinSpacing.convertToPixels()),
|
||||
// new Point(0, 3 * pinSpacing.convertToPixels()),
|
||||
@@ -97,12 +110,29 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
// new Point(3 * pinSpacing.convertToPixels(), 3 *
|
||||
// pinSpacing.convertToPixels()) };
|
||||
transient private Area[] body;
|
||||
transient private String[] parsedPinNames;
|
||||
|
||||
public DIL_IC() {
|
||||
super();
|
||||
updateControlPoints();
|
||||
}
|
||||
|
||||
public DIL_IC(String[] model) {
|
||||
this();
|
||||
|
||||
applyModel(model);
|
||||
}
|
||||
|
||||
// columns: group, part number, row spacing, then one name per pin in pin-number order, so the
|
||||
// pin count is the number of names
|
||||
@Override
|
||||
public void applyModel(String[] model) {
|
||||
setValue(model[1]);
|
||||
setRowSpacing(Size.parseSize(model[2]));
|
||||
setPinCount(PinCount.valueOf("_" + (model.length - 3)));
|
||||
setPinNames(String.join(",", Arrays.copyOfRange(model, 3, model.length)));
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public String getValue() {
|
||||
return value;
|
||||
@@ -425,9 +455,14 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
}
|
||||
}
|
||||
|
||||
if (getDisplayNumbers() == DisplayNumbers.NAMES) {
|
||||
drawPinNames(g2d);
|
||||
}
|
||||
|
||||
// draw pin numbers
|
||||
if (getDisplayNumbers() != DisplayNumbers.NO) {
|
||||
if (getDisplayNumbers() != DisplayNumbers.NO && getDisplayNumbers() != DisplayNumbers.NAMES) {
|
||||
int pinSize = (int) PIN_SIZE.convertToPixels();
|
||||
g2d.setFont(project.getFont().deriveFont((float) (project.getFont().getSize2D() * 0.66)));
|
||||
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
Point2D point = controlPoints[i];
|
||||
@@ -454,16 +489,68 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
textY2 = textY2 - pinSize;
|
||||
}
|
||||
|
||||
g2d.setFont(project.getFont().deriveFont((float) (project.getFont().getSize2D() * 0.66)));
|
||||
String pinNumber = Integer.toString(getPinNumber(i));
|
||||
if (i >= pinCount.getValue() / 2) {
|
||||
g2d.drawString(getControlPointNodeName(i), textX1, textY1);
|
||||
g2d.drawString(pinNumber, textX1, textY1);
|
||||
} else {
|
||||
g2d.drawString(getControlPointNodeName(i), textX2, textY2);
|
||||
g2d.drawString(pinNumber, textX2, textY2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Names are printed the way maker boards print theirs: centred just inside the body from their
|
||||
// pin and running along the row, which leaves the middle of even a 0.3 in body to the name/value
|
||||
// label. Each name has one pin pitch along the row, so a name that would touch the previous one
|
||||
// in its row or run past the end of the body is left out rather than overprinted.
|
||||
private void drawPinNames(Graphics2D g2d) {
|
||||
g2d.setFont(ICPinNames.PIN_NAME_FONT);
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics(ICPinNames.PIN_NAME_FONT);
|
||||
double labelOffset = PIN_NAME_OFFSET.convertToPixels();
|
||||
double pitch = pinSpacing.convertToPixels();
|
||||
int half = pinCount.getValue() / 2;
|
||||
Point2D firstRow = controlPoints[0];
|
||||
Point2D secondRow = controlPoints[half];
|
||||
double rowDistance = firstRow.distance(secondRow);
|
||||
double acrossX = (secondRow.getX() - firstRow.getX()) / rowDistance;
|
||||
double acrossY = (secondRow.getY() - firstRow.getY()) / rowDistance;
|
||||
boolean rowsVertical = Math.abs(acrossX) > Math.abs(acrossY);
|
||||
// along the row the body reaches half a pitch past the first and the last pin
|
||||
double bodyStart = -pitch / 2 + 1;
|
||||
double bodyEnd = (half - 0.5) * pitch - 1;
|
||||
double previousEnd = bodyStart - ICPinNames.PIN_NAME_GAP;
|
||||
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
if (i == half) {
|
||||
previousEnd = bodyStart - ICPinNames.PIN_NAME_GAP;
|
||||
}
|
||||
String name = getPinName(getPinNumber(i));
|
||||
if (name == null) {
|
||||
continue;
|
||||
}
|
||||
String label = AbstractMakerBoard.getDisplayPinLabel(name);
|
||||
double alongRow = (i % half) * pitch;
|
||||
double halfWidth = fontMetrics.stringWidth(label) / 2d;
|
||||
if (alongRow - halfWidth < previousEnd + ICPinNames.PIN_NAME_GAP || alongRow + halfWidth > bodyEnd) {
|
||||
continue;
|
||||
}
|
||||
previousEnd = alongRow + halfWidth;
|
||||
double dirX = i < half ? acrossX : -acrossX;
|
||||
double dirY = i < half ? acrossY : -acrossY;
|
||||
double x = controlPoints[i].getX() + dirX * labelOffset;
|
||||
double y = controlPoints[i].getY() + dirY * labelOffset;
|
||||
AffineTransform oldTransform = g2d.getTransform();
|
||||
// the two rows are mirrored so each name reads away from its pin, as on a maker board; rows
|
||||
// that run horizontally keep their names level so that neither reads upside down
|
||||
if (rowsVertical) {
|
||||
g2d.rotate(dirX > 0 ? Math.PI / 2 : -Math.PI / 2, x, y);
|
||||
}
|
||||
StringUtils.drawCenteredText(g2d, label, x, y, HorizontalAlignment.CENTER,
|
||||
VerticalAlignment.CENTER);
|
||||
g2d.setTransform(oldTransform);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int radius = 6 * width / 32;
|
||||
@@ -527,7 +614,7 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
this.indentColor = indentColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Display Pin #s")
|
||||
@EditableProperty(name = "Pin Labels")
|
||||
public DisplayNumbers getDisplayNumbers() {
|
||||
if (displayNumbers == null) {
|
||||
displayNumbers = DisplayNumbers.NO;
|
||||
@@ -539,6 +626,42 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
this.displayNumbers = numbers;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Pin Names")
|
||||
public String getPinNames() {
|
||||
return pinNames;
|
||||
}
|
||||
|
||||
public void setPinNames(String pinNames) {
|
||||
this.pinNames = pinNames;
|
||||
parsedPinNames = null;
|
||||
}
|
||||
|
||||
// the physical pin number of a control point; control points run down the first row and then
|
||||
// down the second, whereas DIP numbering comes back up the second row
|
||||
private int getPinNumber(int index) {
|
||||
int pinCount = this.pinCount.getValue();
|
||||
int half = pinCount / 2;
|
||||
int position = index + 1;
|
||||
boolean secondRow = position > half;
|
||||
switch (getDisplayNumbers()) {
|
||||
case CONNECTOR:
|
||||
return secondRow ? 2 * (position - half) : 2 * position - 1;
|
||||
case DIP_MIRROR:
|
||||
return secondRow ? position - half : pinCount - position + 1;
|
||||
case CONNECTOR_MIRROR:
|
||||
return secondRow ? 2 * (position - half) - 1 : 2 * position;
|
||||
default:
|
||||
return secondRow ? pinCount + half - position + 1 : position;
|
||||
}
|
||||
}
|
||||
|
||||
private String getPinName(int pinNumber) {
|
||||
if (parsedPinNames == null) {
|
||||
parsedPinNames = ICPinNames.parse(getPinNames());
|
||||
}
|
||||
return ICPinNames.get(parsedPinNames, pinNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return false;
|
||||
@@ -569,35 +692,9 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
index++;
|
||||
|
||||
if (displayNumbers == DisplayNumbers.DIP) {
|
||||
if (index > pinCount.getValue() / 2) {
|
||||
return Integer.toString(pinCount.getValue() * 3 / 2 - index + 1);
|
||||
} else {
|
||||
return Integer.toString(index);
|
||||
}
|
||||
} else if (displayNumbers == DisplayNumbers.CONNECTOR) {
|
||||
if (index > pinCount.getValue() / 2) {
|
||||
return Integer.toString(index - pinCount.getValue() + index);
|
||||
} else {
|
||||
return Integer.toString(index * 2 - 1);
|
||||
}
|
||||
} else if (displayNumbers == DisplayNumbers.DIP_MIRROR) {
|
||||
if (index > pinCount.getValue() / 2) {
|
||||
return Integer.toString((index - pinCount.getValue() / 2));
|
||||
} else {
|
||||
return Integer.toString(pinCount.getValue() - index + 1);
|
||||
}
|
||||
} else if (displayNumbers == DisplayNumbers.CONNECTOR_MIRROR) {
|
||||
if (index > pinCount.getValue() / 2) {
|
||||
return Integer.toString(index - pinCount.getValue() + index - 1);
|
||||
} else {
|
||||
return Integer.toString(2 * index);
|
||||
}
|
||||
}
|
||||
|
||||
return Integer.toString(index);
|
||||
int pinNumber = getPinNumber(index);
|
||||
String name = getPinName(pinNumber);
|
||||
return name == null ? Integer.toString(pinNumber) : name;
|
||||
}
|
||||
|
||||
public static enum PinCount {
|
||||
@@ -616,8 +713,8 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
|
||||
|
||||
public enum DisplayNumbers {
|
||||
|
||||
NO("No"), DIP("DIP"), CONNECTOR("Connector"), DIP_MIRROR("DIP (Mirrored)"), CONNECTOR_MIRROR(
|
||||
"Connector (Mirrored)");
|
||||
NO("None"), NAMES("Names"), DIP("DIP"), CONNECTOR("Connector"), DIP_MIRROR("DIP (Mirrored)"),
|
||||
CONNECTOR_MIRROR("Connector (Mirrored)");
|
||||
|
||||
private String label;
|
||||
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC 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 DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.components.semiconductors;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.diylc.components.AbstractMakerBoard;
|
||||
|
||||
/**
|
||||
* Pin names shared by the IC packages. A package keeps its names as one comma-separated string in
|
||||
* pin-number order, pin 1 first, so the names survive a change of pin count and read back as typed.
|
||||
*/
|
||||
public final class ICPinNames {
|
||||
|
||||
// a size below the maker boards' pin font, as IC pin names are longer than a board's silkscreen
|
||||
// and get only one pin pitch each
|
||||
public static Font PIN_NAME_FONT = new Font(AbstractMakerBoard.SILK_FONT_FAMILY, Font.PLAIN, 6);
|
||||
public static int PIN_NAME_GAP = 2;
|
||||
|
||||
private ICPinNames() {}
|
||||
|
||||
public static String[] parse(String pinNames) {
|
||||
return pinNames == null ? new String[0] : pinNames.split(",", -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param names names as returned by {@link #parse(String)}
|
||||
* @param pinNumber 1-based pin number
|
||||
* @return the trimmed name of the pin, or null if it has none
|
||||
*/
|
||||
public static String get(String[] names, int pinNumber) {
|
||||
if (pinNumber < 1 || pinNumber > names.length) {
|
||||
return null;
|
||||
}
|
||||
String name = names[pinNumber - 1].trim();
|
||||
return name.isEmpty() ? null : name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a pin label outside the package, starting just beyond whichever reaches further in the
|
||||
* given direction, the body or the pin itself, and reading away from the package. The direction
|
||||
* is one of the four axis directions; text pointing left or down is right-aligned so that it never
|
||||
* reads upside down.
|
||||
*
|
||||
* @param pin the pin the label belongs to
|
||||
* @param dirX x component of the unit direction away from the package
|
||||
* @param dirY y component of the unit direction away from the package
|
||||
* @param bodyBounds bounds of the package body
|
||||
* @param pinRadius half the drawn pin size
|
||||
*/
|
||||
public static void drawOutside(Graphics2D g2d, String text, Point2D pin, double dirX, double dirY,
|
||||
Rectangle2D bodyBounds, double pinRadius) {
|
||||
boolean horizontal = Math.abs(dirX) > Math.abs(dirY);
|
||||
double pinReach = (horizontal ? pin.getX() * dirX : pin.getY() * dirY) + pinRadius;
|
||||
double bodyReach = horizontal ? (dirX > 0 ? bodyBounds.getMaxX() : -bodyBounds.getMinX())
|
||||
: (dirY > 0 ? bodyBounds.getMaxY() : -bodyBounds.getMinY());
|
||||
double start = Math.max(pinReach, bodyReach) + PIN_NAME_GAP;
|
||||
double x = horizontal ? start * dirX : pin.getX();
|
||||
double y = horizontal ? pin.getY() : start * dirY;
|
||||
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
int width = fontMetrics.stringWidth(text);
|
||||
float baseline = (fontMetrics.getAscent() - fontMetrics.getDescent()) / 2f;
|
||||
AffineTransform oldTransform = g2d.getTransform();
|
||||
g2d.translate(x, y);
|
||||
double forward;
|
||||
if (horizontal) {
|
||||
forward = dirX;
|
||||
} else {
|
||||
g2d.rotate(-Math.PI / 2);
|
||||
forward = -dirY;
|
||||
}
|
||||
g2d.drawString(text, forward > 0 ? 0 : -width, baseline);
|
||||
g2d.setTransform(oldTransform);
|
||||
}
|
||||
}
|
||||
+220
-113
@@ -30,16 +30,20 @@ import java.awt.Rectangle;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Arrays;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.components.AbstractMakerBoard;
|
||||
import org.diylc.components.AbstractTransparentComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDatasheetSupport;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.AiNote;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
@@ -48,11 +52,16 @@ import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@AiNote("The leads are staggered in two rows and numbered alternately along the package: pin 1 is the first control point, pins 1, 3, 5, ... form the row bent forward in front of the body, away from the heatsink tab, and pins 2, 4, ... the row that leaves the body from underneath. 'Type' picks the package: Multiwatt 11 for LM3886 or TDA7265, Multiwatt 15 for TDA7293 or TDA7294")
|
||||
@AiNote("'Pin Names' is a comma-separated list of pin names in pin-number order; a pin without a name is called by its number. Pins named alike up to a trailing '_1', '_2' are one net inside the package")
|
||||
@AiNote("A datasheet model is a part number such as LM3886 and sets 'Type', 'Pin Names' and 'Value'. Set 'Value' to the same part number together with the model")
|
||||
@ComponentDescriptor(name = "Multiwatt IC", author = "Branislav Stojkovic", category = "Semiconductors",
|
||||
instanceNamePrefix = "IC", description = "Multiwatt package IC typically used for audio amplifiers of high power applications",
|
||||
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE,
|
||||
enableCache = true)
|
||||
public class MultiwattIC extends AbstractTransparentComponent<String> implements IGerberComponentSimple {
|
||||
enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2,
|
||||
datasheetModelColumn = 1)
|
||||
public class MultiwattIC extends AbstractTransparentComponent<String>
|
||||
implements IGerberComponentSimple, IDatasheetSupport {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -67,12 +76,11 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
public static Size PIN_SIZE = new Size(0.7d, SizeUnit.mm);
|
||||
public static Size THICKNESS = new Size(5d, SizeUnit.mm);
|
||||
public static Size TAB_THICKNESS = new Size(1.6d, SizeUnit.mm);
|
||||
// Multiwatt packages use 0.1 inch (2.54mm) spacing between pins in the same row
|
||||
public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in);
|
||||
// from the back of the tab to the lead row that leaves the body from underneath; the other row is
|
||||
// bent forward clear of the body
|
||||
public static Size BACK_TO_NEAR_ROW = new Size(4.55d, SizeUnit.mm);
|
||||
// Multiwatt packages have staggered pins with 0.2 inch (5.08mm) row spacing
|
||||
public static Size ROW_SPACING = new Size(0.2d, SizeUnit.in);
|
||||
// Lead offset due to bent leads
|
||||
public static Size LEAD_OFFSET = new Size(4d, SizeUnit.mm);
|
||||
|
||||
private String value = "";
|
||||
private Orientation orientation = Orientation.DEFAULT;
|
||||
@@ -84,7 +92,10 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
private Color labelColor = LABEL_COLOR;
|
||||
private Color tabColor = TAB_COLOR;
|
||||
private Color tabBorderColor = TAB_BORDER_COLOR;
|
||||
private String pinNames = null;
|
||||
private PinLabels pinLabels = null;
|
||||
transient private Area[] body;
|
||||
transient private String[] parsedPinNames;
|
||||
|
||||
public MultiwattIC() {
|
||||
super();
|
||||
@@ -92,6 +103,27 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
this.alphaPercent = new Percentage(100);
|
||||
}
|
||||
|
||||
public MultiwattIC(String[] model) {
|
||||
this();
|
||||
|
||||
applyModel(model);
|
||||
}
|
||||
|
||||
// columns: group, part number, then one name per pin in pin-number order; the pin count picks
|
||||
// the package type
|
||||
@Override
|
||||
public void applyModel(String[] model) {
|
||||
int pinCount = model.length - 2;
|
||||
MultiwattType modelType = Arrays.stream(MultiwattType.values())
|
||||
.filter(t -> t.getPinCount() == pinCount)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No Multiwatt package with " + pinCount
|
||||
+ " pins"));
|
||||
setValue(model[1]);
|
||||
setType(modelType);
|
||||
setPinNames(String.join(",", Arrays.copyOfRange(model, 2, model.length)));
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public String getValue() {
|
||||
return value;
|
||||
@@ -175,7 +207,7 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
int pinsRight = type.getPinsRight();
|
||||
controlPoints = new Point2D.Double[pinCount];
|
||||
controlPoints[0] = firstPoint;
|
||||
double pinSpacing = PIN_SPACING.convertToPixels();
|
||||
double pinSpacing = type.getRowPitch().convertToPixels();
|
||||
double rowSpacing = ROW_SPACING.convertToPixels();
|
||||
// Update control points for staggered layout
|
||||
double dx1, dy1, dx2, dy2;
|
||||
@@ -234,91 +266,68 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
public Area[] getBody() {
|
||||
if (body == null) {
|
||||
body = new Area[2];
|
||||
double x = controlPoints[0].getX();
|
||||
double y = controlPoints[0].getY();
|
||||
double pinSize = PIN_SIZE.convertToPixels();
|
||||
double pinSpacing = PIN_SPACING.convertToPixels();
|
||||
double rowSpacing = ROW_SPACING.convertToPixels();
|
||||
double tabThickness = TAB_THICKNESS.convertToPixels();
|
||||
double leadOffset = LEAD_OFFSET.convertToPixels();
|
||||
double pinSpacing = type.getRowPitch().convertToPixels();
|
||||
int pinsLeft = type.getPinsLeft();
|
||||
int pinsRight = type.getPinsRight();
|
||||
// Calculate height accounting for staggered pins (right row offset by half spacing)
|
||||
double leftRowHeight = (pinsLeft - 1) * pinSpacing;
|
||||
double rightRowHeight = (pinsRight - 1 + 0.5) * pinSpacing; // Account for half-spacing offset
|
||||
double maxHeight = Math.max(leftRowHeight, rightRowHeight) + pinSpacing; // Add spacing for last pin
|
||||
double bodyX, bodyY, bodyWidth, bodyHeight;
|
||||
double tabX, tabY, tabWidth, tabHeight;
|
||||
|
||||
switch (orientation) {
|
||||
case DEFAULT:
|
||||
bodyWidth = rowSpacing - pinSize;
|
||||
bodyHeight = maxHeight;
|
||||
// Offset body to the left by lead offset (bent leads)
|
||||
bodyX = x + pinSize / 2 - leadOffset;
|
||||
bodyY = y - pinSpacing / 2;
|
||||
// Tab on the left side (where there are more pins) inside the body bounds
|
||||
tabX = bodyX;
|
||||
tabY = bodyY;
|
||||
tabWidth = tabThickness;
|
||||
tabHeight = bodyHeight;
|
||||
break;
|
||||
case _90:
|
||||
bodyWidth = maxHeight;
|
||||
bodyHeight = rowSpacing - pinSize;
|
||||
// Body positioned between the two pin rows
|
||||
// Left pins extend to negative X, body starts from leftmost pin
|
||||
// For _90: left pins go left (negative X), so leftmost is at x - (pinsLeft-1)*pinSpacing
|
||||
// Offset body upward by lead offset (bent leads)
|
||||
bodyX = x - (pinsLeft - 1) * pinSpacing - pinSpacing / 2;
|
||||
bodyY = y + pinSize / 2 - leadOffset;
|
||||
// Tab on the top side (where there are more pins - left row at y) inside the body bounds
|
||||
tabX = bodyX;
|
||||
tabY = bodyY;
|
||||
tabWidth = bodyWidth;
|
||||
tabHeight = tabThickness;
|
||||
break;
|
||||
case _180:
|
||||
bodyWidth = rowSpacing - pinSize;
|
||||
bodyHeight = maxHeight;
|
||||
// Body positioned between the two pin rows
|
||||
// For _180: left pins go up (negative Y), right pins at x - rowSpacing
|
||||
// Left row is at x, right row is at x - rowSpacing
|
||||
// Pins extend upward from y, so body should start from top of pin array
|
||||
// Offset body to the right by lead offset (bent leads)
|
||||
bodyX = x - rowSpacing + pinSize / 2 + leadOffset;
|
||||
bodyY = y - (pinsLeft - 1) * pinSpacing - pinSpacing / 2;
|
||||
// Tab on the right side (where there are more pins - left row at x) inside the body bounds
|
||||
tabX = bodyX + bodyWidth - tabThickness;
|
||||
tabY = bodyY;
|
||||
tabWidth = tabThickness;
|
||||
tabHeight = bodyHeight;
|
||||
break;
|
||||
case _270:
|
||||
bodyWidth = maxHeight;
|
||||
bodyHeight = rowSpacing - pinSize;
|
||||
// Body positioned between the two pin rows
|
||||
// For _270: left pins go right (positive X), so leftmost is at x
|
||||
// Left row is at y, right row is at y - rowSpacing
|
||||
// Similar to _90 but mirrored
|
||||
// Offset body downward by lead offset (bent leads)
|
||||
bodyX = x - pinSpacing / 2;
|
||||
bodyY = y - rowSpacing + pinSize / 2 + leadOffset;
|
||||
// Tab on the bottom side (where there are more pins - left row at y) inside the body bounds
|
||||
tabX = bodyX;
|
||||
tabY = bodyY + bodyHeight - tabThickness;
|
||||
tabWidth = bodyWidth;
|
||||
tabHeight = tabThickness;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unexpected orientation: " + orientation);
|
||||
}
|
||||
body[0] = new Area(new Rectangle2D.Double(bodyX, bodyY, bodyWidth, bodyHeight));
|
||||
body[1] = new Area(new Rectangle2D.Double(tabX, tabY, tabWidth, tabHeight));
|
||||
double rightRowHeight = (pinsRight - 1 + 0.5) * pinSpacing;
|
||||
double length = Math.max(leftRowHeight, rightRowHeight) + pinSpacing;
|
||||
double start = -pinSpacing / 2;
|
||||
double back = ROW_SPACING.convertToPixels() + BACK_TO_NEAR_ROW.convertToPixels();
|
||||
body[0] = new Area(
|
||||
toDrawing(start, start + length, back - THICKNESS.convertToPixels(), back));
|
||||
body[1] = new Area(
|
||||
toDrawing(start, start + length, back - TAB_THICKNESS.convertToPixels(), back));
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
// The rectangle spanning the given distances along the rows and across them, measured from the
|
||||
// first pin with the second row on the positive side, turned to the orientation.
|
||||
private Rectangle2D toDrawing(double alongFrom, double alongTo, double acrossFrom,
|
||||
double acrossTo) {
|
||||
double alongX;
|
||||
double alongY;
|
||||
double acrossX;
|
||||
double acrossY;
|
||||
switch (orientation) {
|
||||
case DEFAULT:
|
||||
alongX = 0;
|
||||
alongY = 1;
|
||||
acrossX = 1;
|
||||
acrossY = 0;
|
||||
break;
|
||||
case _90:
|
||||
alongX = -1;
|
||||
alongY = 0;
|
||||
acrossX = 0;
|
||||
acrossY = 1;
|
||||
break;
|
||||
case _180:
|
||||
alongX = 0;
|
||||
alongY = -1;
|
||||
acrossX = -1;
|
||||
acrossY = 0;
|
||||
break;
|
||||
case _270:
|
||||
alongX = 1;
|
||||
alongY = 0;
|
||||
acrossX = 0;
|
||||
acrossY = -1;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unexpected orientation: " + orientation);
|
||||
}
|
||||
Point2D first = controlPoints[0];
|
||||
double x1 = first.getX() + alongX * alongFrom + acrossX * acrossFrom;
|
||||
double y1 = first.getY() + alongY * alongFrom + acrossY * acrossFrom;
|
||||
double x2 = first.getX() + alongX * alongTo + acrossX * acrossTo;
|
||||
double y2 = first.getY() + alongY * alongTo + acrossY * acrossTo;
|
||||
return new Rectangle2D.Double(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1),
|
||||
Math.abs(y2 - y1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
@@ -337,20 +346,8 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
double pinX = point.getX();
|
||||
double pinY = point.getY();
|
||||
|
||||
// Check if pin is inside the body
|
||||
boolean insideBody = mainArea.contains(pinX, pinY);
|
||||
|
||||
if (insideBody) {
|
||||
// Draw pin as square inside body
|
||||
Rectangle2D rect = new Rectangle2D.Double(pinX - pinSize / 2,
|
||||
pinY - pinSize / 2, pinSize, pinSize);
|
||||
g2d.setColor(PIN_COLOR);
|
||||
drawingObserver.startTracking();
|
||||
g2d.fill(rect);
|
||||
drawingObserver.stopTracking();
|
||||
g2d.setColor(PIN_BORDER_COLOR);
|
||||
g2d.draw(rect);
|
||||
} else {
|
||||
// pins under the body are drawn on top of it further down
|
||||
if (!mainArea.contains(pinX, pinY)) {
|
||||
// Draw rectangular lead from body edge to pin position
|
||||
double bodyX = bodyBounds.getX();
|
||||
double bodyY = bodyBounds.getY();
|
||||
@@ -460,6 +457,25 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
g2d.setColor(finalBorderColor);
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
||||
g2d.draw(mainArea);
|
||||
|
||||
// the near row leaves through the bottom of the body, so its pins are drawn over the body to
|
||||
// stay visible whatever its alpha
|
||||
if (!outlineMode) {
|
||||
int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2;
|
||||
for (Point2D point : controlPoints) {
|
||||
if (mainArea.contains(point.getX(), point.getY())) {
|
||||
Rectangle2D rect = new Rectangle2D.Double(point.getX() - pinSize / 2,
|
||||
point.getY() - pinSize / 2, pinSize, pinSize);
|
||||
g2d.setColor(PIN_COLOR);
|
||||
drawingObserver.startTracking();
|
||||
g2d.fill(rect);
|
||||
drawingObserver.stopTracking();
|
||||
g2d.setColor(PIN_BORDER_COLOR);
|
||||
g2d.draw(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw label.
|
||||
g2d.setFont(project.getFont());
|
||||
Color finalLabelColor;
|
||||
@@ -492,6 +508,44 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2);
|
||||
int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent());
|
||||
g2d.drawString(label, x, y);
|
||||
|
||||
if (getPinLabels() != PinLabels.NONE) {
|
||||
g2d.setColor(finalBorderColor);
|
||||
drawPinLabels(g2d, mainArea.getBounds2D());
|
||||
}
|
||||
}
|
||||
|
||||
// Labels read forward, square to the rows, away from the tab. A pin under the body is labelled
|
||||
// from the front edge of the body, in the gap between the two forward leads either side of it;
|
||||
// a forward pin past the end of its lead. The stagger keeps the two sets apart.
|
||||
private void drawPinLabels(Graphics2D g2d, Rectangle2D bodyBounds) {
|
||||
g2d.setFont(ICPinNames.PIN_NAME_FONT);
|
||||
int pinsLeft = type.getPinsLeft();
|
||||
double acrossX = controlPoints[pinsLeft].getX() - controlPoints[0].getX();
|
||||
double acrossY = controlPoints[pinsLeft].getY() - controlPoints[0].getY();
|
||||
// the stagger adds half a pitch along the row, so the row offset is the larger component
|
||||
if (Math.abs(acrossX) > Math.abs(acrossY)) {
|
||||
acrossX = Math.signum(acrossX);
|
||||
acrossY = 0;
|
||||
} else {
|
||||
acrossX = 0;
|
||||
acrossY = Math.signum(acrossY);
|
||||
}
|
||||
double pinRadius = PIN_SIZE.convertToPixels() / 2;
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
String label;
|
||||
if (getPinLabels() == PinLabels.NUMBERS) {
|
||||
label = Integer.toString(getPinNumber(i));
|
||||
} else {
|
||||
String name = getPinName(getPinNumber(i));
|
||||
if (name == null) {
|
||||
continue;
|
||||
}
|
||||
label = AbstractMakerBoard.getDisplayPinLabel(name);
|
||||
}
|
||||
ICPinNames.drawOutside(g2d, label, controlPoints[i], -acrossX, -acrossY, bodyBounds,
|
||||
pinRadius);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -500,7 +554,7 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
int pinSize = 2 * width / 32;
|
||||
int leftPinX = width / 6 + 9; // Move left pins 9px to the right (4px + 3px + 2px)
|
||||
int rightPinX = 5 * width / 6;
|
||||
int leadOffset = (int) (LEAD_OFFSET.convertToPixels() * width / 100); // Scale lead offset for icon
|
||||
int leadOffset = (int) (BACK_TO_NEAR_ROW.convertToPixels() * width / 100); // Scale lead offset for icon
|
||||
int bodyX = leftPinX + pinSize - leadOffset + 2; // Offset body to the left, then move 2px to the right
|
||||
int bodyWidth = (rightPinX - bodyX - pinSize) / 2 + 2; // Thinner body, make 2px thicker
|
||||
int bodyHeight = height - 2 * margin;
|
||||
@@ -508,13 +562,13 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
|
||||
// Calculate pin spacing to use all vertical space
|
||||
// Use same spacing for both rows, with front row offset by half spacing
|
||||
int backPins = 4;
|
||||
int frontPins = 3;
|
||||
// Use the spacing that fits the back row (more pins)
|
||||
int pinSpacing = (bodyHeight - pinSize) / (backPins - 1);
|
||||
int backStartY = margin + pinSize / 2 + 1; // Move pins 1px down
|
||||
// Front pins start with half spacing offset for staggered effect
|
||||
int frontStartY = margin + pinSize / 2 + pinSpacing / 2 + 1; // Move pins 1px down
|
||||
// the forward row, bent clear of the body, is the one with more pins
|
||||
int backPins = 3;
|
||||
int frontPins = 4;
|
||||
int pinSpacing = (bodyHeight - pinSize) / (frontPins - 1);
|
||||
int frontStartY = margin + pinSize / 2 + 1; // Move pins 1px down
|
||||
// Back pins start with half spacing offset for staggered effect
|
||||
int backStartY = margin + pinSize / 2 + pinSpacing / 2 + 1; // Move pins 1px down
|
||||
|
||||
// Draw thin body between pin rows
|
||||
g2d.setColor(BODY_COLOR);
|
||||
@@ -522,14 +576,14 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
g2d.setColor(BORDER_COLOR);
|
||||
g2d.drawRect(bodyX, bodyY, bodyWidth, bodyHeight);
|
||||
|
||||
// Draw heat sink tab on left side (where there are more pins)
|
||||
// Draw heat sink tab on left side, away from the forward row
|
||||
int tabWidth = pinSize * 2;
|
||||
g2d.setColor(TAB_COLOR);
|
||||
g2d.fillRect(bodyX, bodyY, tabWidth, bodyHeight);
|
||||
g2d.setColor(TAB_BORDER_COLOR);
|
||||
g2d.drawRect(bodyX, bodyY, tabWidth, bodyHeight);
|
||||
|
||||
// Draw 4 pins in the back (left row, more pins) as squares - inside body
|
||||
// Draw 3 pins in the back as squares - inside body
|
||||
g2d.setColor(PIN_COLOR);
|
||||
for (int i = 0; i < backPins; i++) {
|
||||
int pinY = backStartY + i * pinSpacing - pinSize / 2;
|
||||
@@ -539,7 +593,7 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
g2d.setColor(PIN_COLOR);
|
||||
}
|
||||
|
||||
// Draw 3 pins in the front (right row, fewer pins) with leads going left to body
|
||||
// Draw 4 pins in the front with leads going left to body
|
||||
// Use same spacing as back row, just offset by half spacing
|
||||
g2d.setColor(PIN_COLOR);
|
||||
for (int i = 0; i < frontPins; i++) {
|
||||
@@ -628,6 +682,49 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
this.tabBorderColor = tabBorderColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Pin Names")
|
||||
public String getPinNames() {
|
||||
return pinNames;
|
||||
}
|
||||
|
||||
public void setPinNames(String pinNames) {
|
||||
this.pinNames = pinNames;
|
||||
parsedPinNames = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Pin Labels")
|
||||
public PinLabels getPinLabels() {
|
||||
if (pinLabels == null) {
|
||||
pinLabels = PinLabels.NAMES;
|
||||
}
|
||||
return pinLabels;
|
||||
}
|
||||
|
||||
public void setPinLabels(PinLabels pinLabels) {
|
||||
this.pinLabels = pinLabels;
|
||||
}
|
||||
|
||||
// the leads alternate between the rows along the package, so the forward row holds the odd pin
|
||||
// numbers and the row under the body the even ones
|
||||
private int getPinNumber(int index) {
|
||||
int pinsLeft = type.getPinsLeft();
|
||||
return index < pinsLeft ? 2 * index + 1 : 2 * (index - pinsLeft) + 2;
|
||||
}
|
||||
|
||||
private String getPinName(int pinNumber) {
|
||||
if (parsedPinNames == null) {
|
||||
parsedPinNames = ICPinNames.parse(getPinNames());
|
||||
}
|
||||
return ICPinNames.get(parsedPinNames, pinNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
int pinNumber = getPinNumber(index);
|
||||
String name = getPinName(pinNumber);
|
||||
return name == null ? Integer.toString(pinNumber) : name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getCachingBounds() {
|
||||
double minX = Integer.MAX_VALUE;
|
||||
@@ -652,18 +749,28 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
|
||||
public static enum MultiwattType {
|
||||
// Multiwatt-11: 6 pins on left, 5 pins on right (staggered)
|
||||
MULTIWATT_11(11, 6, 5),
|
||||
MULTIWATT_11(11, 6, 5, new Size(1.7d, SizeUnit.mm), "Multiwatt 11"),
|
||||
// Multiwatt-15: 8 pins on left, 7 pins on right (staggered)
|
||||
MULTIWATT_15(15, 8, 7);
|
||||
MULTIWATT_15(15, 8, 7, new Size(1.27d, SizeUnit.mm), "Multiwatt 15");
|
||||
|
||||
private final int pinCount;
|
||||
private final int pinsLeft;
|
||||
private final int pinsRight;
|
||||
// distance between consecutive leads along the package, i.e. from one row to the other
|
||||
private final Size leadPitch;
|
||||
private final String title;
|
||||
|
||||
MultiwattType(int pinCount, int pinsLeft, int pinsRight) {
|
||||
MultiwattType(int pinCount, int pinsLeft, int pinsRight, Size leadPitch, String title) {
|
||||
this.pinCount = pinCount;
|
||||
this.pinsLeft = pinsLeft;
|
||||
this.pinsRight = pinsRight;
|
||||
this.leadPitch = leadPitch;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
// neighbouring leads of the same row are two lead pitches apart
|
||||
public Size getRowPitch() {
|
||||
return leadPitch.scale(2);
|
||||
}
|
||||
|
||||
public int getPinCount() {
|
||||
@@ -680,7 +787,7 @@ public class MultiwattIC extends AbstractTransparentComponent<String> implements
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Multiwatt " + pinCount;
|
||||
return title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC 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 DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.components.semiconductors;
|
||||
|
||||
public enum PinLabels {
|
||||
NONE("None"), NAMES("Names"), NUMBERS("Numbers");
|
||||
|
||||
private String title;
|
||||
|
||||
private PinLabels(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
@@ -32,13 +32,16 @@ import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.Arrays;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.components.AbstractMakerBoard;
|
||||
import org.diylc.components.AbstractTransparentComponent;
|
||||
import org.diylc.components.transform.SIL_ICTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDatasheetSupport;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
@@ -54,11 +57,15 @@ import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@AiNote("The first control point is the anchor; with 'Orientation' DEFAULT the pins run straight down from it 'Pin Spacing' apart and the indent is at the anchor's end of the body. The other orientations rotate this around the anchor")
|
||||
@AiNote("The first control point is pin 1. 'Pin Names' is a comma-separated list of pin names in pin-number order; a pin without a name is called by its number. Pins named alike up to a trailing '_1', '_2' are one net inside the package, while 1IN and 2IN are separate channels")
|
||||
@AiNote("A datasheet model is a part number such as LA4440 and sets 'Pins', 'Pin Spacing', 'Pin Names' and 'Value'. Set 'Value' to the same part number together with the model")
|
||||
@ComponentDescriptor(name = "SIP IC", author = "Branislav Stojkovic", category = "Semiconductors",
|
||||
instanceNamePrefix = "IC", description = "Single-in-line package IC",
|
||||
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = SIL_ICTransformer.class,
|
||||
enableCache = true)
|
||||
public class SIL_IC extends AbstractTransparentComponent<String> implements IGerberComponentSimple {
|
||||
enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2,
|
||||
datasheetModelColumn = 1)
|
||||
public class SIL_IC extends AbstractTransparentComponent<String>
|
||||
implements IGerberComponentSimple, IDatasheetSupport {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -83,6 +90,8 @@ public class SIL_IC extends AbstractTransparentComponent<String> implements IGer
|
||||
private Color borderColor = BORDER_COLOR;
|
||||
private Color labelColor = LABEL_COLOR;
|
||||
private Color indentColor = INDENT_COLOR;
|
||||
private String pinNames = null;
|
||||
private PinLabels pinLabels = null;
|
||||
// new Point(0, pinSpacing.convertToPixels()),
|
||||
// new Point(0, 2 * pinSpacing.convertToPixels()),
|
||||
// new Point(0, 3 * pinSpacing.convertToPixels()),
|
||||
@@ -94,6 +103,7 @@ public class SIL_IC extends AbstractTransparentComponent<String> implements IGer
|
||||
// new Point(3 * pinSpacing.convertToPixels(), 3 *
|
||||
// pinSpacing.convertToPixels()) };
|
||||
transient private Area[] body;
|
||||
transient private String[] parsedPinNames;
|
||||
|
||||
public SIL_IC() {
|
||||
super();
|
||||
@@ -101,6 +111,22 @@ public class SIL_IC extends AbstractTransparentComponent<String> implements IGer
|
||||
this.alphaPercent = new Percentage(100);
|
||||
}
|
||||
|
||||
public SIL_IC(String[] model) {
|
||||
this();
|
||||
|
||||
applyModel(model);
|
||||
}
|
||||
|
||||
// columns: group, part number, pin spacing, then one name per pin in pin-number order, so the
|
||||
// pin count is the number of names
|
||||
@Override
|
||||
public void applyModel(String[] model) {
|
||||
setValue(model[1]);
|
||||
setPinSpacing(Size.parseSize(model[2]));
|
||||
setPinCount(PinCount.valueOf("_" + (model.length - 3)));
|
||||
setPinNames(String.join(",", Arrays.copyOfRange(model, 3, model.length)));
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public String getValue() {
|
||||
return value;
|
||||
@@ -230,7 +256,7 @@ public class SIL_IC extends AbstractTransparentComponent<String> implements IGer
|
||||
int thickness = getClosestOdd(THICKNESS.convertToPixels());
|
||||
double width;
|
||||
double height;
|
||||
double pinSpacing = (int) this.pinSpacing.convertToPixels();
|
||||
double pinSpacing = this.pinSpacing.convertToPixels();
|
||||
Area indentation = null;
|
||||
int indentationSize = getClosestOdd(INDENT_SIZE.convertToPixels());
|
||||
switch (orientation) {
|
||||
@@ -364,6 +390,40 @@ public class SIL_IC extends AbstractTransparentComponent<String> implements IGer
|
||||
int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2);
|
||||
int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent());
|
||||
g2d.drawString(label, x, y);
|
||||
|
||||
if (getPinLabels() != PinLabels.NONE) {
|
||||
g2d.setColor(finalBorderColor);
|
||||
drawPinLabels(g2d, mainArea.getBounds2D());
|
||||
}
|
||||
}
|
||||
|
||||
// Labels sit beside the body, square to the row and reading away from it, on the side the row
|
||||
// turns to clockwise: right of a row running down, below one running left.
|
||||
private void drawPinLabels(Graphics2D g2d, Rectangle2D bodyBounds) {
|
||||
if (controlPoints.length < 2) {
|
||||
return;
|
||||
}
|
||||
g2d.setFont(ICPinNames.PIN_NAME_FONT);
|
||||
if (g2d.getFontMetrics().getAscent() > pinSpacing.convertToPixels()) {
|
||||
return;
|
||||
}
|
||||
double rowDistance = controlPoints[0].distance(controlPoints[1]);
|
||||
double alongX = (controlPoints[1].getX() - controlPoints[0].getX()) / rowDistance;
|
||||
double alongY = (controlPoints[1].getY() - controlPoints[0].getY()) / rowDistance;
|
||||
double pinRadius = PIN_SIZE.convertToPixels() / 2;
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
String label;
|
||||
if (getPinLabels() == PinLabels.NUMBERS) {
|
||||
label = Integer.toString(i + 1);
|
||||
} else {
|
||||
String name = getPinName(i + 1);
|
||||
if (name == null) {
|
||||
continue;
|
||||
}
|
||||
label = AbstractMakerBoard.getDisplayPinLabel(name);
|
||||
}
|
||||
ICPinNames.drawOutside(g2d, label, controlPoints[i], alongY, -alongX, bodyBounds, pinRadius);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -429,6 +489,41 @@ public class SIL_IC extends AbstractTransparentComponent<String> implements IGer
|
||||
public void setIndentColor(Color indentColor) {
|
||||
this.indentColor = indentColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Pin Names")
|
||||
public String getPinNames() {
|
||||
return pinNames;
|
||||
}
|
||||
|
||||
public void setPinNames(String pinNames) {
|
||||
this.pinNames = pinNames;
|
||||
parsedPinNames = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Pin Labels")
|
||||
public PinLabels getPinLabels() {
|
||||
if (pinLabels == null) {
|
||||
pinLabels = PinLabels.NAMES;
|
||||
}
|
||||
return pinLabels;
|
||||
}
|
||||
|
||||
public void setPinLabels(PinLabels pinLabels) {
|
||||
this.pinLabels = pinLabels;
|
||||
}
|
||||
|
||||
private String getPinName(int pinNumber) {
|
||||
if (parsedPinNames == null) {
|
||||
parsedPinNames = ICPinNames.parse(getPinNames());
|
||||
}
|
||||
return ICPinNames.get(parsedPinNames, pinNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
String name = getPinName(index + 1);
|
||||
return name == null ? Integer.toString(index + 1) : name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getCachingBounds() {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
Op-Amp (Single),TL061,0.3 in,N1 (OFFSET),IN-,IN+,VCC-,N2 (OFFSET),OUT,VCC+,NC
|
||||
Op-Amp (Single),TL071,0.3 in,N1 (OFFSET),IN-,IN+,VCC-,N2 (OFFSET),OUT,VCC+,NC
|
||||
Op-Amp (Single),TL081,0.3 in,N1 (OFFSET),IN-,IN+,VCC-,N2 (OFFSET),OUT,VCC+,NC
|
||||
Op-Amp (Single),LM741,0.3 in,N1 (OFFSET),IN-,IN+,VCC-,N2 (OFFSET),OUT,VCC+,NC
|
||||
Op-Amp (Single),LF356,0.3 in,N1 (OFFSET),IN-,IN+,VCC-,N2 (OFFSET),OUT,VCC+,NC
|
||||
Op-Amp (Single),OPA134,0.3 in,NC,IN-,IN+,VCC-,NC,OUT,VCC+,NC
|
||||
Op-Amp (Single),NE5534,0.3 in,BALANCE,IN-,IN+,VCC-,COMP,OUT,VCC+,COMP/BAL
|
||||
Op-Amp (Dual),TL062,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),TL072,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),TL082,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),NE5532,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),JRC4558,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),RC4580,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),OPA2134,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),OPA2604,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),LM4562,0.3 in,1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+
|
||||
Op-Amp (Dual),LM358,0.3 in,1OUT,1IN-,1IN+,GND,2IN+,2IN-,2OUT,VCC
|
||||
Op-Amp (Quad),TL074,0.3 in,1OUT,1IN-,1IN+,VCC+,2IN+,2IN-,2OUT,3OUT,3IN-,3IN+,VCC-,4IN+,4IN-,4OUT
|
||||
Op-Amp (Quad),TL084,0.3 in,1OUT,1IN-,1IN+,VCC+,2IN+,2IN-,2OUT,3OUT,3IN-,3IN+,VCC-,4IN+,4IN-,4OUT
|
||||
Op-Amp (Quad),OPA4134,0.3 in,1OUT,1IN-,1IN+,VCC+,2IN+,2IN-,2OUT,3OUT,3IN-,3IN+,VCC-,4IN+,4IN-,4OUT
|
||||
Op-Amp (Quad),LM324,0.3 in,1OUT,1IN-,1IN+,VCC,2IN+,2IN-,2OUT,3OUT,3IN-,3IN+,GND,4IN+,4IN-,4OUT
|
||||
Timer,NE555,0.3 in,GND,TRIG,OUT,RESET,CONT,THRES,DISCH,VCC
|
||||
Timer,ICM7555,0.3 in,GND,TRIG,OUT,RESET,CONT,THRES,DISCH,VCC
|
||||
Timer,TLC555,0.3 in,GND,TRIG,OUT,RESET,CONT,THRES,DISCH,VCC
|
||||
Timer,NE556,0.3 in,1DISCH,1THRES,1CONT,1RESET,1OUT,1TRIG,GND,2TRIG,2OUT,2RESET,2CONT,2THRES,2DISCH,VCC
|
||||
Timer,ICM7556,0.3 in,1DISCH,1THRES,1CONT,1RESET,1OUT,1TRIG,GND,2TRIG,2OUT,2RESET,2CONT,2THRES,2DISCH,VCC
|
||||
OTA / VCA,LM13700,0.3 in,1IABC (AMP BIAS),1DBIAS (DIODE BIAS),1IN+,1IN-,1OUT,VCC-,1BUFIN,1BUFOUT,2BUFOUT,2BUFIN,VCC+,2OUT,2IN-,2IN+,2DBIAS (DIODE BIAS),2IABC (AMP BIAS)
|
||||
OTA / VCA,CA3080,0.3 in,NC,IN-,IN+,VCC-,IABC (AMP BIAS),OUT,VCC+,NC
|
||||
OTA / VCA,SSM2164,0.3 in,MODE,1IIN,1VC (CONTROL),1IOUT,2IOUT,2VC (CONTROL),2IIN,GND,VCC-,3IIN,3VC (CONTROL),3IOUT,4IOUT,4VC (CONTROL),4IIN,VCC+
|
||||
OTA / VCA,V2164,0.3 in,MODE,1IIN,1VC (CONTROL),1IOUT,2IOUT,2VC (CONTROL),2IIN,GND,VCC-,3IIN,3VC (CONTROL),3IOUT,4IOUT,4VC (CONTROL),4IIN,VCC+
|
||||
Power Amp,LM386,0.3 in,GAIN1,IN-,IN+,GND,VOUT,VS,BYP (BYPASS),GAIN8
|
||||
Power Amp,LM380,0.3 in,BYP (BYPASS),IN+,GND_1,GND_2,GND_3,IN-,GND_4,VOUT,NC,GND_5,GND_6,GND_7,NC,VS
|
||||
Power Amp,TDA7052,0.3 in,VP,IN,GND1 (SIGNAL GND),NC,OUT1,GND2 (POWER GND),NC,OUT2
|
||||
Power Amp,TDA2822,0.3 in,1OUT,VS,2OUT,GND,2IN-,2IN+,1IN+,1IN-
|
||||
BBD,MN3007,0.3 in,GND,CP1 (CLOCK 1),IN,VGG,VDD,CP2 (CLOCK 2),OUT1,OUT2
|
||||
BBD,MN3207,0.3 in,GND,CP1 (CLOCK 1),IN,VGG,VDD,CP2 (CLOCK 2),OUT1,OUT2
|
||||
BBD,BL3207,0.3 in,GND,CP1 (CLOCK 1),IN,VGG,VDD,CP2 (CLOCK 2),OUT1,OUT2
|
||||
BBD,BL3208A,0.3 in,GND,CP1 (CLOCK 1),IN,VGG,VDD,CP2 (CLOCK 2),OUT1,OUT2
|
||||
BBD,V3207,0.3 in,GND,CP1 (CLOCK 1),IN,VGG,VDD,CP2 (CLOCK 2),OUT1,OUT2
|
||||
BBD,MN3008,0.3 in,GND,CP2 (CLOCK 2),NC,NC,NC,OUT1,OUT2,VDD,CP1 (CLOCK 1),NC,NC,NC,IN,VGG
|
||||
BBD,MN3005,0.3 in,GND,CP2 (CLOCK 2),NC,NC,NC,OUT1,OUT2,VDD,CP1 (CLOCK 1),NC,NC,NC,IN,VGG
|
||||
BBD,BL3208B,0.3 in,GND,CP2 (CLOCK 2),NC,NC,NC,OUT1,OUT2,VDD,CP1 (CLOCK 1),NC,NC,NC,IN,VGG
|
||||
BBD Clock,MN3101,0.3 in,GND,CP1 (CLOCK 1),VDD,CP2 (CLOCK 2),OX3,OX2,OX1,VGG (OUTPUT)
|
||||
BBD Clock,MN3102,0.3 in,VDD,CP1 (CLOCK 1),GND,CP2 (CLOCK 2),OX3,OX2,OX1,VGG (OUTPUT)
|
||||
BBD Clock,V3102,0.3 in,VDD,CP1 (CLOCK 1),VSS,CP2 (CLOCK 2),RCEXT3,RCEXT2,RCEXT1,VGG (OUTPUT)
|
||||
Delay / Compander,PT2399,0.3 in,VCC,REF,AGND,DGND,CLKO (CLOCK OUT),VCO,CC1,CC0,OP1-OUT,OP1-IN,OP2-IN,OP2-OUT,LPF2-IN,LPF2-OUT,LPF1-OUT,LPF1-IN
|
||||
Delay / Compander,NE570,0.3 in,1RECTCAP,1RECTIN,1DGIN (DELTA G CELL IN),GND,1INVIN,1R3,1OUT,1THDTRIM,2THDTRIM,2OUT,2R3,2INVIN,VCC,2DGIN (DELTA G CELL IN),2RECTIN,2RECTCAP
|
||||
Delay / Compander,NE571,0.3 in,1RECTCAP,1RECTIN,1DGIN (DELTA G CELL IN),GND,1INVIN,1R3,1OUT,1THDTRIM,2THDTRIM,2OUT,2R3,2INVIN,VCC,2DGIN (DELTA G CELL IN),2RECTIN,2RECTCAP
|
||||
Delay / Compander,SA571,0.3 in,1RECTCAP,1RECTIN,1DGIN (DELTA G CELL IN),GND,1INVIN,1R3,1OUT,1THDTRIM,2THDTRIM,2OUT,2R3,2INVIN,VCC,2DGIN (DELTA G CELL IN),2RECTIN,2RECTCAP
|
||||
Charge Pump,ICL7660,0.3 in,NC,CAP+,GND,CAP-,VOUT,LV,OSC,V+
|
||||
Charge Pump,TC1044,0.3 in,BOOST,CAP+,GND,CAP-,VOUT,LV,OSC,V+
|
||||
Charge Pump,MAX1044,0.3 in,BOOST,CAP+,GND,CAP-,VOUT,LV,OSC,V+
|
||||
Charge Pump,LT1054,0.3 in,FB/SD,CAP+,GND,CAP-,VOUT,VREF,OSC,VCC
|
||||
CMOS Logic / Switch,CD4049,0.3 in,VDD,1Y,1A,2Y,2A,3Y,3A,VSS,4A,4Y,5A,5Y,NC,6A,6Y,NC
|
||||
CMOS Logic / Switch,CD4069,0.3 in,1A,1Y,2A,2Y,3A,3Y,VSS,4Y,4A,5Y,5A,6Y,6A,VDD
|
||||
CMOS Logic / Switch,CD40106,0.3 in,1A,1Y,2A,2Y,3A,3Y,VSS,4Y,4A,5Y,5A,6Y,6A,VDD
|
||||
CMOS Logic / Switch,CD4011,0.3 in,1A,1B,1Y,2Y,2A,2B,VSS,3A,3B,3Y,4Y,4A,4B,VDD
|
||||
CMOS Logic / Switch,CD4013,0.3 in,1Q,1QN,1CLK,1R,1D,1S,VSS,2S,2D,2R,2CLK,2QN,2Q,VDD
|
||||
CMOS Logic / Switch,CD4017,0.3 in,Q5,Q1,Q0,Q2,Q6,Q7,Q3,VSS,Q8,Q4,Q9,CO,CLKINH,CLK,RST,VDD
|
||||
CMOS Logic / Switch,CD4066,0.3 in,1A,1B,2B,2A,2C,3C,VSS,3A,3B,4B,4A,4C,1C,VDD
|
||||
CMOS Logic / Switch,CD4051,0.3 in,CH4,CH6,COM,CH7,CH5,INH,VEE,VSS,C,B,A,CH3,CH0,CH1,CH2,VDD
|
||||
CMOS Logic / Switch,CD4053,0.3 in,2Y,2X,3Y,3COM,3X,INH,VEE,VSS,C,B,A,1X,1Y,1COM,2COM,VDD
|
||||
Optocoupler,PC817,0.3 in,A,K,E,C
|
||||
Optocoupler,4N35,0.3 in,A,K,NC,E,C,B
|
||||
Optocoupler,6N138,0.3 in,NC,A,K,NC,GND,VO,B (VB),VCC
|
||||
Optocoupler,H11L1,0.3 in,A,K,NC,VO,GND,VCC
|
||||
MCU,ATtiny85,0.3 in,PB5 (RESET/ADC0),PB3 (XTAL1/ADC3),PB4 (XTAL2/ADC2),GND,PB0 (MOSI/SDA),PB1 (MISO),PB2 (SCK/SCL/ADC1),VCC
|
||||
MCU,ATmega328P,0.3 in,PC6 (RESET),PD0 (RXD),PD1 (TXD),PD2 (INT0),PD3 (INT1/OC2B),PD4 (T0/XCK),VCC,GND_1,PB6 (XTAL1),PB7 (XTAL2),PD5 (T1/OC0B),PD6 (AIN0/OC0A),PD7 (AIN1),PB0 (ICP1/CLKO),PB1 (OC1A),PB2 (SS/OC1B),PB3 (MOSI/OC2A),PB4 (MISO),PB5 (SCK),AVCC,AREF,GND_2,PC0 (ADC0),PC1 (ADC1),PC2 (ADC2),PC3 (ADC3),PC4 (ADC4/SDA),PC5 (ADC5/SCL)
|
||||
@@ -0,0 +1,4 @@
|
||||
Power Amp,LM3886,VCC+1,NC,OUT,VCC-,VCC+5,NC,GND,MUTE,IN-,IN+,NC
|
||||
Power Amp,TDA7265,VS-1,1OUT,VS+,2OUT,MUTE (MUTE/STBY),VS-6,2IN+,2IN-,GND,1IN-,1IN+
|
||||
Power Amp,TDA7293,STBY-GND,IN-,IN+,GND (SIGNAL),CLIP (CLIP/SC DETECTOR),BOOT,VS+SIG,VS-SIG,STBY,MUTE,BUF (BUFFER DRIVER),BOOTL (BOOTSTRAP LOADER),VS+PWR,OUT,VS-PWR
|
||||
Power Amp,TDA7294,STBY-GND,IN-,IN+,SVR,NC,BOOT,VS+SIG,VS-SIG,STBY,MUTE,NC,NC,VS+PWR,OUT,VS-PWR
|
||||
@@ -0,0 +1,12 @@
|
||||
Power Amp,LA4440,2.54 mm,1NF,1IN,PREGND,MUTE (AC),RIPPLE (DC MUTE),2IN,2NF,2PGND,2BS,2OUT,VCC,1OUT,1BS,1PGND
|
||||
Power Amp,LA4485,2 mm,1IN,2IN,GND,BTLIN (BTL FEEDBACK),BTLOUT (BTL FEEDBACK),RIPPLE (FILTER),PVCC,VCC,STBY,MUTE,2OUT,PGND,1OUT
|
||||
Power Amp,LA4425A,2 mm,IN,GND,PGND (TAB),OUT,VCC
|
||||
Power Amp,TA7205AP,2.54 mm,VCC,BS,RIPPLE,PC1 (PHASE COMP),PC2 (PHASE COMP),IN,NF,PC3 (PHASE COMP),GND,OUT
|
||||
Power Amp,TDA1013B,2.54 mm,PGND,OUT,VCC,RIPPLE (ELECTRONIC FILTER),IN,CTLOUT (CONTROL UNIT OUTPUT),VC (DC VOLUME CONTROL),CTLIN (CONTROL UNIT INPUT),GND (SUBSTRATE)
|
||||
Power Amp,TDA1010A,2.54 mm,PGND,OUT,VCC,BS,RIPPLE,IN (POWER AMP),PREOUT,PREIN,GND (SUBSTRATE)
|
||||
Power Amp,TDA1521A,2.54 mm,1IN+,1IN-,GND (VCC/2 IN SINGLE SUPPLY),1OUT,VEE (GND IN SINGLE SUPPLY),2OUT,VCC,2IN-,2IN+
|
||||
Power Amp,TDA7056,2.54 mm,NC,VCC,IN,GND,NC,OUT+,PGND,OUT-,NC
|
||||
Power Amp,TDA7056A,2.54 mm,NC,VCC,IN,GND,VC (DC VOLUME CONTROL),OUT+,PGND,OUT-,NC
|
||||
Power Amp,BA5406,2.54 mm,VCC,1OUT,1BS,1NF,1IN,RIPPLE (FILTER MUTE),FILTER,2IN,2NF,2BS,2OUT,GND
|
||||
Power Amp,BA5417,2 mm,NC,2BS,2OUT,VCC,1OUT,1BS,PGND,STBY,RIPPLE (FILTER),1NF,1IN,2IN,2NF,1PREGND,2PREGND
|
||||
Preamp,BA3121N,2.54 mm,1OUT,1VM (GROUND SENSE),1IN,GND,2IN,2VM (GROUND SENSE),2OUT,VCC
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC).
|
||||
* Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* DIYLC 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 DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.diylc.components.semiconductors;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.components.semiconductors.DIL_IC.PinCount;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.netlist.Node;
|
||||
import org.diylc.presenter.DatasheetService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DIL_ICDatasheetTest {
|
||||
|
||||
private static final int FIRST_PIN_COLUMN = 3;
|
||||
|
||||
@Test
|
||||
public void everyRowApplies() {
|
||||
for (String[] row : datasheet()) {
|
||||
DIL_IC ic = new DIL_IC(row);
|
||||
String context = String.join(",", row);
|
||||
Assert.assertEquals(context, row[1], ic.getValue());
|
||||
Assert.assertEquals(context, row.length - FIRST_PIN_COLUMN, ic.getControlPointCount());
|
||||
for (int i = 0; i < ic.getControlPointCount(); i++) {
|
||||
Assert.assertFalse(context, ic.getControlPointNodeName(i).matches("\\d+"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partNumbersAreUnique() {
|
||||
Set<String> parts = new HashSet<String>();
|
||||
for (String[] row : datasheet()) {
|
||||
Assert.assertTrue("repeated part " + row[1], parts.add(row[1].toUpperCase()));
|
||||
}
|
||||
}
|
||||
|
||||
/** Two pins share a net only when both say so with a numbered suffix, like GND_1 and GND_2. */
|
||||
@Test
|
||||
public void pinsShareANetOnlyThroughTheSuffix() {
|
||||
for (String[] row : datasheet()) {
|
||||
for (int i = FIRST_PIN_COLUMN; i < row.length; i++) {
|
||||
for (int j = i + 1; j < row.length; j++) {
|
||||
String rail = Node.railName(row[i]);
|
||||
if (rail != null && rail.equals(Node.railName(row[j]))) {
|
||||
Assert.assertTrue(row[1] + " pins " + row[i] + " and " + row[j],
|
||||
row[i].matches(".*_\\d+") && row[j].matches(".*_\\d+"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partIsFoundByNumberNotByGroup() {
|
||||
DatasheetService service = DatasheetService.getInstance();
|
||||
Assert.assertEquals(1, service.findSeries(DIL_IC.class, "tl072").size());
|
||||
Assert.assertTrue(service.findSeries(DIL_IC.class, "Op-Amp (Dual)").isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appliesAllColumns() {
|
||||
DIL_IC ic = new DIL_IC(DatasheetService.getInstance().findSeries(DIL_IC.class, "TL074").get(0));
|
||||
Assert.assertEquals("TL074", ic.getValue());
|
||||
Assert.assertEquals(PinCount._14, ic.getPinCount());
|
||||
Assert.assertEquals(new Size(0.3d, SizeUnit.in), ic.getRowSpacing());
|
||||
Assert.assertEquals("1OUT", ic.getControlPointNodeName(0));
|
||||
Assert.assertEquals("4OUT", ic.getControlPointNodeName(7));
|
||||
}
|
||||
|
||||
/** A new part has a blank value, which must not count as a value the model would change. */
|
||||
@Test
|
||||
public void modelAppliesToNewPart() {
|
||||
DIL_IC ic = new DIL_IC();
|
||||
DatasheetService service = DatasheetService.getInstance();
|
||||
String[] model = service.findModel(ic, service.findSeries(DIL_IC.class, "NE555"));
|
||||
Assert.assertNotNull(model);
|
||||
ic.applyModel(model);
|
||||
Assert.assertEquals("GND", ic.getControlPointNodeName(0));
|
||||
Assert.assertEquals("VCC", ic.getControlPointNodeName(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modelMustMatchTheValue() {
|
||||
DatasheetService service = DatasheetService.getInstance();
|
||||
List<String[]> rows = service.findSeries(DIL_IC.class, "TL072");
|
||||
DIL_IC ic = new DIL_IC();
|
||||
ic.setValue("TL072");
|
||||
Assert.assertNotNull(service.findModel(ic, rows));
|
||||
ic.setValue("NE5532");
|
||||
Assert.assertNull(service.findModel(ic, rows));
|
||||
}
|
||||
|
||||
private static List<String[]> datasheet() {
|
||||
List<String[]> datasheet = DatasheetService.getInstance().loadDatasheet(DIL_IC.class);
|
||||
Assert.assertNotNull(datasheet);
|
||||
Assert.assertFalse(datasheet.isEmpty());
|
||||
return datasheet;
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC).
|
||||
* Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* DIYLC 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 DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.diylc.components.semiconductors;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.components.semiconductors.DIL_IC.DisplayNumbers;
|
||||
import org.diylc.components.semiconductors.DIL_IC.PinCount;
|
||||
import org.diylc.netlist.Node;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Pin numbering and pin names of the DIP IC. Control points run down the first row and then down
|
||||
* the second, so on an 8-pin part control point 4 is pin 8.
|
||||
*/
|
||||
public class DIL_ICTest {
|
||||
|
||||
private static final String TL072 = "1OUT,1IN-,1IN+,VCC-,2IN+,2IN-,2OUT,VCC+";
|
||||
|
||||
@Test
|
||||
public void unnumberedPartReportsDipPinNumbers() {
|
||||
DIL_IC ic = ic(PinCount._8, DisplayNumbers.NO, null);
|
||||
assertNodeNames(ic, "1", "2", "3", "4", "8", "7", "6", "5");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void numberingSchemes() {
|
||||
assertNodeNames(ic(PinCount._8, DisplayNumbers.NAMES, null), "1", "2", "3", "4", "8", "7", "6",
|
||||
"5");
|
||||
assertNodeNames(ic(PinCount._8, DisplayNumbers.DIP, null), "1", "2", "3", "4", "8", "7", "6",
|
||||
"5");
|
||||
assertNodeNames(ic(PinCount._8, DisplayNumbers.DIP_MIRROR, null), "8", "7", "6", "5", "1",
|
||||
"2", "3", "4");
|
||||
assertNodeNames(ic(PinCount._8, DisplayNumbers.CONNECTOR, null), "1", "3", "5", "7", "2", "4",
|
||||
"6", "8");
|
||||
assertNodeNames(ic(PinCount._8, DisplayNumbers.CONNECTOR_MIRROR, null), "2", "4", "6", "8",
|
||||
"1", "3", "5", "7");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everySchemeNumbersEachPinOnce() {
|
||||
for (PinCount pinCount : PinCount.values()) {
|
||||
for (DisplayNumbers numbers : DisplayNumbers.values()) {
|
||||
DIL_IC ic = ic(pinCount, numbers, null);
|
||||
Set<String> seen = new HashSet<String>();
|
||||
for (int i = 0; i < ic.getControlPointCount(); i++) {
|
||||
String name = ic.getControlPointNodeName(i);
|
||||
int number = Integer.parseInt(name);
|
||||
Assert.assertTrue(pinCount + " " + numbers + " pin " + name,
|
||||
number >= 1 && number <= pinCount.getValue());
|
||||
Assert.assertTrue(pinCount + " " + numbers + " repeats " + name, seen.add(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newPartShowsNames() {
|
||||
Assert.assertEquals(DisplayNumbers.NAMES, new DIL_IC().getDisplayNumbers());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void namesFollowPinNumbers() {
|
||||
assertNodeNames(ic(PinCount._8, DisplayNumbers.NO, TL072), "1OUT", "1IN-", "1IN+", "VCC-",
|
||||
"VCC+", "2OUT", "2IN-", "2IN+");
|
||||
}
|
||||
|
||||
/** Names belong to pins, so drawing the part from the solder side moves them with the numbers. */
|
||||
@Test
|
||||
public void namesFollowMirroredNumbering() {
|
||||
assertNodeNames(ic(PinCount._8, DisplayNumbers.DIP_MIRROR, TL072), "VCC+", "2OUT", "2IN-",
|
||||
"2IN+", "1OUT", "1IN-", "1IN+", "VCC-");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingAndBlankNamesFallBackToNumbers() {
|
||||
assertNodeNames(ic(PinCount._8, DisplayNumbers.NO, " TRIG , ,OUT"), "TRIG", "2", "OUT", "4",
|
||||
"8", "7", "6", "5");
|
||||
assertNodeNames(ic(PinCount._4, DisplayNumbers.NO, ""), "1", "2", "4", "3");
|
||||
}
|
||||
|
||||
/** Surplus names are kept, so going back to the larger package restores them. */
|
||||
@Test
|
||||
public void surplusNamesSurvivePinCountChange() {
|
||||
DIL_IC ic = ic(PinCount._8, DisplayNumbers.NO, TL072);
|
||||
ic.setPinCount(PinCount._4);
|
||||
assertNodeNames(ic, "1OUT", "1IN-", "VCC-", "1IN+");
|
||||
ic.setPinCount(PinCount._8);
|
||||
Assert.assertEquals("VCC+", ic.getControlPointNodeName(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void numberedSuffixNamesOneNet() {
|
||||
DIL_IC ic = ic(PinCount._4, DisplayNumbers.NO, "GND_1,GND_2,1IN-,2IN-");
|
||||
Assert.assertEquals(Node.railName(ic.getControlPointNodeName(0)),
|
||||
Node.railName(ic.getControlPointNodeName(1)));
|
||||
Assert.assertNotEquals(Node.railName(ic.getControlPointNodeName(2)),
|
||||
Node.railName(ic.getControlPointNodeName(3)));
|
||||
}
|
||||
|
||||
private static DIL_IC ic(PinCount pinCount, DisplayNumbers numbers, String pinNames) {
|
||||
DIL_IC ic = new DIL_IC();
|
||||
ic.setPinCount(pinCount);
|
||||
ic.setDisplayNumbers(numbers);
|
||||
ic.setPinNames(pinNames);
|
||||
return ic;
|
||||
}
|
||||
|
||||
private static void assertNodeNames(DIL_IC ic, String... expected) {
|
||||
String[] actual = new String[ic.getControlPointCount()];
|
||||
for (int i = 0; i < actual.length; i++) {
|
||||
actual[i] = ic.getControlPointNodeName(i);
|
||||
}
|
||||
Assert.assertArrayEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC).
|
||||
* Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* DIYLC 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 DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.diylc.components.semiconductors;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.netlist.Node;
|
||||
import org.diylc.presenter.DatasheetService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MultiwattICDatasheetTest {
|
||||
|
||||
private static final int FIRST_PIN_COLUMN = 2;
|
||||
|
||||
@Test
|
||||
public void everyRowApplies() {
|
||||
for (String[] row : datasheet()) {
|
||||
MultiwattIC ic = new MultiwattIC(row);
|
||||
String context = String.join(",", row);
|
||||
Assert.assertEquals(context, row[1], ic.getValue());
|
||||
Assert.assertEquals(context, row.length - FIRST_PIN_COLUMN, ic.getControlPointCount());
|
||||
for (int i = 0; i < ic.getControlPointCount(); i++) {
|
||||
Assert.assertFalse(context, ic.getControlPointNodeName(i).matches("\\d+"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partNumbersAreUnique() {
|
||||
Set<String> parts = new HashSet<String>();
|
||||
for (String[] row : datasheet()) {
|
||||
Assert.assertTrue("repeated part " + row[1], parts.add(row[1].toUpperCase()));
|
||||
}
|
||||
}
|
||||
|
||||
/** Two pins share a net only when both say so with a numbered suffix, like GND_1 and GND_2. */
|
||||
@Test
|
||||
public void pinsShareANetOnlyThroughTheSuffix() {
|
||||
for (String[] row : datasheet()) {
|
||||
for (int i = FIRST_PIN_COLUMN; i < row.length; i++) {
|
||||
for (int j = i + 1; j < row.length; j++) {
|
||||
String rail = Node.railName(row[i]);
|
||||
if (rail != null && rail.equals(Node.railName(row[j]))) {
|
||||
Assert.assertTrue(row[1] + " pins " + row[i] + " and " + row[j],
|
||||
row[i].matches(".*_\\d+") && row[j].matches(".*_\\d+"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partIsFoundByNumberNotByGroup() {
|
||||
DatasheetService service = DatasheetService.getInstance();
|
||||
Assert.assertEquals(1, service.findSeries(MultiwattIC.class, "LM3886").size());
|
||||
Assert.assertTrue(service.findSeries(MultiwattIC.class, "Power Amp").isEmpty());
|
||||
}
|
||||
|
||||
private static List<String[]> datasheet() {
|
||||
List<String[]> datasheet = DatasheetService.getInstance().loadDatasheet(MultiwattIC.class);
|
||||
Assert.assertNotNull(datasheet);
|
||||
Assert.assertFalse(datasheet.isEmpty());
|
||||
return datasheet;
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC).
|
||||
* Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* DIYLC 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 DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.diylc.components.semiconductors;
|
||||
|
||||
import org.diylc.components.semiconductors.MultiwattIC.MultiwattType;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Pin numbering, pin names and lead pitch of the staggered power packages. Control points run down
|
||||
* the forward row and then down the row under the body, while the pins are numbered alternately
|
||||
* between them.
|
||||
*/
|
||||
public class MultiwattICTest {
|
||||
|
||||
@Test
|
||||
public void pinsAreNumberedAlternatelyBetweenRows() {
|
||||
assertNodeNames(ic(MultiwattType.MULTIWATT_11, null), "1", "3", "5", "7", "9", "11", "2", "4",
|
||||
"6", "8", "10");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void namesFollowPinNumbers() {
|
||||
assertNodeNames(ic(MultiwattType.MULTIWATT_11, "A,B,C,D,E,F,G,H,I,J,K"), "A", "C", "E", "G",
|
||||
"I", "K", "B", "D", "F", "H", "J");
|
||||
}
|
||||
|
||||
/** Consecutive leads alternate rows, so pin 2 sits one lead pitch along from pin 1. */
|
||||
@Test
|
||||
public void leadPitchFollowsThePackage() {
|
||||
assertLeadPitch(MultiwattType.MULTIWATT_11, new Size(1.7d, SizeUnit.mm));
|
||||
assertLeadPitch(MultiwattType.MULTIWATT_15, new Size(1.27d, SizeUnit.mm));
|
||||
}
|
||||
|
||||
/** Multiwatt 15 keeps the 0.1 in row pitch it always had, so existing layouts do not move. */
|
||||
@Test
|
||||
public void multiwatt15KeepsItsRowPitch() {
|
||||
MultiwattIC ic = ic(MultiwattType.MULTIWATT_15, null);
|
||||
Assert.assertEquals(new Size(0.1d, SizeUnit.in).convertToPixels(),
|
||||
ic.getControlPoint(1).getY() - ic.getControlPoint(0).getY(), 1d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modelPicksThePackageByPinCount() {
|
||||
MultiwattIC ic = new MultiwattIC(new String[] {"Power Amp", "TEST", "A", "B", "C", "D", "E",
|
||||
"F", "G", "H", "I", "J", "K"});
|
||||
Assert.assertEquals(MultiwattType.MULTIWATT_11, ic.getType());
|
||||
Assert.assertEquals("TEST", ic.getValue());
|
||||
// control point 6 opens the second row, which holds pin 2
|
||||
Assert.assertEquals("B", ic.getControlPointNodeName(6));
|
||||
}
|
||||
|
||||
private static void assertLeadPitch(MultiwattType type, Size expected) {
|
||||
MultiwattIC ic = ic(type, null);
|
||||
// with the default orientation the rows run down, so the lead pitch is a y distance
|
||||
double pitch = ic.getControlPoint(type.getPinsLeft()).getY() - ic.getControlPoint(0).getY();
|
||||
Assert.assertEquals(type.toString(), expected.convertToPixels(), pitch, 1d);
|
||||
}
|
||||
|
||||
private static MultiwattIC ic(MultiwattType type, String pinNames) {
|
||||
MultiwattIC ic = new MultiwattIC();
|
||||
ic.setType(type);
|
||||
ic.setPinNames(pinNames);
|
||||
return ic;
|
||||
}
|
||||
|
||||
private static void assertNodeNames(MultiwattIC ic, String... expected) {
|
||||
String[] actual = new String[ic.getControlPointCount()];
|
||||
for (int i = 0; i < actual.length; i++) {
|
||||
actual[i] = ic.getControlPointNodeName(i);
|
||||
}
|
||||
Assert.assertArrayEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC).
|
||||
* Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* DIYLC 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 DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.diylc.components.semiconductors;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.netlist.Node;
|
||||
import org.diylc.presenter.DatasheetService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SIL_ICDatasheetTest {
|
||||
|
||||
private static final int FIRST_PIN_COLUMN = 3;
|
||||
|
||||
@Test
|
||||
public void everyRowApplies() {
|
||||
for (String[] row : datasheet()) {
|
||||
SIL_IC ic = new SIL_IC(row);
|
||||
String context = String.join(",", row);
|
||||
Assert.assertEquals(context, row[1], ic.getValue());
|
||||
Assert.assertEquals(context, row.length - FIRST_PIN_COLUMN, ic.getControlPointCount());
|
||||
for (int i = 0; i < ic.getControlPointCount(); i++) {
|
||||
Assert.assertFalse(context, ic.getControlPointNodeName(i).matches("\\d+"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partNumbersAreUnique() {
|
||||
Set<String> parts = new HashSet<String>();
|
||||
for (String[] row : datasheet()) {
|
||||
Assert.assertTrue("repeated part " + row[1], parts.add(row[1].toUpperCase()));
|
||||
}
|
||||
}
|
||||
|
||||
/** Two pins share a net only when both say so with a numbered suffix, like GND_1 and GND_2. */
|
||||
@Test
|
||||
public void pinsShareANetOnlyThroughTheSuffix() {
|
||||
for (String[] row : datasheet()) {
|
||||
for (int i = FIRST_PIN_COLUMN; i < row.length; i++) {
|
||||
for (int j = i + 1; j < row.length; j++) {
|
||||
String rail = Node.railName(row[i]);
|
||||
if (rail != null && rail.equals(Node.railName(row[j]))) {
|
||||
Assert.assertTrue(row[1] + " pins " + row[i] + " and " + row[j],
|
||||
row[i].matches(".*_\\d+") && row[j].matches(".*_\\d+"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partIsFoundByNumberNotByGroup() {
|
||||
DatasheetService service = DatasheetService.getInstance();
|
||||
Assert.assertEquals(1, service.findSeries(SIL_IC.class, "LA4440").size());
|
||||
Assert.assertTrue(service.findSeries(SIL_IC.class, "Power Amp").isEmpty());
|
||||
}
|
||||
|
||||
private static List<String[]> datasheet() {
|
||||
List<String[]> datasheet = DatasheetService.getInstance().loadDatasheet(SIL_IC.class);
|
||||
Assert.assertNotNull(datasheet);
|
||||
Assert.assertFalse(datasheet.isEmpty());
|
||||
return datasheet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC).
|
||||
* Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* DIYLC 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 DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.diylc.components.semiconductors;
|
||||
|
||||
import org.diylc.components.semiconductors.SIL_IC.PinCount;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SIL_ICTest {
|
||||
|
||||
@Test
|
||||
public void unnamedPinsAreNumberedFromTheAnchor() {
|
||||
SIL_IC ic = new SIL_IC();
|
||||
ic.setPinCount(PinCount._4);
|
||||
assertNodeNames(ic, "1", "2", "3", "4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingAndBlankNamesFallBackToNumbers() {
|
||||
SIL_IC ic = new SIL_IC();
|
||||
ic.setPinCount(PinCount._4);
|
||||
ic.setPinNames("1IN, ,GND");
|
||||
assertNodeNames(ic, "1IN", "2", "GND", "4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modelSetsPitchCountAndNames() {
|
||||
SIL_IC ic = new SIL_IC(new String[] {"Power Amp", "TEST", "2 mm", "IN", "GND", "OUT"});
|
||||
Assert.assertEquals("TEST", ic.getValue());
|
||||
Assert.assertEquals(PinCount._3, ic.getPinCount());
|
||||
Assert.assertEquals(new Size(2d, SizeUnit.mm), ic.getPinSpacing());
|
||||
assertNodeNames(ic, "IN", "GND", "OUT");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newPartShowsNames() {
|
||||
Assert.assertEquals(PinLabels.NAMES, new SIL_IC().getPinLabels());
|
||||
}
|
||||
|
||||
private static void assertNodeNames(SIL_IC ic, String... expected) {
|
||||
String[] actual = new String[ic.getControlPointCount()];
|
||||
for (int i = 0; i < actual.length; i++) {
|
||||
actual[i] = ic.getControlPointNodeName(i);
|
||||
}
|
||||
Assert.assertArrayEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ passive.TransformerCore = none
|
||||
passive.TrimmerPotentiometer = fixed
|
||||
semiconductors.BJTSymbol = fixed
|
||||
semiconductors.BridgeRectifier = fixed
|
||||
semiconductors.DIL_IC = Display Pin #s, Pins
|
||||
semiconductors.DIL_IC = Pin Labels, Pins
|
||||
semiconductors.DiodeGlass = fixed
|
||||
semiconductors.DiodePlastic = fixed
|
||||
semiconductors.DiodeSymbol = fixed
|
||||
|
||||
Reference in New Issue
Block a user