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.exceptions.TineRuntimeErrorException;
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 Map<String,TField> fields = Collections.synchronizedMap(new LinkedHashMap<String,TField>());
private long bfValue;
private byte[] bfBytes = new byte[8];
private static int nfields = 0;
public boolean hasFields() { return 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) throw new TineRuntimeErrorException(TErrorList.invalid_structure_tag);
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:
throw new TineRuntimeErrorException(TErrorList.illegal_format);
}
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,long value)
{
TField fld = fields.get(fieldName);
if (fld == null) return 0; // TODO: throw exception
return fld.getValue(value);
}
public int getField(String fieldName,int value)
{
TField fld = fields.get(fieldName);
if (fld == null) return value;
return fld.getValue(value);
}
public String toString()
{
return toString((int)bfValue);
}
public String toString(int value)
{
StringBuilder bfString = new StringBuilder(fields.size()*(16 + 5)); //name + colon and value + new line character
for (TField f : fields.values()) {
if (bfString.length() > 0) bfString.append('\n');
bfString.append(f.getName()).append(" : ").append(f.getValue(value));
}
return bfString.toString();
}
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 (bfName == null || bfName.length() == 0) return TErrorList.invalid_field;
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 = TErrorList.net_read_error;
for (int i =0; cc == TErrorList.net_read_error && i<3; i++)
{
cc = tl.executeAndClose(200);
}
if (cc == 0)
{
int nflds = dtInfo.getCompletionLength();
if (nflds > 0)
{
short fmt = TFormat.getFormatDataType((short)info[nflds-1].ival);
if (fmt != bfFmt)
{
MsgLog.log("acquireAndRegisterFields", "correcting bitfield "+bfName+" format from "+TFormat.toString(fmt)+" to "+TFormat.toString((short)bfFmt),0,null,0);
bfFmt = fmt;
}
for (int i=0; i<nflds-1; i++)
{
addField(new TField(info[i].name,info[i].ival));
}
}
}
return cc;
}
}