/*******************************************************************************
* Copyright (c) 2008, 2011 Thomas Holland (thomas@innot.de) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Thomas Holland - initial API and implementation
*******************************************************************************/
package de.innot.avreclipse.ui.editors;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWTException;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.progress.UIJob;
import de.innot.avreclipse.core.avrdude.AVRDudeException;
import de.innot.avreclipse.core.avrdude.AVRDudeSchedulingRule;
import de.innot.avreclipse.core.avrdude.ProgrammerConfig;
import de.innot.avreclipse.core.toolinfo.AVRDude;
import de.innot.avreclipse.core.toolinfo.fuses.ByteValues;
import de.innot.avreclipse.ui.actions.ActionType;
import de.innot.avreclipse.ui.dialogs.AVRDudeErrorDialogJob;
import de.innot.avreclipse.ui.dialogs.FileMCUMismatchDialog;
import de.innot.avreclipse.ui.dialogs.SelectProgrammerDialog;
/**
* A <code>IFormPart</code> that adds an action to the form toolbar to read the values from a
* programmer.
*
* @see AbstractActionPart
*
* @author Thomas Holland
* @since 2.3
*
*/
public class MCUReadActionPart extends AbstractActionPart {
/*
* (non-Javadoc)
*
* @see de.innot.avreclipse.ui.editors.AbstractActionPart#getAction()
*/
@Override
protected IAction[] getAction() {
ActionType type = ActionType.READ;
Action readAction = new Action() {
@Override
public void run() {
// Open the "Change MCU" dialog
SelectProgrammerDialog dialog = new SelectProgrammerDialog(getManagedForm()
.getForm().getShell(), null);
if (dialog.open() == IDialogConstants.OK_ID) {
ProgrammerConfig progcfg = dialog.getResult();
readFuseBytesFromDevice(progcfg);
}
}
};
type.setupAction(readAction);
IAction[] allactions = new IAction[1];
allactions[0] = readAction;
return allactions;
}
/**
* Load the Bytes from the currently attached MCU.
*/
private void readFuseBytesFromDevice(final ProgrammerConfig progcfg) {
// Set the form busy. It is restored from the job.
getManagedForm().getForm().setBusy(true);
// The Job that does the actual loading.
Job readJob = new Job("Reading Fuse Bytes") {
@Override
protected IStatus run(IProgressMonitor monitor) {
final ScrolledForm form = getManagedForm().getForm();
try {
monitor.beginTask("Starting AVRDude", 100);
// Read the values from the attached programmer.
final ByteValues newvalues = readByteValues(progcfg, new SubProgressMonitor(
monitor, 95));
// update
if (form.isDisposed()) {
return Status.CANCEL_STATUS;
}
form.getDisplay().syncExec(new Runnable() {
// Run in the UI thread in case we have to open a MCU mismatch dialog.
public void run() {
ByteValues current = getByteValues();
boolean forceMCU = false;
// Check if the mcus are compatible
String projectmcu = getByteValues().getMCUId();
String newmcu = newvalues.getMCUId();
if (current.isCompatibleWith(newmcu)) {
// Compatible MCUs
// Change the MCU type anyway to be consistent
forceMCU = true;
} else {
// No, they are not compatible. Ask the user what to do
// "Convert", "Change" or "Cancel"
Dialog dialog = new FileMCUMismatchDialog(form.getShell(), newmcu,
projectmcu, current.getType());
int choice = dialog.open();
switch (choice) {
case FileMCUMismatchDialog.CANCEL:
return;
case FileMCUMismatchDialog.CHANGE:
// Change project ByteValues to the new MCU and then copy
// the values
forceMCU = true;
break;
case FileMCUMismatchDialog.CONVERT:
// Change the new ByteValues to our MCU and then copy
// the values
forceMCU = false;
break;
}
}
current.setValues(newvalues, forceMCU);
markDirty();
notifyForm();
}
});
monitor.worked(5);
} catch (AVRDudeException ade) {
// Show an Error message and exit
if (!form.isDisposed()) {
UIJob messagejob = new AVRDudeErrorDialogJob(form.getDisplay(), ade,
progcfg.getId());
messagejob.setPriority(Job.INTERACTIVE);
messagejob.schedule();
try {
messagejob.join(); // block until the dialog is closed.
} catch (InterruptedException e) {
// Don't care if the dialog is interrupted from outside.
}
}
} catch (SWTException swte) {
// The display has been disposed, so the user is not
// interested in the results from this job
return Status.CANCEL_STATUS;
} finally {
monitor.done();
// remove the busy cursor
if (!form.isDisposed()) {
form.getDisplay().syncExec(new Runnable() {
public void run() {
form.setBusy(false);
}
});
}
}
return Status.OK_STATUS;
}
};
// now set the Job properties and start it
readJob.setRule(new AVRDudeSchedulingRule(progcfg));
readJob.setPriority(Job.SHORT);
readJob.setUser(true);
readJob.schedule();
}
/**
* Read the bytes values from the attached device.
* <p>
* Depending on the type of the current <code>ByteValues</code> either the FUSES or the
* LOCKBITS are loaded.
* </p>
*
* @param progcfg
* <code>ProgrammerConfig</code> to access the programmer.
* @param monitor
* <code>IProgressMonitor</code> to cancel the operation.
* @return A new <code>ByteValues</code> object representing the state of the attached MCU.
* @throws AVRDudeException
* for any errors during the read operation.
*/
private ByteValues readByteValues(ProgrammerConfig progcfg, IProgressMonitor monitor)
throws AVRDudeException {
switch (getByteValues().getType()) {
case FUSE:
return AVRDude.getDefault().getFuseBytes(progcfg, monitor);
case LOCKBITS:
return AVRDude.getDefault().getLockbits(progcfg, monitor);
default:
// Should not happen.
return null;
}
}
}