package io.sloeber.core.communication; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.ui.console.MessageConsoleStream; import io.sloeber.core.api.BoardDescriptor; import io.sloeber.core.api.Serial; import io.sloeber.core.common.Common; import io.sloeber.core.common.Const; public class ArduinoSerial { private ArduinoSerial() { } /** * This method resets arduino based on setting the baud rate. Used for due, * Leonardo and others * * @param comPort * The port to set the baud rate * @param bautrate * The baud rate to set * @return true is successful otherwise false */ public static boolean reset_Arduino_by_baud_rate(String comPort, int baudRate, long openTime) { Serial serialPort; try { serialPort = new Serial(comPort, baudRate); serialPort.setDTR(false); } catch (Exception e) { e.printStackTrace(); Common.log(new Status(IStatus.WARNING, Const.CORE_PLUGIN_ID, Messages.ArduinoSerial_Unable_To_Open_Port + comPort, e)); return false; } try { Thread.sleep(openTime); } catch (InterruptedException e) {// Jaba is not going to write this // code } serialPort.dispose(); return true; } /** * Waits for a serial port to appear. It is assumed that the default comport * is not available on the system * * @param originalPorts * The ports available on the system * @param defaultComPort * The port to return if no new com port is found * @return the new comport if found else the defaultComPort */ public static String wait_for_com_Port_to_appear(MessageConsoleStream console, List<String> originalPorts, String defaultComPort) { List<String> newPorts; List<String> newPortsCopy; // wait for port to disappear and appear int numTries = 0; int maxTries = 40; // wait for max 10 seconds as arduino does int delayMs = 250; int prefNewPortsCopySize = -10; do { newPorts = Serial.list(); newPortsCopy = new ArrayList<>(newPorts); for (int i = 0; i < originalPorts.size(); i++) { newPortsCopy.remove(originalPorts.get(i)); } /* dump the serial ports to the console */ console.print("PORTS {"); //$NON-NLS-1$ for (int i = 0; i < originalPorts.size(); i++) { console.print(' ' + originalPorts.get(i) + ','); } console.print("} / {"); //$NON-NLS-1$ for (int i = 0; i < newPorts.size(); i++) { console.print(' ' + newPorts.get(i) + ','); } console.print("} => {"); //$NON-NLS-1$ for (int i = 0; i < newPortsCopy.size(); i++) { console.print(' ' + newPortsCopy.get(i) + ','); } console.println("}"); //$NON-NLS-1$ /* end of dump to the console */ // code to capture the case: the com port reappears with a name that // was in the original list int newPortsCopySize = newPorts.size(); if ((newPortsCopy.isEmpty()) && (newPortsCopySize == prefNewPortsCopySize + 1)) { console.println(Messages.ArduinoSerial_Comport_Appeared_and_disappeared); return defaultComPort; } prefNewPortsCopySize = newPortsCopySize; if (numTries++ > maxTries) { console.println(Messages.ArduinoSerial_Comport_is_not_behaving_as_expected); return defaultComPort; } if (newPortsCopy.isEmpty()) // wait a while before we do the next // try { try { Thread.sleep(delayMs); } catch (InterruptedException e) {// Jaba is not going to write // this // code } } } while (newPortsCopy.isEmpty()); console.println( Messages.ArduinoSerial_Comport_reset_took + (numTries * delayMs) + Messages.ArduinoSerial_miliseconds); return newPortsCopy.get(0); } /** * Toggle DTR this is a way to reset an arduino board * * @param Port * the port to toggle * @param delay * the time to wait between the 2 toggle commands * @return true is successful otherwise false */ public static boolean ToggleDTR(Serial serialPort, long delay) { serialPort.setDTR(false); serialPort.setRTS(false); try { Thread.sleep(delay); } catch (InterruptedException e) {// Jaba is not going to write this // code } serialPort.setDTR(true); serialPort.setRTS(true); return true; } /** * reset the arduino * * This method takes into account all the setting to be able to reset all * different types of arduino If RXTXDisabled is set the method only return * the parameter Comport * * @param project * The project related to the com port to reset * @param comPort * The name of the com port to reset * @return The com port to upload to */ public static String makeArduinoUploadready(MessageConsoleStream console, IProject project, String configName, BoardDescriptor boardDescriptor) { boolean use_1200bps_touch = Common .getBuildEnvironmentVariable(project, configName, Const.ENV_KEY_UPLOAD_USE_1200BPS_TOUCH, Const.FALSE) .equalsIgnoreCase(Const.TRUE); boolean bWaitForUploadPort = Common .getBuildEnvironmentVariable(project, configName, Const.ENV_KEY_WAIT_FOR_UPLOAD_PORT, Const.FALSE) .equalsIgnoreCase(Const.TRUE); String comPort = boardDescriptor.getUploadPort(); String boardName = boardDescriptor.getBoardName(); String uploadProtocol = Common.getBuildEnvironmentVariable(project, configName, Common.get_ENV_KEY_PROTOCOL(Const.ACTION_UPLOAD), new String()); boolean bResetPortForUpload = Common .getBuildEnvironmentVariable(project, configName, Const.ENV_KEY_RESET_BEFORE_UPLOAD, Const.TRUE) .equalsIgnoreCase(Const.TRUE); /* * Teensy uses halfkay protocol and does not require a reset in * boards.txt use Const.ENV_KEY_RESET_BEFORE_UPLOAD=FALSE to disable a * reset */ if (!bResetPortForUpload || uploadProtocol.equalsIgnoreCase("halfkay")) { //$NON-NLS-1$ return comPort; } /* * if the com port can not be found and no specific com port reset * method is specified assume it is a network port and do not try to * reset */ List<String> originalPorts = Serial.list(); if (!originalPorts.contains(comPort) && !use_1200bps_touch && !bWaitForUploadPort) { console.println(Messages.ArduinoSerial_comport_not_found); return comPort; } if (use_1200bps_touch) { // Get the list of the current com serial ports console.println(Messages.ArduinoSerial_Using_1200bps_touch + comPort); if (!reset_Arduino_by_baud_rate(comPort, 1200, 400) /* || */) { console.println(Messages.ArduinoSerial_reset_failed); } else { if (boardName.startsWith("Digistump DigiX")) { //$NON-NLS-1$ // Give the DUE/DigiX Atmel SAM-BA bootloader time to // switch-in after the reset try { Thread.sleep(2000); } catch (InterruptedException ex) { // ignore error } } if (bWaitForUploadPort) { String newComport = wait_for_com_Port_to_appear(console, originalPorts, comPort); console.println(Messages.ArduinoSerial_Using_comport + newComport + Messages.ArduinoSerial_From_Now_Onwards); console.println(Messages.ArduinoSerial_Ending_reset); return newComport; } } console.println(Messages.ArduinoSerial_Continuing_to_use + comPort); console.println(Messages.ArduinoSerial_Ending_reset); return comPort; } // connect to the serial port console.println(Messages.ArduinoSerial_reset_dtr_toggle); Serial serialPort; try { serialPort = new Serial(comPort, 9600); } catch (Exception e) { e.printStackTrace(); Common.log(new Status(IStatus.WARNING, Const.CORE_PLUGIN_ID, Messages.ArduinoSerial_exception_while_opening_seral_port + comPort, e)); console.println(Messages.ArduinoSerial_exception_while_opening_seral_port + comPort); console.println(Messages.ArduinoSerial_Continuing_to_use + comPort); console.println(Messages.ArduinoSerial_Ending_reset); return comPort; } if (!serialPort.IsConnected()) { Common.log(new Status(IStatus.WARNING, Const.CORE_PLUGIN_ID, Messages.ArduinoSerial_unable_to_open_serial_port + comPort, null)); console.println(Messages.ArduinoSerial_exception_while_opening_seral_port + comPort); console.println(Messages.ArduinoSerial_Continuing_to_use + comPort); console.println(Messages.ArduinoSerial_Ending_reset); return comPort; } console.println(Messages.ArduinoSerial_23); ToggleDTR(serialPort, 100); serialPort.dispose(); console.println(Messages.ArduinoSerial_Continuing_to_use + comPort); console.println(Messages.ArduinoSerial_Ending_reset); return comPort; } }