consolidate esp32

This commit is contained in:
Bane Stojkovic
2026-08-21 14:25:56 +02:00
parent 08c46b22ea
commit e9e3c322b5
5 changed files with 345 additions and 465 deletions
@@ -21,8 +21,17 @@
*/
package org.diylc.components.micro;
import java.awt.*;
import java.awt.geom.*;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import org.diylc.awt.StringUtils;
import org.diylc.common.HorizontalAlignment;
@@ -36,13 +45,14 @@ import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.KeywordPolicy;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants;
@ComponentDescriptor(name = "ESP32 DevKit", category = "Controllers",
author = "Branislav Stojkovic", description = "ESP32 DevKit V1 DOIT Wi-Fi and Bluetooth Development Board",
author = "Branislav Stojkovic", description = "ESP32 DevKit Wi-Fi and Bluetooth Development Board (30-Pin / 38-Pin)",
instanceNamePrefix = "MCU", zOrder = IDIYComponent.COMPONENT,
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
enableCache = true)
@@ -50,38 +60,95 @@ public class ESP32DevKit extends AbstractMakerBoard {
private static final long serialVersionUID = 1L;
public enum DevKitVersion {
DevKit_V1_30Pin("30-Pin (DevKit V1 / DOIT)"),
DevKitC_V4_38Pin("38-Pin (DevKitC V4)");
private final String label;
DevKitVersion(String label) {
this.label = label;
}
@Override
public String toString() {
return label;
}
}
public static Color ESP_BLACK = Color.decode("#1E1E1E");
public static Color ANTENNA_COLOR = Color.decode("#DAA520");
public static Color BUTTON_BODY_COLOR = Color.decode("#383838");
public static Color BUTTON_BORDER_COLOR = Color.decode("#666666");
public static Color BUTTON_ACTUATOR_COLOR = Color.decode("#A0A0A0");
public static Color SILK_COLOR = Color.WHITE;
public static Size BOARD_WIDTH = new Size(28.2d, SizeUnit.mm);
public static Size BOARD_LENGTH = new Size(51.8d, SizeUnit.mm);
public static Size TOP_MARGIN = new Size(6.7d, SizeUnit.mm);
public static Size ANTENNA_LENGTH = new Size(6.2d, SizeUnit.mm);
public static Size ANTENNA_WIDTH = new Size(20.0d, SizeUnit.mm);
public static Size ROW_SPACING = new Size(1.0d, SizeUnit.in);
public static Size HOLE_DIAMETER = new Size(2.8d, SizeUnit.mm);
public static Size HOLE_EDGE_MARGIN = new Size(0.8d, SizeUnit.mm);
public static final String[] PIN_NAMES = new String[] {
// Left row (pins 0..14)
// 30-Pin (DOIT V1) Dimensions
public static Size BOARD_WIDTH_30 = new Size(28.2d, SizeUnit.mm);
public static Size BOARD_LENGTH_30 = new Size(51.8d, SizeUnit.mm);
public static Size TOP_MARGIN_30 = new Size(6.7d, SizeUnit.mm);
public static Size ANTENNA_LENGTH_30 = new Size(6.2d, SizeUnit.mm);
public static Size ANTENNA_WIDTH_30 = new Size(20.0d, SizeUnit.mm);
public static Size HOLE_DIAMETER_30 = new Size(2.8d, SizeUnit.mm);
public static Size HOLE_EDGE_MARGIN_30 = new Size(0.8d, SizeUnit.mm);
// 38-Pin (DevKitC V4) Dimensions
public static Size BOARD_WIDTH_38 = new Size(27.9d, SizeUnit.mm);
public static Size BOARD_LENGTH_38 = new Size(54.4d, SizeUnit.mm);
public static Size MAIN_BODY_LENGTH_38 = new Size(48.2d, SizeUnit.mm);
public static Size ANTENNA_LENGTH_38 = new Size(6.2d, SizeUnit.mm);
public static Size ANTENNA_WIDTH_38 = new Size(19.0d, SizeUnit.mm);
// Common Spacing
public static Size ROW_SPACING = new Size(1.0d, SizeUnit.in);
public static final String[] PIN_NAMES_30 = new String[] {
// Left row (pins 0..14, top to bottom)
"EN", "VP (GPIO36)", "VN (GPIO39)", "D34", "D35", "D32", "D33", "D25", "D26", "D27", "D14", "D12", "GND1", "D13", "3V3",
// Right row (pins 15..29)
// Right row (pins 15..29, bottom to top)
"VIN", "GND2", "D15", "D2", "D4", "D16 (RX2)", "D17 (TX2)", "D5", "D18", "D19", "D21", "RX0 (GPIO3)", "TX0 (GPIO1)", "D22", "D23"
};
public static final String[] PIN_NAMES_38 = new String[] {
// Left row (pins 0..18, top to bottom)
"3V3", "EN", "VP (GPIO36)", "VN (GPIO39)", "GPIO34", "GPIO35", "GPIO32", "GPIO33",
"GPIO25", "GPIO26", "GPIO27", "GPIO14", "GPIO12", "GND1", "GPIO13",
"D2 (GPIO9)", "D3 (GPIO10)", "CMD (GPIO11)", "5V",
// Right row (pins 19..37, top to bottom)
"GND2", "GPIO23", "GPIO22", "TX0 (GPIO1)", "RX0 (GPIO3)", "GPIO21", "GND3",
"GPIO19", "GPIO18", "GPIO5", "GPIO17", "GPIO16", "GPIO4", "GPIO0", "GPIO2",
"GPIO15", "D1 (GPIO8)", "D0 (GPIO7)", "CLK (GPIO6)"
};
private DevKitVersion version = DevKitVersion.DevKit_V1_30Pin;
public ESP32DevKit() {
super();
this.bodyColor = ESP_BLACK;
updateControlPoints();
}
@EditableProperty(name = "Version")
public DevKitVersion getVersion() {
return version;
}
public void setVersion(DevKitVersion version) {
this.version = version;
updateControlPoints();
invalidateCache();
}
@Override
public String getControlPointNodeName(int index) {
if (index >= 0 && index < PIN_NAMES.length) {
return PIN_NAMES[index];
if (version == DevKitVersion.DevKit_V1_30Pin) {
if (index >= 0 && index < PIN_NAMES_30.length) {
return PIN_NAMES_30[index];
}
} else {
if (index >= 0 && index < PIN_NAMES_38.length) {
return PIN_NAMES_38[index];
}
}
return "Pin " + (index + 1);
}
@@ -90,19 +157,31 @@ public class ESP32DevKit extends AbstractMakerBoard {
protected void updateControlPoints() {
Point2D firstPoint = controlPoints[0];
double spacing = PIN_SPACING.convertToPixels();
double rowSpacing = ROW_SPACING.convertToPixels(); // 200px
double rowSpacing = ROW_SPACING.convertToPixels(); // 200px (1.00")
double[][] relativeOffsets = new double[30][2];
for (int i = 0; i < 15; i++) {
relativeOffsets[i][0] = 0;
relativeOffsets[i][1] = i * spacing;
if (version == DevKitVersion.DevKit_V1_30Pin) {
double[][] relativeOffsets = new double[30][2];
for (int i = 0; i < 15; i++) {
relativeOffsets[i][0] = 0;
relativeOffsets[i][1] = i * spacing;
}
for (int i = 0; i < 15; i++) {
relativeOffsets[15 + i][0] = rowSpacing;
relativeOffsets[15 + i][1] = (14 - i) * spacing;
}
rotatePoints(firstPoint, relativeOffsets);
} else {
double[][] relativeOffsets = new double[PIN_NAMES_38.length][2];
for (int i = 0; i < 19; i++) {
relativeOffsets[i][0] = 0;
relativeOffsets[i][1] = i * spacing;
}
for (int i = 0; i < 19; i++) {
relativeOffsets[19 + i][0] = rowSpacing;
relativeOffsets[19 + i][1] = i * spacing;
}
rotatePoints(firstPoint, relativeOffsets);
}
for (int i = 0; i < 15; i++) {
relativeOffsets[15 + i][0] = rowSpacing;
relativeOffsets[15 + i][1] = (14 - i) * spacing;
}
rotatePoints(firstPoint, relativeOffsets);
}
@Override
@@ -111,12 +190,29 @@ public class ESP32DevKit extends AbstractMakerBoard {
double x = p0.getX();
double y = p0.getY();
double rowSpacing = ROW_SPACING.convertToPixels();
double boardW = BOARD_WIDTH.convertToPixels();
double boardH = BOARD_LENGTH.convertToPixels();
double topMargin = TOP_MARGIN.convertToPixels();
double boardX = (x + rowSpacing / 2.0) - boardW / 2.0;
double boardY = y - topMargin;
return new RoundRectangle2D.Double(boardX, boardY, boardW, boardH, 8, 8);
if (version == DevKitVersion.DevKit_V1_30Pin) {
double boardW = BOARD_WIDTH_30.convertToPixels();
double boardH = BOARD_LENGTH_30.convertToPixels();
double topMargin = TOP_MARGIN_30.convertToPixels();
double boardX = (x + rowSpacing / 2.0) - boardW / 2.0;
double boardY = y - topMargin;
return new RoundRectangle2D.Double(boardX, boardY, boardW, boardH, 8, 8);
} else {
double mainW = BOARD_WIDTH_38.convertToPixels();
double mainH = MAIN_BODY_LENGTH_38.convertToPixels();
double antennaW = ANTENNA_WIDTH_38.convertToPixels();
double antennaH = ANTENNA_LENGTH_38.convertToPixels();
double mainX = (x + rowSpacing / 2.0) - mainW / 2.0;
double mainY = (y + 18 * PIN_SPACING.convertToPixels() / 2.0) - mainH / 2.0;
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = mainY - antennaH;
Area bodyArea = new Area(new RoundRectangle2D.Double(mainX, mainY, mainW, mainH, 8, 8));
bodyArea.add(new Area(new Rectangle2D.Double(antennaX, antennaY, antennaW, antennaH + 1)));
return bodyArea;
}
}
@Override
@@ -136,24 +232,41 @@ public class ESP32DevKit extends AbstractMakerBoard {
}
double rowSpacing = ROW_SPACING.convertToPixels();
double boardW = BOARD_WIDTH.convertToPixels();
double boardH = BOARD_LENGTH.convertToPixels();
double topMargin = TOP_MARGIN.convertToPixels();
double boardX = (x + rowSpacing / 2.0) - boardW / 2.0;
double boardY = y - topMargin;
double antennaW = ANTENNA_WIDTH.convertToPixels();
double antennaH = ANTENNA_LENGTH.convertToPixels();
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = boardY;
Shape boardShape = getBodyShape();
Composite oldComposite = applyAlpha(g2d, componentState);
drawingObserver.startTracking();
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
g2d.fill(boardShape);
if (outlineMode) {
g2d.setColor(Constants.TRANSPARENT_COLOR);
g2d.fill(boardShape);
} else {
if (version == DevKitVersion.DevKit_V1_30Pin) {
g2d.setColor(bodyColor);
g2d.fill(boardShape);
} else {
double mainW = BOARD_WIDTH_38.convertToPixels();
double mainH = MAIN_BODY_LENGTH_38.convertToPixels();
double antennaW = ANTENNA_WIDTH_38.convertToPixels();
double antennaH = ANTENNA_LENGTH_38.convertToPixels();
double mainX = (x + rowSpacing / 2.0) - mainW / 2.0;
double mainY = (y + 18 * PIN_SPACING.convertToPixels() / 2.0) - mainH / 2.0;
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = mainY - antennaH;
// Main board body
g2d.setColor(bodyColor);
g2d.fill(new RoundRectangle2D.Double(mainX, mainY, mainW, mainH, 8, 8));
// Antenna tab in slightly lighter color
Color antennaTabColor = new Color(
Math.min(255, bodyColor.getRed() + 32),
Math.min(255, bodyColor.getGreen() + 32),
Math.min(255, bodyColor.getBlue() + 32)
);
g2d.setColor(antennaTabColor);
g2d.fill(new Rectangle2D.Double(antennaX, antennaY, antennaW, antennaH));
}
}
drawingObserver.stopTracking();
g2d.setColor(getFinalBorderColor(componentState, outlineMode));
@@ -161,19 +274,70 @@ public class ESP32DevKit extends AbstractMakerBoard {
g2d.draw(boardShape);
if (!outlineMode) {
// 4 Corner Mounting Holes (diameter 2.8mm, 0.8mm away from edges in both directions)
double holeDiameter = HOLE_DIAMETER.convertToPixels();
double holeRadius = holeDiameter / 2.0;
double edgeMargin = HOLE_EDGE_MARGIN.convertToPixels();
double leftHoleX = boardX + edgeMargin + holeRadius;
double rightHoleX = boardX + boardW - edgeMargin - holeRadius;
double topHoleY = boardY + edgeMargin + holeRadius;
double bottomHoleY = boardY + boardH - edgeMargin - holeRadius;
double antennaX;
double antennaY;
double antennaW;
double antennaH;
double shieldY;
double shieldH = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldW = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldX = (x + rowSpacing / 2.0) - shieldW / 2.0;
double usbY;
double btnLeftX;
double btnRightX;
double btnY;
double btnW = 20;
double btnH = 20;
double shift1mm = new Size(1.0d, SizeUnit.mm).convertToPixels();
drawMountingHole(g2d, leftHoleX, topHoleY, holeDiameter);
drawMountingHole(g2d, rightHoleX, topHoleY, holeDiameter);
drawMountingHole(g2d, leftHoleX, bottomHoleY, holeDiameter);
drawMountingHole(g2d, rightHoleX, bottomHoleY, holeDiameter);
if (version == DevKitVersion.DevKit_V1_30Pin) {
double boardW = BOARD_WIDTH_30.convertToPixels();
double boardH = BOARD_LENGTH_30.convertToPixels();
double topMargin = TOP_MARGIN_30.convertToPixels();
double boardX = (x + rowSpacing / 2.0) - boardW / 2.0;
double boardY = y - topMargin;
antennaW = ANTENNA_WIDTH_30.convertToPixels();
antennaH = ANTENNA_LENGTH_30.convertToPixels();
antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
antennaY = boardY;
shieldY = boardY + antennaH + shift1mm;
usbY = boardY + boardH - 22;
// 4 Corner Mounting Holes (diameter 2.8mm, 0.8mm away from edges in both directions)
double holeDiameter = HOLE_DIAMETER_30.convertToPixels();
double holeRadius = holeDiameter / 2.0;
double edgeMargin = HOLE_EDGE_MARGIN_30.convertToPixels();
double leftHoleX = boardX + edgeMargin + holeRadius;
double rightHoleX = boardX + boardW - edgeMargin - holeRadius;
double topHoleY = boardY + edgeMargin + holeRadius;
double bottomHoleY = boardY + boardH - edgeMargin - holeRadius;
drawMountingHole(g2d, leftHoleX, topHoleY, holeDiameter);
drawMountingHole(g2d, rightHoleX, topHoleY, holeDiameter);
drawMountingHole(g2d, leftHoleX, bottomHoleY, holeDiameter);
drawMountingHole(g2d, rightHoleX, bottomHoleY, holeDiameter);
btnY = boardY + boardH - 25 - shift1mm;
btnLeftX = leftHoleX + 14 + shift1mm;
btnRightX = rightHoleX - 14 - shift1mm - btnW;
} else {
double mainW = BOARD_WIDTH_38.convertToPixels();
double mainH = MAIN_BODY_LENGTH_38.convertToPixels();
double mainX = (x + rowSpacing / 2.0) - mainW / 2.0;
double mainY = (y + 18 * PIN_SPACING.convertToPixels() / 2.0) - mainH / 2.0;
antennaW = ANTENNA_WIDTH_38.convertToPixels();
antennaH = ANTENNA_LENGTH_38.convertToPixels();
antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
antennaY = mainY - antennaH;
shieldY = mainY + 10;
usbY = mainY + mainH - 22;
btnY = mainY + mainH - 25;
btnLeftX = mainX + 38;
btnRightX = mainX + mainW - 38 - btnW;
}
// Antenna trace (gold/copper serpentine PCB trace)
g2d.setColor(ANTENNA_COLOR);
@@ -195,29 +359,16 @@ public class ESP32DevKit extends AbstractMakerBoard {
antPath.lineTo(antPadX + antPadW, antTopY);
g2d.draw(antPath);
double shift1mm = new Size(1.0d, SizeUnit.mm).convertToPixels();
// ESP32-WROOM-32 metal shield module below antenna
double shieldW = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldH = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldX = (x + rowSpacing / 2.0) - shieldW / 2.0;
double shieldY = boardY + antennaH + shift1mm;
drawMetalConnector(g2d, shieldX, shieldY, shieldW, shieldH, "ESP32-WROOM-32");
// Micro-USB Jack at bottom
double usbW = 58;
double usbH = 34;
double usbX = (x + rowSpacing / 2.0) - usbW / 2.0;
double usbY = boardY + boardH - 22;
drawMetalConnector(g2d, usbX, usbY, usbW, usbH, "USB");
// EN & BOOT tactile buttons at bottom (flanking the Micro-USB port)
double btnW = 20;
double btnH = 20;
double btnY = boardY + boardH - 25 - shift1mm;
double btnLeftX = leftHoleX + 14 + shift1mm;
double btnRightX = rightHoleX - 14 - shift1mm - btnW;
g2d.setColor(BUTTON_BODY_COLOR);
g2d.fill(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.fill(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
@@ -237,7 +388,8 @@ public class ESP32DevKit extends AbstractMakerBoard {
// Silkscreen
g2d.setFont(SILK_FONT);
StringUtils.drawCenteredText(g2d, "ESP32 DevKit V1", x + rowSpacing / 2.0, shieldY + shieldH + 45, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
String silkText = (version == DevKitVersion.DevKit_V1_30Pin) ? "ESP32 DevKit V1" : "ESP32 DevKitC V4";
StringUtils.drawCenteredText(g2d, silkText, x + rowSpacing / 2.0, shieldY + shieldH + 45, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
g2d.setTransform(oldTx);
@@ -1,279 +0,0 @@
/*
*
* 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.micro;
import org.diylc.awt.StringUtils;
import org.diylc.common.HorizontalAlignment;
import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation;
import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractMakerBoard;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.KeywordPolicy;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants;
import java.awt.*;
import java.awt.geom.*;
@ComponentDescriptor(name = "ESP32 DevKitC", category = "Controllers",
author = "Branislav Stojkovic", description = "ESP32 DevKitC V4 Wi-Fi and Bluetooth Development Board",
instanceNamePrefix = "MCU", zOrder = IDIYComponent.COMPONENT,
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
enableCache = true)
public class ESP32DevKitC extends AbstractMakerBoard {
private static final long serialVersionUID = 1L;
public static Color ESP_BLACK = Color.decode("#1E1E1E");
public static Color ANTENNA_COLOR = Color.decode("#DAA520");
public static Color ANTENNA_TAB_COLOR = Color.decode("#383838");
public static Color BUTTON_BODY_COLOR = Color.decode("#383838");
public static Color BUTTON_BORDER_COLOR = Color.decode("#666666");
public static Color BUTTON_ACTUATOR_COLOR = Color.decode("#A0A0A0");
public static Color SILK_COLOR = Color.WHITE;
public static Size BOARD_WIDTH = new Size(27.9d, SizeUnit.mm);
public static Size BOARD_LENGTH = new Size(54.4d, SizeUnit.mm);
public static Size MAIN_BODY_LENGTH = new Size(48.2d, SizeUnit.mm);
public static Size ANTENNA_LENGTH = new Size(6.2d, SizeUnit.mm);
public static Size ANTENNA_WIDTH = new Size(19.0d, SizeUnit.mm);
public static Size ROW_SPACING = new Size(1.0d, SizeUnit.in);
public static final String[] PIN_NAMES = new String[] {
// Left row (pins 0..18, top to bottom)
"3V3", "EN", "VP (GPIO36)", "VN (GPIO39)", "GPIO34", "GPIO35", "GPIO32", "GPIO33",
"GPIO25", "GPIO26", "GPIO27", "GPIO14", "GPIO12", "GND1", "GPIO13",
"D2 (GPIO9)", "D3 (GPIO10)", "CMD (GPIO11)", "5V",
// Right row (pins 19..37, top to bottom)
"GND2", "GPIO23", "GPIO22", "TX0 (GPIO1)", "RX0 (GPIO3)", "GPIO21", "GND3",
"GPIO19", "GPIO18", "GPIO5", "GPIO17", "GPIO16", "GPIO4", "GPIO0", "GPIO2",
"GPIO15", "D1 (GPIO8)", "D0 (GPIO7)", "CLK (GPIO6)"
};
public ESP32DevKitC() {
super();
this.bodyColor = ESP_BLACK;
updateControlPoints();
}
@Override
public String getControlPointNodeName(int index) {
if (index >= 0 && index < PIN_NAMES.length) {
return PIN_NAMES[index];
}
return "Pin " + (index + 1);
}
@Override
protected void updateControlPoints() {
Point2D firstPoint = controlPoints[0];
double spacing = PIN_SPACING.convertToPixels();
double rowSpacing = ROW_SPACING.convertToPixels();
double[][] relativeOffsets = new double[PIN_NAMES.length][2];
for (int i = 0; i < 19; i++) {
relativeOffsets[i][0] = 0;
relativeOffsets[i][1] = i * spacing;
}
for (int i = 0; i < 19; i++) {
relativeOffsets[19 + i][0] = rowSpacing;
relativeOffsets[19 + i][1] = i * spacing;
}
rotatePoints(firstPoint, relativeOffsets);
}
@Override
public Shape getBodyShape() {
Point2D p0 = controlPoints[0];
double x = p0.getX();
double y = p0.getY();
double rowSpacing = ROW_SPACING.convertToPixels();
double mainW = BOARD_WIDTH.convertToPixels();
double mainH = MAIN_BODY_LENGTH.convertToPixels();
double antennaW = ANTENNA_WIDTH.convertToPixels();
double antennaH = ANTENNA_LENGTH.convertToPixels();
double mainX = (x + rowSpacing / 2.0) - mainW / 2.0;
double mainY = (y + 18 * PIN_SPACING.convertToPixels() / 2.0) - mainH / 2.0;
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = mainY - antennaH;
Area bodyArea = new Area(new RoundRectangle2D.Double(mainX, mainY, mainW, mainH, 8, 8));
bodyArea.add(new Area(new Rectangle2D.Double(antennaX, antennaY, antennaW, antennaH + 1)));
return bodyArea;
}
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
if (checkPointsClipped(g2d.getClip())) {
return;
}
Point2D p0 = controlPoints[0];
double x = p0.getX();
double y = p0.getY();
AffineTransform oldTx = g2d.getTransform();
if (orientation != Orientation.DEFAULT) {
g2d.rotate(orientation.toRadians(), x, y);
}
double rowSpacing = ROW_SPACING.convertToPixels();
double mainW = BOARD_WIDTH.convertToPixels();
double mainH = MAIN_BODY_LENGTH.convertToPixels();
double antennaW = ANTENNA_WIDTH.convertToPixels();
double antennaH = ANTENNA_LENGTH.convertToPixels();
double mainX = (x + rowSpacing / 2.0) - mainW / 2.0;
double mainY = (y + 18 * PIN_SPACING.convertToPixels() / 2.0) - mainH / 2.0;
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = mainY - antennaH;
Shape boardShape = getBodyShape();
Composite oldComposite = applyAlpha(g2d, componentState);
drawingObserver.startTracking();
if (outlineMode) {
g2d.setColor(Constants.TRANSPARENT_COLOR);
g2d.fill(boardShape);
} else {
// Main board body
g2d.setColor(bodyColor);
g2d.fill(new RoundRectangle2D.Double(mainX, mainY, mainW, mainH, 8, 8));
// Antenna tab in slightly lighter color
Color antennaColor = new Color(
Math.min(255, bodyColor.getRed() + 32),
Math.min(255, bodyColor.getGreen() + 32),
Math.min(255, bodyColor.getBlue() + 32)
);
g2d.setColor(antennaColor);
g2d.fill(new Rectangle2D.Double(antennaX, antennaY, antennaW, antennaH));
}
drawingObserver.stopTracking();
// Outline border around the full board
g2d.setColor(getFinalBorderColor(componentState, outlineMode));
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1.5f));
g2d.draw(boardShape);
if (!outlineMode) {
// Antenna trace (gold/copper serpentine PCB trace)
g2d.setColor(ANTENNA_COLOR);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1.5f));
Path2D.Double antPath = new Path2D.Double();
double antPadX = antennaX + 16;
double antPadW = antennaW - 32;
double antTopY = antennaY + 10;
double antMidY = antennaY + antennaH - 12;
antPath.moveTo(antPadX, antMidY);
antPath.lineTo(antPadX, antTopY);
antPath.lineTo(antPadX + antPadW * 0.25, antTopY);
antPath.lineTo(antPadX + antPadW * 0.25, antMidY);
antPath.lineTo(antPadX + antPadW * 0.50, antMidY);
antPath.lineTo(antPadX + antPadW * 0.50, antTopY);
antPath.lineTo(antPadX + antPadW * 0.75, antTopY);
antPath.lineTo(antPadX + antPadW * 0.75, antMidY);
antPath.lineTo(antPadX + antPadW, antMidY);
antPath.lineTo(antPadX + antPadW, antTopY);
g2d.draw(antPath);
// Micro-USB Jack at bottom
double usbW = 58;
double usbH = 34;
double usbX = (x + rowSpacing / 2.0) - usbW / 2.0;
double usbY = mainY + mainH - 22;
drawMetalConnector(g2d, usbX, usbY, usbW, usbH, "USB");
// ESP32-WROOM-32 metal shield module below antenna
double shieldW = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldH = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldX = (x + rowSpacing / 2.0) - shieldW / 2.0;
double shieldY = mainY + 10;
drawMetalConnector(g2d, shieldX, shieldY, shieldW, shieldH, "ESP32-WROOM-32");
// EN & BOOT tactile buttons at bottom (flanking the Micro-USB port)
double btnW = 20;
double btnH = 20;
double btnY = mainY + mainH - 25;
double btnLeftX = mainX + 38;
double btnRightX = mainX + mainW - 38 - btnW;
g2d.setColor(BUTTON_BODY_COLOR);
g2d.fill(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.fill(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
g2d.setColor(BUTTON_BORDER_COLOR);
g2d.draw(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.draw(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
// Button actuators
g2d.setColor(BUTTON_ACTUATOR_COLOR);
g2d.fillOval((int) (btnLeftX + btnW / 2.0 - 4), (int) (btnY + btnH / 2.0 - 4), 8, 8);
g2d.fillOval((int) (btnRightX + btnW / 2.0 - 4), (int) (btnY + btnH / 2.0 - 4), 8, 8);
g2d.setColor(SILK_COLOR);
g2d.setFont(SILK_FONT_SMALL);
StringUtils.drawCenteredText(g2d, "EN", btnLeftX + btnW / 2.0, btnY - 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "BOOT", btnRightX + btnW / 2.0, btnY - 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
// Silkscreen
g2d.setFont(SILK_FONT);
StringUtils.drawCenteredText(g2d, "ESP32 DevKitC V4", x + rowSpacing / 2.0, mainY + shieldH + 45, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
g2d.setTransform(oldTx);
drawPins(g2d, 0, controlPoints.length, false, outlineMode, drawingObserver);
g2d.setComposite(oldComposite);
}
@Override
public void drawIcon(Graphics2D g2d, int width, int height) {
g2d.setColor(ESP_BLACK);
g2d.fill(new RoundRectangle2D.Double(5, 6, width - 10, height - 8, 3, 3));
// Antenna tab
g2d.setColor(ANTENNA_TAB_COLOR);
g2d.fillRect(8, 2, width - 16, 5);
g2d.setColor(Color.GRAY);
g2d.draw(new RoundRectangle2D.Double(5, 6, width - 10, height - 8, 3, 3));
// Metal shield
g2d.setColor(METAL_SHIELD_COLOR);
g2d.fillRect(8, 9, width - 16, 10);
g2d.setColor(SILK_COLOR);
g2d.setFont(new Font("SansSerif", Font.BOLD, 5));
StringUtils.drawCenteredText(g2d, "ESP32", width / 2, height / 2 + 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
}
@@ -239,7 +239,6 @@ public class MakerComponentsTest {
public void testControlPointsAreDistinct() throws Exception {
for (Class<? extends IDIYComponent<?>> clazz : allMakerComponentClasses) {
IDIYComponent<?> component = clazz.getDeclaredConstructor().newInstance();
component.setControlPoint(new Point2D.Double(200, 200), 0);
int count = component.getControlPointCount();
for (int i = 0; i < count; i++) {
Point2D p1 = component.getControlPoint(i);
@@ -1,109 +0,0 @@
package org.diylc.components.micro;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.junit.Assert;
import org.junit.Test;
public class ESP32DevKitCTest {
@Test
public void testControlPointCountAndNames() {
ESP32DevKitC devKit = new ESP32DevKitC();
Assert.assertEquals(38, devKit.getControlPointCount());
for (int i = 0; i < devKit.getControlPointCount(); i++) {
String name = devKit.getControlPointNodeName(i);
Assert.assertNotNull("Pin " + i + " name should not be null", name);
Assert.assertFalse("Pin " + i + " name should not be empty", name.trim().isEmpty());
}
// Left row (0..18, top to bottom)
Assert.assertEquals("3V3", devKit.getControlPointNodeName(0));
Assert.assertEquals("EN", devKit.getControlPointNodeName(1));
Assert.assertEquals("VP (GPIO36)", devKit.getControlPointNodeName(2));
Assert.assertEquals("VN (GPIO39)", devKit.getControlPointNodeName(3));
Assert.assertEquals("GPIO34", devKit.getControlPointNodeName(4));
Assert.assertEquals("GPIO35", devKit.getControlPointNodeName(5));
Assert.assertEquals("GPIO32", devKit.getControlPointNodeName(6));
Assert.assertEquals("GPIO33", devKit.getControlPointNodeName(7));
Assert.assertEquals("GPIO25", devKit.getControlPointNodeName(8));
Assert.assertEquals("GPIO26", devKit.getControlPointNodeName(9));
Assert.assertEquals("GPIO27", devKit.getControlPointNodeName(10));
Assert.assertEquals("GPIO14", devKit.getControlPointNodeName(11));
Assert.assertEquals("GPIO12", devKit.getControlPointNodeName(12));
Assert.assertEquals("GND1", devKit.getControlPointNodeName(13));
Assert.assertEquals("GPIO13", devKit.getControlPointNodeName(14));
Assert.assertEquals("D2 (GPIO9)", devKit.getControlPointNodeName(15));
Assert.assertEquals("D3 (GPIO10)", devKit.getControlPointNodeName(16));
Assert.assertEquals("CMD (GPIO11)", devKit.getControlPointNodeName(17));
Assert.assertEquals("5V", devKit.getControlPointNodeName(18));
// Right row (19..37, top to bottom)
Assert.assertEquals("GND2", devKit.getControlPointNodeName(19));
Assert.assertEquals("GPIO23", devKit.getControlPointNodeName(20));
Assert.assertEquals("GPIO22", devKit.getControlPointNodeName(21));
Assert.assertEquals("TX0 (GPIO1)", devKit.getControlPointNodeName(22));
Assert.assertEquals("RX0 (GPIO3)", devKit.getControlPointNodeName(23));
Assert.assertEquals("GPIO21", devKit.getControlPointNodeName(24));
Assert.assertEquals("GND3", devKit.getControlPointNodeName(25));
Assert.assertEquals("GPIO19", devKit.getControlPointNodeName(26));
Assert.assertEquals("GPIO18", devKit.getControlPointNodeName(27));
Assert.assertEquals("GPIO5", devKit.getControlPointNodeName(28));
Assert.assertEquals("GPIO17", devKit.getControlPointNodeName(29));
Assert.assertEquals("GPIO16", devKit.getControlPointNodeName(30));
Assert.assertEquals("GPIO4", devKit.getControlPointNodeName(31));
Assert.assertEquals("GPIO0", devKit.getControlPointNodeName(32));
Assert.assertEquals("GPIO2", devKit.getControlPointNodeName(33));
Assert.assertEquals("GPIO15", devKit.getControlPointNodeName(34));
Assert.assertEquals("D1 (GPIO8)", devKit.getControlPointNodeName(35));
Assert.assertEquals("D0 (GPIO7)", devKit.getControlPointNodeName(36));
Assert.assertEquals("CLK (GPIO6)", devKit.getControlPointNodeName(37));
}
@Test
public void testPinGeometryAndSpacing() {
ESP32DevKitC devKit = new ESP32DevKitC();
// Left row pitch (20px per pin = 0.10")
for (int i = 0; i < 18; i++) {
Point2D p1 = devKit.getControlPoint(i);
Point2D p2 = devKit.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Right row pitch (20px per pin = 0.10")
for (int i = 19; i < 37; i++) {
Point2D p1 = devKit.getControlPoint(i);
Point2D p2 = devKit.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Row spacing: 1.00" = 200px between Left row and Right row
Point2D pLeftTop = devKit.getControlPoint(0);
Point2D pRightTop = devKit.getControlPoint(19);
Assert.assertEquals(200.0, pLeftTop.distance(pRightTop), 0.01);
Assert.assertEquals(pLeftTop.getY(), pRightTop.getY(), 0.01);
}
@Test
public void testBodyShapeDimensions() {
ESP32DevKitC devKit = new ESP32DevKitC();
Shape body = devKit.getBodyShape();
Assert.assertNotNull(body);
Rectangle2D bounds = body.getBounds2D();
double expectedWidth = new Size(27.9d, SizeUnit.mm).convertToPixels();
double expectedTotalLength = new Size(54.4d, SizeUnit.mm).convertToPixels();
Assert.assertEquals(expectedWidth, bounds.getWidth(), 0.1);
Assert.assertEquals(expectedTotalLength, bounds.getHeight(), 0.1);
}
}
@@ -12,8 +12,9 @@ import org.junit.Test;
public class ESP32DevKitTest {
@Test
public void testControlPointCountAndNames() {
public void testControlPointCountAndNames30Pin() {
ESP32DevKit devKit = new ESP32DevKit();
Assert.assertEquals(ESP32DevKit.DevKitVersion.DevKit_V1_30Pin, devKit.getVersion());
Assert.assertEquals(30, devKit.getControlPointCount());
for (int i = 0; i < devKit.getControlPointCount(); i++) {
@@ -58,7 +59,63 @@ public class ESP32DevKitTest {
}
@Test
public void testPinGeometryAndSpacing() {
public void testControlPointCountAndNames38Pin() {
ESP32DevKit devKit = new ESP32DevKit();
devKit.setVersion(ESP32DevKit.DevKitVersion.DevKitC_V4_38Pin);
Assert.assertEquals(ESP32DevKit.DevKitVersion.DevKitC_V4_38Pin, devKit.getVersion());
Assert.assertEquals(38, devKit.getControlPointCount());
for (int i = 0; i < devKit.getControlPointCount(); i++) {
String name = devKit.getControlPointNodeName(i);
Assert.assertNotNull("Pin " + i + " name should not be null", name);
Assert.assertFalse("Pin " + i + " name should not be empty", name.trim().isEmpty());
}
// Left row (0..18, top to bottom)
Assert.assertEquals("3V3", devKit.getControlPointNodeName(0));
Assert.assertEquals("EN", devKit.getControlPointNodeName(1));
Assert.assertEquals("VP (GPIO36)", devKit.getControlPointNodeName(2));
Assert.assertEquals("VN (GPIO39)", devKit.getControlPointNodeName(3));
Assert.assertEquals("GPIO34", devKit.getControlPointNodeName(4));
Assert.assertEquals("GPIO35", devKit.getControlPointNodeName(5));
Assert.assertEquals("GPIO32", devKit.getControlPointNodeName(6));
Assert.assertEquals("GPIO33", devKit.getControlPointNodeName(7));
Assert.assertEquals("GPIO25", devKit.getControlPointNodeName(8));
Assert.assertEquals("GPIO26", devKit.getControlPointNodeName(9));
Assert.assertEquals("GPIO27", devKit.getControlPointNodeName(10));
Assert.assertEquals("GPIO14", devKit.getControlPointNodeName(11));
Assert.assertEquals("GPIO12", devKit.getControlPointNodeName(12));
Assert.assertEquals("GND1", devKit.getControlPointNodeName(13));
Assert.assertEquals("GPIO13", devKit.getControlPointNodeName(14));
Assert.assertEquals("D2 (GPIO9)", devKit.getControlPointNodeName(15));
Assert.assertEquals("D3 (GPIO10)", devKit.getControlPointNodeName(16));
Assert.assertEquals("CMD (GPIO11)", devKit.getControlPointNodeName(17));
Assert.assertEquals("5V", devKit.getControlPointNodeName(18));
// Right row (19..37, top to bottom)
Assert.assertEquals("GND2", devKit.getControlPointNodeName(19));
Assert.assertEquals("GPIO23", devKit.getControlPointNodeName(20));
Assert.assertEquals("GPIO22", devKit.getControlPointNodeName(21));
Assert.assertEquals("TX0 (GPIO1)", devKit.getControlPointNodeName(22));
Assert.assertEquals("RX0 (GPIO3)", devKit.getControlPointNodeName(23));
Assert.assertEquals("GPIO21", devKit.getControlPointNodeName(24));
Assert.assertEquals("GND3", devKit.getControlPointNodeName(25));
Assert.assertEquals("GPIO19", devKit.getControlPointNodeName(26));
Assert.assertEquals("GPIO18", devKit.getControlPointNodeName(27));
Assert.assertEquals("GPIO5", devKit.getControlPointNodeName(28));
Assert.assertEquals("GPIO17", devKit.getControlPointNodeName(29));
Assert.assertEquals("GPIO16", devKit.getControlPointNodeName(30));
Assert.assertEquals("GPIO4", devKit.getControlPointNodeName(31));
Assert.assertEquals("GPIO0", devKit.getControlPointNodeName(32));
Assert.assertEquals("GPIO2", devKit.getControlPointNodeName(33));
Assert.assertEquals("GPIO15", devKit.getControlPointNodeName(34));
Assert.assertEquals("D1 (GPIO8)", devKit.getControlPointNodeName(35));
Assert.assertEquals("D0 (GPIO7)", devKit.getControlPointNodeName(36));
Assert.assertEquals("CLK (GPIO6)", devKit.getControlPointNodeName(37));
}
@Test
public void testPinGeometryAndSpacing30Pin() {
ESP32DevKit devKit = new ESP32DevKit();
// Left row pitch (20px per pin = 0.10")
@@ -85,7 +142,35 @@ public class ESP32DevKitTest {
}
@Test
public void testBodyShapeDimensions() {
public void testPinGeometryAndSpacing38Pin() {
ESP32DevKit devKit = new ESP32DevKit();
devKit.setVersion(ESP32DevKit.DevKitVersion.DevKitC_V4_38Pin);
// Left row pitch (20px per pin = 0.10")
for (int i = 0; i < 18; i++) {
Point2D p1 = devKit.getControlPoint(i);
Point2D p2 = devKit.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Right row pitch (20px per pin = 0.10")
for (int i = 19; i < 37; i++) {
Point2D p1 = devKit.getControlPoint(i);
Point2D p2 = devKit.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Row spacing: 1.00" = 200px between Left row and Right row
Point2D pLeftTop = devKit.getControlPoint(0);
Point2D pRightTop = devKit.getControlPoint(19);
Assert.assertEquals(200.0, pLeftTop.distance(pRightTop), 0.01);
Assert.assertEquals(pLeftTop.getY(), pRightTop.getY(), 0.01);
}
@Test
public void testBodyShapeDimensions30Pin() {
ESP32DevKit devKit = new ESP32DevKit();
Shape body = devKit.getBodyShape();
@@ -102,4 +187,36 @@ public class ESP32DevKitTest {
Point2D p0 = devKit.getControlPoint(0);
Assert.assertEquals(expectedTopMargin, p0.getY() - bounds.getY(), 0.1);
}
@Test
public void testBodyShapeDimensions38Pin() {
ESP32DevKit devKit = new ESP32DevKit();
devKit.setVersion(ESP32DevKit.DevKitVersion.DevKitC_V4_38Pin);
Shape body = devKit.getBodyShape();
Assert.assertNotNull(body);
Rectangle2D bounds = body.getBounds2D();
double expectedWidth = new Size(27.9d, SizeUnit.mm).convertToPixels();
double expectedTotalLength = new Size(54.4d, SizeUnit.mm).convertToPixels();
Assert.assertEquals(expectedWidth, bounds.getWidth(), 0.1);
Assert.assertEquals(expectedTotalLength, bounds.getHeight(), 0.1);
}
@Test
public void testVersionSwitching() {
ESP32DevKit devKit = new ESP32DevKit();
Assert.assertEquals(30, devKit.getControlPointCount());
devKit.setVersion(ESP32DevKit.DevKitVersion.DevKitC_V4_38Pin);
Assert.assertEquals(38, devKit.getControlPointCount());
Assert.assertEquals("5V", devKit.getControlPointNodeName(18));
Assert.assertEquals("CLK (GPIO6)", devKit.getControlPointNodeName(37));
devKit.setVersion(ESP32DevKit.DevKitVersion.DevKit_V1_30Pin);
Assert.assertEquals(30, devKit.getControlPointCount());
Assert.assertEquals("3V3", devKit.getControlPointNodeName(14));
Assert.assertEquals("D23", devKit.getControlPointNodeName(29));
}
}