/*******************************************************************************
* 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.core.toolinfo.fuses;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import de.innot.avreclipse.AVRPlugin;
import de.innot.avreclipse.core.toolinfo.fuses.ConversionResults.ConversionStatus;
/**
* A container for byte values.
* <p>
* This class holds the actual byte values for either the Fuse bytes or a Lockbit byte. These byte
* values are only valid for the current MCU type.
* </p>
* <p>
* This class can notify registered {@link IByteValuesChangeListener}'s about changes to the value
* of the stored bytes.
* </p>
*
* @author Thomas Holland
* @since 2.2
* @since 2.3 Change listeners
*
*/
public class ByteValues {
/** The type of Bytes, FUSE oder LOCKBITS */
private final FuseType fType;
/** The MCU for which the byte values are valid. */
private String fMCUId;
/** The number of bytes in this object */
private int fByteCount;
/** The actual byte values. */
private int[] fValues;
/** Map of all bitfield descriptions mapped to their name for easy access */
private Map<String, BitFieldDescription> fBitFieldNames;
/** A user provided comment for this ByteValue object. */
private String fComment;
/**
* The results of the last conversion, if this <code>ByteValues</code> object has had its MCU
* changed.
*/
private ConversionResults fConversionResults;
/** List of all registered Listeners. */
private ListenerList fListenerList;
/** Name of the {@link ByteValueChangeEvent} in case the MCU has been changed. */
public final static String MCU_CHANGE_EVENT = "mcuChangeEvent";
/** Name of the {@link ByteValueChangeEvent} in case the Comment has been changed. */
public final static String COMMENT_CHANGE_EVENT = "commentChangeEvent";
/**
* Create a new byte values container for a given MCU.
* <p>
* All values are cleared (set to <code>-1</code>).
* </p>
*
* @param type
* Either <code>FuseType.FUSE</code> or <code>FuseType.LOCKBITS</code>.
* @param mcuid
* <code>String</code> with a MCU id value.
*/
public ByteValues(FuseType type, String mcuid) {
Assert.isNotNull(mcuid);
fType = type;
fMCUId = mcuid;
fByteCount = loadByteCount();
fValues = new int[fByteCount];
clearValues();
fComment = null;
fConversionResults = null;
}
/**
* Clone constructor.
* <p>
* Creates a new byte values container and copies all values (and the MCU id) from the source.
* </p>
* <p>
* The list of change listeners from the source object is <em>not</em> copied.
* </p>
*
* @param source
* <code>ByteValues</code> object to clone.
*/
public ByteValues(ByteValues source) {
Assert.isNotNull(source);
fType = source.fType;
fMCUId = source.fMCUId;
fByteCount = source.fByteCount;
fValues = new int[fByteCount];
System.arraycopy(source.fValues, 0, fValues, 0, fByteCount);
fComment = source.fComment;
fConversionResults = source.fConversionResults;
}
/**
* Get the Fuse type for these byte values.
* <p>
* Currently {@link FuseType#FUSE} and {@link FuseType#LOCKBITS} are the only supported types.
* </p>
*
* @return
*/
public FuseType getType() {
return fType;
}
/**
* Get the MCU associated with this ByteValues object and for which the byte values are valid.
*
* @return <code>String</code> with a MCU id.
*/
public String getMCUId() {
return fMCUId;
}
/**
* Change this <code>ByteValues</code> object to a new MCU.
* <p>
*
*
* @param mcuid
* @param convert
*/
public void setMCUId(String mcuid, boolean convert) {
if (fMCUId.equals(mcuid)) {
// do nothing if the mcu is the same
return;
}
ByteValues conversioncopy = null;
if (convert) {
fConversionResults = new ConversionResults();
conversioncopy = convertTo(mcuid, fConversionResults);
} else {
fConversionResults = null;
}
fMCUId = mcuid;
fByteCount = loadByteCount();
fValues = new int[fByteCount];
fBitFieldNames = null;
// First inform all listeners that we have a new MCU
fireBitFieldChangedEvent(MCU_CHANGE_EVENT, 0, 0, 0);
// and then set the new values (about which the listeners will be informed as well.
if (conversioncopy != null) {
setValues(conversioncopy.getValues());
} else {
clearValues();
}
}
/**
* Get the actual number of bytes supported by the MCU.
* <p>
* Depending on the type of this object either the number of fuse bytes (0 up to 6) or the
* number of lockbits bytes (currently always 1) is returned.
* </p>
* <p>
* If the MCU is not supported <code>0</code> is returned.
* </p>
*
* @return Number of bytes supported by the MCU. Between <code>0</code> and <code>6</code>.
*/
public int getByteCount() {
return fByteCount;
}
/**
* Sets the byte at the given index to a value.
* <p>
* If this object has been converted before, then the status of all BitFields of this Byte are
* set to {@link ConversionStatus#MODIFIED}.
* </p>
*
* @param index
* The index of the byte to set. Must be between 0 and {@link #getByteCount()}-1.
* @param value
* The new value. Must be a byte value (0-255) or -1 to unset the value.
* @throws IllegalArgumentException
* if the index is out of bounds or the value is out of range.
*/
public void setValue(int index, int value) {
checkIndex(index);
if (value < -1 || 255 < value) {
throw new IllegalArgumentException("Value [" + value + "] out of range (-1...255)");
}
fValues[index] = value;
if (fConversionResults != null) {
IMCUDescription desc = getDescription(fMCUId);
IFuseObjectDescription bytedesc = desc.getByteDescription(fType, index);
List<BitFieldDescription> allbfds = bytedesc.getBitFieldDescriptions();
for (BitFieldDescription bfd : allbfds) {
String name = bfd.getName();
fConversionResults.setModified(name);
}
}
fireByteChangedEvent(index, value);
}
/**
* Get the value of the byte with the given index.
*
* @param index
* The index of the byte to read. Must be between 0 and {@link #getByteCount()}-1.
* @return <code>int</code> with a byte value (0-255) or <code>-1</code> if the value is not
* set.
* @throws IllegalArgumentException
* if the index is out of bounds.
*/
public int getValue(int index) {
checkIndex(index);
return fValues[index];
}
/**
* Set all byte values.
* <p>
* Copies all values from the given array to the internal storage. If the given
* <code>int[]</code> has less entries than this class supports, then the remaining bytes are
* untouched. Only {@link #getByteCount()} bytes are copied. Any additional bytes in the source
* array are ignored.
* </p>
* <p>
* The values of the source are not checked.
* </p>
*
* @param newvalues
* Array of <code>int</code> with the new byte values (0 to 255 or -1).
*/
public void setValues(int[] newvalues) {
int count = Math.min(newvalues.length, fValues.length);
System.arraycopy(newvalues, 0, fValues, 0, count);
for (int index = 0; index < count; index++) {
fireByteChangedEvent(index, fValues[index]);
}
}
/**
* Returns an array with all byte values.
* <p>
* The returned array is a copy of the internal structure and any changes to it will not be
* reflected.
* </p>
*
* @return Array of <code>int</code> with the current byte values (0 to 255 or -1).
*/
public int[] getValues() {
// make a copy and return it
int[] copy = new int[fValues.length];
System.arraycopy(fValues, 0, copy, 0, fValues.length);
return copy;
}
/**
* Gets the value of the bitfield with the given name.
* <p>
* The result is the current value of the bitfield, already normalized (range 0 to maxValue).
* </p>
*
* @param name
* The name of the bitfield.
* @return The current value of the bitfield, or <code>-1</code> if the bitfield value is not
* yet set.
* @throws IllegalArgumentException
* if the name of the bitfield is not valid.
*/
public int getNamedValue(String name) {
initBitFieldNames();
BitFieldDescription desc = fBitFieldNames.get(name);
if (desc == null) {
throw new IllegalArgumentException("Bitfield name [" + name + "] is not known.");
}
int index = desc.getIndex();
int value = fValues[index];
if (value == -1)
return value;
return desc.byteToBitField(value);
}
/**
* Sets the value of the bitfield with the given name.
*
* @param name
* The name of the bitfield.
* @param value
* The normalized new value for the bitfield (between 0 to maxValue)
* @throws IllegalArgumentException
* if the name of the bitfield is not valid or the value is out of range (0 to
* maxValue).
*/
public void setNamedValue(String name, int value) {
initBitFieldNames();
BitFieldDescription desc = fBitFieldNames.get(name);
if (desc == null) {
throw new IllegalArgumentException("Bitfield name [" + name + "] is not known.");
}
// clear the conversion results for this BitField (if there is one)
if (fConversionResults != null) {
fConversionResults.setModified(name);
}
// Test if the value is within bounds
if (value < 0 || desc.getMaxValue() < value) {
throw new IllegalArgumentException("Value [" + value + "] out of range (0..."
+ desc.getMaxValue() + ")");
}
int index = desc.getIndex();
// Now left-shift the value to the right place and insert it
// into the current value.
int bitfieldvalue = desc.bitFieldToByte(value);
int oldvalue = fValues[index];
boolean completeByte = false;
if (oldvalue == -1) {
oldvalue = 0xff;
completeByte = true;
}
int newvalue = oldvalue & ~desc.getMask();
newvalue |= bitfieldvalue;
if (completeByte) {
setValue(index, newvalue); // setValue will fire the notifications
} else {
fValues[index] = newvalue;
fireBitFieldChangedEvent(name, value, index, newvalue);
}
}
/**
* Get the descriptive text for the value of the named bitfield.
* <p>
* This method returns a human readable text for the value of the bitfield. This may be one of
* the enumerations from the part description file or some other meaningful text if no
* enumerations have been defined.
* </p>
*
* @see IBitFieldDescription#getValueText(int)
* @param name
* The name of the BitField.
* @return Human readable string
*
*/
public String getNamedValueText(String name) {
initBitFieldNames();
BitFieldDescription desc = fBitFieldNames.get(name);
int value = getNamedValue(name);
if (value == -1) {
return "undefined";
}
String valuetext = desc.getValueText(value);
return valuetext;
}
/**
* Set the value of a BitField to the default.
* <p>
* The default value comes from the part description file. For some MCUs there exist no default
* fuse byte values and LockBits never have a default value. In these cases the method will set
* the value of the BitField to all <code>1</code>s.
* </p>
*
* @param name
* The name of the BitField.
*/
public void setNamedValueToDefault(String name) {
initBitFieldNames();
BitFieldDescription desc = fBitFieldNames.get(name);
int defaultvalue = desc.getDefaultValue();
if (defaultvalue != -1) {
setNamedValue(name, defaultvalue);
} else {
setNamedValue(name, desc.getMaxValue());
}
}
/**
* Set all byte values of this object to their default value.
* <p>
* The default values come from the part description file. If the part description file did not
* have any default values (like for the ATXmega series), then <code>-1</code> is set for the
* byte.
* </p>
* <p>
* The default value for Lockbits is always <code>0xff</code>, which means all locks diabled.
* </p>
*/
public void setDefaultValues() {
IMCUDescription desc = getDescription(fMCUId);
List<IFuseObjectDescription> allbytes = desc.getByteDescriptions(fType);
for (IFuseObjectDescription bytedesc : allbytes) {
if (bytedesc != null) {
@SuppressWarnings("deprecation")
int value = bytedesc.getDefaultValue();
int index = bytedesc.getIndex();
setValue(index, value);
}
}
}
/**
* Gets the conversion status of a named BitField after a conversion.
* <p>
* Conversion is caused by a change of the MCU id for this object. If no conversion was
* performed {@link ConversionStatus#NO_CONVERSION} is returned.
* </p>
*
* @see ConversionStatus
*
* @param bitFieldName
* The name of the BitField
* @return The status in regard to the last conversion applied.
*/
public ConversionStatus getConversionStatus(String bitFieldName) {
if (fConversionResults != null) {
return fConversionResults.getStatusForName(bitFieldName);
}
return ConversionStatus.NO_CONVERSION;
}
/**
* Gets the complete ConversionResults from the last conversion applied to this ByteValues
* object.
*
* @return
*/
public ConversionResults getConversionResults() {
return fConversionResults;
}
/**
* Clears all values.
* <p>
* This method will set the value of all bytes to <code>-1</code>
* </p>
*/
public void clearValues() {
for (int i = 0; i < fValues.length; i++) {
setValue(i, -1); // setValue() notififies the listeners
}
}
/**
* Get a list of all BitField names.
* <p>
* The returned list is a copy of the internal list.
* </p>
*
* @return <code>List<String></code> with the names.
*/
public List<String> getBitfieldNames() {
initBitFieldNames();
return new ArrayList<String>(fBitFieldNames.keySet());
}
/**
* Get a list of all {@link BitFieldDescription} objects.
* <p>
* The returned list is a copy of the internal list.
* </p>
*
* @return <code>List<IBitFieldDescription></code>.
*/
public List<BitFieldDescription> getBitfieldDescriptions() {
initBitFieldNames();
return new ArrayList<BitFieldDescription>(fBitFieldNames.values());
}
/**
* Get a single named {@link BitFieldDescription}.
*
* @param name
* of the BitField
* @return The <code>BitFieldDescription</code> or <code>null</code> if no BitField with the
* given name exists.
*/
public BitFieldDescription getBitFieldDescription(String name) {
initBitFieldNames();
return fBitFieldNames.get(name);
}
/**
* Get the name of the byte at the given index.
*
* @param index
* Between 0 and {@link #getByteCount()} - 1.
* @return Name of the byte from the part description file, or <code>null</code> if the byte was
* not defined, i.e. the Fusebyte3 of all ATXmega MCUs
*/
public String getByteName(int index) {
IMCUDescription fusesdesc = getDescription(fMCUId);
IFuseObjectDescription bytedesc = fusesdesc.getByteDescription(fType, index);
return bytedesc != null ? bytedesc.getName() : null;
}
/**
* Get the user supplied comment for this <code>ByteValues</code> object.
* <p>
* The returned String may be <code>null</code> if no comment has been set.
* </p>
*
* @return The comment String.
*/
public String getComment() {
return fComment;
}
/**
* Sets a user supplied comment for this <code>ByteValues</code> object.
* <p>
* This class does not do anything with the comment other than store it. It is up to subclasses
* or to the caller to handle the comment.
* </p>
*
* @param comment
* The new comment or <code>null</code> to clear the comment.
*/
public void setComment(String comment) {
fComment = comment;
fireBitFieldChangedEvent(COMMENT_CHANGE_EVENT, 0, 0, 0);
}
/**
* Checks if the index is valid for the subclass.
*
* @param index
* Index value to test.
* @throws IllegalArgumentException
* if the index is not valid.
*/
private void checkIndex(int index) {
if (!(0 <= index && index < getByteCount())) {
throw new IllegalArgumentException("[" + index + "] is not a valid byte index.");
}
}
/**
* Initialize the Map of Bitfield names to their corresponding description objects.
*
*/
private void initBitFieldNames() {
if (fBitFieldNames != null) {
// return if the map has already been initialized
return;
}
fBitFieldNames = new HashMap<String, BitFieldDescription>();
IMCUDescription fusedescription = getDescription(fMCUId);
if (fusedescription == null) {
// If the fusedescription could not be read we leave the map empty.
return;
}
// Get all byte descriptions, get the bitfield descriptions from them
// and fill the map.
List<IFuseObjectDescription> bytedesclist = fusedescription.getByteDescriptions(fType);
for (IFuseObjectDescription bytedesc : bytedesclist) {
if (bytedesc != null) {
List<BitFieldDescription> bitfieldlist = bytedesc.getBitFieldDescriptions();
for (BitFieldDescription desc : bitfieldlist) {
fBitFieldNames.put(desc.getName(), desc);
}
}
}
}
/**
* Determine the bytecount for the mcu from the description object.
* <p>
* In case of errors determining the actual bytecount <code>0</code> is returned.
* </p>
*
* @return Number of bytes supported by the MCU. Between <code>0</code> and <code>6</code>.
*/
private int loadByteCount() {
IMCUDescription fusedescription = getDescription(fMCUId);
if (fusedescription == null) {
return 0;
}
return fusedescription.getByteCount(fType);
}
/**
* Get the description object for the given mcu id.
*
* @param mcuid
* @return <code>IFusesdescription</code> Object or <code>null</code> if the description could
* not be loaded.
*/
private IMCUDescription getDescription(String mcuid) {
// we used to cache the value but the Fuses class already caches all results it is not
// necessary to do it again.
IMCUDescription description = null;
try {
description = Fuses.getDefault().getDescription(mcuid);
} catch (IOException e) {
// Could not read the Description from the plugin
// Log the error and return null (indicates no fuse bytes)
IStatus status = new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID,
"Could not read the description file from the filesystem", e);
AVRPlugin.getDefault().log(status);
return null;
}
return description;
}
/**
* Test if this Object is compatible with the given MCU.
* <p>
* The test will be successful iff all BitFields for this and the given MCU have the same name
* and the same mask. In this case we assume that the meaning of the BitFields is also the same
* or at least very close.
* </p>
* <p>
* If the two MCUs are compatible they can be converted to each other without significant loss
* of information.
* </p>
*
* @return <code>true</code> if the current byte values are also valid for the given MCU id.
*
*/
public boolean isCompatibleWith(String mcuid) {
IMCUDescription ourdesc = getDescription(fMCUId);
IMCUDescription targetdesc = getDescription(mcuid);
if (ourdesc == null || targetdesc == null) {
return false;
}
return ourdesc.isCompatibleWith(targetdesc, fType);
}
/**
* Set the Byte values from the given ByteValues object.
* <p>
* If the source values are for an incompatible MCU type then two cases are possible as
* determined by the <code>forceMCU</code> flag.
* <ul>
* <li><code>true</code>: The MCU of this ByteValues object is changed to the MCU of the source
* ByteValues and then the values from the source are copied 1:1.</li>
* <li><code>false</code>: The MCU of this ByteValues object remains the same and the source
* ByteValues are first converted to this MCU and then the values are copied.</li>
* </ul>
* Another difference is, that in only the second case a <code>ConversionResults</code> is
* generated.
* </p>
*
* @param sourcevalues
* An <code>ByteValues</code> object with the source values
* @param forceMCU
* <code>true</code> to change this MCU to that of the source, <code>false</code> to
* convert the source values to this MCU.
*/
public void setValues(ByteValues sourcevalues, boolean forceMCU) {
if (forceMCU) {
// Change our MCU to that of the source values
setMCUId(sourcevalues.getMCUId(), false);
setValues(sourcevalues.getValues());
return;
}
if (isCompatibleWith(sourcevalues.getMCUId())) {
// Compatible mcu -> just copy the values and we're done
setValues(sourcevalues.getValues());
return;
}
// Don't change our MCU -> convert the source first and then use the
// resulting values as our values.
ConversionResults results = new ConversionResults();
ByteValues converted = sourcevalues.convertTo(getMCUId(), results);
setValues(converted.getValues());
fConversionResults = results;
}
/**
* Convert this ByteValue object to a different MCU.
* <p>
* This method works by getting a list of all BitField names for the new target MCU and compares
* them one by one with the BitField names of this object. If the names match and also the
* length of the mask match, then the single BitField value is copied from this object to a new
* ByteValues object.
* </p>
* <p>
* All BitFields of the newly created target <code>ByteValues</code>, which do not have a
* matching BitField in this <code>ByteValues</code> object, are set to their default value (if
* defined) or to all <code>1</code>s.
* </p>
*
* @param mcuid
* The MCU id for the new <code>ByteValues</code> object.
* @param results
* A {@link ConversionResults} object which will maintain the lists of successful and
* unsuccessful BitField conversions.
* @return A new <code>ByteValues</code> object valid for the given MCU and with those BitFields
* filled that match this object. All other bits are set to <code>1</code>.
*/
public ByteValues convertTo(String mcuid, ConversionResults results) {
initBitFieldNames();
// Create a new ByteValues Object for the target mcu
ByteValues target = new ByteValues(fType, mcuid);
// Init the results object.
// We use a copy of ourself as the source, because the setMCUId() method will copy the
// results of this method to this object, effectively making the target the source.
results.init(new ByteValues(this), target);
List<String> targetbfdnames = target.getBitfieldNames();
for (String name : targetbfdnames) {
// Check if the name matches.
if (fBitFieldNames.containsKey(name)) {
// OK, we have a matching name. Now check if the size of the BitField matches
BitFieldDescription targetbfd = target.getBitFieldDescription(name);
BitFieldDescription ourbfd = fBitFieldNames.get(name);
if (targetbfd.getMaxValue() == ourbfd.getMaxValue()) {
// identical BitField sizes: now copy the value
int ourvalue = getNamedValue(name);
if (ourvalue == -1) {
// If the value is undefined we do not copy
results.addUnset(ourbfd);
continue;
}
target.setNamedValue(name, ourvalue);
// mark the BitField as success and skip over the no-match parts
results.addSuccess(targetbfd);
results.removeNotCopied(ourbfd);
continue;
}
}
// no match found. Set to default value and add to the list
target.setNamedValueToDefault(name);
results.addUnset(target.getBitFieldDescription(name));
}
results.setReady();
return target;
}
/**
* Registers the change listener with the ByteValues object. After registration the
* <code>IByteValuesChangeListener</code> is informed about each change of the ByteValues. If
* the listener is already registered nothing happens.
* <p>
*
* @since 2.3
*
* @param listener
* The listener to be registered.
*/
public void addChangeListener(IByteValuesChangeListener listener) {
Assert.isNotNull(listener);
if (fListenerList == null) {
fListenerList = new ListenerList(ListenerList.IDENTITY);
}
fListenerList.add(listener);
}
/**
* Removes the listener from the <code>ByteValues</code> list of change listeners. If the
* listener is not registered with the <code>ByteValues</code> nothing happens.
* <p>
*
* @since 2.3
*
* @param listener
* The listener to be removed.
*/
public void removeChangeListener(IByteValuesChangeListener listener) {
if (fListenerList == null) {
return;
}
fListenerList.remove(listener);
}
/**
* Fire a {@link ByteValueChangeEvent} event to inform all listeners that the value of a single
* BitField has changed.
*
* @param name
* Name of the BitField
* @param value
* Normalized value of the BitField
* @param byteindex
* Index of the byte containing the BitField
* @param bytevalue
* Value of the byte containing the BitField
*/
private void fireBitFieldChangedEvent(String name, int value, int byteindex, int bytevalue) {
if (fListenerList == null || fListenerList.size() == 0) {
// quick exit if we have no listeners
return;
}
ByteValueChangeEvent event = createEvent(name, value, byteindex, bytevalue);
fireEvents(new ByteValueChangeEvent[] { event });
}
/**
* Fire an array of {@link ByteValueChangeEvent}'s event to inform all listeners that one
* complete byte of this ByteValues has changed.
*
* @param name
* Name of the BitField
* @param value
* Normalized value of the BitField
* @param byteindex
* Index of the byte containing the BitField
* @param bytevalue
* Value of the byte containing the BitField
*/
private void fireByteChangedEvent(int byteindex, int bytevalue) {
if (fListenerList == null || fListenerList.size() == 0) {
// quick exit if we have no listeners
return;
}
List<ByteValueChangeEvent> allevents = new ArrayList<ByteValueChangeEvent>();
initBitFieldNames();
for (BitFieldDescription bfd : fBitFieldNames.values()) {
if (bfd.getIndex() == byteindex) {
String name = bfd.getName();
int value = bfd.byteToBitField(bytevalue);
ByteValueChangeEvent event = createEvent(name, value, byteindex, bytevalue);
allevents.add(event);
}
}
fireEvents(allevents.toArray(new ByteValueChangeEvent[allevents.size()]));
}
/**
* Fire the given Events to all listeners.
*
* @param events
* Array of Events.
*/
private void fireEvents(ByteValueChangeEvent[] events) {
Object[] listeners = fListenerList.getListeners();
for (int i = 0; i < listeners.length; ++i) {
((IByteValuesChangeListener) listeners[i]).byteValuesChanged(events);
}
}
/**
* Create a new Event with the given parameters.
*
* @param name
* Name of the BitField
* @param value
* Normalized value of the BitField
* @param byteindex
* Index of the byte containing the BitField
* @param bytevalue
* Value of the byte containing the BitField
* @return A new <code>ByteValueChangeEvent</code>
*/
private ByteValueChangeEvent createEvent(String name, int value, int byteindex, int bytevalue) {
ByteValueChangeEvent event = new ByteValueChangeEvent();
event.name = name;
event.bitfieldvalue = value;
event.byteindex = byteindex;
event.bytevalue = bytevalue;
event.source = this;
return event;
}
}