343 lines
8.5 KiB
Java
343 lines
8.5 KiB
Java
package org.hwo.servicelink;
|
||
|
||
import java.io.IOException;
|
||
import java.io.ObjectInputStream.GetField;
|
||
import java.lang.ref.ReferenceQueue;
|
||
import java.nio.ByteBuffer;
|
||
import java.nio.ByteOrder;
|
||
import java.util.ArrayList;
|
||
import java.util.Hashtable;
|
||
import java.util.List;
|
||
|
||
import org.hwo.ChkSum;
|
||
import org.hwo.Smoother;
|
||
import org.hwo.bitfields.BitField;
|
||
import org.hwo.interactiveobjects.InteractiveObject;
|
||
import org.hwo.io.SerialPort;
|
||
import org.hwo.io.NewSerialPort.NewSerialPort;
|
||
|
||
/* ServiceLink
|
||
*
|
||
* Kommunikation via USB mit RegBus f<>higem System
|
||
*
|
||
* <20>bertragungssicherheit wird durch USB sichergestellt
|
||
*
|
||
* <20>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;
|
||
|
||
|
||
public class ServiceTelegram
|
||
{
|
||
private byte request;
|
||
private byte achse;
|
||
private byte knoten;
|
||
private 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);
|
||
|
||
if (register > 32767)
|
||
bb.putShort((short)(register));
|
||
else
|
||
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();
|
||
if (ch != SL_MAGIC)
|
||
System.err.println(String.format("PRE-JUNK: 0x%02x",ch));
|
||
}
|
||
|
||
getSerialPort().getInputStream().read(rxbuffer,0,5);
|
||
|
||
request = bb.get();
|
||
achse = bb.get();
|
||
knoten = bb.get();
|
||
register = bb.getShort();
|
||
if (register < 0)
|
||
register = (register & 0x7FFF) | 0x8000;
|
||
|
||
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();
|
||
|
||
//System.err.println(String.format("recv(): %d.%d:%d = 0x%08x",achse,knoten,register,bb.getInt(5)));
|
||
|
||
} catch (IOException e) {
|
||
getSerialPort().close();
|
||
|
||
System.err.println(e.toString());
|
||
throw new ServiceLinkException(e);
|
||
}
|
||
}
|
||
|
||
public byte getRequest() {
|
||
return request;
|
||
}
|
||
|
||
public void setRequest(byte request) {
|
||
this.request = request;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
public int getRegister() {
|
||
return register;
|
||
}
|
||
|
||
public void setRegister(int register) {
|
||
this.register = register;
|
||
}
|
||
|
||
}
|
||
|
||
private NewSerialPort serialPort;
|
||
int retries;
|
||
private ServiceRegisterCache
|
||
serviceRegisterCache;
|
||
|
||
Smoother requestTime;
|
||
|
||
private AsynchronServiceLinkProvider
|
||
asynchronServiceLinkProvider;
|
||
|
||
public ServiceLink(NewSerialPort serialPort)
|
||
{
|
||
this.retries = 3;
|
||
this.serialPort = serialPort;
|
||
this.serialPort.setTimeOut(250);
|
||
this.serviceRegisterCache = new ServiceRegisterCache(this);
|
||
this.asynchronServiceLinkProvider = new AsynchronServiceLinkProvider(serviceRegisterCache);
|
||
this.requestTime = new Smoother();
|
||
this.requestTime.setTn(16);
|
||
}
|
||
|
||
public int getAverageRequestTime()
|
||
{
|
||
return requestTime.getWert();
|
||
}
|
||
|
||
public ServiceRegisterCache getServiceRegisterCache()
|
||
{
|
||
return this.serviceRegisterCache;
|
||
}
|
||
|
||
public AsynchronServiceLinkProvider getAsynchronServiceLinkProvider() {
|
||
return asynchronServiceLinkProvider;
|
||
}
|
||
|
||
public synchronized void open() throws ServiceLinkException
|
||
{
|
||
if (serialPort != null)
|
||
serialPort.open();
|
||
throwNotOpen();
|
||
}
|
||
|
||
public synchronized void close()
|
||
{
|
||
if (serialPort != null)
|
||
serialPort.close();
|
||
}
|
||
|
||
@Override
|
||
protected void finalize() throws Throwable {
|
||
if (serialPort.isOpen())
|
||
serialPort.close();
|
||
}
|
||
|
||
public Integer readInt(int achse,int knoten,int register) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
||
{
|
||
return readInt((byte)achse, (byte)knoten, register);
|
||
}
|
||
|
||
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(int achse,int knoten,int register,int value) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
||
{
|
||
writeInt((byte)achse, (byte)knoten, register, value);
|
||
}
|
||
|
||
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
|
||
{
|
||
long rstart,rend;
|
||
|
||
ServiceTelegram telegram = new ServiceTelegram();
|
||
|
||
telegram.setRequest(request);
|
||
telegram.setAchse(achse);
|
||
telegram.setKnoten(knoten);
|
||
telegram.setRegister(register);
|
||
|
||
if (value.length == 4)
|
||
telegram.value = value;
|
||
|
||
|
||
telegram.send();
|
||
rstart = System.currentTimeMillis();
|
||
for (int n = 0; n<3; n++)
|
||
{
|
||
telegram.recv();
|
||
if (
|
||
(telegram.getAchse() == achse) &&
|
||
(telegram.getKnoten() == knoten) &&
|
||
(telegram.getRegister() == register)
|
||
)
|
||
break;
|
||
};
|
||
rend = System.currentTimeMillis();
|
||
|
||
requestTime.cycle((int)(rend - rstart));
|
||
|
||
if ((telegram.getRequest() & REQ_ACK)==0)
|
||
throw new ServiceLinkRequestFailedException(telegram);
|
||
|
||
return telegram;
|
||
}
|
||
|
||
public synchronized NewSerialPort getSerialPort() {
|
||
return serialPort;
|
||
}
|
||
|
||
public synchronized void setSerialPort(NewSerialPort serialPort) {
|
||
if (isOpen())
|
||
this.serialPort.close();
|
||
|
||
this.serialPort = serialPort;
|
||
}
|
||
|
||
private synchronized void throwNotOpen() throws ServiceLinkException
|
||
{
|
||
if (!isOpen())
|
||
throw new ServiceLinkException("Port not Opened!");
|
||
}
|
||
|
||
public synchronized boolean isOpen()
|
||
{
|
||
return this.serialPort.isOpen();
|
||
}
|
||
|
||
|
||
}
|