diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/EspToolCommands.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/EspToolCommands.java new file mode 100644 index 000000000..1ea92bb43 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/EspToolCommands.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright 2023 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ + +package com.espressif.idf.core.util; + +import java.util.ArrayList; +import java.util.List; + +import com.espressif.idf.core.IDFConstants; + +/** + * Class to get the commands and processes for the esptool.py + * @author Ali Azam Rana + * + */ +public class EspToolCommands +{ + private Process chipInfoProcess; + private Process flashEraseProcess; + + public Process chipInformation(String port) throws Exception + { + destroyAnyChipInfoProcess(); + chipInfoProcess = new ProcessBuilder(getChipInfoCommand(port)).start(); + return chipInfoProcess; + } + + public Process eraseFlash(String port) throws Exception + { + destroyAnyChipInfoProcess(); + flashEraseProcess = new ProcessBuilder(getFlashEraseCommand(port)).start(); + return flashEraseProcess; + } + + private List getChipInfoCommand(String port) + { + List command = new ArrayList(); + command.add(IDFUtil.getIDFPythonEnvPath()); + command.add(IDFUtil.getEspToolScriptFile().getAbsolutePath()); + command.add("-p"); //$NON-NLS-1$ + command.add(port); + command.add(IDFConstants.ESP_TOOL_CHIP_ID_CMD); + return command; + } + + private List getFlashEraseCommand(String port) + { + List command = new ArrayList(); + command.add(IDFUtil.getIDFPythonEnvPath()); + command.add(IDFUtil.getEspToolScriptFile().getAbsolutePath()); + command.add("-p"); //$NON-NLS-1$ + command.add(port); + command.add(IDFConstants.ESP_TOOL_ERASE_FLASH_CMD); + return command; + } + + private void destroyAnyChipInfoProcess() + { + if (chipInfoProcess != null && chipInfoProcess.isAlive()) + { + chipInfoProcess.destroy(); + } + } + + public boolean checkActiveFlashEraseProcess() + { + if (flashEraseProcess != null) + { + return flashEraseProcess.isAlive(); + } + + return false; + } + + public void killEraseFlashProcess() + { + if (flashEraseProcess != null) + { + flashEraseProcess.destroy(); + } + } +} diff --git a/bundles/com.espressif.idf.launch.serial.ui/META-INF/MANIFEST.MF b/bundles/com.espressif.idf.launch.serial.ui/META-INF/MANIFEST.MF index b1cd771bd..10395e501 100644 --- a/bundles/com.espressif.idf.launch.serial.ui/META-INF/MANIFEST.MF +++ b/bundles/com.espressif.idf.launch.serial.ui/META-INF/MANIFEST.MF @@ -14,7 +14,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.13.0", org.eclipse.cdt.launch;bundle-version="9.2.0", org.eclipse.cdt.debug.core, com.espressif.idf.core, - org.eclipse.cdt.core + org.eclipse.cdt.core, + org.eclipse.jface Bundle-Activator: com.espressif.idf.launch.serial.ui.internal.Activator Bundle-ActivationPolicy: lazy Automatic-Module-Name: org.eclipse.cdt.launch.serial.ui diff --git a/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/Messages.java b/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/Messages.java index 79da016c0..ba8cf3c94 100644 --- a/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/Messages.java +++ b/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/Messages.java @@ -47,6 +47,11 @@ public class Messages extends NLS { public static String IDFLaunchTargetNotFoundIDFLaunchTargetNotFoundTitle; public static String IDFLaunchTargetNotFoundMsg3; + public static String TargetPortUpdatingMessage; + public static String TargetPortInformationMessage; + public static String TargetPortFoundMessage; + public static String TargetPortNotFoundMessage; + static { // initialize resource bundle NLS.initializeMessages(BUNDLE_NAME, Messages.class); diff --git a/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/NewSerialFlashTargetWizardPage.java b/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/NewSerialFlashTargetWizardPage.java index d578ab67d..5bbc90bf9 100644 --- a/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/NewSerialFlashTargetWizardPage.java +++ b/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/NewSerialFlashTargetWizardPage.java @@ -15,9 +15,18 @@ *******************************************************************************/ package com.espressif.idf.launch.serial.ui.internal; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.cdt.core.build.IToolChain; import org.eclipse.cdt.serial.SerialPort; @@ -26,14 +35,20 @@ import org.eclipse.jface.wizard.WizardPage; import org.eclipse.launchbar.core.target.ILaunchTarget; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import com.espressif.idf.core.build.ESPToolChainManager; +import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.util.EspToolCommands; +import com.espressif.idf.core.util.StringUtil; import com.espressif.idf.launch.serial.SerialFlashLaunchTargetProvider; public class NewSerialFlashTargetWizardPage extends WizardPage { @@ -46,12 +61,18 @@ public class NewSerialFlashTargetWizardPage extends WizardPage { private Text nameText; private Combo serialPortCombo; private Combo idfTargetCombo; + private Text infoArea; + private Map> targetPortMap; + private TargetPortMapUpdateThread targetPortMapUpdateThread; + private Display display; public NewSerialFlashTargetWizardPage(ILaunchTarget launchTarget) { super(NewSerialFlashTargetWizardPage.class.getName()); this.launchTarget = launchTarget; + targetPortMap = new HashMap<>(); setTitle(Messages.NewSerialFlashTargetWizardPage_Title); setDescription(Messages.NewSerialFlashTargetWizardPage_Description); + targetPortMapUpdateThread = new TargetPortMapUpdateThread(); } @Override @@ -59,6 +80,8 @@ public void createControl(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); comp.setLayout(new GridLayout(2, false)); setControl(comp); + display = comp.getDisplay(); + targetPortMapUpdateThread.start(); Label label = new Label(comp, SWT.NONE); label.setText(Messages.NewSerialFlashTargetWizardPage_Name); @@ -73,9 +96,13 @@ public void createControl(Composite parent) { label.setText(Messages.NewSerialFlashTargetWizardPage_IDFTarget); idfTargetCombo = new Combo(comp, SWT.NONE); + List idfTargetList = getIDFTargetList(); + idfTargetCombo.setItems(idfTargetList.toArray(new String[idfTargetList.size()])); idfTargetCombo.setToolTipText(Messages.NewSerialFlashTargetWizardPage_IDFTargetToolTipMsg); + idfTargetCombo.addSelectionListener(new TargetComboSelectionAdapter()); + if (idfTargetCombo.getItemCount() > 0 && idfTargetCombo.getSelectionIndex() < 0) { idfTargetCombo.select(0); } @@ -121,6 +148,9 @@ public void createControl(Composite parent) { Activator.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.NewSerialFlashTargetWizardPage_Fetching, e)); } + + infoArea = new Text(comp, SWT.BORDER | SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI); + infoArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); } public String getTargetName() { @@ -166,4 +196,111 @@ private List getIDFTargetList() { private Collection getToolchains() { return new ESPToolChainManager().getAllEspToolchains(); } + + private void putPortInMapForTarget(String target, String port) { + List portsForTargetMatched = targetPortMap.get(target); + if (portsForTargetMatched != null) { + portsForTargetMatched.add(port); + } else { + portsForTargetMatched = new ArrayList<>(); + portsForTargetMatched.add(port); + targetPortMap.put(target, portsForTargetMatched); + } + } + + private String extractChipFromChipInfoOutput(String chipInfoOutput) { + Pattern pattern = Pattern.compile("Chip is (ESP32[^\\s]*)"); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(chipInfoOutput); + if (matcher.find()) { + String chipType = matcher.group(1); + chipType = chipType.replace("-", StringUtil.EMPTY).toLowerCase(); //$NON-NLS-1$ + return chipType; + } + + return StringUtil.EMPTY; + } + + private class TargetComboSelectionAdapter extends SelectionAdapter { + @Override + public void widgetSelected(SelectionEvent e) { + String selectedTarget = idfTargetCombo.getText(); + + List comPortList = targetPortMap.get(selectedTarget); + if (comPortList != null && comPortList.size() > 0) { + serialPortCombo.select(serialPortCombo.indexOf(comPortList.get(0))); + infoArea.setText( + String.format(Messages.TargetPortInformationMessage, selectedTarget, comPortList.toString())); + } + } + } + + private class TargetPortMapUpdateThread extends Thread { + @Override + public void run() { + try { + updateTargetHashMap(); + } catch (Exception e) { + Logger.log(e); + } + } + + private void updateTargetHashMap() throws Exception { + EspToolCommands espToolCommands = new EspToolCommands(); + List idfTargetList = getIDFTargetList(); + for (String idfTarget : idfTargetList) { + targetPortMap.put(idfTarget, null); + } + + String[] ports = SerialPort.list(); + if (ports == null || ports.length == 0) + return; + + for (String port : ports) { + String message = String.format(Messages.TargetPortUpdatingMessage, port); + + display.asyncExec(() -> { + if (infoArea != null && !infoArea.isDisposed()) + infoArea.setText(infoArea.getText() + System.lineSeparator() + message); + }); + + Process chipInfoProcess = espToolCommands.chipInformation(port); + InputStream targetIn = chipInfoProcess.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(targetIn)); + StringBuilder chipInfo = new StringBuilder(); + String readLine; + while ((readLine = bufferedReader.readLine()) != null) { + chipInfo.append(readLine); + chipInfo.append(System.lineSeparator()); + } + String chipType = extractChipFromChipInfoOutput(chipInfo.toString()); + if (StringUtil.isEmpty(chipType)) { + display.asyncExec(() -> { + if (infoArea != null && !infoArea.isDisposed()) + infoArea.setText(infoArea.getText() + System.lineSeparator() + + String.format(Messages.TargetPortNotFoundMessage, port)); + }); + continue; + } + + Optional optTarget = idfTargetList.stream().filter(t -> t.equals(chipType)).findFirst(); + if (optTarget.isPresent()) { + String targetMatched = optTarget.get(); + putPortInMapForTarget(targetMatched, port); + display.asyncExec(() -> { + infoArea.setText(infoArea.getText() + System.lineSeparator() + + String.format(Messages.TargetPortFoundMessage, port, targetMatched)); + }); + } else { + // if we dont find the board from chip type + // assuming esp32 as the chipinfo for that gives additional info + putPortInMapForTarget("esp32", port); //$NON-NLS-1$ + display.asyncExec(() -> { + infoArea.setText(infoArea.getText() + System.lineSeparator() + + String.format(Messages.TargetPortFoundMessage, port, "esp32")); //$NON-NLS-1$ + }); + } + } + + } + } } diff --git a/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/messages.properties b/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/messages.properties index f0a924283..675e27754 100644 --- a/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/messages.properties +++ b/bundles/com.espressif.idf.launch.serial.ui/src/com/espressif/idf/launch/serial/ui/internal/messages.properties @@ -36,3 +36,9 @@ IDFLaunchTargetNotFoundMsg1=IDF Launch Target with IDFLaunchTargetNotFoundMsg2=\ is not found. IDFLaunchTargetNotFoundIDFLaunchTargetNotFoundTitle=IDF Launch Target not found IDFLaunchTargetNotFoundMsg3=Do you want to create a new IDF launch target? + + +TargetPortUpdatingMessage=Finding Targets for %s port. +TargetPortInformationMessage=Target: %s\nAvailable Ports: %s +TargetPortFoundMessage=Port: %s is Linked to Target: %s +TargetPortNotFoundMessage=No suitable target found for Port: %s \ No newline at end of file diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/EraseFlashDialog.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/EraseFlashDialog.java index fda3d75d8..7dc85effe 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/EraseFlashDialog.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/dialogs/EraseFlashDialog.java @@ -9,8 +9,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; import org.eclipse.cdt.serial.SerialPort; import org.eclipse.jface.dialogs.IDialogConstants; @@ -31,9 +29,8 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; -import com.espressif.idf.core.IDFConstants; import com.espressif.idf.core.logging.Logger; -import com.espressif.idf.core.util.IDFUtil; +import com.espressif.idf.core.util.EspToolCommands; /** * Erase Flash Dialog class to erase flash on selected com port device @@ -241,72 +238,4 @@ public void run() } } } - - private class EspToolCommands - { - private Process chipInfoProcess; - private Process flashEraseProcess; - - private Process chipInformation(String port) throws Exception - { - destroyAnyChipInfoProcess(); - chipInfoProcess = new ProcessBuilder(getChipInfoCommand(port)).start(); - return chipInfoProcess; - } - - private Process eraseFlash(String port) throws Exception - { - destroyAnyChipInfoProcess(); - flashEraseProcess = new ProcessBuilder(getFlashEraseCommand(port)).start(); - return flashEraseProcess; - } - - private List getChipInfoCommand(String port) - { - List command = new ArrayList(); - command.add(IDFUtil.getIDFPythonEnvPath()); - command.add(IDFUtil.getEspToolScriptFile().getAbsolutePath()); - command.add("-p"); //$NON-NLS-1$ - command.add(port); - command.add(IDFConstants.ESP_TOOL_CHIP_ID_CMD); - return command; - } - - private List getFlashEraseCommand(String port) - { - List command = new ArrayList(); - command.add(IDFUtil.getIDFPythonEnvPath()); - command.add(IDFUtil.getEspToolScriptFile().getAbsolutePath()); - command.add("-p"); //$NON-NLS-1$ - command.add(port); - command.add(IDFConstants.ESP_TOOL_ERASE_FLASH_CMD); - return command; - } - - private void destroyAnyChipInfoProcess() - { - if (chipInfoProcess != null && chipInfoProcess.isAlive()) - { - chipInfoProcess.destroy(); - } - } - - private boolean checkActiveFlashEraseProcess() - { - if (flashEraseProcess != null) - { - return flashEraseProcess.isAlive(); - } - - return false; - } - - private void killEraseFlashProcess() - { - if (flashEraseProcess != null) - { - flashEraseProcess.destroy(); - } - } - } }