Next Generation Servicelink Implementation (serial,tcp, streams)
parent
50913ab552
commit
71712279cf
|
@ -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<Integer, List<ServiceRegisterListener>> serviceRegisterListeners;
|
||||||
|
|
||||||
|
public AsynchronServiceLinkProvider(ServiceRegisterCache cache){
|
||||||
|
this.cache = cache;
|
||||||
|
this.serviceRegisterListeners = new Hashtable<Integer, List<ServiceRegisterListener>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private List<ServiceRegisterListener> getListeners(Integer hash){
|
||||||
|
if (!serviceRegisterListeners.containsKey(hash))
|
||||||
|
serviceRegisterListeners.put(hash, new LinkedList<ServiceRegisterListener>());
|
||||||
|
|
||||||
|
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<Integer, List<ServiceRegisterListener>> getServiceRegisterListeners() {
|
||||||
|
return serviceRegisterListeners;
|
||||||
|
}
|
||||||
|
public void setServiceRegisterListeners(
|
||||||
|
Hashtable<Integer, List<ServiceRegisterListener>> 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);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package org.hwo.servicelink.ng;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class ObjectPool {
|
||||||
|
|
||||||
|
static LinkedList<ServiceLinkRequestBuffer> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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<Integer,ServiceLinkRequestBuffer> 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");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Integer, BaseCacheItem>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package org.hwo.ui.servicelink.register;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
import org.hwo.bitfields.BitField;
|
import org.hwo.bitfields.BitField;
|
||||||
import org.hwo.servicelink.ServiceLink;
|
import org.hwo.servicelink.ng.ServiceLink;
|
||||||
import org.hwo.bitfields.ui.BitFieldEditor;
|
import org.hwo.bitfields.ui.BitFieldEditor;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ package org.hwo.ui.servicelink.register;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
import org.hwo.servicelink.ServiceLink;
|
import org.hwo.servicelink.ng.ServiceLink;
|
||||||
|
|
||||||
public class FloatServiceRegister extends ServiceRegister {
|
public class FloatServiceRegister extends ServiceRegister {
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import java.util.LinkedList;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
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.ui.servicelink.register.IndexedListRegisterEditor.IndexedItem;
|
||||||
import org.hwo.xml.NodeListIterator;
|
import org.hwo.xml.NodeListIterator;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
|
@ -2,7 +2,7 @@ package org.hwo.ui.servicelink.register;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
import org.hwo.servicelink.ServiceLink;
|
import org.hwo.servicelink.ng.ServiceLink;
|
||||||
|
|
||||||
public class IntegerServiceRegister extends ServiceRegister {
|
public class IntegerServiceRegister extends ServiceRegister {
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
package org.hwo.ui.servicelink.register;
|
package org.hwo.ui.servicelink.register;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
import org.hwo.i18n.Messages;
|
import org.hwo.i18n.Messages;
|
||||||
import org.hwo.interactiveobjects.InteractiveObject;
|
import org.hwo.interactiveobjects.InteractiveObject;
|
||||||
import org.hwo.servicelink.ServiceLink;
|
import org.hwo.servicelink.ng.ServiceLink;
|
||||||
import org.hwo.servicelink.ServiceRegisterListener;
|
import org.hwo.servicelink.ng.ServiceRegisterListener;
|
||||||
import org.hwo.servicelink.exceptions.ServiceLinkException;
|
|
||||||
import org.hwo.servicelink.exceptions.ServiceLinkRequestFailedException;
|
|
||||||
import org.hwo.models.TableMapper.TableColumn;
|
import org.hwo.models.TableMapper.TableColumn;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
@ -69,15 +66,11 @@ public abstract class ServiceRegister implements ServiceRegisterListener {
|
||||||
|
|
||||||
private boolean asFloat;
|
private boolean asFloat;
|
||||||
|
|
||||||
private String registerType;
|
|
||||||
private String registerName;
|
private String registerName;
|
||||||
|
|
||||||
protected Integer lastAsyncIntValue;
|
protected Integer lastAsyncIntValue;
|
||||||
protected Float lastAsyncFloatValue;
|
protected Float lastAsyncFloatValue;
|
||||||
|
|
||||||
private ServiceRegisterControl
|
|
||||||
serviceRegisterControl;
|
|
||||||
|
|
||||||
public ServiceRegister(ServiceLink serviceLink,boolean asFloat)
|
public ServiceRegister(ServiceLink serviceLink,boolean asFloat)
|
||||||
{
|
{
|
||||||
this.serviceLink = serviceLink;
|
this.serviceLink = serviceLink;
|
||||||
|
@ -199,13 +192,7 @@ public abstract class ServiceRegister implements ServiceRegisterListener {
|
||||||
|
|
||||||
public Float readFloatValueSynchron()
|
public Float readFloatValueSynchron()
|
||||||
{
|
{
|
||||||
try {
|
return serviceLink.readFloat(ax.byteValue(), node.byteValue(), register);
|
||||||
return serviceLink.readFloat(ax.byteValue(), node.byteValue(), register);
|
|
||||||
} catch (ServiceLinkRequestFailedException e) {
|
|
||||||
} catch (IOException e) {
|
|
||||||
} catch (ServiceLinkException e) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,13 +205,7 @@ public abstract class ServiceRegister implements ServiceRegisterListener {
|
||||||
}
|
}
|
||||||
public void writeIntegerValue(Integer value)
|
public void writeIntegerValue(Integer value)
|
||||||
{
|
{
|
||||||
try
|
this.serviceLink.writeInteger(ax.byteValue(), node.byteValue(), register,value);
|
||||||
{
|
|
||||||
this.serviceLink.writeInt(ax.byteValue(), node.byteValue(), register,value);
|
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue