/*
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
*
* 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 2 of
* the License, or (at your option) 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package com.fr3ts0n.ecu;
import com.fr3ts0n.prot.ProtUtils;
import com.fr3ts0n.prot.ProtoHeader;
import org.apache.log4j.Logger;
/**
* Definition of a single ECU Data item (EcuDataItem)
*
* @author erwin
*/
public class EcuDataItem
implements Cloneable
{
/** conversion systems METRIC and IMPERIAL */
public static final int SYSTEM_METRIC = 0;
public static final int SYSTEM_IMPERIAL = 1;
public static final int SYSTEM_TYPES = 2;
/** names of conversion system types */
public static final String[] cnvSystems =
{
"METRIC",
"IMPERIAL",
};
// current conversion system
public static int cnvSystem = SYSTEM_METRIC;
public int pid; ///< pid
public int ofs; ///< Offset within message
public Conversion[] cnv; ///< type of conversion
int bytes; ///< number of data bytes expected from vehicle
int bitOffset = 0; ///< bit offset within extracted long
int numBits = 32; ///< number of relevant bits within extracted long
long bitMask = 0xFFFFFFFF; ///< mask for relevant bits within extracted long
String fmt; ///< Format for text output
public String label; ///< text label
public EcuDataPv pv; ///< the process variable for displaying
boolean enabled = true; ///< if not enabled, do not process
// Logger object
public static final Logger log = Logger.getLogger("data.ecu");
public static int[] byteValues =
{
0xFFFF, // fake default max value for length 0
0xFF,
0xFFFF,
0xFFFFFF,
0xFFFFFFFF
};
/**
* Creates a new instance of EcuDataItem
*/
public EcuDataItem()
{
}
/**
* Creates a new instance of EcuDataItem
*
* @param newPid PID of data item
* @param offset offset within PID data (in bytes)
* @param numBytes length of parameter in bytes
* @param bitOfs Bit offset of measurement within numeric value
* @param numberOfBits Number of relevant bits within numeric value
* @param conversions data conversion to be used with this item
* @param format formatting string for text representation
* @param minValue minimum physical value to display/scale
* @param maxValue maximum physical value to display/scale
* @param labelText descriptive text label
*/
public EcuDataItem( int newPid,
int offset,
int numBytes,
int bitOfs,
int numberOfBits,
long maskingBits,
Conversion[] conversions,
String format,
Number minValue,
Number maxValue,
String labelText)
{
pid = newPid;
ofs = offset;
bytes = numBytes;
bitOffset = bitOfs;
numBits = numberOfBits;
bitMask = maskingBits;
cnv = conversions;
fmt = format;
label = labelText;
pv = new EcuDataPv();
Number minVal = minValue;
Number maxVal = maxValue;
// initialize new PID with current data
pv.put(EcuDataPv.FID_PID, Integer.valueOf(pid));
pv.put(EcuDataPv.FID_OFS, Integer.valueOf(ofs));
pv.put(EcuDataPv.FID_BIT_OFS, Integer.valueOf(bitOffset));
pv.put(EcuDataPv.FID_DESCRIPT, label);
pv.put(EcuDataPv.FID_UNITS,
(cnv != null && cnv[cnvSystem] != null)
? cnv[cnvSystem].getUnits()
: "");
pv.put(EcuDataPv.FID_VALUE, Float.valueOf(0));
pv.put(EcuDataPv.FID_FORMAT, fmt);
pv.put(EcuDataPv.FID_CNVID, cnv);
if(cnv != null && cnv[cnvSystem] != null)
{
if(minVal == null) minVal = cnv[cnvSystem].memToPhys(0);
if(maxVal == null) maxVal = cnv[cnvSystem].memToPhys((1L<<numBits)-1);
}
pv.put(EcuDataPv.FID_MIN, minVal);
pv.put(EcuDataPv.FID_MAX, maxVal);
}
@Override
public String toString()
{
return (String.format("%02X.%d.%d", pid, ofs, bitOffset));
}
/**
* get physical value from buffer
*
* @param buffer communication buffer content
* @return physical value
*/
Object physFromBuffer(char[] buffer)
{
Object result;
try
{
if (cnv != null && cnv[cnvSystem] != null)
{
// extract value from buffer
long value = ProtoHeader.getParamInt(ofs, bytes, buffer).longValue();
// calculate effective value ...
// shift on bit offset
value = (value >> bitOffset);
// mask with bit lenth mask
value = (value & ((1L << numBits)-1));
// mask with specific bit mask
value = (value & bitMask);
// now run conversion to physical value on it ...
result = cnv[cnvSystem].memToPhys(value);
}
else
{
result = String.copyValueOf(buffer, ofs, bytes);
}
} catch(Exception ex)
{
result = "n/a";
log.warn(String.format("%s: %s - [%s]", toString(), ex.getMessage(), ProtUtils.hexDumpBuffer(buffer)));
enabled = false;
}
return (result);
}
/**
* Update process var from Buffer value
*
* @param buffer communication buffer content
*/
public void updatePvFomBuffer(char[] buffer)
{
if(enabled)
{
try
{
// get physical value
Object result = physFromBuffer(buffer);
pv.put(EcuDataPv.FID_VALUE, result);
log.debug(String.format("%02X %-30s %16s %s",
pid,
label,
pv.get(EcuDataPv.FID_VALUE),
pv.get(EcuDataPv.FID_UNITS)));
}
catch(Exception ex)
{
log.error(ex);
}
}
}
@Override
public Object clone()
{
EcuDataItem result = null;
try
{
result = (EcuDataItem) super.clone();
result.pv = (EcuDataPv) pv.clone();
} catch (CloneNotSupportedException ex)
{
ex.printStackTrace();
}
return (result);
}
}