UartBus source documentation
UartBusDevice.java
1 package eu.javaexperience.electronic.uartbus.rpc.client.device;
2 
3 import java.lang.reflect.Method;
4 import java.lang.reflect.Type;
5 import java.util.Arrays;
6 import java.util.concurrent.TimeUnit;
7 
8 import eu.javaexperience.datastorage.TransactionException;
13 import eu.javaexperience.pdw.ProxyHelpedLazyImplementation;
14 import eu.javaexperience.reflect.Mirror;
15 
16 public class UartBusDevice
17 {
18  protected UartBus bus;
19  protected int address;
20 
21  public long timeout = 100;
22  public TimeUnit timeoutUnit = TimeUnit.MILLISECONDS;
23  public int retryCount = 5;
24 
25  protected final ProxyHelpedLazyImplementation<UbDeviceNs, UbDeviceNsLazyImpl, UbDevStdNsRoot> handler;
26 
27  public UbDevStdNsRoot getRpcRoot()
28  {
29  return handler.getRoot();
30  }
31 
32  public UartBusDevice(UartBus bus, int address)
33  {
34  this.bus = bus;
35  this.address = address;
36  handler = createNsHandler(this, UbDevStdNsRoot.class);
37  }
38 
39  public int getAddress()
40  {
41  return address;
42  }
43 
44  public static <R extends UbDeviceNs> ProxyHelpedLazyImplementation<UbDeviceNs, UbDeviceNsLazyImpl, R> createNsHandler(UartBusDevice device, Class<R> rootCls)
45  {
46  try
47  {
48  return new ProxyHelpedLazyImplementation<UbDeviceNs, UbDeviceNsLazyImpl, R>(UbDeviceNs.class, new UbDeviceNsLazyImpl(device), rootCls)
49  {
50  @Override
51  public Object handleInterfaceCall
52  (
53  UbDeviceNsLazyImpl root,
54  Method method,
55  Object[] params
56  )
57  throws Throwable
58  {
59  if(UbDeviceNs.class.isAssignableFrom(method.getReturnType()))
60  {
61  //wrapping the NS
62  if("cast".equals(method.getName()))
63  {
64  return wrapWithClass((Class) params[0], root);
65  }
66  else if("customNs".equals(method.getName()))
67  {
68  return stepPath(root, (Class) params[0], true, (short) params[1]);
69  }
70 
71  UbIndex ui = method.getAnnotation(UbIndex.class);
72  /*if(null == ui)
73  {
74  throw new RuntimeException("No namespace index specified for "+method);
75  }*/
76  return stepPath(root, (Class<R>) method.getReturnType(), null != ui, null == ui?-1:ui.ns(), params);
77  }
78 
79  return device.handleDeviceRpcCall(root.path, method, params);
80  }
81 
82  public Object stepPath(UbDeviceNsLazyImpl root, Class<R> cls, boolean hasNs, short ns, Object... objs) throws Exception
83  {
84  if(null == objs || 0 == objs.length)
85  {
86  byte[] p = Arrays.copyOf(root.path, root.path.length+1);
87  p[root.path.length] = (byte) ns;
88  return wrapWithClass(cls, new UbDeviceNsLazyImpl(root.dev, p));
89  }
90 
91  try(PacketAssembler pa = new PacketAssembler())
92  {
93  pa.write(root.path);
94  if(hasNs)
95  {
96  pa.writeByte(ns);
97  }
98 
99  UbRpcTools.appendElements(pa, objs);
100 
101  return wrapWithClass(cls, new UbDeviceNsLazyImpl(root.dev, pa.done()));
102  }
103  }
104 
105  @Override
106  protected void handleException(Throwable e)
107  {
108  Mirror.throwCheckedExceptionAsUnchecked(e);
109  }
110  };
111  }
112  catch(Exception e)
113  {
114  Mirror.propagateAnyway(e);
115  return null;
116  }
117  }
118 
119  protected Object handleDeviceRpcCall(byte[] path, Method method, Object[] params) throws Exception
120  {
121  PacketAssembler pa = new PacketAssembler();
122 
123  UbIndex ns = method.getAnnotation(UbIndex.class);
124  if(null == ns)
125  {
126  throw new IllegalStateException("Uartbus RPC function doesn't have @UbIndex annotation used to identify RPC function index: "+method);
127  }
128 
129  path = Arrays.copyOf(path, path.length+1);
130  path[path.length-1] = (byte) ns.ns();
131  UbRpcTools.appendElements(pa, path);
132  if(null != params && params.length > 0)
133  {
134  UbRpcTools.appendElements(pa, params);
135  }
136 
137  Type ret = method.getReturnType();
138  TransactionException trex = null;
139  byte[] data = pa.done();
140  boolean mayRetransmit = null != method.getAnnotation(UbRetransmittable.class);
141  for(int i=0;i<retryCount;++i)
142  {
143  try(UartbusTransaction tr = bus.newTransaction(address, path, data, true))
144  {
145  if(NoReturn.class == ret)
146  {
147  return null;
148  }
149 
150  try
151  {
152  byte[] res = tr.ensureResponse(timeout, timeoutUnit, method.toString());
153 
154  return UbRpcTools.extractOrThrowResult
155  (
156  method,
157  Arrays.copyOfRange(res, path.length+1, res.length)
158  );
159  }
160  catch(TransactionException ex)
161  {
162  if(!mayRetransmit)
163  {
164  throw ex;
165  }
166  trex = ex;
167  }
168  }
169  }
170  TransactionException te = new TransactionException("Device not responded after "+retryCount+" attempt.");
171  te.addSuppressed(trex);
172  throw te;
173  }
174 
175  public void setTimeout(long timeout, TimeUnit unit)
176  {
177  this.timeout = timeout;
178  this.timeoutUnit = unit;
179  }
180 
181  public UartBus getBus()
182  {
183  return bus;
184  }
185 }