blob: 026b13e5eec3c0ac3ef12641310b2479c57343d4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2016 Wind River Systems, Inc. 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:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.cdt.debug.ui.memory.transport;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import org.eclipse.cdt.debug.ui.memory.transport.model.IMemoryExporter;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IMemoryBlockExtension;
import org.eclipse.debug.core.model.MemoryByte;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
public class SRecordExporter implements IMemoryExporter
{
File fOutputFile;
BigInteger fStartAddress;
BigInteger fEndAddress;
private Text fStartText;
private Text fEndText;
private Text fLengthText;
private Text fFileText;
private IMemoryBlock fMemoryBlock;
private ExportMemoryDialog fParentDialog;
private IDialogSettings fProperties;
public Control createControl(final Composite parent, IMemoryBlock memBlock, IDialogSettings properties, ExportMemoryDialog parentDialog)
{
fMemoryBlock = memBlock;
fParentDialog = parentDialog;
fProperties = properties;
Composite composite = new Composite(parent, SWT.NONE)
{
public void dispose()
{
fProperties.put(TRANSFER_FILE, fFileText.getText().trim());
fProperties.put(TRANSFER_START, fStartText.getText().trim());
fProperties.put(TRANSFER_END, fEndText.getText().trim());
try
{
fStartAddress = getStartAddress();
fEndAddress = getEndAddress();
fOutputFile = getFile();
}
catch(Exception e) {}
super.dispose();
}
};
FormLayout formLayout = new FormLayout();
formLayout.spacing = 5;
formLayout.marginWidth = formLayout.marginHeight = 9;
composite.setLayout(formLayout);
// start address
Label startLabel = new Label(composite, SWT.NONE);
startLabel.setText(Messages.getString("SRecordExporter.StartAddress")); //$NON-NLS-1$
FormData data = new FormData();
startLabel.setLayoutData(data);
fStartText = new Text(composite, SWT.BORDER);
data = new FormData();
data.left = new FormAttachment(startLabel);
data.width = 120;
fStartText.setLayoutData(data);
// end address
Label endLabel = new Label(composite, SWT.NONE);
endLabel.setText(Messages.getString("SRecordExporter.EndAddress")); //$NON-NLS-1$
data = new FormData();
data.top = new FormAttachment(fStartText, 0, SWT.CENTER);
data.left = new FormAttachment(fStartText);
endLabel.setLayoutData(data);
fEndText = new Text(composite, SWT.BORDER);
data = new FormData();
data.top = new FormAttachment(fStartText, 0, SWT.CENTER);
data.left = new FormAttachment(endLabel);
data.width = 120;
fEndText.setLayoutData(data);
// length
Label lengthLabel = new Label(composite, SWT.NONE);
lengthLabel.setText(Messages.getString("SRecordExporter.Length")); //$NON-NLS-1$
data = new FormData();
data.top = new FormAttachment(fStartText, 0, SWT.CENTER);
data.left = new FormAttachment(fEndText);
lengthLabel.setLayoutData(data);
fLengthText = new Text(composite, SWT.BORDER);
data = new FormData();
data.top = new FormAttachment(fStartText, 0, SWT.CENTER);
data.left = new FormAttachment(lengthLabel);
data.width = 120;
fLengthText.setLayoutData(data);
// file
Label fileLabel = new Label(composite, SWT.NONE);
fFileText = new Text(composite, SWT.BORDER);
Button fileButton = new Button(composite, SWT.PUSH);
fileLabel.setText(Messages.getString("Exporter.FileName")); //$NON-NLS-1$
data = new FormData();
data.top = new FormAttachment(fileButton, 0, SWT.CENTER);
fileLabel.setLayoutData(data);
data = new FormData();
data.top = new FormAttachment(fileButton, 0, SWT.CENTER);
data.left = new FormAttachment(fileLabel);
data.width = 360;
fFileText.setLayoutData(data);
fileButton.setText(Messages.getString("Exporter.Browse")); //$NON-NLS-1$
data = new FormData();
data.top = new FormAttachment(fLengthText);
data.left = new FormAttachment(fFileText);
fileButton.setLayoutData(data);
// Restriction notice about 32-bit support
Label spacingLabel = new Label(composite, SWT.NONE);
spacingLabel.setText(""); //$NON-NLS-1$
data = new FormData();
data.left = new FormAttachment(0);
data.top = new FormAttachment(fileLabel);
spacingLabel.setLayoutData(data);
Label restrictionLabel = new Label(composite, SWT.NONE);
restrictionLabel.setText(Messages.getString("SRecordExporter.32BitLimitationMessage")); //$NON-NLS-1$
data = new FormData();
data.left = new FormAttachment(0);
data.top = new FormAttachment(spacingLabel);
restrictionLabel.setLayoutData(data);
String textValue = fProperties.get(TRANSFER_FILE);
fFileText.setText(textValue != null ? textValue : ""); //$NON-NLS-1$
textValue = fProperties.get(TRANSFER_START);
fStartText.setText(textValue != null ? textValue : "0x0"); //$NON-NLS-1$
try
{
getStartAddress();
}
catch(Exception e)
{
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
textValue = fProperties.get(TRANSFER_END);
fEndText.setText(textValue != null ? textValue : "0x0"); //$NON-NLS-1$
try
{
getEndAddress();
}
catch(Exception e)
{
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
try
{
BigInteger length = getEndAddress().subtract(getStartAddress());
fLengthText.setText(length.toString());
if(length.compareTo(BigInteger.ZERO) <= 0) {
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
}
catch(Exception e)
{
fLengthText.setText("0");
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
fileButton.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
// TODO Auto-generated method stub
}
public void widgetSelected(SelectionEvent e) {
FileDialog dialog = new FileDialog(parent.getShell(), SWT.SAVE);
dialog.setText(Messages.getString("SRecordExporter.ChooseFile")); //$NON-NLS-1$
dialog.setFilterExtensions(new String[] { "*.*;*" } ); //$NON-NLS-1$
dialog.setFilterNames(new String[] { Messages.getString("Exporter.AllFiles") } ); //$NON-NLS-1$
dialog.setFileName(fFileText.getText().trim());
dialog.open();
String filename = dialog.getFileName();
if(filename != null && filename.length() != 0 )
{
fFileText.setText(dialog.getFilterPath() + File.separator + filename);
}
validate();
}
});
fStartText.addKeyListener(new KeyListener() {
public void keyReleased(KeyEvent e) {
try
{
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
BigInteger startAddress = getStartAddress();
BigInteger actualLength = getEndAddress().subtract(startAddress);
fLengthText.setText(actualLength.toString());
if(actualLength.compareTo(BigInteger.ZERO) <= 0) {
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
if(startAddress.compareTo(BigInteger.ZERO) < 0) {
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
BigInteger endAddress = getEndAddress();
if(endAddress.compareTo(BigInteger.ZERO) < 0) {
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
}
catch(Exception ex)
{
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
validate();
}
public void keyPressed(KeyEvent e) {}
});
fEndText.addKeyListener(new KeyListener() {
public void keyReleased(KeyEvent e) {
try
{
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
BigInteger actualLength = getEndAddress().subtract(getStartAddress());
fLengthText.setText(actualLength.toString());
if(actualLength.compareTo(BigInteger.ZERO) <= 0) {
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
BigInteger startAddress = getStartAddress();
if(startAddress.compareTo(BigInteger.ZERO) < 0) {
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
BigInteger endAddress = getEndAddress();
if(endAddress.compareTo(BigInteger.ZERO) < 0) {
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
}
catch(Exception ex)
{
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
validate();
}
public void keyPressed(KeyEvent e) {}
});
fLengthText.addKeyListener(new KeyListener() {
public void keyReleased(KeyEvent e) {
try
{
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
fStartText.setText(fStartText.getText().trim());
BigInteger length = getLength();
String endString;
BigInteger startAddress = getStartAddress();
BigInteger endAddress = startAddress.add(length);
if(length.compareTo(BigInteger.ZERO) <= 0) {
if(endAddress.compareTo(BigInteger.ZERO) < 0) {
endString = endAddress.toString(16); //$NON-NLS-1$
}
else {
endString = "0x" + endAddress.toString(16); //$NON-NLS-1$
}
}
else {
endString = "0x" + endAddress.toString(16); //$NON-NLS-1$
}
fEndText.setText(endString);
if(length.compareTo(BigInteger.ZERO) <= 0) {
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
if(startAddress.compareTo(BigInteger.ZERO) < 0) {
fStartText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
if(endAddress.compareTo(BigInteger.ZERO) < 0) {
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
}
catch(Exception ex)
{
if ( fLengthText.getText().trim().length() != 0 ) {
fEndText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
fLengthText.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
}
validate();
}
public void keyPressed(KeyEvent e) {
}
});
fFileText.addKeyListener(new KeyListener() {
public void keyReleased(KeyEvent e) {
validate();
}
public void keyPressed(KeyEvent e) {
}
});
composite.pack();
parent.pack();
/*
* We need to perform a validation. If we do it immediately we will get an exception
* because things are not totally setup. So we schedule an immediate running of the
* validation. For a very brief time the view logically may show a state which does
* not reflect the true state of affairs. But the validate immediately corrects the
* info. In practice the user never sees the invalid state displayed, because of the
* speed of the draw of the dialog.
*/
Display.getDefault().asyncExec(new Runnable(){
public void run()
{
validate();
}
});
return composite;
}
public BigInteger getEndAddress()
{
String text = fEndText.getText();
text = text.trim();
boolean hex = text.startsWith("0x"); //$NON-NLS-1$
BigInteger endAddress = new BigInteger(hex ? text.substring(2) : text,
hex ? 16 : 10);
if ( endAddress.bitLength() > 32 ) {
throw(new NumberFormatException("End Address is larger than 32 bits"));
}
return endAddress;
}
public BigInteger getStartAddress()
{
String text = fStartText.getText();
text = text.trim();
boolean hex = text.startsWith("0x"); //$NON-NLS-1$
BigInteger startAddress = new BigInteger(hex ? text.substring(2) : text,
hex ? 16 : 10);
if ( startAddress.bitLength() > 32 ) {
throw(new NumberFormatException("Start Address is larger than 32 bits"));
}
return startAddress;
}
public BigInteger getLength()
{
String text = fLengthText.getText();
text = text.trim();
boolean hex = text.startsWith("0x"); //$NON-NLS-1$
BigInteger lengthAddress = new BigInteger(hex ? text.substring(2) : text,
hex ? 16 : 10);
return lengthAddress;
}
public File getFile()
{
return new File(fFileText.getText().trim());
}
private void validate()
{
boolean isValid = true;
try
{
getEndAddress();
getStartAddress();
BigInteger length = getLength();
if(length.compareTo(BigInteger.ZERO) <= 0)
isValid = false;
if ( fFileText.getText().trim().length() == 0 )
isValid = false;
File file = getFile();
if ( file != null ) {
File parentFile = file.getParentFile();
if(parentFile != null && ! parentFile.exists() )
isValid = false;
if(parentFile != null && parentFile.exists() && ( ! parentFile.canRead() || ! parentFile.isDirectory() ) )
isValid = false;
if ( file.isDirectory() )
isValid = false;
}
}
catch(Exception e)
{
isValid = false;
}
fParentDialog.setValid(isValid);
}
public String getId()
{
return "srecord"; //$NON-NLS-1$
}
public String getName()
{
return Messages.getString("SRecordExporter.Name"); //$NON-NLS-1$
}
public void exportMemory()
{
Job job = new Job("Memory Export to S-Record File"){ //$NON-NLS-1$
public IStatus run(IProgressMonitor monitor) {
try
{
// FIXME 4 byte default
BigInteger DATA_PER_RECORD = BigInteger.valueOf(16);
BigInteger transferAddress = fStartAddress;
FileWriter writer = new FileWriter(fOutputFile);
BigInteger jobs = fEndAddress.subtract(transferAddress).divide(DATA_PER_RECORD);
BigInteger factor = BigInteger.ONE;
if(jobs.compareTo(BigInteger.valueOf(0x7FFFFFFF)) > 0)
{
factor = jobs.divide(BigInteger.valueOf(0x7FFFFFFF));
jobs = jobs.divide(factor);
}
monitor.beginTask(Messages.getString("Exporter.ProgressTitle"), jobs.intValue()); //$NON-NLS-1$
BigInteger jobCount = BigInteger.ZERO;
while(transferAddress.compareTo(fEndAddress) < 0 && !monitor.isCanceled())
{
BigInteger length = DATA_PER_RECORD;
if(fEndAddress.subtract(transferAddress).compareTo(length) < 0)
length = fEndAddress.subtract(transferAddress);
monitor.subTask(String.format(Messages.getString("Exporter.Progress"), length.toString(10), transferAddress.toString(16))); //$NON-NLS-1$
writer.write("S3"); // FIXME 4 byte address //$NON-NLS-1$
StringBuilder buf = new StringBuilder();
BigInteger sRecordLength = BigInteger.valueOf(4); // address size
sRecordLength = sRecordLength.add(length);
sRecordLength = sRecordLength.add(BigInteger.ONE); // checksum
String transferAddressString = transferAddress.toString(16);
String lengthString = sRecordLength.toString(16);
if(lengthString.length() == 1)
buf.append("0"); //$NON-NLS-1$
buf.append(lengthString);
for(int i = 0; i < 8 - transferAddressString.length(); i++)
buf.append("0"); //$NON-NLS-1$
buf.append(transferAddressString);
// data
MemoryByte bytes[] = ((IMemoryBlockExtension) fMemoryBlock).getBytesFromAddress(transferAddress,
length.longValue() / ((IMemoryBlockExtension) fMemoryBlock).getAddressableSize());
for(int byteIndex = 0; byteIndex < bytes.length; byteIndex++)
{
String bString = BigInteger.valueOf(0xFF & bytes[byteIndex].getValue()).toString(16);
if(bString.length() == 1)
buf.append("0"); //$NON-NLS-1$
buf.append(bString);
}
/*
* The least significant byte of the one's complement of the sum of the values
* represented by the pairs of characters making up the records length, address,
* and the code/data fields.
*/
byte checksum = 0;
for(int i = 0; i < buf.length(); i+=2)
{
BigInteger value = new BigInteger(buf.substring(i, i+2), 16);
checksum += value.byteValue();
}
String bString = BigInteger.valueOf(0xFF - checksum).and(BigInteger.valueOf(0xFF)).toString(16);
if(bString.length() == 1)
buf.append("0"); //$NON-NLS-1$
buf.append(bString);
writer.write(buf.toString().toUpperCase());
writer.write("\n"); //$NON-NLS-1$
transferAddress = transferAddress.add(length);
jobCount = jobCount.add(BigInteger.ONE);
if(jobCount.compareTo(factor) == 0)
{
jobCount = BigInteger.ZERO;
monitor.worked(1);
}
}
writer.close();
monitor.done();
} catch (IOException ex) {
MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrFile"), ex)); //$NON-NLS-1$
return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrFile"), ex); //$NON-NLS-1$
} catch (DebugException ex) {
MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrReadTarget"), ex)); //$NON-NLS-1$
return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrReadTarget"), ex); //$NON-NLS-1$
} catch (Exception ex) {
MemoryTransportPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.INTERNAL_ERROR, Messages.getString("Exporter.Falure"), ex)); //$NON-NLS-1$
return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.INTERNAL_ERROR, Messages.getString("Exporter.Falure"), ex); //$NON-NLS-1$
}
return Status.OK_STATUS;
}};
job.setUser(true);
job.schedule();
}
}