From 71712279cf9dcc02aa73ffb82a94f996d3d8dc92 Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Sat, 10 Feb 2018 12:58:16 +0100 Subject: [PATCH] Next Generation Servicelink Implementation (serial,tcp, streams) --- .../ng/AsynchronServiceLinkProvider.java | 100 ++++++++ src/org/hwo/servicelink/ng/ObjectPool.java | 25 ++ .../hwo/servicelink/ng/RegBUSInterface.java | 13 + src/org/hwo/servicelink/ng/ServiceLink.java | 237 ++++++++++++++++++ .../ng/ServiceLinkRequestBuffer.java | 124 +++++++++ .../hwo/servicelink/ng/ServiceLinkStream.java | 37 +++ .../servicelink/ng/ServiceRegisterCache.java | 159 ++++++++++++ .../ng/ServiceRegisterListener.java | 8 + .../hwo/servicelink/ng/StreamContainer.java | 113 +++++++++ .../hwo/servicelink/ng/TelegramStreamV2.java | 163 ++++++++++++ .../register/BitFieldServiceRegister.java | 2 +- .../register/FloatServiceRegister.java | 2 +- .../register/IndexedListServiceRegister.java | 2 +- .../register/IntegerServiceRegister.java | 2 +- .../servicelink/register/ServiceRegister.java | 27 +- 15 files changed, 987 insertions(+), 27 deletions(-) create mode 100644 src/org/hwo/servicelink/ng/AsynchronServiceLinkProvider.java create mode 100644 src/org/hwo/servicelink/ng/ObjectPool.java create mode 100644 src/org/hwo/servicelink/ng/RegBUSInterface.java create mode 100644 src/org/hwo/servicelink/ng/ServiceLink.java create mode 100644 src/org/hwo/servicelink/ng/ServiceLinkRequestBuffer.java create mode 100644 src/org/hwo/servicelink/ng/ServiceLinkStream.java create mode 100644 src/org/hwo/servicelink/ng/ServiceRegisterCache.java create mode 100644 src/org/hwo/servicelink/ng/ServiceRegisterListener.java create mode 100644 src/org/hwo/servicelink/ng/StreamContainer.java create mode 100644 src/org/hwo/servicelink/ng/TelegramStreamV2.java diff --git a/src/org/hwo/servicelink/ng/AsynchronServiceLinkProvider.java b/src/org/hwo/servicelink/ng/AsynchronServiceLinkProvider.java new file mode 100644 index 0000000..d03f81c --- /dev/null +++ b/src/org/hwo/servicelink/ng/AsynchronServiceLinkProvider.java @@ -0,0 +1,100 @@ +package org.hwo.servicelink.ng; + +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; + +public class AsynchronServiceLinkProvider { + + ServiceRegisterCache cache; + Hashtable> serviceRegisterListeners; + + public AsynchronServiceLinkProvider(ServiceRegisterCache cache){ + this.cache = cache; + this.serviceRegisterListeners = new Hashtable>(); + } + + + private List getListeners(Integer hash){ + if (!serviceRegisterListeners.containsKey(hash)) + serviceRegisterListeners.put(hash, new LinkedList()); + + return serviceRegisterListeners.get(hash); + } + + public void addServiceRegisterListener(int ax,int node,int registerno,boolean asFloat,ServiceRegisterListener listener){ + getListeners(cache.calcHash(ax, node, registerno,asFloat)).add(listener); + } + public void removeServiceRegisterListener(int ax,int node,int registerno,boolean asFloat,ServiceRegisterListener listener){ + getListeners(cache.calcHash(ax, node, registerno,asFloat)).remove(listener); + } + + public Hashtable> getServiceRegisterListeners() { + return serviceRegisterListeners; + } + public void setServiceRegisterListeners( + Hashtable> serviceRegisterListeners) { + this.serviceRegisterListeners = serviceRegisterListeners; + } + + /* + public void telegramReceived(ServiceLinkTelegram telegram){ + + if ((telegram.getOpcode() & ServiceLinkTelegram.REQ_READ) != 0){ + int hash = cache.calcHash(telegram.getAddress(), ((telegram.getOpcode() & ServiceLinkTelegram.REQ_FLOAT) == ServiceLinkTelegram.REQ_FLOAT)); + + cache.updateValue(hash, telegram.getValue()); + + //fireUpdates(hash); + } + } + */ + + public void fireUpdates(int hash){ + Object v = cache.getCachedValue(hash); + + if (Integer.class.isInstance(v)){ + Integer i = (Integer)v; + + for (ServiceRegisterListener listener: getListeners(hash)){ + listener.ServiceRegisterValueUpdated(ServiceRegisterCache.axFromHash(hash),ServiceRegisterCache.nodeFromHash(hash),ServiceRegisterCache.regFromHash(hash),i); + } + } + if (Float.class.isInstance(v)){ + Float f = (Float)v; + + for (ServiceRegisterListener listener: getListeners(hash)){ + listener.ServiceRegisterValueUpdated(ServiceRegisterCache.axFromHash(hash),ServiceRegisterCache.nodeFromHash(hash),ServiceRegisterCache.regFromHash(hash),f); + } + } + + } + + public void update(){ + + for (Integer hash: serviceRegisterListeners.keySet()){ + if (!getListeners(hash).isEmpty()){ + + cache.updateValue(hash); + fireUpdates(hash); + + /* + int opcode = ServiceLinkTelegram.REQ_READ; + if ((hash & 0x40000000)!=0){ + opcode |= ServiceLinkTelegram.REQ_FLOAT; + } + + ServiceLinkTelegram telegram = cache.getServiceLink().createTelegram(cache.axFromHash(hash), cache.nodeFromHash(hash), cache.regFromHash(hash), opcode, null); + + log(DEBUGDETAIL,"non-pending request: %s", telegram.getAddress() ); + + cache.getServiceLink().queueRequestNonPending(telegram); + + cache.getServiceLink().queueRequest(telegram); + */ + } + } + } + + +} diff --git a/src/org/hwo/servicelink/ng/ObjectPool.java b/src/org/hwo/servicelink/ng/ObjectPool.java new file mode 100644 index 0000000..ef8f5a9 --- /dev/null +++ b/src/org/hwo/servicelink/ng/ObjectPool.java @@ -0,0 +1,25 @@ +package org.hwo.servicelink.ng; + +import java.util.LinkedList; + +public class ObjectPool { + + static LinkedList requestBuffers = new LinkedList<>(); + + private ObjectPool() + { + } + + public synchronized static ServiceLinkRequestBuffer popRequestBuffer() { + if (requestBuffers.size() == 0) { + return new ServiceLinkRequestBuffer(); + } + return requestBuffers.removeFirst(); + } + public synchronized static void push(ServiceLinkRequestBuffer buffer) { + buffer.clear(); + requestBuffers.add(buffer); + } + + +} diff --git a/src/org/hwo/servicelink/ng/RegBUSInterface.java b/src/org/hwo/servicelink/ng/RegBUSInterface.java new file mode 100644 index 0000000..d230a3d --- /dev/null +++ b/src/org/hwo/servicelink/ng/RegBUSInterface.java @@ -0,0 +1,13 @@ +package org.hwo.servicelink.ng; + +public interface RegBUSInterface { + + boolean isConnected(); + + Float readFloat(int ax,int node,int reg); + Integer readInteger(int ax,int node,int reg); + + boolean writeFloat(int ax,int node,int reg,float value); + boolean writeInteger(int ax,int node,int reg,int value); + +} diff --git a/src/org/hwo/servicelink/ng/ServiceLink.java b/src/org/hwo/servicelink/ng/ServiceLink.java new file mode 100644 index 0000000..325d595 --- /dev/null +++ b/src/org/hwo/servicelink/ng/ServiceLink.java @@ -0,0 +1,237 @@ +package org.hwo.servicelink.ng; + +import java.io.IOException; +import java.util.Hashtable; + +import javax.swing.DebugGraphics; + +import org.hwo.Smoother; + +import static org.hwo.logging.Logging.*; +import static org.hwo.logging.LogLevel.*; + +public class ServiceLink implements RegBUSInterface { + + ServiceLinkStream stream = null; + Hashtable pendingRequests = new Hashtable<>(); + int timeout = 175; + boolean closed = false; + + ServiceRegisterCache registerCache = new ServiceRegisterCache(this); + AsynchronServiceLinkProvider asynchronServiceLinkProvider = new AsynchronServiceLinkProvider(registerCache); + + Smoother turnAroundTime = new Smoother(); + + Thread readerThread = new Thread(new Runnable() { + @Override + public void run() { + reader(); + } + }); + + public ServiceLink() { + this.readerThread.start(); + this.initialize(); + } + + public ServiceLink(ServiceLinkStream stream) { + this.stream = stream; + this.readerThread.start(); + this.initialize(); + } + + private void initialize() { + this.turnAroundTime.setTn(10); + } + + public void close() { + this.stream.close(); + } + + @Override + public boolean isConnected() { + return (this.stream != null) && (this.stream.isConnected()); + } + + public ServiceRegisterCache getRegisterCache() { + return registerCache; + } + + public AsynchronServiceLinkProvider getAsynchronServiceLinkProvider() { + return asynchronServiceLinkProvider; + } + + private boolean request(ServiceLinkRequestBuffer buffer) { + long tStart = System.currentTimeMillis(); + + if ((this.stream == null)||(!this.stream.isConnected())) { + return false; + } + + synchronized(this.pendingRequests) { + this.pendingRequests.put(buffer.hashCode(), buffer); + } + + synchronized(buffer) { + try { + this.stream.write(buffer); + buffer.wait(this.timeout); + } catch (Exception e) { + log(e); + } + } + + synchronized(this.pendingRequests) { + this.pendingRequests.remove(buffer.hashCode()); + } + + long tLen = System.currentTimeMillis() - tStart; + turnAroundTime.cycle((int)tLen); + + return buffer.isSuccess(); + } + + public int getTurnAroundTime() { + return this.turnAroundTime.getLastValue(); + } + + public synchronized ServiceLinkStream getServiceLinkStream() { + return stream; + } + public synchronized void setServiceLinkStream(ServiceLinkStream stream) { + this.stream = stream; + } + + + @Override + public Float readFloat(int ax, int node, int reg) { + Float result = null; + ServiceLinkRequestBuffer buffer = ObjectPool.popRequestBuffer(); + + buffer.setAx(ax); + buffer.setNode(node); + buffer.setRegister(reg); + buffer.setValue(0.0f); + + if (request(buffer)) { + result = (Float)buffer.getValue(); + } + + ObjectPool.push(buffer); + return result; + } + + @Override + public Integer readInteger(int ax, int node, int reg) { + Integer result = null; + ServiceLinkRequestBuffer buffer = ObjectPool.popRequestBuffer(); + + buffer.setAx(ax); + buffer.setNode(node); + buffer.setRegister(reg); + buffer.setValue(0); + + if (request(buffer)) { + result = (Integer)buffer.getValue(); + } + + ObjectPool.push(buffer); + return result; + } + + @Override + public boolean writeFloat(int ax, int node, int reg, float value) { + ServiceLinkRequestBuffer buffer = ObjectPool.popRequestBuffer(); + + buffer.setAx(ax); + buffer.setNode(node); + buffer.setRegister(reg); + buffer.setValue(value); + + boolean success = request(buffer); + + ObjectPool.push(buffer); + + return success; + } + + @Override + public boolean writeInteger(int ax, int node, int reg, int value) { + ServiceLinkRequestBuffer buffer = ObjectPool.popRequestBuffer(); + + buffer.setAx(ax); + buffer.setNode(node); + buffer.setRegister(reg); + buffer.setValue(value); + + boolean success = request(buffer); + + ObjectPool.push(buffer); + + return success; + } + + public int getTimeout() { + return timeout; + } + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + private void reader() { + ServiceLinkRequestBuffer buffer = new ServiceLinkRequestBuffer(); + + while (!closed) { + if ((this.stream == null) || !this.stream.isConnected()) { + try { + log(DEBUG,"ServiceLink:reader() sleeps..."); + Thread.sleep(1000); + log(DEBUG,"ServiceLink:reader() slept."); + } catch (InterruptedException e) { + log(e); + } + } else { + buffer.clear(); + try { + if (this.stream.isConnected() && this.stream.read(buffer)) { + + int hash = buffer.hashCode(); + ServiceLinkRequestBuffer req; + + synchronized(this.pendingRequests) { + req = this.pendingRequests.remove(hash); + } + + if (req != null) { + req.setValue(buffer.getValue()); + req.setSuccess(buffer.isSuccess()); + + + synchronized(req) { + req.notifyAll(); + } + } else { + log(DEBUG,"REPLY WITHOUT PENDING REQUEST"); + } + } + } catch (Exception e) { + log(e); + close(); + try { + Thread.sleep(250); + } catch (InterruptedException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + + log(DEBUG,"ServiceLinke:reader() exits"); + + } + + + + +} diff --git a/src/org/hwo/servicelink/ng/ServiceLinkRequestBuffer.java b/src/org/hwo/servicelink/ng/ServiceLinkRequestBuffer.java new file mode 100644 index 0000000..e0ab29c --- /dev/null +++ b/src/org/hwo/servicelink/ng/ServiceLinkRequestBuffer.java @@ -0,0 +1,124 @@ +package org.hwo.servicelink.ng; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class ServiceLinkRequestBuffer { + + int ax; + int node; + int register; + Object value; + boolean write; + boolean reply; + + boolean success; + + public ServiceLinkRequestBuffer() + { + } + + public void clear() { + ax = 0; + node = 0; + register = 0; + value = null; + write = false; + success = false; + } + + @Override + public int hashCode() { + return ((ax & 0x0F) << 20) | ((node & 0x0F) << 16) | ((register & 0xFFFF) << 0) | (write ? 0x01000000 : 0) | (hasFloatValue() ? 0x02000000 : 0); + } + + public boolean hasFloatValue() { + return Float.class.isInstance(this.value) || Double.class.isInstance(this.value); + } + public boolean hasIntegerValue() { + return Integer.class.isInstance(this.value); + } + + 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) { + if (register < 0) { + register += 65536; + } + this.register = register; + } + + + public byte[] getValueAsBytes() { + byte[] v = new byte[4]; + if (Float.class.isInstance(value) || Double.class.isInstance(value)) { + ByteBuffer.wrap(v).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().put(Float.floatToIntBits((Float)value)); + } else if (Integer.class.isInstance(value)) { + ByteBuffer.wrap(v).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().put((Integer)value); + } + return v; + } + + public Object getValue() { + return value; + } + + + public void setValue(Object value) { + if (!Integer.class.isInstance(value) && !Float.class.isInstance(value) && !Double.class.isInstance(value)) { + throw new IllegalArgumentException(); + } + this.value = value; + } + + public boolean isWrite() { + return write; + } + + public void setWrite(boolean write) { + this.write = write; + } + + public boolean isReply() { + return reply; + } + public void setReply(boolean reply) { + this.reply = reply; + } + + public boolean isSuccess() { + return success; + } + public void setSuccess(boolean success) { + this.success = success; + } + + @Override + public String toString() { + return String.format("[ServiceLinkRequestBuffer(ax=%d node=%d reg=%d value=%s write=%s success=%s hash=0x%08X)]",ax,node,register,value,write,success,hashCode()); + } + +} diff --git a/src/org/hwo/servicelink/ng/ServiceLinkStream.java b/src/org/hwo/servicelink/ng/ServiceLinkStream.java new file mode 100644 index 0000000..6c9880b --- /dev/null +++ b/src/org/hwo/servicelink/ng/ServiceLinkStream.java @@ -0,0 +1,37 @@ +package org.hwo.servicelink.ng; + +import java.io.IOException; + +import org.hwo.logging.Logging; + +public abstract class ServiceLinkStream { + + protected StreamContainer streamContainer; + + abstract boolean write(ServiceLinkRequestBuffer buffer) throws IOException; + abstract boolean read(ServiceLinkRequestBuffer buffer) throws IOException; + + abstract boolean isConnected(); + abstract void close(); + + ServiceLinkRequestBuffer read() { + ServiceLinkRequestBuffer buffer = ObjectPool.popRequestBuffer(); + try { + if (read(buffer)) { + return buffer; + } + } catch (Exception e) { + Logging.log(e); + } + ObjectPool.push(buffer); + return null; + } + + public StreamContainer getStreamContainer() { + return streamContainer; + } + public void setStreamContainer(StreamContainer streamContainer) { + this.streamContainer = streamContainer; + } + +} diff --git a/src/org/hwo/servicelink/ng/ServiceRegisterCache.java b/src/org/hwo/servicelink/ng/ServiceRegisterCache.java new file mode 100644 index 0000000..a27b529 --- /dev/null +++ b/src/org/hwo/servicelink/ng/ServiceRegisterCache.java @@ -0,0 +1,159 @@ +package org.hwo.servicelink.ng; + +import java.util.Hashtable; +import static org.hwo.logging.Logging.*; +import static org.hwo.logging.LogLevel.*; + +public class ServiceRegisterCache { + ServiceLink serviceLink; + Hashtable + cache; + + public class BaseCacheItem + { + Integer ax, + node, + register; + + boolean isFloat; + + long lastReadTime; + + Object value; + + public BaseCacheItem(int hash){ + this.ax = axFromHash(hash); + this.node = nodeFromHash(hash); + this.register = regFromHash(hash); + this.isFloat = ((hash & 0x40000000) != 0); + this.value = null; + } + + public BaseCacheItem(int ax,int node,int register, boolean isFloat) + { + this.ax = ax; + this.node = node; + this.register = register; + this.isFloat = isFloat; + this.value = null; + } + + long age() + { + return System.currentTimeMillis() - lastReadTime; + } + + boolean isOld() + { + return age() > 250; + } + + private void fetchValue(){ + if (isOld() && serviceLink.isConnected()) + { + try { + if (isFloat){ + Float f = serviceLink.readFloat(ax.byteValue(),node.byteValue(),register); + setValue(f); + } else { + Integer i = serviceLink.readInteger(ax.byteValue(),node.byteValue(),register); + setValue(i); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public Object getValue(){ + if (isOld()){ + log(DEBUGDETAIL,"OLDCACHE:SLA: [%d:%d:%d:%s] = %s", ax,node,register,isFloat ? "F" : "I",value); + fetchValue(); + log(DEBUGDETAIL,"NEWCACHE:SLA: [%d:%d:%d:%s] = %s", ax,node,register,isFloat ? "F" : "I",value); + } + + return value; + } + + public void setValue(Object value){ + this.value = value; + this.lastReadTime = System.currentTimeMillis(); + log(DEBUGDETAIL,"CACHE: SLA: [%d:%d:%d:%s] = %s", ax,node,register,isFloat ? "F" : "I",value); + } + + public void invalidate(){ + this.lastReadTime = 0; + } + } + + + + public static Integer axFromHash(Integer hash){ + return (hash >> 20) & 0x0F; + } + public static Integer nodeFromHash(Integer hash){ + return (hash >> 16) & 0x0F; + } + public static Integer regFromHash(Integer hash){ + return (hash) & 0xFFFF; + } + + public int calcHash(int ax,int node,int register,boolean isFloat) + { + return (isFloat ? 0x40000000 : 0) | (ax << 20) | (node << 16) | register; + } + + ServiceRegisterCache(ServiceLink serviceLink) + { + this.serviceLink = serviceLink; + this.cache = new Hashtable<>(); + } + + public ServiceLink getServiceLink() { + return serviceLink; + } + + private BaseCacheItem getCacheItem(int hash){ + if (!cache.containsKey(hash)){ + BaseCacheItem bci = new BaseCacheItem(hash); + cache.put(new Integer(hash), bci); + log( DEBUGDETAIL, "new cache-item: 0x%08x = %s", hash, bci); + } + return cache.get(hash); + } + + public void updateValue(int hash){ + BaseCacheItem bci = getCacheItem(hash); + bci.invalidate(); + bci.getValue(); + } + + public void updateValue(int hash,Object value){ + getCacheItem(hash).setValue(value); + } + + public synchronized Object getCachedValue(int hash){ + return getCacheItem(hash).getValue(); + } + public synchronized Object getCachedValue(int ax,int node,int register,boolean isFloat){ + int hash = calcHash(ax, node, register, isFloat); + return getCacheItem(hash).getValue(); + } + + public synchronized Integer getCachedInteger(int ax,int node,int register) + { + return (Integer)getCachedValue(ax, node, register, false); + } + + public synchronized Float getCachedFloat(int ax,int node,int register) + { + return (Float)getCachedValue(ax, node, register, true); + } + + public synchronized void invalidate(int ax,int node,int register,boolean isFloat) + { + cache.remove(calcHash(ax, node, register,isFloat)); + } + +} diff --git a/src/org/hwo/servicelink/ng/ServiceRegisterListener.java b/src/org/hwo/servicelink/ng/ServiceRegisterListener.java new file mode 100644 index 0000000..d3023b5 --- /dev/null +++ b/src/org/hwo/servicelink/ng/ServiceRegisterListener.java @@ -0,0 +1,8 @@ +package org.hwo.servicelink.ng; + +public interface ServiceRegisterListener { + + void ServiceRegisterValueUpdated(int ax,int node,int registervalue,Integer value); + void ServiceRegisterValueUpdated(int ax,int node,int registervalue,Float value); + +} diff --git a/src/org/hwo/servicelink/ng/StreamContainer.java b/src/org/hwo/servicelink/ng/StreamContainer.java new file mode 100644 index 0000000..76bda82 --- /dev/null +++ b/src/org/hwo/servicelink/ng/StreamContainer.java @@ -0,0 +1,113 @@ +package org.hwo.servicelink.ng; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +import static org.hwo.logging.Logging.*; + +import org.hwo.io.NewSerialPort.NewSerialPort; + +public class StreamContainer { + + boolean exceptionCaught = false; + + InputStream inStream; + OutputStream outStream; + + Socket socket = null; + NewSerialPort newSerialPort = null; + + public StreamContainer(String url) { + + int dots = url.indexOf(':'); + String proto,target; + + if (dots == -1) { + proto = "serial"; + target = url; + } else { + proto = url.substring(0, dots); + target = url.substring(dots + 1); + } + + switch (proto) { + case "serial": + + newSerialPort = new NewSerialPort(target); + newSerialPort.setTimeOut(250); + if (newSerialPort.open()) { + inStream = newSerialPort.getInputStream(); + outStream = newSerialPort.getOutputStream(); + } + + break; + case "tcp": + + try { + socket = new Socket(target,3009); + socket.setSoTimeout(150); + socket.setTcpNoDelay(true); + + inStream = socket.getInputStream(); + outStream = socket.getOutputStream(); + + } catch (IOException e) { + log(e); + } + + + break; + } + + } + + public StreamContainer(InputStream inStream,OutputStream outStream) + { + this.inStream = inStream; + this.outStream = outStream; + } + + public StreamContainer(NewSerialPort serialPort) + { + this.inStream = serialPort.getInputStream(); + this.outStream = serialPort.getOutputStream(); + } + + public StreamContainer(Socket socket) throws IOException + { + this.inStream = socket.getInputStream(); + this.outStream = socket.getOutputStream(); + } + + public void close() { + try { + if (this.inStream != null) + this.inStream.close(); + + if (this.outStream != null) + this.outStream.close(); + + if (this.socket != null) { + this.socket.close(); + } + + if (this.newSerialPort != null) { + this.newSerialPort.close(); + } + + } catch (IOException e) { + log(e); + } + exceptionCaught = true; + } + + public InputStream getInStream() { + return inStream; + } + public OutputStream getOutStream() { + return outStream; + } + +} diff --git a/src/org/hwo/servicelink/ng/TelegramStreamV2.java b/src/org/hwo/servicelink/ng/TelegramStreamV2.java new file mode 100644 index 0000000..2a631b2 --- /dev/null +++ b/src/org/hwo/servicelink/ng/TelegramStreamV2.java @@ -0,0 +1,163 @@ +package org.hwo.servicelink.ng; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import org.hwo.ByteArrayHexlifier; +import static org.hwo.logging.Logging.*; +import static org.hwo.logging.LogLevel.*; + +public class TelegramStreamV2 extends ServiceLinkStream { + + boolean exceptionCaught = false; + + public TelegramStreamV2(){ + } + + public TelegramStreamV2(StreamContainer streamContainer) { + setStreamContainer(streamContainer); + } + + public TelegramStreamV2(InputStream inStream,OutputStream outStream){ + this.setStreamContainer(new StreamContainer(inStream,outStream)); + } + + public TelegramStreamV2(Socket socket) throws IOException { + this.setStreamContainer(new StreamContainer(socket)); + } + + @Override + boolean isConnected() { + return (this.streamContainer != null) && !exceptionCaught; + } + + @Override + void close() { + this.streamContainer.close(); + exceptionCaught = true; + } + + @Override + boolean write(ServiceLinkRequestBuffer rbuffer) throws IOException { + + if ((this.streamContainer == null) || (this.streamContainer.getOutStream() == null)) + { + throw new IOException(); + } + + byte[] buffer = new byte[8]; + + byte[] bv; + int i; + + i = rbuffer.isWrite() ? 0x01 : 0x00; + i |= rbuffer.hasFloatValue() ? 0x02 : 0x00; + + buffer[0] = (byte)i; + buffer[1] = (byte)( ((rbuffer.getAx()&0x0F)<<4) | (rbuffer.getNode() & 0x0F) ); + buffer[2] = (byte)(rbuffer.getRegister() & 0xFF); + buffer[3] = (byte)((rbuffer.getRegister()>>8) & 0xFF); + + bv = rbuffer.getValueAsBytes(); + buffer[4] = bv[0]; + buffer[5] = bv[1]; + buffer[6] = bv[2]; + buffer[7] = bv[3]; + + try { + log(DEBUGDETAIL,"TX BUFFER: %s",rbuffer); + log(DEBUGDETAIL,"TX BYTES: %s",ByteArrayHexlifier.byteArrayToString(buffer)); + + synchronized(this.streamContainer.getOutStream()) { + this.streamContainer.getOutStream().write(buffer); + } + + return true; + } catch (IOException e) { + exceptionCaught = true; + log(e); + } + return false; + } + + @Override + boolean read(ServiceLinkRequestBuffer rbuffer) throws IOException{ + byte[] buffer = new byte[8]; + int bufferUsed = 0; + + if ((streamContainer == null) || (this.streamContainer.getInStream() == null)) { + log(DEBUG,"TelegramStreamV2: streamContainer == null || getInStream() == null"); + throw new IOException(); + } + + try { + while (bufferUsed != 8) { + long start = System.currentTimeMillis(); + int n; + try { + n = streamContainer.getInStream().read(buffer, bufferUsed, 8 - bufferUsed); + } catch (SocketTimeoutException ste) { + n = 0; + } + if (n > 0){ + bufferUsed += n; + } else if (n < 0) { + throw new IOException(); + } + log(DEBUGDETAIL,"TelegramStreamV2: read(...): bufferUsed=%d n=%d dT=%dms",bufferUsed,n,System.currentTimeMillis() - start); + } + } catch (IOException e) { + exceptionCaught = true; + log(e); + throw new RuntimeException(e); + } + + log(DEBUGDETAIL,"RX BYTES: %s",ByteArrayHexlifier.byteArrayToString(buffer)); + + if (bufferUsed != 8){ + return false; + } + + rbuffer.setAx((buffer[1]>>4) & 0x0F); + rbuffer.setNode(buffer[1] & 0x0F); + rbuffer.setRegister((((int)buffer[2])&0xff) | (((int)buffer[3])<<8)&0xFF00); + rbuffer.setWrite( (buffer[0] & 0x01) == 0 ); + rbuffer.setSuccess( ( buffer[0] & 0x04 ) == 0 ); + + ByteBuffer bb = ByteBuffer.wrap(buffer); + + if ( (buffer[0] & 0x02 ) == 0) { + rbuffer.setValue(bb.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().get(1)); + } else { + rbuffer.setValue( bb.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer().get(1) ); + } + + log(DEBUGDETAIL,String.format("RX BUFFER: %s",rbuffer)); + + return rbuffer.isSuccess(); + } + + public InputStream getInStream() { + return streamContainer.getInStream(); + } + public OutputStream getOutStream() { + return streamContainer.getOutStream(); + } + + @Override + public StreamContainer getStreamContainer() { + return this.streamContainer; + } + + @Override + public void setStreamContainer(StreamContainer streamContainer) { + this.streamContainer = streamContainer; + exceptionCaught = false; + } + +} + diff --git a/src/org/hwo/ui/servicelink/register/BitFieldServiceRegister.java b/src/org/hwo/ui/servicelink/register/BitFieldServiceRegister.java index afdb2e5..03b6677 100644 --- a/src/org/hwo/ui/servicelink/register/BitFieldServiceRegister.java +++ b/src/org/hwo/ui/servicelink/register/BitFieldServiceRegister.java @@ -3,7 +3,7 @@ package org.hwo.ui.servicelink.register; import javax.swing.JComponent; import org.hwo.bitfields.BitField; -import org.hwo.servicelink.ServiceLink; +import org.hwo.servicelink.ng.ServiceLink; import org.hwo.bitfields.ui.BitFieldEditor; import org.w3c.dom.Element; diff --git a/src/org/hwo/ui/servicelink/register/FloatServiceRegister.java b/src/org/hwo/ui/servicelink/register/FloatServiceRegister.java index c798ab4..1682432 100644 --- a/src/org/hwo/ui/servicelink/register/FloatServiceRegister.java +++ b/src/org/hwo/ui/servicelink/register/FloatServiceRegister.java @@ -2,7 +2,7 @@ package org.hwo.ui.servicelink.register; import javax.swing.JComponent; -import org.hwo.servicelink.ServiceLink; +import org.hwo.servicelink.ng.ServiceLink; public class FloatServiceRegister extends ServiceRegister { diff --git a/src/org/hwo/ui/servicelink/register/IndexedListServiceRegister.java b/src/org/hwo/ui/servicelink/register/IndexedListServiceRegister.java index 0e8dac7..34d44ee 100644 --- a/src/org/hwo/ui/servicelink/register/IndexedListServiceRegister.java +++ b/src/org/hwo/ui/servicelink/register/IndexedListServiceRegister.java @@ -5,7 +5,7 @@ import java.util.LinkedList; import javax.swing.JComponent; -import org.hwo.servicelink.ServiceLink; +import org.hwo.servicelink.ng.ServiceLink; import org.hwo.ui.servicelink.register.IndexedListRegisterEditor.IndexedItem; import org.hwo.xml.NodeListIterator; import org.w3c.dom.Element; diff --git a/src/org/hwo/ui/servicelink/register/IntegerServiceRegister.java b/src/org/hwo/ui/servicelink/register/IntegerServiceRegister.java index 3d410e1..7581b81 100644 --- a/src/org/hwo/ui/servicelink/register/IntegerServiceRegister.java +++ b/src/org/hwo/ui/servicelink/register/IntegerServiceRegister.java @@ -2,7 +2,7 @@ package org.hwo.ui.servicelink.register; import javax.swing.JComponent; -import org.hwo.servicelink.ServiceLink; +import org.hwo.servicelink.ng.ServiceLink; public class IntegerServiceRegister extends ServiceRegister { diff --git a/src/org/hwo/ui/servicelink/register/ServiceRegister.java b/src/org/hwo/ui/servicelink/register/ServiceRegister.java index 9e17e12..c354cc4 100644 --- a/src/org/hwo/ui/servicelink/register/ServiceRegister.java +++ b/src/org/hwo/ui/servicelink/register/ServiceRegister.java @@ -1,16 +1,13 @@ package org.hwo.ui.servicelink.register; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import javax.swing.JComponent; import org.hwo.i18n.Messages; import org.hwo.interactiveobjects.InteractiveObject; -import org.hwo.servicelink.ServiceLink; -import org.hwo.servicelink.ServiceRegisterListener; -import org.hwo.servicelink.exceptions.ServiceLinkException; -import org.hwo.servicelink.exceptions.ServiceLinkRequestFailedException; +import org.hwo.servicelink.ng.ServiceLink; +import org.hwo.servicelink.ng.ServiceRegisterListener; import org.hwo.models.TableMapper.TableColumn; import org.w3c.dom.Element; @@ -69,15 +66,11 @@ public abstract class ServiceRegister implements ServiceRegisterListener { private boolean asFloat; - private String registerType; private String registerName; protected Integer lastAsyncIntValue; protected Float lastAsyncFloatValue; - private ServiceRegisterControl - serviceRegisterControl; - public ServiceRegister(ServiceLink serviceLink,boolean asFloat) { this.serviceLink = serviceLink; @@ -199,13 +192,7 @@ public abstract class ServiceRegister implements ServiceRegisterListener { public Float readFloatValueSynchron() { - try { - return serviceLink.readFloat(ax.byteValue(), node.byteValue(), register); - } catch (ServiceLinkRequestFailedException e) { - } catch (IOException e) { - } catch (ServiceLinkException e) { - } - return null; + return serviceLink.readFloat(ax.byteValue(), node.byteValue(), register); } @@ -218,13 +205,7 @@ public abstract class ServiceRegister implements ServiceRegisterListener { } public void writeIntegerValue(Integer value) { - try - { - this.serviceLink.writeInt(ax.byteValue(), node.byteValue(), register,value); - } catch (Exception e) - { - e.printStackTrace(); - } + this.serviceLink.writeInteger(ax.byteValue(), node.byteValue(), register,value); } @Override