package de.desy.tine.bitfieldUtils;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.util.*;
import de.desy.tine.client.TLink;
import de.desy.tine.dataUtils.*;
import de.desy.tine.definitions.*;
import de.desy.tine.endianUtils.*;
import de.desy.tine.server.logger.MsgLog;
import de.desy.tine.types.*;
public class TBitfield implements TCompoundDataObject
{
@Override
public TBitfield clone()
{
return new TBitfield(this);
}
private String srvName; // context and server
private String bfName; // 16 chars
private int bfFmt; // CF_BYTE, CF_SHORT, CF_LONG
private Hashtable<String,TField> fields = new Hashtable<String,TField>();
private long bfValue;
private byte[] bfBytes = new byte[8];
private static int nfields = 0;
public double getDoubleValue() { return (double)bfValue; }
public int getIntegerValue() { return (int)bfValue; }
public void setValue(long value)
{
bfValue = value;
for (int i=0; i<8; i++)
bfBytes[i] = (byte)((value>>(8*i)) & 0x08);
}
private int getBitShiftFromMask(long mask,int fmt)
{
int shf = 0, b = 1, mshf;
mshf = TFormat.formatSizeOf((short)fmt) * 8 - 1;
while ((mask & b) == 0)
{
if (++shf == mshf) break;
b *= 2;
}
return shf;
}
public TBitfield(TBitfield instance)
{
this(instance.getSrvName(),instance.getName(),instance.getFormat());
fields = instance.fields;
}
public TBitfield(String name, short format)
{
this(null,name,format);
}
public TBitfield(String server, String name, short format)
{
//if (name == null) TODO : throw exception
switch (format)
{
case TFormat.CF_BYTE:
case TFormat.CF_BITFIELD8:
bfFmt = TFormat.CF_BITFIELD8;
break;
case TFormat.CF_INT16:
case TFormat.CF_BITFIELD16:
bfFmt = TFormat.CF_BITFIELD16;
break;
case TFormat.CF_INT32:
case TFormat.CF_BITFIELD32:
bfFmt = TFormat.CF_BITFIELD32;
break;
case TFormat.CF_INT64:
case TFormat.CF_BITFIELD64:
bfFmt = TFormat.CF_BITFIELD64;
break;
default:
// TODO: throw exception
return;
}
srvName = server == null ? "this" : server;
bfName = name.length() > 16 ? name.substring(0, 16) : name;
TBitfieldRegistry.add(this);
}
public void addField(TField field)
{
if (field == null) return;
String key = field.getName();
if (fields.containsKey(key)) return;
long mask = field.getBitmask();
field.setBitshift(getBitShiftFromMask(mask, bfFmt));
field.setOrderIndex(nfields);
nfields++;
fields.put(key, field);
}
public int getField(String fieldName)
{
return getField(fieldName,(int)bfValue);
}
//TODO: allow int64 bitfields !
public int getField(String fieldName,int value)
{
TField fld = fields.get(fieldName);
if (fld == null) return 0; // TODO: throw exception
return fld.getValue(value);
}
public String toString()
{
return toString((int)bfValue);
}
public String toString(int value)
{
String bfString = "";
TField[] flds = fields.values().toArray(new TField[0]);
for (int i=0,k=0; i<flds.length && k<flds.length; i++)
{ // print these out in registration order
if (flds[i].getOrderIndex() == k)
{
if (bfString.length() > 0) bfString += "\n";
bfString += flds[i].getName() + " : " + flds[i].getValue(value);
k++; i = 0;
}
}
return bfString;
}
public String getCsvString()
{
return ""+bfValue;
}
public String getSrvName()
{
return srvName;
}
public void setSrvName(String serverName)
{
srvName = serverName;
}
public short getFormat()
{
return (short)bfFmt;
}
public String getTag()
{
return bfName;
}
public String getName()
{
return bfName;
}
public TField[] getFields()
{
return fields.values().toArray(new TField[0]);
}
public boolean isField(String fieldName)
{
return fields.keySet().contains(fieldName);
}
public byte[] toByteArray()
{
byte[] ba = null;
switch (bfFmt)
{
case TFormat.CF_BITFIELD8:
ba = new byte[1];
ba[0] = (byte)bfValue;
break;
case TFormat.CF_BITFIELD16:
ba = Swap.ShortToBytes((int)bfValue);
break;
case TFormat.CF_BITFIELD32:
ba = Swap.LongToBytes((int)bfValue);
break;
case TFormat.CF_BITFIELD64:
ba = Swap.DLongToBytes(bfValue);
break;
}
System.arraycopy(ba, 0, bfBytes, 0, ba.length);
return ba;
}
public void toStruct()
{
try
{
ByteArrayInputStream dis = new ByteArrayInputStream(bfBytes);
DataInputStream ds = new DataInputStream(dis);
switch (bfFmt)
{
case TFormat.CF_BITFIELD8:
bfValue = ds.readByte();
break;
case TFormat.CF_BITFIELD16:
bfValue = Swap.Short(ds.readShort());
break;
case TFormat.CF_BITFIELD32:
bfValue = Swap.Long(ds.readInt());
break;
case TFormat.CF_BITFIELD64:
bfValue = Swap.DLong(ds.readLong());
break;
}
ds.close(); dis.close();
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("TBitfield.toStruct",e.getMessage(),TErrorList.code_failure,e,0);
}
}
public byte[] getByteArray()
{
return bfBytes;
}
public int getSizeInBytes()
{
return TFormat.formatSizeOf((short)bfFmt);
}
public void setByteArray(byte[] byteArray)
{
int maxlen = byteArray.length;
if (maxlen > 8) maxlen = 8;
System.arraycopy(byteArray, 0, bfBytes, 0, maxlen);
}
public synchronized int acquireAndRegisterFields(String devName)
{
int cc = TErrorList.invalid_structure_tag;
if (devName == null) return TErrorList.argument_list_error;
if (!devName.startsWith("/")) return TErrorList.illegal_context;
String[] dn = devName.split("/");
String tgt;
switch (dn.length)
{
case 4:
case 3:
tgt = "/" + dn[1] + "/" + dn[2];
break;
default:
return TErrorList.invalid_name;
}
tgt = tgt + "/" + bfName;
TBitfield bf = TBitfieldRegistry.getBitfield(tgt);
if (bf != null && bf.fields.size() > 0) return 0;
NAME16I[] info = new NAME16I[32];
TDataType dtInfo = new TDataType(info);
TDataType dtTag = new TDataType(bfName.toCharArray());
TLink tl = new TLink(devName,"BITFIELDFORMAT",dtInfo,dtTag,TAccess.CA_READ);
cc = tl.execute(200, true);
tl.close();
if (cc == 0)
{
int nflds = dtInfo.getCompletionLength();
if (nflds > 0)
{
short fmt = TFormat.getFormatDataType((short)info[nflds-1].ival);
if (fmt != bfFmt) return TErrorList.illegal_format; // TODO: ?
for (int i=0; i<nflds-1; i++)
{
addField(new TField(info[i].name,info[i].ival));
}
}
}
return cc;
}
}