diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/micro/ESP32DevKit.java b/diylc/diylc-library/src/main/java/org/diylc/components/micro/ESP32DevKit.java index 0321ade5..83f429c8 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/micro/ESP32DevKit.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/micro/ESP32DevKit.java @@ -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); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/micro/ESP32DevKitC.java b/diylc/diylc-library/src/main/java/org/diylc/components/micro/ESP32DevKitC.java deleted file mode 100644 index 6f8070f4..00000000 --- a/diylc/diylc-library/src/main/java/org/diylc/components/micro/ESP32DevKitC.java +++ /dev/null @@ -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 . - * - */ -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); - } -} diff --git a/diylc/diylc-library/src/test/java/org/diylc/components/maker/MakerComponentsTest.java b/diylc/diylc-library/src/test/java/org/diylc/components/maker/MakerComponentsTest.java index cf48ff52..6ef24998 100644 --- a/diylc/diylc-library/src/test/java/org/diylc/components/maker/MakerComponentsTest.java +++ b/diylc/diylc-library/src/test/java/org/diylc/components/maker/MakerComponentsTest.java @@ -239,7 +239,6 @@ public class MakerComponentsTest { public void testControlPointsAreDistinct() throws Exception { for (Class> 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); diff --git a/diylc/diylc-library/src/test/java/org/diylc/components/micro/ESP32DevKitCTest.java b/diylc/diylc-library/src/test/java/org/diylc/components/micro/ESP32DevKitCTest.java deleted file mode 100644 index fa30b881..00000000 --- a/diylc/diylc-library/src/test/java/org/diylc/components/micro/ESP32DevKitCTest.java +++ /dev/null @@ -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); - } -} diff --git a/diylc/diylc-library/src/test/java/org/diylc/components/micro/ESP32DevKitTest.java b/diylc/diylc-library/src/test/java/org/diylc/components/micro/ESP32DevKitTest.java index bea80561..69ee2b8e 100644 --- a/diylc/diylc-library/src/test/java/org/diylc/components/micro/ESP32DevKitTest.java +++ b/diylc/diylc-library/src/test/java/org/diylc/components/micro/ESP32DevKitTest.java @@ -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)); + } }