forked from LupusNobilis/java-org.hwo
492 lines
11 KiB
Java
492 lines
11 KiB
Java
|
package org.hwo.io.servicelink;
|
|||
|
|
|||
|
import java.io.IOException;
|
|||
|
import java.lang.ref.ReferenceQueue;
|
|||
|
import java.nio.ByteBuffer;
|
|||
|
import java.nio.ByteOrder;
|
|||
|
import java.util.ArrayList;
|
|||
|
import java.util.List;
|
|||
|
|
|||
|
import org.hwo.BitField;
|
|||
|
import org.hwo.ChkSum;
|
|||
|
import org.hwo.interactiveobjects.InteractiveObject;
|
|||
|
import org.hwo.io.SerialPort;
|
|||
|
import org.hwo.models.TableMapper.TableColumn;
|
|||
|
|
|||
|
/* ServiceLink
|
|||
|
*
|
|||
|
* Kommunikation via USB mit RegBus f<EFBFBD>higem System
|
|||
|
*
|
|||
|
* <EFBFBD>bertragungssicherheit wird durch USB sichergestellt
|
|||
|
*
|
|||
|
* <EFBFBD>bertragen werden Telegramme mit folgendem Aufbau:
|
|||
|
*
|
|||
|
* Offset Type Inhalt
|
|||
|
* 0 Byte RequestTyp ( 0 = NoOP, 1 = Wert lesen, 2 = Wert schreiben, 3 = Ereignis senden )
|
|||
|
* 1 Byte Achse
|
|||
|
* 2 Byte Knoten
|
|||
|
* 3 Short Register Nummer
|
|||
|
* 5 Int32/Float Wert (nur bei schreiben oder lesen antwort)
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
public class ServiceLink {
|
|||
|
|
|||
|
static int REQ_READ = 0x01;
|
|||
|
static int REQ_WRITE = 0x02;
|
|||
|
static int REQ_EVENT = 0x04;
|
|||
|
static int REQ_FAIL = 0x08;
|
|||
|
|
|||
|
static int REQ_INT = 0x10;
|
|||
|
static int REQ_FLOAT = 0x20;
|
|||
|
static int REQ_ACK = 0x40;
|
|||
|
|
|||
|
static int SL_MAGIC = 0x66;
|
|||
|
|
|||
|
|
|||
|
class ServiceTelegram
|
|||
|
{
|
|||
|
byte request;
|
|||
|
byte achse;
|
|||
|
byte knoten;
|
|||
|
int register;
|
|||
|
byte[] value;
|
|||
|
|
|||
|
public ServiceTelegram()
|
|||
|
{
|
|||
|
request = 0;
|
|||
|
achse = 0;
|
|||
|
knoten = 0;
|
|||
|
register = 0;
|
|||
|
value = new byte[4];
|
|||
|
ByteBuffer.wrap(value).asIntBuffer().put(0);
|
|||
|
}
|
|||
|
|
|||
|
public void send()
|
|||
|
{
|
|||
|
byte[] txbuffer = new byte[12];
|
|||
|
ByteBuffer bb = ByteBuffer.wrap(txbuffer).order(ByteOrder.LITTLE_ENDIAN);
|
|||
|
|
|||
|
bb.put( (byte)SL_MAGIC );
|
|||
|
bb.put(request);
|
|||
|
bb.put(achse);
|
|||
|
bb.put(knoten);
|
|||
|
bb.putShort((short)register);
|
|||
|
if ((request & REQ_WRITE) == REQ_WRITE)
|
|||
|
bb.put(value);
|
|||
|
|
|||
|
short chk = ChkSum.chksum(txbuffer, 1, bb.position()-1);
|
|||
|
bb.putShort(chk);
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
getSerialPort().getOutputStream().write(txbuffer,0,bb.position());
|
|||
|
} catch (IOException ex)
|
|||
|
{
|
|||
|
getSerialPort().close();
|
|||
|
System.err.println(ex.toString());
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public void recv() throws ServiceLinkException
|
|||
|
{
|
|||
|
byte[] rxbuffer = new byte[12];
|
|||
|
ByteBuffer bb = ByteBuffer.wrap(rxbuffer).order(ByteOrder.LITTLE_ENDIAN);
|
|||
|
|
|||
|
try {
|
|||
|
int ch = getSerialPort().getInputStream().read();
|
|||
|
|
|||
|
while ((ch != SL_MAGIC) && (ch >= 0))
|
|||
|
ch = getSerialPort().getInputStream().read();
|
|||
|
|
|||
|
getSerialPort().getInputStream().read(rxbuffer,0,5);
|
|||
|
|
|||
|
request = bb.get();
|
|||
|
achse = bb.get();
|
|||
|
knoten = bb.get();
|
|||
|
register = bb.getShort();
|
|||
|
|
|||
|
if ((request & (REQ_READ | REQ_ACK)) == (REQ_READ | REQ_ACK))
|
|||
|
{
|
|||
|
getSerialPort().getInputStream().read(rxbuffer,bb.position(),4);
|
|||
|
bb.get(value);
|
|||
|
};
|
|||
|
getSerialPort().getInputStream().read(rxbuffer,bb.position(),2);
|
|||
|
short chksum = bb.getShort();
|
|||
|
|
|||
|
if (chksum != ChkSum.chksum(rxbuffer, 0, bb.position() - 2))
|
|||
|
throw new ServiceLinkException();
|
|||
|
|
|||
|
} catch (IOException e) {
|
|||
|
getSerialPort().close();
|
|||
|
|
|||
|
System.err.println(e.toString());
|
|||
|
throw new ServiceLinkException(e);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public class ServiceNode
|
|||
|
{
|
|||
|
@InteractiveObject(editor=RegisterEditor.class)
|
|||
|
public class ServiceNodeRegister
|
|||
|
{
|
|||
|
@TableColumn(label="Register",readonly=true,width=60)
|
|||
|
Integer register;
|
|||
|
@TableColumn(label="Bezeichnung",readonly=true,width=150)
|
|||
|
String label;
|
|||
|
|
|||
|
private Float floatValue;
|
|||
|
private Integer intValue;
|
|||
|
|
|||
|
boolean floatType;
|
|||
|
|
|||
|
private BitField bitField;
|
|||
|
|
|||
|
public ServiceNodeRegister(int register,boolean floatType)
|
|||
|
{
|
|||
|
this.label = String.format("%d", register);
|
|||
|
this.register = register;
|
|||
|
this.floatType = floatType;
|
|||
|
}
|
|||
|
public ServiceNodeRegister(int register,String label,boolean floatType)
|
|||
|
{
|
|||
|
this.label = label;
|
|||
|
this.register = register;
|
|||
|
this.floatType = floatType;
|
|||
|
}
|
|||
|
|
|||
|
public boolean isBitField()
|
|||
|
{
|
|||
|
return (bitField != null);
|
|||
|
}
|
|||
|
|
|||
|
public boolean isFloat()
|
|||
|
{
|
|||
|
return floatType;
|
|||
|
}
|
|||
|
|
|||
|
public boolean isInteger()
|
|||
|
{
|
|||
|
return (!isBitField() && !isFloat());
|
|||
|
}
|
|||
|
|
|||
|
@TableColumn(label="Wert",width=500)
|
|||
|
public String value()
|
|||
|
{
|
|||
|
if (bitField != null)
|
|||
|
return bitField.toText(intValue);
|
|||
|
if (intValue != null)
|
|||
|
return String.format("%d", intValue);
|
|||
|
if (floatValue != null)
|
|||
|
return String.format("%f", floatValue);
|
|||
|
return "N/A";
|
|||
|
}
|
|||
|
|
|||
|
public void setValue(String value)
|
|||
|
{
|
|||
|
if (floatType)
|
|||
|
floatValue = new Float(value);
|
|||
|
else
|
|||
|
intValue = new Integer(value);
|
|||
|
}
|
|||
|
|
|||
|
public void read()
|
|||
|
{
|
|||
|
try {
|
|||
|
if (floatType)
|
|||
|
floatValue = ServiceNode.this.readFloat(register);
|
|||
|
else
|
|||
|
intValue = ServiceNode.this.readInt(register);
|
|||
|
} catch (Exception e) {
|
|||
|
floatValue = null;
|
|||
|
intValue = 0;
|
|||
|
e.printStackTrace();
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
public void write()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
if (floatType)
|
|||
|
ServiceNode.this.writeFloat(register, floatValue);
|
|||
|
else
|
|||
|
ServiceNode.this.writeInt(register, intValue);
|
|||
|
} catch (Exception e)
|
|||
|
{
|
|||
|
e.printStackTrace();
|
|||
|
}
|
|||
|
}
|
|||
|
public BitField getBitField() {
|
|||
|
return bitField;
|
|||
|
}
|
|||
|
public void setBitField(BitField bitField) {
|
|||
|
this.bitField = bitField;
|
|||
|
}
|
|||
|
public Integer getIntValue() {
|
|||
|
return intValue;
|
|||
|
}
|
|||
|
public void setIntValue(Integer intValue) {
|
|||
|
this.intValue = intValue;
|
|||
|
}
|
|||
|
public Float getFloatValue() {
|
|||
|
return floatValue;
|
|||
|
}
|
|||
|
public void setFloatValue(Float floatValue) {
|
|||
|
this.floatValue = floatValue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
private byte achse;
|
|||
|
private byte knoten;
|
|||
|
|
|||
|
List<ServiceNodeRegister> registers;
|
|||
|
|
|||
|
public ServiceNode(byte achse,byte knoten)
|
|||
|
{
|
|||
|
this.achse = achse;
|
|||
|
this.knoten = knoten;
|
|||
|
this.registers = new ArrayList<ServiceLink.ServiceNode.ServiceNodeRegister>();
|
|||
|
}
|
|||
|
|
|||
|
public ServiceNodeRegister createRegister(int register,String label,boolean floatType)
|
|||
|
{
|
|||
|
return new ServiceNodeRegister(register, label, floatType);
|
|||
|
}
|
|||
|
|
|||
|
public List<ServiceNodeRegister> getRegisters()
|
|||
|
{
|
|||
|
return registers;
|
|||
|
}
|
|||
|
|
|||
|
public void read()
|
|||
|
{
|
|||
|
for (ServiceNodeRegister r:registers)
|
|||
|
r.read();
|
|||
|
}
|
|||
|
|
|||
|
public ServiceLink getServiceLink()
|
|||
|
{
|
|||
|
return ServiceLink.this;
|
|||
|
}
|
|||
|
|
|||
|
public int readInt(int register) throws IOException, ServiceLinkException
|
|||
|
{
|
|||
|
for (int n=0;n<retries;n++)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
return ServiceLink.this.readInt(achse, knoten, register);
|
|||
|
} catch (ServiceLinkException e)
|
|||
|
{
|
|||
|
if (n == (retries -1))
|
|||
|
throw e;
|
|||
|
}
|
|||
|
}
|
|||
|
throw new ServiceLinkException();
|
|||
|
}
|
|||
|
|
|||
|
public float readFloat(int register) throws IOException, ServiceLinkException
|
|||
|
{
|
|||
|
for (int n=0;n<retries;n++)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
return ServiceLink.this.readFloat(achse, knoten, register);
|
|||
|
} catch (ServiceLinkException e)
|
|||
|
{
|
|||
|
if (n == (retries -1))
|
|||
|
throw e;
|
|||
|
}
|
|||
|
}
|
|||
|
throw new ServiceLinkException();
|
|||
|
}
|
|||
|
|
|||
|
public void writeInt(int register,int value) throws IOException, ServiceLinkException
|
|||
|
{
|
|||
|
for (int n=0;n<retries;n++)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
ServiceLink.this.writeInt(achse, knoten, register, value);
|
|||
|
return;
|
|||
|
} catch (ServiceLinkException e)
|
|||
|
{
|
|||
|
if (n == (retries -1))
|
|||
|
throw e;
|
|||
|
}
|
|||
|
}
|
|||
|
throw new ServiceLinkException();
|
|||
|
}
|
|||
|
|
|||
|
public void writeFloat(int register,float value) throws IOException, ServiceLinkException
|
|||
|
{
|
|||
|
for (int n=0;n<retries;n++)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
ServiceLink.this.writeFloat(achse, knoten, register,value);
|
|||
|
return;
|
|||
|
} catch (ServiceLinkException e)
|
|||
|
{
|
|||
|
if (n == (retries -1))
|
|||
|
throw e;
|
|||
|
}
|
|||
|
}
|
|||
|
throw new ServiceLinkException();
|
|||
|
}
|
|||
|
|
|||
|
public byte getAchse() {
|
|||
|
return achse;
|
|||
|
}
|
|||
|
|
|||
|
public void setAchse(byte achse) {
|
|||
|
this.achse = achse;
|
|||
|
}
|
|||
|
|
|||
|
public byte getKnoten() {
|
|||
|
return knoten;
|
|||
|
}
|
|||
|
|
|||
|
public void setKnoten(byte knoten) {
|
|||
|
this.knoten = knoten;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
private SerialPort serialPort;
|
|||
|
int retries;
|
|||
|
|
|||
|
public ServiceLink(SerialPort serialPort)
|
|||
|
{
|
|||
|
this.retries = 3;
|
|||
|
this.serialPort = serialPort;
|
|||
|
this.serialPort.setTimeout(500);
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
System.err.println(String.format("BRKVAL : 0x%04x",readInt((byte)0,(byte)0,(short)0x200)));
|
|||
|
System.err.println(String.format("SPLIMIT: 0x%04x",readInt((byte)0,(byte)0,(short)0x201)));
|
|||
|
} catch (Exception e)
|
|||
|
{
|
|||
|
e.printStackTrace();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void open() throws ServiceLinkException
|
|||
|
{
|
|||
|
if (serialPort != null)
|
|||
|
serialPort.open();
|
|||
|
throwNotOpen();
|
|||
|
}
|
|||
|
|
|||
|
public void close()
|
|||
|
{
|
|||
|
if (serialPort != null)
|
|||
|
serialPort.close();
|
|||
|
}
|
|||
|
|
|||
|
@Override
|
|||
|
protected void finalize() throws Throwable {
|
|||
|
if (serialPort.isOpen())
|
|||
|
serialPort.close();
|
|||
|
}
|
|||
|
|
|||
|
public ServiceNode getServiceNode(byte achse,byte knoten)
|
|||
|
{
|
|||
|
return new ServiceNode(achse, knoten);
|
|||
|
}
|
|||
|
|
|||
|
public Integer readInt(byte achse,byte knoten,int register) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
|||
|
{
|
|||
|
throwNotOpen();
|
|||
|
return ByteBuffer.wrap( request((byte)(REQ_READ | REQ_INT), achse, knoten, register).value ).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().get();
|
|||
|
}
|
|||
|
|
|||
|
public Float readFloat(byte achse,byte knoten,int register) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
|||
|
{
|
|||
|
throwNotOpen();
|
|||
|
return ByteBuffer.wrap( request((byte)(REQ_READ | REQ_FLOAT), achse, knoten, register).value ).order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer().get();
|
|||
|
}
|
|||
|
|
|||
|
public void writeInt(byte achse,byte knoten,int register,int value) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
|||
|
{
|
|||
|
throwNotOpen();
|
|||
|
|
|||
|
byte[] v = new byte[4];
|
|||
|
ByteBuffer bb = ByteBuffer.wrap(v).order(ByteOrder.LITTLE_ENDIAN);
|
|||
|
bb.putInt(value);
|
|||
|
|
|||
|
ServiceTelegram telegram = request((byte)(REQ_WRITE | REQ_INT), achse, knoten, register, v);
|
|||
|
}
|
|||
|
|
|||
|
public void writeFloat(byte achse,byte knoten,int register,float value) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
|||
|
{
|
|||
|
throwNotOpen();
|
|||
|
|
|||
|
byte[] v = new byte[4];
|
|||
|
ByteBuffer bb = ByteBuffer.wrap(v).order(ByteOrder.LITTLE_ENDIAN);
|
|||
|
bb.putFloat(value);
|
|||
|
|
|||
|
ServiceTelegram telegram = request((byte)(REQ_WRITE | REQ_FLOAT), achse, knoten, register, v);
|
|||
|
}
|
|||
|
|
|||
|
private synchronized ServiceTelegram request(byte request,byte achse,byte knoten,int register) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
|||
|
{
|
|||
|
return request(request,achse,knoten,register,new byte[0]);
|
|||
|
}
|
|||
|
private synchronized ServiceTelegram request(byte request,byte achse,byte knoten,int register,byte[] value) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
|||
|
{
|
|||
|
ServiceTelegram telegram = new ServiceTelegram();
|
|||
|
|
|||
|
telegram.request = request;
|
|||
|
telegram.achse = achse;
|
|||
|
telegram.knoten = knoten;
|
|||
|
telegram.register = register;
|
|||
|
|
|||
|
if (value.length == 4)
|
|||
|
telegram.value = value;
|
|||
|
|
|||
|
|
|||
|
telegram.send();
|
|||
|
telegram.recv();
|
|||
|
|
|||
|
if ((telegram.request & REQ_ACK)==0)
|
|||
|
throw new ServiceLinkRequestFailedException();
|
|||
|
|
|||
|
return telegram;
|
|||
|
}
|
|||
|
|
|||
|
public SerialPort getSerialPort() {
|
|||
|
return serialPort;
|
|||
|
}
|
|||
|
|
|||
|
public void setSerialPort(SerialPort serialPort) {
|
|||
|
if (isOpen())
|
|||
|
this.serialPort.close();
|
|||
|
|
|||
|
this.serialPort = serialPort;
|
|||
|
}
|
|||
|
|
|||
|
private void throwNotOpen() throws ServiceLinkException
|
|||
|
{
|
|||
|
if (!isOpen())
|
|||
|
throw new ServiceLinkException("Port not Opened!");
|
|||
|
}
|
|||
|
|
|||
|
public boolean isOpen()
|
|||
|
{
|
|||
|
return this.serialPort.isOpen();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|