/*
CanZE
Take a closer look at your ZE car
Copyright (C) 2015 - The CanZE Team
http://canze.fisch.lu
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This class represents a CAN frame
*/
package lu.fisch.canze.actors;
import lu.fisch.canze.activities.MainActivity;
import lu.fisch.canze.classes.FieldLogger;
/**
*
* @author robertfisch
*/
public class Message {
// A message represents a message coming from a device as a result from a frame request.
// Note that for ISO-TP frames, a frame is always a subframe
// If an error occurs while fetching a message, the error flag is set to true and the data
// part now represents a readable error. The methods ensure that the data part is only
// processed when there is no error condition set
protected Frame frame;
protected String data;
protected boolean error;
public Message(Frame frame, String data, boolean error) {
this.frame=frame;
this.data=data;
this.error=error;
}
/* --------------------------------
* Getters & setters
\ ------------------------------ */
public String getData() {
return (error || data == null) ? "" : data;
}
/* public void setData(String data) {
this.data = data;
}*/
public Frame getFrame() {
return frame;
}
/* public void setFrame(Frame frame) {
this.frame = frame;
} */
public boolean isError () {return error;}
public String getError () { return error ? data : ""; }
public void onMessageIncompleteEvent () {
for (Field field : frame.getAllFields()) {
field.updateLastRequest();
}
}
public void onMessageCompleteEvent() {
// If a message frame comes in, simply update all fields that are defined for it.
// Note that for an IsoTP field, the getFrame() method returns as subframe. The subframe's
// getAllFields() method only returns the fields with the ssame responseId.
// this function is called from DtcActivity ("manual mode") and
// Device.queryNextFilter ("auto mode")
if (error) return;
String binString = getAsBinaryString();
for (Field field : frame.getAllFields()) {
onMessageCompleteEventField(binString, field);
}
}
private void onMessageCompleteEventField(String binString, Field field) {
if(binString.length()>= field.getTo()) {
// parseInt --> signed, so the first bit is "cut-off"!
try {
binString = binString.substring(field.getFrom(), field.getTo() + 1);
if (field.isString()) {
String val = "";
for (int i = 0; i < binString.length(); i += 8) {
val += Character.toString((char) Integer.parseInt("0" + binString.substring(i, i+8), 2));
}
field.setValue(val);
// do field logging
if (MainActivity.fieldLogMode)
FieldLogger.getInstance().log(field.getSID() + "," + val);
} else if (binString.length() <= 4 || binString.contains("0")) {
// experiment with unavailable: any field >= 5 bits whose value contains only 1's
int val;
if (field.isSigned() && binString.startsWith("1")) {
// ugly method: flip bits, add a minus in front and substract one
val = Integer.parseInt("-" + binString.replace('0', 'q').replace('1','0').replace('q','1'), 2) - 1;
} else {
val = Integer.parseInt("0" + binString, 2);
}
//MainActivity.debug("Value of " + field.getHexId() + "." + field.getResponseId() + "." + field.getFrom()+" = "+val);
//MainActivity.debug("Fields: onMessageCompleteEvent > "+field.getSID()+" = "+val);
// update the value of the field. This triggers updating all of all listeners of that field
field.setValue(val);
// do field logging
if(MainActivity.fieldLogMode)
FieldLogger.getInstance().log(field.getSID()+","+val);
} else {
field.setValue(Double.NaN);
// do field logging
if(MainActivity.fieldLogMode)
FieldLogger.getInstance().log(field.getSID()+",NaN");
}
// update the fields last request date
field.updateLastRequest();
/*
int val = Integer.parseInt("0" + binString.substring(field.getFrom(), field.getTo() + 1), 2);
//MainActivity.debug("Value of " + field.getHexId() + "." + field.getResponseId() + "." + field.getFrom()+" = "+val);
//MainActivity.debug("Fields: onMessageCompleteEvent > "+field.getSID()+" = "+val);
field.setValue(val);
// update the fields last request date
field.updateLastRequest();
*/
} catch (Exception e)
{
MainActivity.debug("Message.onMessageCompleteEventField: Exception!!");
// ignore
}
}
}
/* --------------------------------
* Some utilities
\ ------------------------------ */
public String getAsBinaryString()
{
String result = "";
if (!error) {
for (int i = 0; i < data.length(); i += 2) {
try {
result += String.format("%8s", Integer.toBinaryString(Integer.parseInt(data.substring(i, i + 2), 16) & 0xFF)).replace(' ', '0');
} catch (Exception e) {
}
}
}
return result;
}
}