package com.openxc.messages;
import java.util.Arrays;
import java.util.HashMap;
import android.os.Parcel;
import com.google.gson.annotations.SerializedName;
import com.openxc.util.Range;
/**
* An abstract base class to hold common fields and logic for diagnostic
* requests and responses.
*
* Diagnostic messages are keyed on the bus, message ID, mode and PID (if set).
*/
public abstract class DiagnosticMessage extends KeyedMessage {
protected static final String ID_KEY = CanMessage.ID_KEY;
protected static final String BUS_KEY = CanMessage.BUS_KEY;
protected static final String MODE_KEY = "mode";
protected static final String PID_KEY = "pid";
protected static final String PAYLOAD_KEY = "payload";
protected static final Range<Integer> BUS_RANGE = new Range<>(1, 2);
protected static final Range<Integer> MODE_RANGE = new Range<>(1, 0xff);
// Note that this is a limit of the OpenXC Vi firmware at the moment - a
// diagnostic request can technically have a much larger payload.
// TODO this is not checked anywhere!
private static final int MAX_PAYLOAD_LENGTH_IN_BYTES = 7;
@SerializedName(BUS_KEY)
private int mBusId;
@SerializedName(ID_KEY)
private int mId;
@SerializedName(MODE_KEY)
private int mMode;
@SerializedName(PID_KEY)
// PID is an optional field, so it is stored as an Integer so it can be
// nulled.
private Integer mPid;
@SerializedName(PAYLOAD_KEY)
private byte[] mPayload;
public DiagnosticMessage(int busId, int id, int mode) {
mBusId = busId;
mId = id;
mMode = mode;
}
public DiagnosticMessage(int busId, int id, int mode, int pid) {
this(busId, id, mode);
mPid = pid;
}
public boolean hasPid() {
return mPid != null;
}
public int getBusId() {
return mBusId;
}
public int getId() {
return mId;
}
public int getMode() {
return mMode;
}
public Integer getPid() {
return mPid;
}
public byte[] getPayload() {
return mPayload;
}
public void setPid(int pid) {
mPid = pid;
}
public boolean hasPayload() {
return mPayload != null;
}
public void setPayload(byte[] payload) {
if(payload != null) {
mPayload = new byte[payload.length];
System.arraycopy(payload, 0, mPayload, 0, payload.length);
} else {
mPayload = null;
}
}
@Override
public MessageKey getKey() {
if(super.getKey() == null) {
HashMap<String, Object> key = new HashMap<>();
key.put(CanMessage.BUS_KEY, getBusId());
key.put(CanMessage.ID_KEY, getId());
key.put(MODE_KEY, getMode());
key.put(PID_KEY, getPid());
setKey(new MessageKey(key));
}
return super.getKey();
}
@Override
public boolean equals(Object obj) {
if(!super.equals(obj) || getClass() != obj.getClass()) {
return false;
}
final DiagnosticMessage other = (DiagnosticMessage) obj;
return mBusId == other.mBusId
&& mId == other.mId
&& mMode == other.mMode
&& ((!hasPid() && !other.hasPid())
|| mPid.equals(other.mPid))
&& Arrays.equals(mPayload, other.mPayload);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(getBusId());
out.writeInt(getId());
out.writeInt(getMode());
out.writeValue(getPid());
if(getPayload() != null) {
out.writeInt(getPayload().length);
out.writeByteArray(getPayload());
} else {
out.writeInt(0);
}
}
@Override
protected void readFromParcel(Parcel in) {
super.readFromParcel(in);
mBusId = in.readInt();
mId = in.readInt();
mMode = in.readInt();
mPid = (Integer) in.readValue(Integer.class.getClassLoader());
int payloadSize = in.readInt();
if(payloadSize > 0) {
mPayload = new byte[payloadSize];
in.readByteArray(mPayload);
}
}
protected DiagnosticMessage() { }
}