/*
AVR8 Burn-O-Mat
Copyright (C) 2007 Torsten Brischalle
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/
*/
package avr8_burn_o_mat;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Vector;
import java.util.logging.Level;
import java.util.prefs.Preferences;
import de.lazyzero.kkMulticopterFlashTool.KKMulticopterFlashTool;
public class AvrdudeControl {
public enum FileFormat { RAW, INTEL_HEX, MOTOROLA_S_RECORD, AUTO_DETECT }
private String m_avrdude;
private String m_avrdudeConfig;
private String m_port = "/dev/parport0";
private Boolean m_disableAutoErase = false;
private Boolean m_exitSpecActivated = false;
private Boolean m_leftResetActivated = false;
private Boolean m_leftVccActivated = false;
private Boolean m_disableFuseCheck = false;
private InterfaceTextOutput m_intfTextOutput;
private AvrdudeProgrammer m_programmer = new AvrdudeProgrammer("stk200","par","STK200");
private AvrdudeConfigFile m_avrdudeConfigFile = new AvrdudeConfigFile();
private String m_additionalOptions = "";
/** Creates a new instance of AVRDUDECtrl
* @param isUSBtiny */
public AvrdudeControl(InterfaceTextOutput intfTextOutput, boolean isUSBtiny) throws IOException {
m_intfTextOutput = intfTextOutput;
String os = System.getProperty("os.name").toLowerCase();
String arch = System.getProperty("os.arch");
System.out.println("OS for avrdude settings is: " + os);
if (os.contains("windows") && !isUSBtiny) {
m_avrdude = System.getProperty("user.dir")+"\\lib\\avrdude\\windows\\avrdude.exe";
m_avrdudeConfig = System.getProperty("user.dir")+"\\lib\\avrdude\\windows\\avrdude.conf";
} else if (os.contains("windows") && isUSBtiny) {
m_avrdude = System.getProperty("user.dir")+"\\lib\\avrdude\\windows\\usbtiny\\avrdude.exe";
m_avrdudeConfig = System.getProperty("user.dir")+"\\lib\\avrdude\\windows\\usbtiny\\avrdude.conf";
} else if (os.contains("mac") && !isUSBtiny) {
String path = System.getProperty("java.library.path");
path = path.substring(0, path.indexOf(":"));
m_avrdude = path + "/lib/avrdude/mac/avrdude";
m_avrdudeConfig = path + "/lib/avrdude/mac/avrdude.conf";
} else if (os.contains("mac") && isUSBtiny) {
String path = System.getProperty("java.library.path");
path = path.substring(0, path.indexOf(":"));
m_avrdude = path + "/lib/avrdude/mac/usbtiny/avrdude";
m_avrdudeConfig = path + "/lib/avrdude/mac/usbtiny/avrdude.conf";
} else if (os.contains("linux")) {
if (arch.equals("amd64")) {
m_avrdude = System.getProperty("user.dir")+"/lib/avrdude/linux64/avrdude";
m_avrdudeConfig = System.getProperty("user.dir")+"/lib/avrdude/linux64/avrdude.conf";
} else {//32-bit branch
if (!isUSBtiny) {
m_avrdude = System.getProperty("user.dir")+"/lib/avrdude/linux/avrdude";
m_avrdudeConfig = System.getProperty("user.dir")+"/lib/avrdude/linux/avrdude.conf";
} else {
m_avrdude = System.getProperty("user.dir")+"/lib/avrdude/linux/usbtiny/avrdude";
m_avrdudeConfig = System.getProperty("user.dir")+"/lib/avrdude/linux/usbtiny/avrdude.conf";
}
}
}
loadPreferences();
}
public Vector <AvrdudeProgrammer> getProgrammerList() {
return m_avrdudeConfigFile.getProgrammerList();
}
public void savePreferences() {
try {
Preferences prefs = Preferences.userNodeForPackage(this.getClass());
prefs.put("Avrdude",m_avrdude);
prefs.put("AvrdudeConfig",m_avrdudeConfig);
prefs.put("Programmer",m_programmer.getId());
prefs.put("Port",m_port);
prefs.put("AdditionalOptions",m_additionalOptions);
prefs.putBoolean("DisableAutoErase",m_disableAutoErase);
prefs.putBoolean("ExitSpecActivated",m_exitSpecActivated);
prefs.putBoolean("LeftResetActivated",m_leftResetActivated);
prefs.putBoolean("LeftVccActivated",m_leftVccActivated);
prefs.putBoolean("DisableFuseCheck",m_disableFuseCheck);
prefs.flush();
} catch (Exception e) {
System.err.println("Error while saving preferences: " + e.getMessage());
}
}
public void loadPreferences() {
try {
Preferences prefs = Preferences.userNodeForPackage(this.getClass());
// m_avrdude = prefs.get("Avrdude",m_avrdude);
// m_avrdudeConfig = prefs.get("AvrdudeConfig",m_avrdudeConfig);
m_port = prefs.get("Port","/dev/parport0");
m_additionalOptions = prefs.get("AdditionalOptions","");
m_disableAutoErase = prefs.getBoolean("DisableAutoErase",false);
m_exitSpecActivated = prefs.getBoolean("ExitSpecActivated",false);
m_leftResetActivated = prefs.getBoolean("LeftResetActivated",false);
m_leftVccActivated = prefs.getBoolean("LeftVccActivated",false);
m_disableFuseCheck = prefs.getBoolean("DisableFuseCheck",false);
String programmer = prefs.get("Programmer","");
m_avrdudeConfigFile.readAvrdudeConfigFile(m_avrdudeConfig);
Vector <AvrdudeProgrammer> progList = m_avrdudeConfigFile.getProgrammerList();
for (AvrdudeProgrammer p : progList) {
if (p.equals(programmer)) {
m_programmer = p;
}
}
} catch (Exception e) {
System.err.println("Error while loading preferences: " + e.getMessage());
}
}
public String getAvrdude() {
return m_avrdude;
}
public void setAvrdude(String avrdude) {
m_avrdude = avrdude;
}
public AvrdudeProgrammer getProgrammer() {
return m_programmer;
}
public void setProgrammer(AvrdudeProgrammer programmer) {
m_programmer = programmer;
}
public String getPort() {
return m_port;
}
public void setPort(String port) {
m_port = port;
}
public String getAdditionalOptions() {
return m_additionalOptions;
}
public void setAdditionalOptions(String additionalOptions) {
m_additionalOptions = additionalOptions;
}
public String getAvrdudeConfig() {
return m_avrdudeConfig;
}
public void setAvrdudeConfig(String avrdudeConfig) {
m_avrdudeConfig = avrdudeConfig;
}
public void addAdditionalOption(String option) {
m_additionalOptions = m_additionalOptions.concat(m_additionalOptions.length()>0?" "+option:option);
}
public void addAndUpdateAdditionalOptions(String additionalOptions) {
if (null != additionalOptions){
String[] addOptions = additionalOptions.split(" ");
for (int i = 0; i < addOptions.length; i++) {
if (addOptions[i].startsWith("-")){
if (m_additionalOptions.contains(addOptions[i])) {
//replace existing option
if (i < addOptions.length-1) {
//check if the option has parameter
if(!addOptions[i+1].startsWith("-")) {
int start = m_additionalOptions.indexOf(addOptions[i]);
int end = (start==0?m_additionalOptions.indexOf("-", 1):m_additionalOptions.indexOf("-", start)) -1;
m_additionalOptions = (start==0?"":m_additionalOptions.substring(0, start)) + (addOptions[i] + " " + addOptions[i+1]) + m_additionalOptions.substring(end);
}
}
} else {
if (i < addOptions.length-1) {
//check if the option has parameter
if(!addOptions[i+1].startsWith("-")) {
addAdditionalOption(addOptions[i] + " " + addOptions[i+1]);
} else {
addAdditionalOption(addOptions[i]);
}
} else {
addAdditionalOption(addOptions[i]);
}
}
}
}
}
}
private void addAdditionalOptions(Vector <String> cmd) {
String[ ] options = m_additionalOptions.split(" ");
for (String o : options) {
cmd.add(o);
}
}
private Vector <String> getCmd(AVR avr) {
Vector <String> cmd = new Vector <String>();
cmd.add(m_avrdude);
//cmd.add("-q");
if (m_disableFuseCheck)
cmd.add("-u");
if (m_avrdudeConfig.length() > 0) {
cmd.add("-C");
cmd.add(m_avrdudeConfig);
}
cmd.add("-p");
cmd.add(avr.getCaptionAliasFree());
cmd.add("-P");
cmd.add(m_port);
cmd.add("-c");
cmd.add(m_programmer.getId());
if (m_disableAutoErase) {
cmd.add("-D");
}
if (m_exitSpecActivated) {
String exitSpec;
if (m_leftResetActivated)
exitSpec = "reset";
else
exitSpec = "noreset";
if (m_leftVccActivated)
exitSpec += ",vcc";
else
exitSpec += ",novcc";
cmd.add("-E");
cmd.add(exitSpec);
}
addAdditionalOptions(cmd);
return cmd;
}
public void readFuses(AVR avr, String path) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
// if (!m_disableFuseCheck)
// cmd.add("-u");
cmd.add("-U");
cmd.add(String.format("lfuse:r:%s:r", path + "/lfuse.hex"));
cmd.add("-U");
cmd.add(String.format("hfuse:r:%s:r", path + "/hfuse.hex"));
// AVRDUDE starten
int exitValue = startAvrdudeFusesReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error reading fuses!");
}
// Fuses aus Datei lesen
FileInputStream fs = new FileInputStream(path + "/lfuse.hex");
int data = fs.read();
avr.setLfuse(data + "");
fs.close();
fs = new FileInputStream(path + "/hfuse.hex");
data = fs.read();
avr.setHfuse(data + "");
fs.close();
}
public void writeFuses(AVR avr) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
//
// if (!m_disableFuseCheck)
// cmd.add("-u");
cmd.add("-U");
cmd.add(String.format("lfuse:w:%s:m",avr.getLfuse()));
cmd.add("-U");
cmd.add(String.format("hfuse:w:%s:m",avr.getHfuse()));
if (avr.getEfuse() != null) {
cmd.add("-U");
cmd.add(String.format("efuse:w:%s:m", avr.getEfuse()));
}
// AVRDUDE starten
int exitValue = startAvrdudeFusesReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error writing fuses!");
}
}
public void verifyFuses(AVR avr) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
//if (!m_disableFuseCheck)
// cmd.add("-u");
cmd.add("-U");
cmd.add(String.format("lfuse:v:0x%s:m",avr.getLfuse()));
cmd.add("-U");
cmd.add(String.format("hfuse:v:0x%s:m",avr.getHfuse()));
// AVRDUDE starten
int exitValue = startAvrdudeFusesReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error verifying fuses!");
}
}
public void readFlash(AVR avr, String filename, FileFormat fileFormat) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
cmd.add("-U");
cmd.add(String.format("flash:r:%s:%s",filename,FileFormat2AvrdudeOption(fileFormat)));
// AVRDUDE starten
int exitValue = startAvrdudeFlashReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error reading flash!");
}
}
public void writeFlash(AVR avr, String filename, FileFormat fileFormat) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
cmd.add("-U");
cmd.add(String.format("flash:w:%s:%s",filename,FileFormat2AvrdudeOption(fileFormat)));
// AVRDUDE starten
int exitValue = startAvrdudeFlashReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error writing flash!");
}
}
public void verifyFlash(AVR avr, String filename, FileFormat fileFormat) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
cmd.add("-U");
cmd.add(String.format("flash:v:%s:%s",filename,FileFormat2AvrdudeOption(fileFormat)));
// AVRDUDE starten
int exitValue = startAvrdudeFlashReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error verifying flash!");
}
}
public void readEEPROM(AVR avr, String filename, FileFormat fileFormat) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
cmd.add("-U");
cmd.add(String.format("eeprom:r:%s:%s",filename,FileFormat2AvrdudeOption(fileFormat)));
// AVRDUDE starten
int exitValue = startAvrdudeFlashReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error reading EEPROM!");
}
}
public void writeEEPROM(AVR avr, String filename, FileFormat fileFormat) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
cmd.add("-U");
cmd.add(String.format("eeprom:w:%s:%s",filename,FileFormat2AvrdudeOption(fileFormat)));
// AVRDUDE starten
int exitValue = startAvrdudeFlashReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error writing EEPROM!");
}
}
public void verifyEEPROM(AVR avr, String filename, FileFormat fileFormat) throws Exception {
// Kommandostring zusammen bauen
Vector <String> cmd = getCmd(avr);
cmd.add("-U");
cmd.add(String.format("eeprom:v:%s:%s",filename,FileFormat2AvrdudeOption(fileFormat)));
// AVRDUDE starten
int exitValue = startAvrdudeFlashReadWrite(cmd);
if (exitValue != 0) {
throw new Exception("Error verifying EEPROM!");
}
}
private int startAvrdudeFusesReadWrite(Vector <String> cmd) throws Exception {
//m_intfTextOutput.clearText();
m_intfTextOutput.println("");
for (String s : cmd) {
m_intfTextOutput.print(s + " ");
}
m_intfTextOutput.println("");
String [] cmdArray = new String [cmd.size()];
cmd.toArray(cmdArray);
final Process p = Runtime.getRuntime().exec(cmdArray);
new Thread() {
public void run() {
int line;
BufferedInputStream bis = new BufferedInputStream(p.getErrorStream());
try {
while ((line = bis.read()) != -1) {
m_intfTextOutput.print(((char)line)+"");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
new Thread() {
public void run() {
int line;
BufferedInputStream bis = new BufferedInputStream(p.getInputStream());
try {
while ((line = bis.read()) != -1) {
m_intfTextOutput.print(((char)line)+"");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
KKMulticopterFlashTool.getLogger().log(Level.INFO, m_intfTextOutput.getText());
System.out.println("start waiting for the process to finish.");
p.waitFor();
System.out.println("process finished.");
return p.exitValue();
}
private int startAvrdudeFlashReadWrite(Vector <String> cmd) throws Exception {
m_intfTextOutput.println("");
for (String s : cmd) {
m_intfTextOutput.print(s + " ");
}
m_intfTextOutput.println("");
String [] cmdArray = new String [cmd.size()];
cmd.toArray(cmdArray);
final Process p = Runtime.getRuntime().exec(cmdArray);
new Thread() {
public void run() {
int line;
BufferedInputStream bis = new BufferedInputStream(p.getErrorStream());
try {
while ((line = bis.read()) != -1) {
m_intfTextOutput.print(((char)line)+"");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
new Thread() {
public void run() {
int line;
BufferedInputStream bis = new BufferedInputStream(p.getInputStream());
try {
while ((line = bis.read()) != -1) {
m_intfTextOutput.print(((char)line)+"");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
p.waitFor();
return p.exitValue();
}
private String FileFormat2AvrdudeOption(FileFormat fileFormat) {
switch (fileFormat) {
case RAW: return "r";
case INTEL_HEX: return "i";
case MOTOROLA_S_RECORD: return "s";
case AUTO_DETECT: return "a";
default:
assert false;
return "";
}
}
static public FileFormat String2FileFormat(String fileFormat) {
if (fileFormat.equals("Intel Hex"))
return FileFormat.INTEL_HEX;
else if (fileFormat.equals("Motorola S-record"))
return FileFormat.MOTOROLA_S_RECORD;
else if (fileFormat.equals("raw"))
return FileFormat.RAW;
else
return FileFormat.AUTO_DETECT;
}
public Boolean getDisableAutoErase() {
return m_disableAutoErase;
}
public void setDisableAutoErase(Boolean disableAutoErase) {
m_disableAutoErase = disableAutoErase;
}
public Boolean getExitSpecActivated() {
return m_exitSpecActivated;
}
public void setExitSpecActivated(Boolean exitSpecActivated) {
m_exitSpecActivated = exitSpecActivated;
}
public Boolean getLeftResetActivated() {
return m_leftResetActivated;
}
public void setLeftResetActivated(Boolean leftResetActivated) {
m_leftResetActivated = leftResetActivated;
}
public Boolean getLeftVccActivated() {
return m_leftVccActivated;
}
public void setLeftVccActivated(Boolean leftVccActivated) {
m_leftVccActivated = leftVccActivated;
}
public Boolean getDisableFuseCheck() {
return m_disableFuseCheck;
}
public void setDisableFuseCheck(Boolean disableFuseCheck) {
m_disableFuseCheck = disableFuseCheck;
}
}