package com.openxc.messages.formatters.binary;
import java.io.IOException;
import java.io.InputStream;
import android.util.Log;
import com.openxc.BinaryMessages;
import com.openxc.messages.CanMessage;
import com.openxc.messages.Command;
import com.openxc.messages.Command.CommandType;
import com.openxc.messages.CommandResponse;
import com.openxc.messages.DiagnosticRequest;
import com.openxc.messages.DiagnosticResponse;
import com.openxc.messages.EventedSimpleVehicleMessage;
import com.openxc.messages.NamedVehicleMessage;
import com.openxc.messages.SimpleVehicleMessage;
import com.openxc.messages.UnrecognizedMessageTypeException;
import com.openxc.messages.VehicleMessage;
public class BinaryDeserializer {
private final static String TAG = "BinaryDeserializer";
public static VehicleMessage deserialize(InputStream data)
throws UnrecognizedMessageTypeException {
VehicleMessage result = null;
try {
BinaryMessages.VehicleMessage message =
BinaryMessages.VehicleMessage.parseFrom(data);
if(message != null) {
result = deserialize(message);
}
} catch(IOException e) {
Log.w(TAG, "Unable to deserialize from binary stream", e);
}
return result;
}
private static NamedVehicleMessage deserializeNamedMessage(
BinaryMessages.VehicleMessage binaryMessage) throws UnrecognizedMessageTypeException {
BinaryMessages.SimpleMessage simpleMessage =
binaryMessage.getSimpleMessage();
String name;
if(simpleMessage.hasName()) {
name = simpleMessage.getName();
} else {
throw new UnrecognizedMessageTypeException(
"Binary message is missing name");
}
Object value = null;
BinaryMessages.DynamicField field =
simpleMessage.getValue();
if(field.hasNumericValue()) {
value = field.getNumericValue();
} else if(field.hasBooleanValue()) {
value = field.getBooleanValue();
} else if(field.hasStringValue()) {
value = field.getStringValue();
}
Object event = null;
if(simpleMessage.hasEvent()) {
field = simpleMessage.getEvent();
if(field.hasNumericValue()) {
event = field.getNumericValue();
} else if(field.hasBooleanValue()) {
event = field.getBooleanValue();
} else if(field.hasStringValue()) {
event = field.getStringValue();
}
}
if(event == null) {
if(value == null) {
return new NamedVehicleMessage(name);
} else {
return new SimpleVehicleMessage(name, value);
}
} else {
return new EventedSimpleVehicleMessage(name, value, event);
}
}
private static CanMessage deserializeCanMessage(
BinaryMessages.VehicleMessage binaryMessage) {
BinaryMessages.CanMessage canMessage = binaryMessage.getCanMessage();
return new CanMessage(canMessage.getBus(),
canMessage.getId(),
canMessage.getData().toByteArray());
}
private static Command deserializeDiagnosticCommand(
BinaryMessages.ControlCommand command)
throws UnrecognizedMessageTypeException {
if(!command.hasDiagnosticRequest()) {
throw new UnrecognizedMessageTypeException(
"Diagnostic command missing request details");
}
BinaryMessages.DiagnosticControlCommand diagnosticCommand =
command.getDiagnosticRequest();
String action;
if(!diagnosticCommand.hasAction()) {
throw new UnrecognizedMessageTypeException(
"Diagnostic command missing action");
} else if(diagnosticCommand.getAction() ==
BinaryMessages.DiagnosticControlCommand.Action.ADD) {
action = DiagnosticRequest.ADD_ACTION_KEY;
} else if(diagnosticCommand.getAction() ==
BinaryMessages.DiagnosticControlCommand.Action.CANCEL) {
action = DiagnosticRequest.CANCEL_ACTION_KEY;
} else {
throw new UnrecognizedMessageTypeException(
"Unrecognized action: " + diagnosticCommand.getAction());
}
BinaryMessages.DiagnosticRequest serializedRequest =
diagnosticCommand.getRequest();
DiagnosticRequest request = new DiagnosticRequest(
serializedRequest.getBus(),
serializedRequest.getMessageId(),
serializedRequest.getMode());
if(serializedRequest.hasPayload()) {
request.setPayload(
serializedRequest.getPayload().toByteArray());
}
if(serializedRequest.hasPid()) {
request.setPid(serializedRequest.getPid());
}
if(serializedRequest.hasMultipleResponses()) {
request.setMultipleResponses(
serializedRequest.getMultipleResponses());
}
if(serializedRequest.hasFrequency()) {
request.setFrequency(serializedRequest.getFrequency());
}
if(serializedRequest.hasName()) {
request.setName(serializedRequest.getName());
}
return new Command(request, action);
}
private static Command deserializeCommand(
BinaryMessages.VehicleMessage binaryMessage)
throws UnrecognizedMessageTypeException {
BinaryMessages.ControlCommand command =
binaryMessage.getControlCommand();
CommandType commandType;
if(command.hasType()) {
BinaryMessages.ControlCommand.Type serializedType = command.getType();
if(serializedType.equals(BinaryMessages.ControlCommand.Type.VERSION)) {
commandType = CommandType.VERSION;
} else if(serializedType.equals(BinaryMessages.ControlCommand.Type.DEVICE_ID)) {
commandType = CommandType.DEVICE_ID;
} else if(serializedType.equals(BinaryMessages.ControlCommand.Type.DIAGNOSTIC)) {
commandType = CommandType.DIAGNOSTIC_REQUEST;
} else {
throw new UnrecognizedMessageTypeException(
"Unrecognized command type in command: " +
command.getType());
}
} else {
throw new UnrecognizedMessageTypeException(
"Command missing type");
}
Command deserializedCommand;
if(commandType.equals(CommandType.DIAGNOSTIC_REQUEST)) {
deserializedCommand = deserializeDiagnosticCommand(command);
} else {
deserializedCommand = new Command(commandType);
}
return deserializedCommand;
}
private static DiagnosticResponse deserializeDiagnosticResponse(
BinaryMessages.VehicleMessage binaryMessage)
throws UnrecognizedMessageTypeException {
BinaryMessages.DiagnosticResponse serializedResponse =
binaryMessage.getDiagnosticResponse();
if(!serializedResponse.hasBus() || !serializedResponse.hasMessageId() ||
!serializedResponse.hasMode()) {
throw new UnrecognizedMessageTypeException(
"Diagnostic response missing one or more required fields");
}
DiagnosticResponse response = new DiagnosticResponse(
serializedResponse.getBus(),
serializedResponse.getMessageId(),
serializedResponse.getMode());
if(serializedResponse.hasPid()) {
response.setPid(serializedResponse.getPid());
}
if(serializedResponse.hasPayload()) {
response.setPayload(serializedResponse.getPayload().toByteArray());
}
if(serializedResponse.hasNegativeResponseCode()) {
response.setNegativeResponseCode(
DiagnosticResponse.NegativeResponseCode.get(
serializedResponse.getNegativeResponseCode()));
}
if(serializedResponse.hasValue()) {
response.setValue(serializedResponse.getValue());
}
return response;
}
private static CommandResponse deserializeCommandResponse(
BinaryMessages.VehicleMessage binaryMessage)
throws UnrecognizedMessageTypeException {
BinaryMessages.CommandResponse response =
binaryMessage.getCommandResponse();
CommandType commandType;
if(response.hasType()) {
BinaryMessages.ControlCommand.Type serializedType = response.getType();
if(serializedType.equals(BinaryMessages.ControlCommand.Type.VERSION)) {
commandType = CommandType.VERSION;
} else if(serializedType.equals(BinaryMessages.ControlCommand.Type.DEVICE_ID)) {
commandType = CommandType.DEVICE_ID;
} else if(serializedType.equals(BinaryMessages.ControlCommand.Type.DIAGNOSTIC)) {
commandType = CommandType.DIAGNOSTIC_REQUEST;
} else {
throw new UnrecognizedMessageTypeException(
"Unrecognized command type in response: " +
response.getType());
}
} else {
throw new UnrecognizedMessageTypeException(
"Command response missing type");
}
if(!response.hasStatus()) {
throw new UnrecognizedMessageTypeException(
"Command response missing status");
}
String message = null;
if(response.hasMessage()) {
message = response.getMessage();
}
return new CommandResponse(commandType, response.getStatus(), message);
}
private static VehicleMessage deserialize(
BinaryMessages.VehicleMessage binaryMessage)
throws UnrecognizedMessageTypeException {
if(binaryMessage.hasSimpleMessage()) {
return deserializeNamedMessage(binaryMessage);
} else if(binaryMessage.hasCanMessage()) {
return deserializeCanMessage(binaryMessage);
} else if(binaryMessage.hasCommandResponse()) {
return deserializeCommandResponse(binaryMessage);
} else if(binaryMessage.hasControlCommand()) {
return deserializeCommand(binaryMessage);
} else if(binaryMessage.hasDiagnosticResponse()) {
return deserializeDiagnosticResponse(binaryMessage);
} else {
throw new UnrecognizedMessageTypeException(
"Binary message type not recognized");
}
}
}