WIP161212

master
Harald Wolff 2016-12-12 11:34:21 +01:00
parent 0d07076547
commit 984dd94fd1
5 changed files with 206 additions and 104 deletions

View File

@ -3,6 +3,8 @@ package org.hwo.servicelink;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import static org.hwo.logging.Logging.*;
import static org.hwo.logging.LogLevel.*;
public class AsynchronServiceLinkProvider {
@ -13,23 +15,7 @@ public class AsynchronServiceLinkProvider {
this.cache = cache;
this.serviceRegisterListeners = new Hashtable<Integer, List<ServiceRegisterListener>>();
}
private Integer calcRegisterHash(int ax,int node,int registerno,boolean asFloat){
Integer hash = (ax << 24) | (node << 16) | registerno;
if (asFloat)
hash |= 0x40000000;
return hash;
}
private Integer axFromHash(Integer hash){
return (hash >> 24) & 0x0F;
}
private Integer nodeFromHash(Integer hash){
return (hash >> 16) & 0x0F;
}
private Integer regFromHash(Integer hash){
return (hash) & 0xFFFF;
}
private List<ServiceRegisterListener> getListeners(Integer hash){
if (!serviceRegisterListeners.containsKey(hash))
@ -39,10 +25,10 @@ public class AsynchronServiceLinkProvider {
}
public void addServiceRegisterListener(int ax,int node,int registerno,boolean asFloat,ServiceRegisterListener listener){
getListeners(calcRegisterHash(ax, node, registerno,asFloat)).add(listener);
getListeners(cache.calcHash(ax, node, registerno,asFloat)).add(listener);
}
public void removeServiceRegisterListener(int ax,int node,int registerno,boolean asFloat,ServiceRegisterListener listener){
getListeners(calcRegisterHash(ax, node, registerno,asFloat)).remove(listener);
getListeners(cache.calcHash(ax, node, registerno,asFloat)).remove(listener);
}
public Hashtable<Integer, List<ServiceRegisterListener>> getServiceRegisterListeners() {
@ -53,24 +39,61 @@ public class AsynchronServiceLinkProvider {
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));
log(DEBUGDETAIL,"servicelink cache update %s = %s", telegram.getAddress(), telegram.getValue());
cache.updateValue(hash, telegram.getValue());
//fireUpdates(hash);
}
}
public void fireUpdates(int hash){
ServiceLinkAddress sla = cache.getAddress(hash);
Object v = cache.getCachedValue(hash);
if (Integer.class.isInstance(v)){
Integer i = (Integer)v;
for (ServiceRegisterListener listener: getListeners(hash)){
listener.ServiceRegisterValueUpdated(sla.getAx(),sla.getNode(),sla.getRegister(),i);
}
}
if (Float.class.isInstance(v)){
Float f = (Float)v;
for (ServiceRegisterListener listener: getListeners(hash)){
listener.ServiceRegisterValueUpdated(sla.getAx(),sla.getNode(),sla.getRegister(),f);
}
}
}
public void update(){
for (Integer hash: serviceRegisterListeners.keySet()){
if (!getListeners(hash).isEmpty()){
//System.err.println(String.format("AsyncUpdate for Hash: 0x%08x", hash));
if ((hash & 0x40000000) != 0){
Float f = this.cache.getCachedFloat( axFromHash(hash),nodeFromHash(hash),regFromHash(hash));
for (ServiceRegisterListener listener: getListeners(hash)){
listener.ServiceRegisterValueUpdated(axFromHash(hash),nodeFromHash(hash),regFromHash(hash),f);
}
} else {
Integer i = this.cache.getCachedInteger( axFromHash(hash),nodeFromHash(hash),regFromHash(hash));
for (ServiceRegisterListener listener: getListeners(hash)){
listener.ServiceRegisterValueUpdated(axFromHash(hash),nodeFromHash(hash),regFromHash(hash),i);
}
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);
*/
}
}
}

View File

