WIP161104
parent
bccf82d416
commit
a9b700c9c0
|
@ -1,64 +1,22 @@
|
|||
package org.hwo.servicelink;
|
||||
|
||||
import static org.hwo.logging.Logging.*;
|
||||
import static org.hwo.logging.Logging.log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hwo.ByteArrayHelper;
|
||||
import org.hwo.ByteArrayHexlifier;
|
||||
import org.hwo.Smoother;
|
||||
import org.hwo.StringHelper;
|
||||
import org.hwo.io.NewSerialPort.NewSerialPort;
|
||||
import org.hwo.io.NewSerialPort.NewSerialPortListener;
|
||||
|
||||
import static org.hwo.servicelink.ServiceLinkTelegram.*;
|
||||
import static org.hwo.logging.LogLevel.*;
|
||||
|
||||
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.LinkedList;
|
||||
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;
|
||||
import org.hwo.io.NewSerialPort.NewSerialPortListener;
|
||||
|
||||
|
||||
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.LinkedList;
|
||||
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;
|
||||
import org.hwo.io.NewSerialPort.NewSerialPortListener;
|
||||
import static org.hwo.logging.Logging.*;
|
||||
|
||||
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.LinkedList;
|
||||
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;
|
||||
import org.hwo.io.NewSerialPort.NewSerialPortListener;
|
||||
|
||||
/* ServiceLink
|
||||
*
|
||||
* Kommunikation via USB mit RegBus f<EFBFBD>higem System
|
||||
|
@ -78,164 +36,32 @@ import org.hwo.io.NewSerialPort.NewSerialPortListener;
|
|||
|
||||
|
||||
public class ServiceLink implements NewSerialPortListener {
|
||||
private NewSerialPort
|
||||
serialPort;
|
||||
|
||||
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;
|
||||
|
||||
TxQueue txQueue;
|
||||
Smoother requestTime;
|
||||
int requestTimeOut;
|
||||
|
||||
LinkedList<ServiceLinkTelegram> txQueue;
|
||||
Hashtable<ServiceLinkAddress, List<ServiceLinkTelegram>>
|
||||
pendingRequests;
|
||||
|
||||
RxWorker rxWorker;
|
||||
TxWorker txWorker;
|
||||
|
||||
private List<ServiceLinkListener> serviceLinkListeners;
|
||||
|
||||
public ServiceLink(NewSerialPort serialPort)
|
||||
{
|
||||
this.requestTimeOut = 50;
|
||||
|
||||
this.serviceLinkListeners = new LinkedList<ServiceLinkListener>();
|
||||
this.retries = 3;
|
||||
this.serialPort = serialPort;
|
||||
|
@ -245,9 +71,148 @@ public class ServiceLink implements NewSerialPortListener {
|
|||
this.asynchronServiceLinkProvider = new AsynchronServiceLinkProvider(serviceRegisterCache);
|
||||
this.requestTime = new Smoother();
|
||||
this.requestTime.setTn(16);
|
||||
this.txQueue = null;
|
||||
|
||||
this.txWorker = null;
|
||||
this.rxWorker = null;
|
||||
|
||||
this.txQueue = new LinkedList<>();
|
||||
this.pendingRequests = new Hashtable<>();
|
||||
}
|
||||
|
||||
/** Handling der Seriellen Verbindung **/
|
||||
|
||||
private void _open(){
|
||||
this.txWorker = new TxWorker();
|
||||
this.rxWorker = new RxWorker();
|
||||
|
||||
this.serialPort.open();
|
||||
this.serialPort.setTimeOut(250);
|
||||
|
||||
this.txWorker.start();
|
||||
this.rxWorker.start();
|
||||
}
|
||||
private void _close(){
|
||||
log(DEBUG,"servicelink closing connection...");
|
||||
log(DEBUG,"txWorker...");
|
||||
this.txWorker.exit();
|
||||
log(DEBUG,"rxWorker...");
|
||||
this.rxWorker.exit();
|
||||
|
||||
this.txWorker = null;
|
||||
this.rxWorker = null;
|
||||
|
||||
log(DEBUG,"serialPort...");
|
||||
this.serialPort.close();
|
||||
}
|
||||
|
||||
public synchronized void open() throws ServiceLinkException
|
||||
{
|
||||
close();
|
||||
|
||||
if (serialPort != null){
|
||||
_open();
|
||||
} else {
|
||||
throwNotOpen();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void close()
|
||||
{
|
||||
if (txWorker != null){
|
||||
_close();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void throwNotOpen() throws ServiceLinkException
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new ServiceLinkException("serial port not opened!");
|
||||
}
|
||||
|
||||
public synchronized boolean isOpen()
|
||||
{
|
||||
return (this.serialPort != null) && (this.serialPort.isOpen()) && (this.txWorker != null);
|
||||
}
|
||||
|
||||
/** -- ENDE: Handling der seriellen Verbindung -- **/
|
||||
|
||||
/** Handling der Queues **/
|
||||
|
||||
private void addPendingRequest(ServiceLinkTelegram request){
|
||||
synchronized (pendingRequests) {
|
||||
if (!pendingRequests.containsKey(request.getAddress())){
|
||||
pendingRequests.put(request.getAddress(),new LinkedList<ServiceLinkTelegram>());
|
||||
}
|
||||
List<ServiceLinkTelegram> ll = pendingRequests.get(request.getAddress());
|
||||
ll.add(request);
|
||||
}
|
||||
}
|
||||
private void removePendingRequest(ServiceLinkTelegram request){
|
||||
synchronized (pendingRequests) {
|
||||
if (pendingRequests.containsKey(request.getAddress())){
|
||||
pendingRequests.get(request.getAddress()).remove(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void appendRequest(ServiceLinkTelegram request){
|
||||
addPendingRequest(request);
|
||||
|
||||
synchronized (txQueue) {
|
||||
txQueue.add(request);
|
||||
txQueue.notify();
|
||||
}
|
||||
}
|
||||
public void removeRequest(ServiceLinkTelegram request){
|
||||
synchronized (txQueue) {
|
||||
txQueue.remove(request);
|
||||
}
|
||||
removePendingRequest(request);
|
||||
}
|
||||
|
||||
public void queueRequest(ServiceLinkTelegram request){
|
||||
appendRequest(request);
|
||||
|
||||
synchronized (request) {
|
||||
try {
|
||||
request.wait(requestTimeOut);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
removeRequest(request);
|
||||
|
||||
log(DEBUG,"queuedRequest finished. %s Value: %s",request.getAddress().toString(),request.value);
|
||||
|
||||
}
|
||||
|
||||
public void received(ServiceLinkTelegram rx){
|
||||
|
||||
synchronized (pendingRequests) {
|
||||
if (pendingRequests.containsKey(rx.getAddress())){
|
||||
for (ServiceLinkTelegram pending: pendingRequests.get(rx.getAddress())){
|
||||
if ((pending.getOpcode() & (REQ_INT | REQ_FLOAT))==(rx.getOpcode() & (REQ_INT | REQ_FLOAT))){
|
||||
synchronized (pending) {
|
||||
pending.setValue(rx.getValue());
|
||||
pending.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** ENDE: Handling der Queues **/
|
||||
|
||||
public int getRequestTimeOut() {
|
||||
return requestTimeOut;
|
||||
}
|
||||
public void setRequestTimeOut(int requestTimeOut) {
|
||||
this.requestTimeOut = requestTimeOut;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void addServiceLinkListener(ServiceLinkListener listener){
|
||||
serviceLinkListeners.add(listener);
|
||||
}
|
||||
|
@ -274,24 +239,7 @@ public class ServiceLink implements NewSerialPortListener {
|
|||
return asynchronServiceLinkProvider;
|
||||
}
|
||||
|
||||
public synchronized void open() throws ServiceLinkException
|
||||
{
|
||||
if (serialPort != null){
|
||||
serialPort.open();
|
||||
txQueue = new TxQueue();
|
||||
}
|
||||
throwNotOpen();
|
||||
}
|
||||
|
||||
public synchronized void close()
|
||||
{
|
||||
if (serialPort != null){
|
||||
if (txQueue != null){
|
||||
txQueue.exit();
|
||||
}
|
||||
serialPort.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
|
@ -301,95 +249,25 @@ public class ServiceLink implements NewSerialPortListener {
|
|||
|
||||
public Integer readInt(int achse,int knoten,int register) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
||||
{
|
||||
return readInt((byte)achse, (byte)knoten, register);
|
||||
ServiceLinkTelegram request = ServiceLinkTelegram.create(REQ_INT | REQ_READ, achse, knoten, register, null);
|
||||
queueRequest(request);
|
||||
return (Integer)request.getValue();
|
||||
}
|
||||
public Float readFloat(int achse,int knoten,int register) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
|
||||
{
|
||||
return readFloat((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();
|
||||
ServiceLinkTelegram request = ServiceLinkTelegram.create(REQ_FLOAT | REQ_READ, achse, knoten, register, null);
|
||||
queueRequest(request);
|
||||
return (Float)request.getValue();
|
||||
}
|
||||
|
||||
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);
|
||||
ServiceLinkTelegram request = ServiceLinkTelegram.create(REQ_INT | REQ_WRITE, achse, knoten, register, value);
|
||||
queueRequest(request);
|
||||
}
|
||||
public void writeFloat(int achse,int knoten,int register,float value) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException{
|
||||
writeFloat((byte)achse,(byte)knoten,register,value);
|
||||
}
|
||||
|
||||
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();
|
||||
ServiceTelegram rx = new ServiceTelegram();
|
||||
|
||||
telegram.setRequest(request);
|
||||
telegram.setAchse(achse);
|
||||
telegram.setKnoten(knoten);
|
||||
telegram.setRegister(register);
|
||||
|
||||
if (value.length == 4)
|
||||
telegram.value = value;
|
||||
|
||||
txQueue.appendRequest(telegram);
|
||||
|
||||
rstart = System.currentTimeMillis();
|
||||
for (int n = 0; n<3; n++)
|
||||
{
|
||||
rx.recv();
|
||||
if (
|
||||
(rx.getAchse() == achse) &&
|
||||
(rx.getKnoten() == knoten) &&
|
||||
(rx.getRegister() == register)
|
||||
)
|
||||
break;
|
||||
};
|
||||
rend = System.currentTimeMillis();
|
||||
|
||||
requestTime.cycle((int)(rend - rstart));
|
||||
|
||||
if ((rx.getRequest() & REQ_ACK)==0)
|
||||
throw new ServiceLinkRequestFailedException(telegram);
|
||||
|
||||
return rx;
|
||||
ServiceLinkTelegram request = ServiceLinkTelegram.create(REQ_FLOAT | REQ_WRITE, achse, knoten, register, value);
|
||||
queueRequest(request);
|
||||
}
|
||||
|
||||
public synchronized NewSerialPort getSerialPort() {
|
||||
|
@ -406,16 +284,7 @@ public class ServiceLink implements NewSerialPortListener {
|
|||
this.serialPort.addNewSerialPortListener(this);
|
||||
}
|
||||
|
||||
private synchronized void throwNotOpen() throws ServiceLinkException
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new ServiceLinkException("Port not Opened!");
|
||||
}
|
||||
|
||||
public synchronized boolean isOpen()
|
||||
{
|
||||
return this.serialPort.isOpen();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void connectionStateChanged(NewSerialPort port, boolean connected) {
|
||||
|
@ -423,19 +292,52 @@ public class ServiceLink implements NewSerialPortListener {
|
|||
}
|
||||
|
||||
|
||||
|
||||
private class TxQueue extends Thread{
|
||||
private LinkedList<ServiceTelegram> queue;
|
||||
private class RxWorker extends Thread {
|
||||
private boolean exit;
|
||||
|
||||
public TxQueue(){
|
||||
queue = new LinkedList<>();
|
||||
public synchronized void exit(){
|
||||
exit = true;
|
||||
this.notifyAll();
|
||||
try {
|
||||
this.wait(2000);
|
||||
|
||||
if (this.isAlive()){
|
||||
this.stop();
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ServiceLinkTelegram rx;
|
||||
|
||||
while (true){
|
||||
synchronized (this) {
|
||||
if (exit){
|
||||
this.notifyAll();
|
||||
return;
|
||||
}
|
||||
}
|
||||
rx = ServiceLinkTelegram.read(getSerialPort().getInputStream());
|
||||
if (rx != null){
|
||||
received(rx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TxWorker extends Thread{
|
||||
private boolean exit;
|
||||
|
||||
public TxWorker(){
|
||||
exit = false;
|
||||
}
|
||||
|
||||
public synchronized void exit(){
|
||||
exit = true;
|
||||
this.notify();
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
|
@ -445,50 +347,48 @@ public class ServiceLink implements NewSerialPortListener {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
ServiceLinkTelegram tx;
|
||||
|
||||
while (true){
|
||||
synchronized (this) {
|
||||
|
||||
synchronized (txQueue) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (Exception e){
|
||||
txQueue.wait(100);
|
||||
} catch (InterruptedException e) {
|
||||
log(e);
|
||||
}
|
||||
|
||||
if (exit){
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
while (true){
|
||||
ServiceTelegram tx = null;
|
||||
|
||||
|
||||
synchronized (this) {
|
||||
tx = queue.pollFirst();
|
||||
};
|
||||
|
||||
if (tx != null){
|
||||
tx.send();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
try {
|
||||
if (exit){
|
||||
break;
|
||||
}
|
||||
} catch (Exception e){
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (txQueue) {
|
||||
tx = txQueue.pollFirst();
|
||||
}
|
||||
|
||||
while (tx != null){
|
||||
byte[] txbytes = tx.toByteArray();
|
||||
try {
|
||||
log(DEBUG,"TX BYTES: %s",ByteArrayHexlifier.byteArrayToString(txbytes));
|
||||
serialPort.getOutputStream().write(txbytes);
|
||||
} catch (IOException e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
synchronized (txQueue) {
|
||||
tx = txQueue.pollFirst();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
this.notifyAll();
|
||||
}
|
||||
this.notify();
|
||||
}
|
||||
|
||||
public synchronized void appendRequest(ServiceTelegram request){
|
||||
queue.add(request);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.hwo.servicelink;
|
||||
|
||||
public class ServiceLinkAddress {
|
||||
|
||||
private int ax,
|
||||
node;
|
||||
private int register;
|
||||
|
||||
public ServiceLinkAddress(){
|
||||
}
|
||||
public ServiceLinkAddress(int ax,int node,int register){
|
||||
this.ax = ax;
|
||||
this.node = node;
|
||||
this.register = register;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ((ax & 0x0F) << 20) | ((node & 0x0F) << 16) | ((register & 0xFFFF) << 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (ax == ((ServiceLinkAddress)obj).ax) &&
|
||||
(node == ((ServiceLinkAddress)obj).node) &&
|
||||
(register == ((ServiceLinkAddress)obj).register);
|
||||
}
|
||||
|
||||
public int getAx() {
|
||||
return ax;
|
||||
}
|
||||
public void setAx(int ax) {
|
||||
this.ax = ax;
|
||||
}
|
||||
public int getNode() {
|
||||
return node;
|
||||
}
|
||||
public void setNode(int node) {
|
||||
this.node = node;
|
||||
}
|
||||
public int getRegister() {
|
||||
return register;
|
||||
}
|
||||
public void setRegister(int register) {
|
||||
this.register = register;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("SLA: [%d:%d:%d]",ax,node,register);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
package org.hwo.servicelink;
|
||||
|
||||
import org.hwo.servicelink.ServiceLink.ServiceTelegram;
|
||||
|
||||
public class ServiceLinkRequestFailedException extends ServiceLinkException {
|
||||
|
||||
private ServiceTelegram serviceTelegram;
|
||||
private ServiceLinkTelegram serviceTelegram;
|
||||
|
||||
public ServiceLinkRequestFailedException(ServiceTelegram telegram)
|
||||
public ServiceLinkRequestFailedException(ServiceLinkTelegram telegram)
|
||||
{
|
||||
serviceTelegram = telegram;
|
||||
}
|
||||
|
@ -16,15 +15,15 @@ public class ServiceLinkRequestFailedException extends ServiceLinkException {
|
|||
serviceTelegram = null;
|
||||
}
|
||||
|
||||
public ServiceTelegram getServiceTelegram()
|
||||
public ServiceLinkTelegram getServiceLinkTelegram()
|
||||
{
|
||||
return this.serviceTelegram;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (getServiceTelegram()!=null)
|
||||
return String.format("ServiceLinkRequestFailedException: %d.%d:%d",getServiceTelegram().getAchse(),getServiceTelegram().getKnoten(),getServiceTelegram().getRegister());
|
||||
if (getServiceLinkTelegram()!=null)
|
||||
return String.format("ServiceLinkRequestFailedException: %d.%d:%d",getServiceLinkTelegram().getAddress().getAx(),getServiceLinkTelegram().getAddress().getNode(),getServiceLinkTelegram().getAddress().getRegister());
|
||||
return "ServiceLinkRequestFailedException";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
package org.hwo.servicelink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import org.hwo.ByteArrayHexlifier;
|
||||
import org.hwo.ChkSum;
|
||||
import static org.hwo.logging.Logging.*;
|
||||
import static org.hwo.logging.LogLevel.*;
|
||||
|
||||
public class ServiceLinkTelegram {
|
||||
static int REQ_READ = 0x01;
|
||||
|
@ -13,24 +24,104 @@ public class ServiceLinkTelegram {
|
|||
|
||||
static int SL_MAGIC = 0x66;
|
||||
|
||||
public static ServiceLinkTelegram create(int operation,int achse,int knoten,int register,Object value){
|
||||
return new ServiceLinkTelegram(operation,achse,knoten,register,value);
|
||||
}
|
||||
|
||||
public static byte[] readTelegramBytes(InputStream in){
|
||||
int l,
|
||||
sync,
|
||||
opcode;
|
||||
|
||||
byte[] rxbuffer;
|
||||
|
||||
try {
|
||||
int ch = in.read();
|
||||
|
||||
while ((ch != SL_MAGIC)) {
|
||||
ch = in.read();
|
||||
if (ch != SL_MAGIC){
|
||||
if (ch == -1){
|
||||
return null;
|
||||
}
|
||||
|
||||
System.err.println(String.format("PRE-JUNK: 0x%02x",ch));
|
||||
}
|
||||
}
|
||||
sync = (byte)ch;
|
||||
opcode = (byte)in.read();
|
||||
|
||||
l = ((opcode & (REQ_READ | REQ_ACK)) == (REQ_READ | REQ_ACK)) ? 10 : 6;
|
||||
|
||||
rxbuffer = new byte[ l + 2 ];
|
||||
|
||||
rxbuffer[0] = (byte)sync;
|
||||
rxbuffer[1] = (byte)opcode;
|
||||
|
||||
l = in.read(rxbuffer,2,l);
|
||||
log(DEBUG,"RX BYTES: %2d: %s",rxbuffer.length,ByteArrayHexlifier.byteArrayToString(rxbuffer));
|
||||
|
||||
int opcode,
|
||||
achse,
|
||||
knoten,
|
||||
register;
|
||||
return rxbuffer;
|
||||
} catch (IOException e) {
|
||||
log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ServiceLinkTelegram read(InputStream in){
|
||||
byte[] rx = readTelegramBytes(in);
|
||||
|
||||
if (rx != null){
|
||||
try {
|
||||
return new ServiceLinkTelegram(rx);
|
||||
} catch (Exception e){
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
int opcode;
|
||||
ServiceLinkAddress
|
||||
address;
|
||||
Object
|
||||
value;
|
||||
|
||||
protected ServiceLinkTelegram(){
|
||||
protected ServiceLinkTelegram(){
|
||||
}
|
||||
|
||||
protected ServiceLinkTelegram(int operation,int achse,int knoten,int register,Object value){
|
||||
this.opcode = operation;
|
||||
this.achse = achse;
|
||||
this.knoten = knoten;
|
||||
this.register = register;
|
||||
this.address = new ServiceLinkAddress(achse, knoten, register);
|
||||
this.value = value;
|
||||
}
|
||||
protected ServiceLinkTelegram(byte[] buffer){
|
||||
if ((buffer.length != 12) && (buffer.length != 8) ){
|
||||
throw new ArrayIndexOutOfBoundsException(String.format("ServiceLinkTelegram needs to be constructed from 8 or 12 bytes! But got %d bytes.",buffer.length));
|
||||
}
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN);
|
||||
short chk = ChkSum.chksum(buffer, 1, buffer.length - 3);
|
||||
//log(DEBUG,"CHK: 0x%04x", chk);
|
||||
|
||||
|
||||
if (bb.getShort(buffer.length - 2) != chk) {
|
||||
log(DEBUG,"CRC failed: 0x%04x != 0x%04x",bb.getShort(buffer.length - 2),chk);
|
||||
throw new RuntimeException("CRC Failed");
|
||||
}
|
||||
|
||||
this.opcode = bb.get(1);
|
||||
this.address = new ServiceLinkAddress(bb.get(2),bb.get(3),bb.getShort(4));
|
||||
if (buffer.length == 12){
|
||||
int v = bb.getInt(6);
|
||||
if ((opcode & REQ_FLOAT)==REQ_FLOAT){
|
||||
this.value = Float.intBitsToFloat(v);
|
||||
} else if ((opcode & REQ_INT)==REQ_INT){
|
||||
this.value = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPlausible(){
|
||||
if ((opcode & REQ_WRITE)!=0){
|
||||
|
@ -39,11 +130,163 @@ public class ServiceLinkTelegram {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] valueAsByteArray(){
|
||||
byte[] v = new byte[4];
|
||||
|
||||
if (value == null)
|
||||
return new byte[]{0,0,0,0};
|
||||
if (Integer.class.isInstance(value)){
|
||||
ByteBuffer.wrap(v).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().put((Integer)value);
|
||||
} else {
|
||||
ByteBuffer.wrap(v).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().put(Float.floatToIntBits((Float)value));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public byte[] toByteArray(){
|
||||
byte[] txbuffer = new byte[ ((opcode & REQ_WRITE) == REQ_WRITE) ? 12 : 8 ];
|
||||
ByteBuffer bb = ByteBuffer.wrap(txbuffer).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
bb.put( (byte)SL_MAGIC );
|
||||
bb.put( (byte)opcode );
|
||||
bb.put( (byte)address.getAx());
|
||||
bb.put( (byte)address.getNode());
|
||||
bb.putShort((short)(address.getRegister()));
|
||||
|
||||
|
||||
if ((opcode & REQ_WRITE) == REQ_WRITE){
|
||||
bb.put(valueAsByteArray());
|
||||
}
|
||||
|
||||
short chk = ChkSum.chksum(txbuffer, 1, bb.position()-1);
|
||||
bb.putShort(chk);
|
||||
|
||||
return txbuffer;
|
||||
}
|
||||
|
||||
public static ServiceLinkTelegram create(int operation,int achse,int knoten,int register,Object value){
|
||||
return new ServiceLinkTelegram(operation,achse,knoten,register,value);
|
||||
public ServiceLinkAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
public void setAddress(ServiceLinkAddress address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public int getOpcode() {
|
||||
return opcode;
|
||||
}
|
||||
public void setOpcode(int opcode) {
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* 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 recv() throws ServiceLinkException
|
||||
{
|
||||
byte[] rxbuffer = new byte[12];
|
||||
ByteBuffer bb = ByteBuffer.wrap(rxbuffer).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
try {
|
||||
int ch = in.read();
|
||||
|
||||
while ((ch != SL_MAGIC) && (ch >= 0)) {
|
||||
ch = in.read();
|
||||
if (ch != SL_MAGIC)
|
||||
System.err.println(String.format("PRE-JUNK: 0x%02x",ch));
|
||||
}
|
||||
|
||||
in.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))
|
||||
{
|
||||
in.read(rxbuffer,bb.position(),4);
|
||||
bb.get(value);
|
||||
};
|
||||
in.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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
|
@ -12,7 +12,6 @@ import javax.swing.JComponent;
|
|||
import org.hwo.i18n.Messages;
|
||||
import org.hwo.interactiveobjects.InteractiveObject;
|
||||
import org.hwo.servicelink.ServiceLink;
|
||||
import org.hwo.servicelink.ServiceLink.ServiceTelegram;
|
||||
import org.hwo.servicelink.ServiceLinkException;
|
||||
import org.hwo.servicelink.ServiceLinkRequestFailedException;
|
||||
import org.hwo.servicelink.ServiceRegisterListener;
|
||||
|
|
Loading…
Reference in New Issue