/*
* (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.prot.obd;
import com.fr3ts0n.ecu.Conversions;
import com.fr3ts0n.ecu.EcuDataPv;
import com.fr3ts0n.prot.ProtoHeader;
import com.fr3ts0n.pvs.PvList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;
/**
* Base class for all CAN protocol implementations
*
* @author erwin
*/
public abstract class CanProt extends ProtoHeader
{
public static final int ID_CAN_SVC = 0;
/**
* additional field indices (extending message parameters)
* to table below
*/
public static final int FLD_ID_CONV = 3;
public static final int FLD_ID_DECIMALS = 4;
public static final int FLD_ID_CANID = 5;
/**
* List of telegram parameters in order of appearance
*/
static final int CAN_PARAMETERS[][] =
/* START, LEN, PARAM-TYPE // REMARKS */
/* ------------------------------------------- */
{{0, 2, PT_HEX}, // ID_CAN_SVC
};
static final String[] CAN_DESCRIPTORS =
{
"CAN Service",
};
/** process variable list which holds all parameters */
public PvList CanPvs = new PvList();
/** internal Map for CAN messages to parameters */
HashMap<Integer, Vector<Integer>> canMsgMap = new HashMap<Integer, Vector<Integer>>();
/** Creates a new instance of CanProt */
public CanProt()
{
for (int i = 0; i < getMsgParameters().length; i++)
{
int convId = getMsgParameters()[i][FLD_ID_CONV];
Integer paramId = Integer.valueOf(i);
Integer canId = getMsgParameters()[i][FLD_ID_CANID];
// enter all parameters per CAN message
Vector<Integer> paramList = canMsgMap.get(canId);
if (paramList == null)
paramList = new Vector<Integer>();
paramList.add(paramId);
canMsgMap.put(canId, paramList);
/** enter process variables for each parameter */
EcuDataPv pidData = new EcuDataPv();
pidData.put(EcuDataPv.FID_PID, paramId);
pidData.put(EcuDataPv.FID_DESCRIPT, getMsgDescriptors()[i]);
pidData.put(EcuDataPv.FID_UNITS, Conversions.getUnits(convId));
pidData.put(EcuDataPv.FID_VALUE, Float.valueOf(0));
pidData.put(EcuDataPv.FID_FORMAT, "%."+getMsgParameters()[i][FLD_ID_DECIMALS]+"d");
pidData.put(EcuDataPv.FID_CNVID, Integer.valueOf(getMsgParameters()[i][FLD_ID_CONV]));
CanPvs.put(paramId, pidData);
}
}
/**
* prepare process variables for each PID
*
* @param checkIfSupported if true, only supported PIDs will be processed
*/
public void preparePidPvs(boolean checkIfSupported)
{
for (int i = 0; i < getMsgParameters().length; i++)
{
Integer paramId = i;
/** enter process variables for each parameter */
EcuDataPv pidData = (EcuDataPv) CanPvs.get(paramId);
if (pidData != null)
{
int convId = getMsgParameters()[i][FLD_ID_CONV];
pidData.put(EcuDataPv.FID_UNITS, Conversions.getUnits(convId));
}
}
}
/**
* get List of message dependent telegram parameters in order of appearance
* Each parameter set contains following elements<br>
* <pre>START, LEN, TYPE, CONVERSION_ID, , ID // REMARKS </pre>
* <pre>---------------------------------------------------------------------------------</pre>
*/
public abstract int[][] getMsgParameters();
/**
* get list of message parameter descriptions
*
* @return list of messag parameter descriptors
*/
public abstract String[] getMsgDescriptors();
/**
* get physical parameter value from message buffer
*/
float getMsgValue(int ID, char[] buffer)
{
int memVal = ((Integer) getParamValue(ID, getMsgParameters(), buffer)).intValue();
return (Conversions.memToPhys(memVal, getMsgParameters()[ID][FLD_ID_CONV]));
}
/**
* create a new telegram header for selected payload data buffer
* inclunding setting all ID's, sizes and validity issues
*
* @param buffer buffer of payload data
* @return buffer of new telegram header
*/
protected char[] getNewHeader(char[] buffer)
{
return (emptyBuffer);
}
/**
* return message footer for protocol payload
*
* @param buffer buffer of payload data
* @return buffer of message footer
*/
public char[] getFooter(char[] buffer)
{
return (emptyBuffer);
}
/**
* create a new telegram header inclunding setting all ID's, sizes and
* validity issues
*
* @return buffer of new telegram header
*/
protected char[] getNewHeader(char[] buffer, int type, Object id)
{
return (emptyBuffer);
}
/**
* list of parameters for specific protocol
*
* @return complete set of protocol parameters
*/
public int[][] getTelegramParams()
{
return (CAN_PARAMETERS);
}
/**
* list of parameter descriptions for specific protocol
*
* @return complete set of protocol parameter description strings
*/
protected String[] getParamDescriptors()
{
return (CAN_DESCRIPTORS);
}
/**
* handle incoming protocol telegram
* default implementaion only checks telegram and notifies listeners with
* protocol payload
*
* @param buffer - telegram buffer
* @return number of listeners notified
*/
@SuppressWarnings("rawtypes")
@Override
public int handleTelegram(char[] buffer)
{
int retValue = 0;
try
{
Integer msgId = (Integer) getParamValue(ID_CAN_SVC, buffer);
Vector params = canMsgMap.get(msgId);
if (params != null)
{
Iterator it = params.iterator();
while (it.hasNext())
{
Integer parId = (Integer) it.next();
float value = getMsgValue(parId.intValue(), buffer);
EcuDataPv pv = (EcuDataPv) CanPvs.get(parId);
if (pv != null)
{
// now store all changes to PV
pv.put(EcuDataPv.FIELDS[EcuDataPv.FID_VALUE], new Float(value));
}
}
retValue = params.size();
}
} catch (Exception e)
{
log.error(e);
}
return retValue;
}
}