diff --git a/diylc/catalog_full.json b/diylc/catalog_full.json index cb9c9320..cd8d2e6a 100644 --- a/diylc/catalog_full.json +++ b/diylc/catalog_full.json @@ -19805,7 +19805,8 @@ "namePrefix" : "V", "description" : "Various types of tube/valve sockets", "creationMethod" : "SINGLE_CLICK", - "notes" : [ "The first control point is the socket centre, not a pin. Pins sit on a circle and are numbered clockwise, starting after the gap (B9A, B7G, B12C) or the key (OCTAL), which points right at 'Angle' 0; 'Angle' rotates the socket clockwise in degrees. This is the bottom view used for wiring" ], + "notes" : [ "The first control point is the socket centre, not a pin. Pins sit on a circle and are numbered clockwise, starting after the gap (B9A, B7G, B12C) or the key (OCTAL), which points right at 'Angle' 0; 'Angle' rotates the socket clockwise in degrees. This is the bottom view used for wiring", "'Electrode Labels' is a comma-separated list of electrode names in pin order starting at pin 1: P plate, G triode grid, G1/G2/G3 control, screen and suppressor grids, K cathode, BP beam plates, IS internal shield, HCT heater centre tap. Sections of a multi-section tube are numbered first (1P, 1G, 2P); heater ends are named after their pin (H4, H5) because they are separate nets; pins joined inside the tube end in _1, _2; NC and IC pins are never connected", "A datasheet model is a tube type such as 12AX7 or EL34 and sets 'Base', 'Electrode Labels' and 'Designation'. Set 'Designation' to the same tube type together with the model" ], + "datasheetModels" : [ "12AX7", "ECC83", "7025", "5751", "12AT7", "ECC81", "12AU7", "ECC82", "12AY7", "6072", "12BH7", "12DW7", "12AZ7", "5965", "ECC99", "6922", "E88CC", "6DJ8", "ECC88", "7308", "6CG7", "ECC85", "6FQ7", "5687", "6N1P", "6N2P", "6H30P", "6SN7", "6SL7", "6080", "6AS7", "6BX7", "6BL7", "12B4A", "6J5", "6C5", "EF86", "6267", "5879", "EF80", "EF184", "6AU6", "6BA6", "6AK5", "6SJ7", "12BE6", "6BE6", "12BA6", "6BD6", "12AV6", "12AT6", "6AV6", "6AT6", "50C5", "35W4", "6SA7", "12SA7", "6SK7", "12SK7", "6SG7", "6SQ7", "12SQ7", "50L6GT", "35Z5GT", "ECH81", "ECH83", "UCH81", "EF85", "EBF89", "UBF89", "EABC80", "UCL82", "EM84", "EM80", "EM81", "6AF6", "1629", "12K5", "12AD6", "12EG6", "12AF6", "12CX6", "12DZ6", "12EK6", "12AC6", "12BL6", "12AE6", "12FM6", "12FK6", "12EL6", "12FX8", "12DS7", "12EM6", "12J8", "12DL8", "EL84", "6BQ5", "7189", "7189A", "6CW5", "EL86", "6V6GT", "6V6", "6L6GC", "6L6", "5881", "7581A", "KT66", "EL34", "6CA7", "KT88", "6550", "KT120", "KT150", "7591", "6AQ5", "6BF5", "50B5", "6973", "12AB5", "6BM8", "ECL82", "ECL86", "6GW8", "6F6G", "6K6GT", "6Y6G", "6AS5", "6CU5", "35C5", "6EH5", "6CZ5", "6EM5", "6BW6", "6DL5", "EL95", "6AK6", "6AR5", "6CM6", "6CL6", "5AR4", "GZ34", "5V4G", "GZ32", "5Y3GT", "5U4GB", "EZ81", "EZ80", "6CA4", "6X4", "6X5GT", "6X5", "6AX5GT", "0A2", "0B2", "0D3", "0C3", "0A3", "6N2P-EV", "6N1P-EV", "6N6P", "6N23P", "6N23P-EV", "6N24P", "6N3P", "6N8S", "6N9S", "6N13S", "6N5S", "6S45P", "6S19P", "6S4S", "6Zh32P", "6Zh1P", "6P14P", "6P14P-EV", "6P18P", "6P15P", "EL91", "6AM5", "6P1P", "6P3S", "6P3S-E", "6P6S", "6P27S", "5C3S", "5C4S", "6C4P" ], "properties" : [ { "name" : "Alpha", "type" : "Percentage", diff --git a/diylc/diylc-core/src/main/java/org/diylc/netlist/Node.java b/diylc/diylc-core/src/main/java/org/diylc/netlist/Node.java index 92f1ee2b..ef9bec10 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/netlist/Node.java +++ b/diylc/diylc-core/src/main/java/org/diylc/netlist/Node.java @@ -39,7 +39,7 @@ public class Node implements Comparable { /** Pin names that mark an absent connection, so repeats of them are not one net. */ private static final Set NON_NET_NAMES = - new HashSet(Arrays.asList("NC", "RSV")); + new HashSet(Arrays.asList("NC", "RSV", "IC")); private IDIYComponent component; private int pointIndex; diff --git a/diylc/diylc-core/src/main/resources/import-defaults/variants.xml b/diylc/diylc-core/src/main/resources/import-defaults/variants.xml index 4603176e..66115702 100644 --- a/diylc/diylc-core/src/main/resources/import-defaults/variants.xml +++ b/diylc/diylc-core/src/main/resources/import-defaults/variants.xml @@ -948,232 +948,27 @@ Chassis Noval 9A (12A?7) - - - Color - - - - Mount - CHASSIS - - - Label - - - - Electrode Labels - A,G,C,H,H,A,G,C,CT - - - Base - B9A - - - - - - - - - - - - - - - false - 2022-10-30T13:25:15.3894874 + 2026-11-02T14:00:00 Chassis Noval 9CV (EL84) - - - Color - - - - Mount - CHASSIS - - - Label - - - - Electrode Labels - n/c,G,C,H,H,n/c,P,n/c,S - - - Base - B9A - - - - - - - - - - - - - - - false - 2022-10-30T13:25:15.3894874 + 2026-11-02T14:00:00 Chassis Octal 5T - - - Color - - - - Mount - CHASSIS - - - Label - - - - Electrode Labels - n/c,H,n/c,P,n/c,P,n/c,H - - - Base - OCTAL - - - - - - - - - - - - - - false - 2022-10-30T13:25:15.3894874 + 2026-11-02T14:00:00 Chassis Octal 7AC (6?6) - - - Color - - - - Mount - CHASSIS - - - Label - - - - Electrode Labels - n/c,H,P,S,G,n/c,H,C - - - Base - OCTAL - - - - - - - - - - - - - - false - 2022-10-30T13:25:15.3894874 + 2026-11-02T14:00:00 Chassis 7-pin 7BK - - - Color - - - - Mount - CHASSIS - - - Label - - - - Electrode Labels - G,IS,H,H,P,S,C - - - Base - B7G - - - - - - - - - - - - - false - 2022-10-30T13:25:15.3894874 + 2026-11-02T14:00:00 Chassis Octal 8ET (EL34) - - - Color - - - - Mount - CHASSIS - - - Label - - - - Electrode Labels - IS,H,P,S,G,n/c,H,C - - - Base - OCTAL - - - - - - - - - - - - - - false - 2022-10-30T13:25:15.3894874 + 2026-11-02T14:00:00 diff --git a/diylc/diylc-core/src/main/resources/update.xml b/diylc/diylc-core/src/main/resources/update.xml index 826b5aad..4c171aa2 100644 --- a/diylc/diylc-core/src/main/resources/update.xml +++ b/diylc/diylc-core/src/main/resources/update.xml @@ -525,6 +525,10 @@ NEW_FEATURE Added 'Pinout' property to 'Transistor (TO-3)' and a terminal in the mounting hole next to the pins, so the case (collector) can be wired and shows up in netlists and AI analysis + + NEW_FEATURE + Added a datasheet to 'Tube Socket' - pick a tube by its type from the component's submenu to set its base and electrode labels at once - more than 180 preamp, power, rectifier, radio, space-charge and Soviet tubes; the AI Assistant can place these tubes by type too + NEW_FEATURE 'Chassis Panel' is now 'Enclosure' and can draw an exploded view of the whole box; set 'Height' and choose which 'Sides' to unfold @@ -573,6 +577,10 @@ BUG_FIX SPICE netlists listed the pins of transistors with E-C-B pinout in the wrong order + + BUG_FIX + 'Tube Socket' variants with electrode labels connected pins that share a label in netlists and AI analysis, e.g. both anodes of a 12AX7 or both heater ends; these variants are replaced by the datasheet + https://github.com/bancika/diy-layout-creator/releases diff --git a/diylc/diylc-core/src/test/java/org/diylc/netlist/NodeNameTest.java b/diylc/diylc-core/src/test/java/org/diylc/netlist/NodeNameTest.java index 9b2c95eb..cde30dec 100644 --- a/diylc/diylc-core/src/test/java/org/diylc/netlist/NodeNameTest.java +++ b/diylc/diylc-core/src/test/java/org/diylc/netlist/NodeNameTest.java @@ -87,6 +87,8 @@ public class NodeNameTest { public void railNameRejectsPinsThatNameNoNet() { Assert.assertNull(Node.railName("NC_1")); Assert.assertNull(Node.railName("RSV_2")); + // a tube pin marked "internal connection" must not be used as a tie point + Assert.assertNull(Node.railName("IC")); Assert.assertNull(Node.railName(null)); } diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/tube/TubeSocket.java b/diylc/diylc-library/src/main/java/org/diylc/components/tube/TubeSocket.java index c50092e7..1391f88c 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/tube/TubeSocket.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/tube/TubeSocket.java @@ -30,6 +30,8 @@ import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; +import java.util.Arrays; + import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.awt.StringUtils; @@ -38,8 +40,10 @@ import org.diylc.common.IPlugInPort; import org.diylc.common.ObjectCache; import org.diylc.common.VerticalAlignment; import org.diylc.components.AbstractAngledComponent; +import org.diylc.components.AbstractMakerBoard; import org.diylc.components.transform.AngledComponentTransformer; import org.diylc.core.ComponentState; +import org.diylc.core.IDatasheetSupport; import org.diylc.core.IDIYComponent; import org.diylc.core.IDrawingObserver; import org.diylc.core.Project; @@ -55,11 +59,15 @@ import org.diylc.core.measures.SizeUnit; import org.diylc.utils.Constants; @AiNote("The first control point is the socket centre, not a pin. Pins sit on a circle and are numbered clockwise, starting after the gap (B9A, B7G, B12C) or the key (OCTAL), which points right at 'Angle' 0; 'Angle' rotates the socket clockwise in degrees. This is the bottom view used for wiring") +@AiNote("'Electrode Labels' is a comma-separated list of electrode names in pin order starting at pin 1: P plate, G triode grid, G1/G2/G3 control, screen and suppressor grids, K cathode, BP beam plates, IS internal shield, HCT heater centre tap. Sections of a multi-section tube are numbered first (1P, 1G, 2P); heater ends are named after their pin (H4, H5) because they are separate nets; pins joined inside the tube end in _1, _2; NC and IC pins are never connected") +@AiNote("A datasheet model is a tube type such as 12AX7 or EL34 and sets 'Base', 'Electrode Labels' and 'Designation'. Set 'Designation' to the same tube type together with the model") @ComponentDescriptor(name = "Tube Socket", author = "Branislav Stojkovic", category = "Tubes", instanceNamePrefix = "V", description = "Various types of tube/valve sockets", zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true, - transformer = AngledComponentTransformer.class) -public class TubeSocket extends AbstractAngledComponent implements IGerberComponentSimple { + transformer = AngledComponentTransformer.class, enableDatasheet = true, + datasheetCreationStepCount = 2, datasheetModelColumn = 1) +public class TubeSocket extends AbstractAngledComponent + implements IGerberComponentSimple, IDatasheetSupport { private static final Size B9A_PIN_SPACING_CHASSIS = new Size(12.5d, SizeUnit.mm); private static final Size B9A_PIN_SPACING_PCB = new Size(21d, SizeUnit.mm); @@ -103,6 +111,21 @@ public class TubeSocket extends AbstractAngledComponent implements IGerb updateControlPoints(); } + public TubeSocket(String[] model) { + this(); + + applyModel(model); + } + + // columns: group, tube type, base, RETMA basing code, then one electrode name per pin in pin + // order + @Override + public void applyModel(String[] model) { + setValue(model[1]); + setBase(Base.valueOf(model[2])); + setElectrodeLabels(String.join(",", Arrays.copyOfRange(model, 4, model.length))); + } + @EditableProperty public Base getBase() { return base; @@ -304,7 +327,7 @@ public class TubeSocket extends AbstractAngledComponent implements IGerb double electrodeLabelOffset = project.getFont().getSize2D() * (getBase() == Base.B9A && getMount() == Mount.PCB ? 1.5 : 1); for (int i = 0; i < labels.length; i++) { if (i < controlPoints.length - 1) { - String label = labels[i]; + String label = AbstractMakerBoard.getDisplayPinLabel(labels[i]); double theta = Math.atan2(controlPoints[i + 1].getY() - controlPoints[0].getY(), controlPoints[i + 1].getX() - controlPoints[0].getX()); double x = controlPoints[i + 1].getX() - Math.cos(theta) * electrodeLabelOffset; double y = controlPoints[i + 1].getY() - Math.sin(theta) * electrodeLabelOffset; diff --git a/diylc/diylc-library/src/main/resources/datasheets/TubeSocket.datasheet b/diylc/diylc-library/src/main/resources/datasheets/TubeSocket.datasheet new file mode 100644 index 00000000..766a3c69 --- /dev/null +++ b/diylc/diylc-library/src/main/resources/datasheets/TubeSocket.datasheet @@ -0,0 +1,188 @@ +Dual Triode,12AX7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,ECC83,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,7025,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,5751,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,12AT7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,ECC81,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,12AU7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,ECC82,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,12AY7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,6072,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,12BH7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,12DW7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,12AZ7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,5965,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,ECC99,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT +Dual Triode,6922,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,E88CC,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,6DJ8,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,ECC88,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,7308,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,6CG7,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,ECC85,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,6FQ7,B9A,9LP,2P,2G,2K,H4,H5,1P,1G,1K,NC +Dual Triode,5687,B9A,9H,2P,2G,2K,H4,H5,1K,1G,HCT,1P +Dual Triode,6N1P,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS +Dual Triode,6N2P,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS +Dual Triode,6H30P,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS +Dual Triode,6SN7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Dual Triode,6SL7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Dual Triode,6080,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Dual Triode,6AS7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Dual Triode,6BX7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Dual Triode,6BL7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Triode,12B4A,B9A,9AG,K,G_1,HCT,H4,H5,NC,G_2,NC,P +Triode,6J5,OCTAL,6Q,SH,H2,P,NC,G,NC,H7,K +Triode,6C5,OCTAL,6Q,SH,H2,P,NC,G,NC,H7,K +Pentode,EF86,B9A,9CQ,G2,IS_1,K,H4,H5,P,IS_2,G3,G1 +Pentode,6267,B9A,9CQ,G2,IS_1,K,H4,H5,P,IS_2,G3,G1 +Pentode,5879,B9A,9AD,G1,NC,K,H4,H5,NC,G2,P,G3 +Pentode,EF80,B9A,9AQ,K_1,G1,K_2,H4,H5,IS,P,G2,G3 +Pentode,EF184,B9A,9AQ,K_1,G1,K_2,H4,H5,IS,P,G2,G3 +Pentode,6AU6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Pentode,6BA6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Pentode,6AK5,B7G,7BD,G1,K_1,H3,H4,P,G2,K_2 +Pentode,6SJ7,OCTAL,8N,SH,H2,G3,G1,K,G2,H7,P +Converter,12BE6,B7G,7CH,G1,K,H3,H4,P,G2,G3 +Converter,6BE6,B7G,7CH,G1,K,H3,H4,P,G2,G3 +Pentode (RF/IF),12BA6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Pentode (RF/IF),6BD6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Diode-Triode,12AV6,B7G,7BT,TG,K,H3,H4,2D,1D,TP +Diode-Triode,12AT6,B7G,7BT,TG,K,H3,H4,2D,1D,TP +Diode-Triode,6AV6,B7G,7BT,TG,K,H3,H4,2D,1D,TP +Diode-Triode,6AT6,B7G,7BT,TG,K,H3,H4,2D,1D,TP +Beam Tetrode,50C5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P +Rectifier,35W4,B7G,5BQ,NC,NC,H3,H4,P,HT,K +Converter,6SA7,OCTAL,8R,G5,H2,P,G2,G1,K,H7,G3 +Converter,12SA7,OCTAL,8R,G5,H2,P,G2,G1,K,H7,G3 +Pentode (RF/IF),6SK7,OCTAL,8N,SH,H2,G3,G1,K,G2,H7,P +Pentode (RF/IF),12SK7,OCTAL,8N,SH,H2,G3,G1,K,G2,H7,P +Pentode (RF/IF),6SG7,OCTAL,8BK,SH,H2,K_1,G1,K_2,G2,H7,P +Diode-Triode,6SQ7,OCTAL,8Q,SH,TG,K,2D,1D,TP,H7,H8 +Diode-Triode,12SQ7,OCTAL,8Q,SH,TG,K,2D,1D,TP,H7,H8 +Beam Tetrode,50L6GT,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Rectifier,35Z5GT,OCTAL,6AD,NC,H2,HT,NC,P,NC,H7,K +Converter,ECH81,B9A,9CA,HG2,HG1,K,H4,H5,HP,HG3,TP,TG +Converter,ECH83,B9A,9CA,HG2,HG1,K,H4,H5,HP,HG3,TP,TG +Converter,UCH81,B9A,9CA,HG2,HG1,K,H4,H5,HP,HG3,TP,TG +Pentode (RF/IF),EF85,B9A,9AQ,K_1,G1,K_2,H4,H5,IS,P,G2,G3 +Diode-Pentode,EBF89,B9A,9HE,PG2,PG1,K,H4,H5,PP,1D,2D,PG3 +Diode-Pentode,UBF89,B9A,9HE,PG2,PG1,K,H4,H5,PP,1D,2D,PG3 +Diode-Triode,EABC80,B9A,9E,3D,2D,2DK,H4,H5,1D,K,TG,TP +Triode-Pentode,UCL82,B9A,9EX,TG,PK,PG1,H4,H5,PP,PG2,TK,TP +Tuning Indicator,EM84,B9A,9GA,G,IC,K,H4,H5,TA,DE,IC,P +Tuning Indicator,EM80,B9A,9DB,G,K,IC,H4,H5,IC,P,IC,TA +Tuning Indicator,EM81,B9A,9DB,G,K,IC,H4,H5,IC,P,IC,TA +Tuning Indicator,6AF6,OCTAL,7AG,NC,H2,2RC,1RC,TA,NC,H7,K +Tuning Indicator,1629,OCTAL,7AL,NC,H2,P,TA,G,NC,H7,K +Space-Charge,12K5,B7G,7FD,K,G2,H3,H4,G1_1,G1_2,P +Space-Charge,12AD6,B7G,7CH,G1,K,H3,H4,P,G2,G3 +Space-Charge,12EG6,B7G,7CH,G1,K,H3,H4,P,G2,G3 +Space-Charge,12AF6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Space-Charge,12CX6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Space-Charge,12DZ6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Space-Charge,12EK6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Space-Charge,12AC6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Space-Charge,12BL6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Space-Charge,12AE6,B7G,7BT,TG,K,H3,H4,2D,1D,TP +Space-Charge,12FM6,B7G,7BT,TG,K,H3,H4,2D,1D,TP +Space-Charge,12FK6,B7G,7BT,TG,K,H3,H4,2D,1D,TP +Space-Charge,12EL6,B7G,7FB,TG,TP,H3,H4,2D,1D,K +Space-Charge,12FX8,B9A,9KV,HG2,HG1,HP,H4,H5,TG,HK,TP,HG3 +Space-Charge,12DS7,B9A,9JU,2D,NC,G1,H4,H5,P,G2,K,1D +Space-Charge,12EM6,B9A,9HV,G1,K,G2,H4,H5,P,IC,IC,D +Space-Charge,12J8,B9A,9GC,G1,K,G2,H4,H5,P,DK,2D,1D +Space-Charge,12DL8,B9A,9HR,2D,K,G1,H4,H5,P,G2,DK,1D +Power Pentode,EL84,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2 +Power Pentode,6BQ5,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2 +Power Pentode,7189,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2 +Power Pentode,7189A,B9A,9LE,G1_1,G1_2,K,H4,H5,G2_1,P,IC,G2_2 +Power Pentode,6CW5,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2 +Power Pentode,EL86,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2 +Beam Tetrode,6V6GT,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6V6,OCTAL,7AC,SH,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6L6GC,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6L6,OCTAL,7AC,SH,H2,P,G2,G1,NC,H7,K +Beam Tetrode,5881,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,7581A,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,KT66,OCTAL,7AC,IC,H2,P,G2,G1,NC,H7,K +Power Pentode,EL34,OCTAL,8ET,G3,H2,P,G2,G1,NC,H7,K +Power Pentode,6CA7,OCTAL,8ET,G3,H2,P,G2,G1,NC,H7,K +Beam Tetrode,KT88,OCTAL,7AC,SH,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6550,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,KT120,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,KT150,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Power Pentode,7591,OCTAL,8KG,NC,H2,P,G2_1,K,G1,H7,G2_2 +Beam Tetrode,6AQ5,B7G,7BZ,G1_1,K,H3,H4,P,G2,G1_2 +Beam Tetrode,6BF5,B7G,7BZ,G1_1,K,H3,H4,P,G2,G1_2 +Beam Tetrode,50B5,B7G,7BZ,G1_1,K,H3,H4,P,G2,G1_2 +Beam Tetrode,6973,B9A,9EU,G2_1,NC,G1_1,H4,H5,G1_2,K,G2_2,P +Beam Tetrode,12AB5,B9A,9EU,G2_1,NC,G1_1,H4,H5,G1_2,K,G2_2,P +Triode-Pentode,6BM8,B9A,9EX,TG,PK,PG1,H4,H5,PP,PG2,TK,TP +Triode-Pentode,ECL82,B9A,9EX,TG,PK,PG1,H4,H5,PP,PG2,TK,TP +Triode-Pentode,ECL86,B9A,9LZ,TG,TK,PG2,H4,H5,PP,PK,PG1,TP +Triode-Pentode,6GW8,B9A,9LZ,TG,TK,PG2,H4,H5,PP,PK,PG1,TP +Power Pentode,6F6G,OCTAL,7S,NC,H2,P,G2,G1,NC,H7,K +Power Pentode,6K6GT,OCTAL,7S,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6Y6G,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6AS5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P +Beam Tetrode,6CU5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P +Beam Tetrode,35C5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P +Power Pentode,6EH5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P +Beam Tetrode,6CZ5,B9A,9HN,G2,NC,G1_1,H4,H5,G1_2,K,IC,P +Beam Tetrode,6EM5,B9A,9HN,G2,NC,G1_1,H4,H5,G1_2,K,IC,P +Beam Tetrode,6BW6,B9A,9AM,IC,G1,K,H4,H5,NC,P,G2,BP +Power Pentode,6DL5,B7G,7DQ,G1_1,K,H3,H4,P,G2,G1_2 +Power Pentode,EL95,B7G,7DQ,G1_1,K,H3,H4,P,G2,G1_2 +Power Pentode,6AK6,B7G,7BK,G1,G3,H3,H4,P,G2,K +Power Pentode,6AR5,B7G,6CC,G1,K,H3,H4,P,G2,NC +Beam Tetrode,6CM6,B9A,9CK,G2,NC,G1_1,H4,H5,G1_2,K,NC,P +Power Pentode,6CL6,B9A,9BV,K,G1_1,G2_1,H4,H5,P,G3,G2_2,G1_2 +Rectifier,5AR4,OCTAL,5L,IC,H2,NC,1P,NC,2P,NC,HK8 +Rectifier,GZ34,OCTAL,5L,IC,H2,NC,1P,NC,2P,NC,HK8 +Rectifier,5V4G,OCTAL,5L,NC,H2,NC,1P,NC,2P,NC,HK8 +Rectifier,GZ32,OCTAL,5L,NC,H2,NC,1P,NC,2P,NC,HK8 +Rectifier,5Y3GT,OCTAL,5T,NC,F2,NC,2P,NC,1P,NC,F8 +Rectifier,5U4GB,OCTAL,5T,NC,F2,NC,2P,NC,1P,NC,F8 +Rectifier,EZ81,B9A,9M,1P,IC,K,H4,H5,IC,2P,IC,IC +Rectifier,EZ80,B9A,9M,1P,IC,K,H4,H5,IC,2P,IC,IC +Rectifier,6CA4,B9A,9M,1P,NC,K,H4,H5,NC,2P,NC,NC +Rectifier,6X4,B7G,7CF,2P,NC,H3,H4,NC,1P,K +Rectifier,6X5GT,OCTAL,6S,NC,H2,2P,NC,1P,NC,H7,K +Rectifier,6X5,OCTAL,6S,SH,H2,2P,NC,1P,NC,H7,K +Rectifier,6AX5GT,OCTAL,6S,NC,H2,2P,NC,1P,NC,H7,K +Voltage Reference,0A2,B7G,5BO,P_1,K_1,IC,K_2,P_2,IC,K_3 +Voltage Reference,0B2,B7G,5BO,P_1,K_1,IC,K_2,P_2,IC,K_3 +Voltage Reference,0D3,OCTAL,4AJ,NC,K,J_1,NC,P,NC,J_2,NC +Voltage Reference,0C3,OCTAL,4AJ,NC,K,J_1,NC,P,NC,J_2,NC +Voltage Reference,0A3,OCTAL,4AJ,NC,K,J_1,NC,P,NC,J_2,NC +Dual Triode,6N2P-EV,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS +Dual Triode,6N1P-EV,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS +Dual Triode,6N6P,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS +Dual Triode,6N23P,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,6N23P-EV,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS +Dual Triode,6N24P,B9A,-,2K,2G,2P,H4,H5,1G,1K_1,1K_2,1P +Dual Triode,6N3P,B9A,-,H1,1K,1G,1P,IS,2P,2G,2K,H9 +Dual Triode,6N8S,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Dual Triode,6N9S,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Dual Triode,6N13S,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Dual Triode,6N5S,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8 +Triode,6S45P,B9A,-,K_1,G_1,K_2,H4,H5,K_3,P,G_2,K_4 +Power Triode,6S19P,B9A,-,P_1,G_1,P_2,H4,H5,P_3,G_2,P_4,K +Power Triode,6S4S,OCTAL,5S,NC,F2,P,NC,G,NC,F7,NC +Pentode,6Zh32P,B9A,9CQ,G2,IS_1,K,H4,H5,P,IS_2,G3,G1 +Pentode,6Zh1P,B7G,-,G1,K_1,H3,H4,P,G2,K_2 +Power Pentode,6P14P,B9A,9CV,NC,G1,K,H4,H5,NC,P,NC,G2 +Power Pentode,6P14P-EV,B9A,9CV,NC,G1,K,H4,H5,NC,P,NC,G2 +Power Pentode,6P18P,B9A,9CV,NC,G1,K,H4,H5,NC,P,NC,G2 +Power Pentode,6P15P,B9A,-,G3_1,G1,K,H4,H5,G3_2,P,NC,G2 +Power Pentode,EL91,B7G,-,G1,K,H3,H4,P,NC,G2 +Power Pentode,6AM5,B7G,-,G1,K,H3,H4,P,NC,G2 +Beam Tetrode,6P1P,B9A,-,P_1,G2_1,K_1,H4,H5,P_2,G1,K_2,G2_2 +Beam Tetrode,6P3S,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6P3S-E,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6P6S,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Beam Tetrode,6P27S,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K +Rectifier,5C3S,OCTAL,5T,NC,F2,NC,2P,NC,1P,NC,F8 +Rectifier,5C4S,OCTAL,5L,NC,H2,NC,1P,NC,2P,NC,HK8 +Rectifier,6C4P,B7G,-,1P,NC,H3,H4,K,NC,2P diff --git a/diylc/diylc-library/src/test/java/org/diylc/components/tube/TubeSocketDatasheetTest.java b/diylc/diylc-library/src/test/java/org/diylc/components/tube/TubeSocketDatasheetTest.java new file mode 100644 index 00000000..f3a089a1 --- /dev/null +++ b/diylc/diylc-library/src/test/java/org/diylc/components/tube/TubeSocketDatasheetTest.java @@ -0,0 +1,117 @@ +/* + + 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 . + +*/ +package org.diylc.components.tube; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.diylc.netlist.Node; +import org.diylc.presenter.DatasheetService; +import org.junit.Assert; +import org.junit.Test; + +public class TubeSocketDatasheetTest { + + private static final int FIRST_PIN_COLUMN = 4; + private static final Set UNUSED_PIN_NAMES = + new HashSet(Arrays.asList("NC", "IC", "SH")); + + @Test + public void everyRowNamesEveryPinOfItsBase() { + for (String[] row : datasheet()) { + TubeSocket socket = new TubeSocket(row); + String context = String.join(",", row); + Assert.assertEquals(context, row[1], socket.getValue()); + // control point 0 is the socket centre + Assert.assertEquals(context, row.length - FIRST_PIN_COLUMN, + socket.getControlPointCount() - 1); + } + } + + @Test + public void designationsAreUnique() { + Set tubes = new HashSet(); + for (String[] row : datasheet()) { + Assert.assertTrue("repeated tube " + row[1], tubes.add(row[1].toUpperCase())); + } + } + + /** Two pins share a net only when both say so with a numbered suffix, like K_3 and K_8. */ + @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+")); + } + } + } + } + } + + /** A basing code fixes what each pin is, so every tube on one basing names its pins alike. */ + @Test + public void tubesOnOneBasingNameTheirPinsAlike() { + Map byBasing = new HashMap(); + for (String[] row : datasheet()) { + // "-" marks a tube with no RETMA basing, e.g. most Soviet types + if (row[3].equals("-")) { + continue; + } + String key = row[2] + " " + row[3]; + String[] names = Arrays.copyOfRange(row, FIRST_PIN_COLUMN, row.length); + // a basing fixes the electrodes; an unused pin is the metal shell, a no-connect or an + // internal connection depending on the envelope and the maker + for (int i = 0; i < names.length; i++) { + if (UNUSED_PIN_NAMES.contains(names[i])) { + names[i] = "unused"; + } + } + String[] first = byBasing.putIfAbsent(key, names); + if (first != null) { + Assert.assertArrayEquals(row[1] + " on " + key, first, names); + } + } + } + + @Test + public void tubeIsFoundByTypeNotByGroup() { + DatasheetService service = DatasheetService.getInstance(); + String[] first = datasheet().get(0); + Assert.assertEquals(1, service.findSeries(TubeSocket.class, first[1]).size()); + Assert.assertTrue(service.findSeries(TubeSocket.class, first[0]).isEmpty()); + } + + private static List datasheet() { + List datasheet = DatasheetService.getInstance().loadDatasheet(TubeSocket.class); + Assert.assertNotNull(datasheet); + Assert.assertFalse(datasheet.isEmpty()); + return datasheet; + } +} diff --git a/diylc/diylc-library/src/test/java/org/diylc/components/tube/TubeSocketTest.java b/diylc/diylc-library/src/test/java/org/diylc/components/tube/TubeSocketTest.java new file mode 100644 index 00000000..9016e511 --- /dev/null +++ b/diylc/diylc-library/src/test/java/org/diylc/components/tube/TubeSocketTest.java @@ -0,0 +1,49 @@ +/* + + 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 . + +*/ +package org.diylc.components.tube; + +import org.diylc.components.tube.TubeSocket.Base; +import org.diylc.components.tube.TubeSocket.Mount; +import org.diylc.core.Angle; +import org.junit.Assert; +import org.junit.Test; + +public class TubeSocketTest { + + @Test + public void modelSetsBaseLabelsAndDesignation() { + TubeSocket socket = new TubeSocket(); + socket.setMount(Mount.PCB); + socket.setAngle(Angle.of(45)); + socket.applyModel(new String[] {"Power Pentode", "TEST", "OCTAL", "8XX", "NC", "H2", "P", + "G2", "G1", "NC", "H7", "K"}); + + Assert.assertEquals("TEST", socket.getValue()); + Assert.assertEquals(Base.OCTAL, socket.getBase()); + Assert.assertEquals("NC,H2,P,G2,G1,NC,H7,K", socket.getElectrodeLabels()); + Assert.assertEquals(Mount.PCB, socket.getMount()); + Assert.assertEquals(Angle.of(45), socket.getAngle()); + // control point 0 is the socket centre, so pin 1 is control point 1 + Assert.assertEquals("H2", socket.getControlPointNodeName(2)); + Assert.assertEquals("K", socket.getControlPointNodeName(8)); + } +} diff --git a/diylc/docs/plans/tube-socket-datasheets.md b/diylc/docs/plans/tube-socket-datasheets.md new file mode 100644 index 00000000..a48df91d --- /dev/null +++ b/diylc/docs/plans/tube-socket-datasheets.md @@ -0,0 +1,212 @@ +# Tube Socket Datasheets + +Naming every electrode of a `TubeSocket` from the tube that plugs into it. + +## 1. Goal + +Follows [DIP IC Pin Names](dip-ic-pin-names.md) and [Transistor Pinouts](transistor-pinouts.md). A +tube socket already carries a free-text "Electrode Labels" property, and every consumer reads it +through `getControlPointNodeName`: the netlist, hover tooltips, the AI project context and the +schematic view. In practice it is almost never filled in. Of 95 tube sockets in the sample corpus, +the user typed a designation on about half (12AY7 24 times, 6L6GT, 5Y3, KT88, 12AX7) but real +electrode names on only four; the rest carry the default `1,2,...,9`. A datasheet of the tubes +DIYers use (guitar amps, hi-fi, radio) sets the base, the electrode names and the designation in one +step, from the toolbox or from the AI. + +### What is wrong today + +Pins of one component that share a name are one net (`NetlistBuilder`, `Node.railName`). The six +factory variants that carry electrode names break that rule: + +| Variant | Labels | Effect in the netlist | +|---|---|---| +| Chassis Noval 9A (12A?7) | `A,G,C,H,H,A,G,C,CT` | both anodes, both grids, both cathodes and both heater ends shorted together | +| Chassis Noval 9CV (EL84) | `n/c,G,C,H,H,n/c,P,n/c,S` | heater ends shorted; the three `n/c` pins joined (only `NC` and `RSV` are exempt) | +| Chassis Octal 5T | `n/c,H,n/c,P,n/c,P,n/c,H` | both rectifier plates shorted, filament ends shorted, `n/c` pins joined | +| Chassis Octal 7AC (6?6) | `n/c,H,P,S,G,n/c,H,C` | heater ends shorted, `n/c` pins joined | +| Chassis 7-pin 7BK | `G,IS,H,H,P,S,C` | heater ends shorted | +| Chassis Octal 8ET (EL34) | `IS,H,P,S,G,n/c,H,C` | heater ends shorted | + +Heater ends are separate nets: a 12AX7 runs on 12.6 V across pins 4-5 or on 6.3 V with 4 and 5 +joined against 9, and that choice is made by the wiring, not the tube. + +## 2. Design decisions + +| # | Decision | Choice | Rationale | +|---|---|---|---| +| V1 | Datasheet row | `group, tube, base, basing, name1, ..., nameN`, e.g. `Dual Triode,12AX7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT`. `base` is a `TubeSocket.Base` constant; `basing` is the RETMA basing code, or `-` for a tube that has none (most Soviet types); the name count must equal the base's pin count | The trailing-names shape of the IC datasheets. The basing code is what tube data books print, so rows can be checked against them, and it lets a test assert that tubes sharing a basing share their names. | +| V2 | Model identity | `enableDatasheet = true`, `datasheetCreationStepCount = 2`, `datasheetModelColumn = 1` | The toolbox groups by family, the AI names the tube. | +| V3 | `applyModel` | Sets base, electrode labels and designation. Leaves mount, angle and colours alone | The datasheet says what the tube is, not how the user mounts the socket. | +| V4 | One row per tube | Equivalents get their own rows (12AX7, ECC83, 7025, 5751; 6L6GC, 5881, KT66), as the ICs list TL072 and NE5532 separately | Users and the AI look a tube up by the number printed on it. | +| V5 | Electrode names | Role letters as in American data books: `P` plate, `G` grid of a triode, `G1`/`G2`/`G3` control, screen and suppressor grids, `K` cathode, `BP` beam plates, `IS` internal shield, `SH` the metal shell or base sleeve (pin 1 of metal and GT octals), `HCT` heater centre tap. A tube with two or more sections puts the section number first, as the ICs do: `1P`, `1G`, `1K`, `2P` (and `T`/`P` prefixes for triode-pentodes: `TP`, `TG`, `PG1`) | Section-first keeps `G1` meaning control grid, never "grid of section 1". | +| V6 | Heater and filament ends | Named after their pin: `H4`, `H5` on a noval, `H2`, `H7` on an octal. A directly heated filament, which is also the cathode, is `F2`/`F8`. The `_n` suffix is never used for them | Each end is its own net (§1). Naming by pin follows `VCC+1`/`VCC+5` on the LM3886, the precedent for repeated roles that the package does not join. | +| V7 | Joined pins | A repeated name with the `_n` suffix, numbered by occurrence as on the ICs, only where the data book says the pins are connected inside the tube (e.g. the EF80 cathode on pins 1 and 3, `K_1`/`K_2`) | Same rule as the ICs, so `NetlistBuilder` joins exactly what the tube joins. | +| V8 | Unused pins | `NC` for no connection. Pins the data book marks "IC" (internal connection - do not use as a tie point) are `IC`, and `IC` joins `NC` and `RSV` in `Node.NON_NET_NAMES` | Several `IC` pins on one tube must not become one net. One-line core change. | +| V9 | Factory variants | The six named variants of §1 are retired (`deletedOn`), as the DIP8/DIP16 and resistor variants were; the four plain ones (PCB/Chassis Noval/Octal) stay as mount presets | The datasheet replaces them with correct names; leaving them would keep handing out shorted netlists. | +| V11 | Drawn labels | Drawn through `AbstractMakerBoard.getDisplayPinLabel`, so `G1_1` shows as `G1` and parenthesised notes are dropped, as on the ICs; node names keep the suffix | Joined pins carry one role; printing the suffix crowded small sockets (6S19P). | +| V12 | Equivalents on one basing | A tube given a RETMA basing takes that basing's names, including its section numbers, even where its own data sheet numbers the units the other way (6N8S and 6N9S use the 6SN7's); tubes with no RETMA code keep their sheet's numbering | Swapping a 6N8S for a 6SN7 must not relabel the socket; section numbers are labels, the pin grouping is identical. | +| V10 | Existing projects | Unchanged. A project placed from a retired variant keeps its labels and its shorted nets; nothing rewrites user data | Labels are user data. The release note can say how to re-apply a model. | + +### Explicitly out of scope + +- `Jumbo4PinTubeSocket` (fixed `G,F1,P,F2` for 211/805/845) and the UX4 base of 300B, 2A3 and 45: + a 4-pin base is not a `TubeSocket.Base`. Candidate for a second phase. +- Magnoval (B9D: EL509, PL519), loctal and the B12C compactrons: no datasheet rows until a user + asks; B12C exists as a base but few DIY tubes use it. +- `SubminiTube` and the tube schematic symbols. +- Translating group names, as for the ICs and transistors. + +## 3. Changes + +### diylc-core + +- `Node.NON_NET_NAMES`: add `IC` (V8). +- `import-defaults/variants.xml`: retire the six named `TubeSocket` variants (V9). + +### diylc-library + +- `TubeSocket`: `implements IDatasheetSupport`, descriptor attributes (V2), `applyModel` (V3), a + `TubeSocket(String[] model)` constructor. `@AiNote` extended with the naming rules of V5-V8 and + the datasheet model. +- `datasheets/TubeSocket.datasheet`: rows per V1, each read from a manufacturer data sheet or a + tube data book (RCA, GE, Sylvania, Tung-Sol, Philips/Mullard, JJ, Svetlana, Electro-Harmonix), or + two independent agreeing sources. + +### Generated + +- `catalog_full.json` regenerated; `pinout-drivers.txt` updated if the analyzer starts reporting + "Electrode Labels" differently. + +## 4. Datasheet inventory + +`TubeSocket.datasheet` small-signal rows, 46 tubes: + +| Group | Basing | Tubes | +|---|---|---| +| Dual Triode | 9A | 12AX7, ECC83, 7025, 5751, 12AT7, ECC81, 12AU7, ECC82, 12AY7, 6072, 12BH7, 12DW7, 12AZ7, 5965, ECC99 | +| Dual Triode | 9AJ | 6922, E88CC, 6DJ8, ECC88, 7308, 6CG7, ECC85 | +| Dual Triode | 9LP / 9H / - | 6FQ7 / 5687 / 6N1P, 6N2P, 6H30P | +| Dual Triode | 8BD | 6SN7, 6SL7, 6080, 6AS7, 6BX7, 6BL7 | +| Triode | 9AG / 6Q | 12B4A / 6J5, 6C5 | +| Pentode | 9CQ / 9AD / 9AQ | EF86, 6267 / 5879 / EF80, EF184 | +| Pentode | 7BK / 7BD / 8N | 6AU6, 6BA6 / 6AK5 / 6SJ7 | + +Small-signal sourcing notes: + +- Read from RCA, Tung-Sol, GE, Sylvania, Philips, Brimar and JJ sheets (frank.pocnet.net mirror, + tubebooks.org) cross-checked against TDSL basing codes. 6SL7, 6080, 6BL7, 6BA6 and 6C5 rest on + their basing code without the sheet opened; 6H30P on a blurry lead drawing - the weakest rows. +- Lookalikes that differ: 6FQ7 has pin 9 NC, not a shield, so it is 9LP, not 6CG7's 9AJ; 5687 is + not a 12AU7 (plate 1 on pin 9, centre tap on pin 8); 6N2P has a shield on pin 9 and no centre tap, + so it is not a 12AX7; 6N1P has the 9AJ functions but its sheet numbers the units the other way. +- 12DW7: unit 1 (pins 6-8) is the 12AX7-like section, unit 2 (pins 1-3) the 12AU7-like one. +- Left out: 6C45P (no pin list found), 6N8S (said to equal 6SN7, unit order unconfirmed), 6SF5. + +`TubeSocket.datasheet` radio rows, 54 tubes: + +| Group | Tubes | +|---|---| +| Converter | 12BE6, 6BE6, 6SA7, 12SA7, ECH81, ECH83, UCH81 | +| Pentode (RF/IF) | 12BA6, 6BD6, 6SK7, 12SK7, 6SG7, EF85 | +| Diode-Triode / Diode-Pentode | 12AV6, 12AT6, 6AV6, 6AT6, 6SQ7, 12SQ7, EABC80 / EBF89, UBF89 | +| Triode-Pentode | UCL82 | +| Beam Tetrode (radio output) | 50C5, 50L6GT | +| Rectifier | 35W4, 35Z5GT | +| Tuning Indicator | EM84, EM80, EM81, 6AF6, 1629 | +| Space-Charge | 12K5, 12AD6, 12EG6, 12AF6, 12CX6, 12DZ6, 12EK6, 12AC6, 12BL6, 12AE6, 12FM6, 12FK6, 12EL6, 12FX8, 12DS7, 12EM6, 12J8, 12DL8 | + +`TubeSocket.datasheet` power, rectifier and reference rows, 63 tubes: + +| Group | Tubes | +|---|---| +| Power Pentode | EL84, 6BQ5, 7189, 7189A, 6CW5, EL86, EL34, 6CA7, 7591, 6F6G, 6K6GT, 6EH5, 6DL5, EL95, 6AK6, 6AR5, 6CL6 | +| Beam Tetrode | 6V6GT, 6V6, 6L6GC, 6L6, 5881, 7581A, KT66, KT88, 6550, KT120, KT150, 6Y6G, 6AQ5, 6BF5, 50B5, 6973, 12AB5, 6AS5, 6CU5, 35C5, 6CZ5, 6EM5, 6BW6, 6CM6 | +| Triode-Pentode | 6BM8, ECL82, ECL86, 6GW8 | +| Rectifier | 5AR4, GZ34, 5V4G, GZ32, 5Y3GT, 5U4GB, EZ81, EZ80, 6CA4, 6X4, 6X5GT, 6X5, 6AX5GT | +| Voltage Reference | 0A2, 0B2, 0D3, 0C3, 0A3 | + +Radio and power sourcing notes: + +- Read from RCA, GE, Tung-Sol, Sylvania, Philips, Amperex, GEC/M-OV, JJ, Brimar and Svetlana sheets + (frank.pocnet.net), with TDSL as the second source. Where TDSL's basing code disagrees with the + printed data book the book wins: EL34 8ET (TDSL 8EP), 6X4 7CF (5BS), 6F6 7S (7AC), 7591 8KG + (Sylvania; TDSL 8KQ). +- A pin carrying several electrodes takes the main one's name: K for cathode + g3/beam plates/shield, + G3 for g3 + shield on 7BK, G5 for shell + g5 on 6SA7, H5 for heater end + triode cathode on 12FX8. +- Space-charge tubes follow each data book's grid numbering: on 12K5, 12DS7 and 12DL8 G1 is the + space-charge grid and G2 the control grid; on 12J8 and 12EM6 G1 is the control grid. +- Other names introduced: `HT` the panel-lamp heater tap on 35W4/35Z5GT (not a centre tap); `HK8` + the heater-cathode pin of 5AR4-type rectifiers; `J_1`/`J_2` the base jumper of octal regulators + (0A3/0C3/0D3), which opens the supply when the tube is pulled; `TA` target, `DE` deflection + electrode, `1RC`/`2RC` ray-control electrodes of tuning indicators; `DK` a separate diode cathode. +- Rectifier plate numbers follow each book: 5L (Amperex) has plate 1 on pin 4, 5T (RCA) plate 2. +- **KT88 conflict:** the row follows GEC (pin 1 base shell); JJ brings g3 out on pin 1. +- The same-basing test treats `NC`, `IC` and `SH` as interchangeable, because the unused pin 1 of a + basing is a shell, a no-connect or an internal connection depending on envelope and maker. +- Left out: EF89 (basing code and joined shield pins unconfirmed), 12DK6 (no sheet), metal 6F6 + (shell pin assumed), 6V4 and 6005 (TDSL only), 6AV5 (octal TV sweep tube); 6E5 and 6U5 are on the + unsupported UX6 base - 1629 is their octal counterpart. + +`TubeSocket.datasheet` Soviet rows and EL91, 30 tubes (6N1P and 6N2P are counted with the +small-signal rows): + +| Group | Tubes | +|---|---| +| Dual Triode | 6N1P-EV, 6N2P-EV, 6N6P, 6N23P, 6N23P-EV, 6N24P, 6N3P, 6N8S, 6N9S, 6N13S, 6N5S | +| Triode / Power Triode | 6S45P / 6S19P, 6S4S | +| Pentode | 6Zh32P, 6Zh1P | +| Power Pentode | 6P14P, 6P14P-EV, 6P18P, 6P15P, EL91, 6AM5 | +| Beam Tetrode | 6P1P, 6P3S, 6P3S-E, 6P6S, 6P27S | +| Rectifier | 5C3S, 5C4S, 6C4P | + +Soviet sourcing notes: + +- Ranked by use in guitar and hi-fi DIY (6N2P, 6P14P, 6N23P, 6N1P, 6P3S, 6N8S lead); read from + Soviet reference sheets (magictubes.ru, r-type.org handbook scans, chipdip, radiolamps.ru) and + Voskhod/Svetlana/Sovtek sheets. +- Compatibility, never assumed: 6P14P and 6P18P are EL84 pinout; 6P15P is not (g3 + shield on pins 1 + and 6); 6P3S/6P6S are 6L6/6V6 pinout; 6P27S fits an EL34 socket but is a 7AC beam tetrode, not + 8ET; 6N8S/6N9S/6N13S/6N5S are 6SN7/6SL7/6AS7 pinout; 6N23P is 6922 pinout; 6N1P and 6N6P have the + 9AJ functions but no RETMA code; 6Zh32P is EF86; 6Zh1P is close to 6AK5 but carries k + g3 + + shield on both pins 2 and 7; 6C4P is not a 6X4. +- 5C4S is indirectly heated with its cathode on pin 8, so it takes 5AR4's names. EL91/6AM5 is listed + as 7BZ by its source but does not match the 6AQ5, which is 7BZ, so its basing is left as `-`. +- Weakest rows: 6S19P and 6P27S (one sheet each), 6S45P (Sovtek sheet only), 5C3S and 6C4P (pinout + pictures without labels), 6P3S-E and the -EV grades (assumed identical to the base type). +- Left out: 6N30P (lead drawing unlabelled - the existing 6H30P row covers it), 6P43P, 6S41S, + 6Zh52P, 6P9, 6Zh4 (not sourced or conflicting); 6S33S/6C33C, GU-50, GU-19, 6D22S and 6P45S sit on + bases `TubeSocket` does not have. + +Rules for every row: names as in V5-V8; a part is added only after its basing diagram has been read +from a data book or manufacturer sheet, or from two independent sources; equivalents are listed only +where the basing is confirmed identical (the 6L6 family is not uniformly 7AC, and Russian +"equivalents" such as 6N1P are not pin-compatible with 6DJ8). + +## 5. Tests + +- `TubeSocketDatasheetTest`, after `SIL_ICDatasheetTest`: every row parses and applies; the name + count equals the base's pin count; designations are unique; within a row no two names share a net + unless both carry the `_n` suffix; rows sharing a basing code have identical names; `findSeries` + finds a tube and not a group. +- `TubeSocketTest`: `applyModel` sets base, labels and designation and leaves mount and angle; + `IC` and `NC` pins stay apart in the netlist. + +## 6. Verification + +- `mvn -q test` over the whole reactor (core and library change). +- Done: whole reactor passes (core 227, library 508, swing 29). +- Done: 12AX7, EL84, EL34, 5AR4, 6AQ5, 12K5, 0A2 and 6S19P rendered headlessly from the datasheet; + labels sit by their pins and fit once the suffix is dropped (V11). +- Regression suite: no rendering or netlist change is expected for existing projects (V10); the run + confirms it. + +## 7. Phases + +1. **Plan**: this document. +2. **Code**: done - V2, V3, V8 (`IC` in `Node.NON_NET_NAMES`, covered by `NodeNameTest`), V9 (six + variants retired 2026-11-02T14:00), `TubeSocketTest`, `TubeSocketDatasheetTest`, `@AiNote`s. + The datasheet test fails until the datasheet exists. +3. **Library**: done - 188 tubes (46 small-signal, 54 radio and space-charge, 58 power, rectifier + and reference, 30 Soviet and EL91). `catalog_full.json` regenerated; release notes in 6.10 + (datasheet, and the shorted-variant fix). +4. **Later, on request**: the UX4/jumbo 4-pin bases (300B, 2A3, 211, 845), magnoval.