@ -2,6 +2,7 @@ package org.hwo.servicelink;
import static org.hwo.logging.Logging.log;
import java.awt.DisplayMode;
import java.io.IOException;
import java.util.Hashtable;
import java.util.LinkedList;
@ -64,7 +65,7 @@ public class ServiceLink implements NewSerialPortListener {
public ServiceLink(NewSerialPort serialPort)
{
this.requestTimeOut = 500;
this.requestTimeOut = 50;
this.serviceLinkListeners = new LinkedList<ServiceLinkListener>();
this.retries = 3;
@ -142,6 +143,13 @@ public class ServiceLink implements NewSerialPortListener {
/** Handling der Queues **/
public boolean isUseV2() {
return useV2;
}
public void setUseV2(boolean useV2) {
this.useV2 = useV2;
}
private void addPendingRequest(ServiceLinkTelegram request){
synchronized (pendingRequests) {
if (!pendingRequests.containsKey(request.getAddress())){
@ -174,7 +182,16 @@ public class ServiceLink implements NewSerialPortListener {
removePendingRequest(request);
}
public void queueRequestNonPending(ServiceLinkTelegram request){
synchronized (txQueue) {
txQueue.add(request);
txQueue.notify();
}
}
public void queueRequest(ServiceLinkTelegram request){
long ts_start = System.currentTimeMillis();
appendRequest(request);
synchronized (request) {
@ -187,6 +204,8 @@ public class ServiceLink implements NewSerialPortListener {
removeRequest(request);
requestTime.cycle( (int)(System.currentTimeMillis() - ts_start) );
log(DEBUG,"ServiceLink: queuedRequest: %s Value: %s",request.getAddress().toString(),request.value);
}
@ -197,15 +216,21 @@ public class ServiceLink implements NewSerialPortListener {
if (pendingRequests.containsKey(rx.getAddress())){
for (ServiceLinkTelegram pending: pendingRequests.get(rx.getAddress())){
log(DEBUGDETAIL,"Found Pending: %s", pending);
if ((pending.getOpcode() & (REQ_INT | REQ_FLOAT))==(rx.getOpcode() & (REQ_INT | REQ_FLOAT))){
synchronized (pending) {
pending.setValue(rx.getValue());
log(DEBUGDETAIL,"req.handling time: %d",rx.getTimestamp() - pending.getTimestamp());
pending.notifyAll();
}
}
}
}
}
asynchronServiceLinkProvider.telegramReceived(rx);
}
/** ENDE: Handling der Queues **/
@ -253,6 +278,15 @@ public class ServiceLink implements NewSerialPortListener {
serialPort.close();
}
public ServiceLinkTelegram createTelegram(int achse,int knoten,int register,int opcode,Object value){
ServiceLinkTelegram request = useV2 ?
new ServiceLinkV2Telegram(opcode, achse, knoten, register, value) :
new ServiceLinkV1Telegram(opcode, achse, knoten, register, value);
return request;
}
public Integer readInt(int achse,int knoten,int register) throws IOException, ServiceLinkException, ServiceLinkRequestFailedException
{
ServiceLinkTelegram request = useV2 ?
@ -397,6 +431,13 @@ public class ServiceLink implements NewSerialPortListener {
try {
log(DEBUGDETAIL,"TX BYTES: %s",ByteArrayHexlifier.byteArrayToString(txbytes));
serialPort.getOutputStream().write(txbytes);
/* try {
sleep(10);
} catch (InterruptedException e) {
log(e);
}
*/
} catch (IOException e) {
log(e);
}

View File

@ -25,7 +25,10 @@ public abstract class ServiceLinkTelegram {
Object
value;
long timestamp;
protected ServiceLinkTelegram(){
timestamp = System.currentTimeMillis();
}
protected ServiceLinkTelegram(int operation,int achse,int knoten,int register,Object value){
@ -34,6 +37,8 @@ public abstract class ServiceLinkTelegram {
this.value = value;
this.checkPlausible();
timestamp = System.currentTimeMillis();
}
private void checkPlausible(){
@ -85,5 +90,8 @@ public abstract class ServiceLinkTelegram {
return (getAddress().getAx()==0) && (getAddress().getNode()==0) && (getAddress().getRegister()==0) && (opcode == 0) && value.equals(0);
}
public long getTimestamp() {
return timestamp;
}
}

View File

@ -54,10 +54,8 @@ public class ServiceLinkV2Telegram extends ServiceLinkTelegram {
ByteBuffer bb = ByteBuffer.wrap(buffer);
if ((op & REQ_FLOAT)==REQ_FLOAT){
log(DEBUGDETAIL,"############################################################");
setValue( bb.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer().get(1) );
} else {
log(DEBUGDETAIL,"*************************************************************");
setValue( bb.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().get(1) );
}

View File

@ -2,6 +2,8 @@ package org.hwo.servicelink;
import java.io.IOException;
import java.util.Hashtable;
import static org.hwo.logging.Logging.*;
import static org.hwo.logging.LogLevel.*;
public class ServiceRegisterCache {
@ -11,13 +13,27 @@ public class ServiceRegisterCache {
node,
register;
boolean isFloat;
long lastReadTime;
public BaseCacheItem(int ax,int node,int register)
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()
@ -29,107 +45,123 @@ public class ServiceRegisterCache {
{
return age() > 250;
}
}
public class IntegerCacheItem extends BaseCacheItem
{
public IntegerCacheItem(int ax,int node,int register)
{
super(ax,node,register);
intValue = null;
}
Integer intValue;
Integer intValue()
{
private void fetchValue(){
if (isOld() && serviceLink.isOpen())
{
try {
intValue = serviceLink.readInt(ax.byteValue(),node.byteValue(),register);
if (isFloat){
Float f = serviceLink.readFloat(ax.byteValue(),node.byteValue(),register);
} else {
Integer i = serviceLink.readInt(ax.byteValue(),node.byteValue(),register);
}
} catch (Exception e) {
e.printStackTrace();
intValue = null;
}
lastReadTime = System.currentTimeMillis();
}
return intValue;
}
public Object getValue(){
if (isOld())
fetchValue();
return value;
}
public void setValue(Object value){
this.value = value;
this.lastReadTime = System.currentTimeMillis();
log(DEBUGDETAIL,"cached value update: [%02d:%02d:%04d] = %s", ax,node,register,value);
}
public void invalidate(){
this.lastReadTime = 0;
}
}
public class FloatCacheItem extends BaseCacheItem
{
public FloatCacheItem(int ax,int node,int register)
{
super(ax,node,register);
floatValue = null;
}
Float floatValue;
Float floatValue()
{
if (isOld() && serviceLink.isOpen())
{
try {
floatValue = serviceLink.readFloat(ax.byteValue(),node.byteValue(),register);
} catch (Exception e) {
e.printStackTrace();
floatValue = null;
}
lastReadTime = System.currentTimeMillis();
}
return floatValue;
}
public Integer axFromHash(Integer hash){
return (hash >> 20) & 0x0F;
}
public Integer nodeFromHash(Integer hash){
return (hash >> 16) & 0x0F;
}
public Integer regFromHash(Integer hash){
return (hash) & 0xFFFF;
}
int calcHash(int ax,int node,int register)
public int calcHash(int ax,int node,int register,boolean isFloat)
{
return (ax << 20)|(node << 16)|register;
return (isFloat ? 0x40000000 : 0) | (ax << 20) | (node << 16) | register;
}
public int calcHash(ServiceLinkAddress sla,boolean isFloat){
Integer hash = (sla.getAx() << 20) | (sla.getNode() << 16) | sla.getRegister();
if (isFloat)
hash |= 0x40000000;
return hash;
}
public ServiceLinkAddress getAddress(int hash){
return new ServiceLinkAddress( axFromHash(hash), nodeFromHash(hash), regFromHash(hash) );
}
ServiceLink serviceLink;
Hashtable<Integer, IntegerCacheItem>
integerCache;
Hashtable<Integer, FloatCacheItem>
floatCache;
Hashtable<Integer, BaseCacheItem>
cache;
ServiceRegisterCache(ServiceLink serviceLink)
{
this.serviceLink = serviceLink;
this.integerCache = new Hashtable<Integer, ServiceRegisterCache.IntegerCacheItem>();
this.floatCache = new Hashtable<Integer, ServiceRegisterCache.FloatCacheItem>();
this.cache = new Hashtable<>();
}
public ServiceLink getServiceLink() {
return serviceLink;
}
private BaseCacheItem getCacheItem(int hash){
BaseCacheItem bci;
if (!cache.contains(hash)){
cache.put(hash, new BaseCacheItem(hash));
}
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)
{
int hash = calcHash(ax, node, register);
IntegerCacheItem ici = integerCache.get(hash);
if (ici == null)
{
ici = new IntegerCacheItem(ax,node,register);
integerCache.put(hash, ici);
}
return ici.intValue();
return (Integer)getCachedValue(ax, node, register, false);
}
public synchronized Float getCachedFloat(int ax,int node,int register)
{
int hash = calcHash(ax, node, register);
FloatCacheItem ici = floatCache.get(hash);
if (ici == null)
{
ici = new FloatCacheItem(ax,node,register);
floatCache.put(hash, ici);
}
return ici.floatValue();
return (Float)getCachedValue(ax, node, register, true);
}
public synchronized void invalidate(int ax,int node,int register)
public synchronized void invalidate(int ax,int node,int register,boolean isFloat)
{
int hash = calcHash(ax, node, register);
integerCache.remove(hash);
floatCache.remove(hash);
cache.remove(calcHash(ax, node, register,isFloat));
}
}