UartBus source documentation
UbRpcTools.java
1 package eu.javaexperience.electronic.uartbus.rpc.client.device;
2 
3 import java.io.IOException;
4 import java.lang.reflect.Array;
5 import java.lang.reflect.Field;
6 import java.lang.reflect.Method;
7 import java.lang.reflect.ParameterizedType;
8 import java.lang.reflect.Type;
9 import java.math.BigInteger;
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.List;
13 
23 import eu.javaexperience.interfaces.simple.getBy.GetBy1;
24 import eu.javaexperience.nativ.posix.ERRNO;
25 import eu.javaexperience.nativ.posix.PosixErrnoException;
26 import eu.javaexperience.reflect.Mirror;
27 import eu.javaexperience.reflect.PrimitiveTools;
28 import eu.javaexperience.resource.pool.IssuedResource;
29 import eu.javaexperience.resource.pool.TrackedLimitedResourcePool;
30 import eu.javaexperience.text.StringTools;
31 
32 public class UbRpcTools
33 {
34  public static Object extractOrThrowResult(Method method, byte[] bs) throws PosixErrnoException
35  {
36  boolean posix = false;
37 
38  PacketReader pr = new PacketReader(bs);
39 
40  for(Class c:method.getExceptionTypes())
41  {
42  if(PosixErrnoException.class.isAssignableFrom(c))
43  {
44  posix = true;
45  break;
46  }
47  }
48 
49  if(posix)
50  {
51  short err = pr.readUByte();
52  if(0 != err)
53  {
54  throw new PosixErrnoException(ERRNO.ERRNOOfValue(err));
55  }
56  }
57 
58  Class<?> retc = method.getReturnType();
59 
60  if(Void.class == retc || void.class == retc)
61  {
62  return null;
63  }
64 
65  Object ret = readType(pr, retc, method.getGenericReturnType());
66  if(null != ret)
67  {
68  return ret;
69  }
70 
71  throw new RuntimeException("Unknown, unextractable returning type: "+method);
72  }
73 
74  protected static Object tryExtractStruct(Class c, Type t, PacketReader pr)
75  {
76  String n = StringTools.getSubstringAfterFirstString(c.getName(), "eu.javaexperience.struct.GenericStruct", null);
77  if(null == n)
78  {
79  return null;
80  }
81 
82  Integer p = Integer.parseInt(n);
83 
84  try
85  {
86  ParameterizedType pt = (ParameterizedType) t;
87  Type[] ts = pt.getActualTypeArguments();
88  Object ret = c.newInstance();
89 
90  for(int i=0;i<p;++i)
91  {
92  Field f = Mirror.getClassFieldOrNull(c, String.valueOf(((char)('a'+i))));
93  if(null != f)
94  {
95  f.set(ret, readType(pr, Mirror.extracClass(ts[i])));
96  }
97  }
98 
99  return ret;
100  }
101  catch(Exception e)
102  {
103  Mirror.propagateAnyway(e);
104  return null;
105  }
106  }
107 
108  protected static Object[] extractStruct(Object o)
109  {
110  String n = StringTools.getSubstringAfterFirstString(o.getClass().getName(), "eu.javaexperience.struct.GenericStruct", null);
111  if(null == n)
112  {
113  return null;
114  }
115 
116  Integer p = Integer.parseInt(n);
117  Object[] ret = new Object[p];
118  try
119  {
120  for(int i=0;i<p;++i)
121  {
122  Field f = Mirror.getClassFieldOrNull(o.getClass(), String.valueOf(((char)('a'+i))));
123  ret[i] = f.get(o);
124  }
125 
126  return ret;
127  }
128  catch(Exception e)
129  {
130  Mirror.propagateAnyway(e);
131  return null;
132  }
133  }
134 
135  public static Object readType(PacketReader reader, Class reqType)
136  {
137  return readType(reader, reqType, null);
138  }
139 
140  public static Object readType(PacketReader reader, Class reqClass, Type reqType)
141  {
142  reqClass = PrimitiveTools.toObjectClassType(reqClass, reqClass);
143 
144  if(reqClass == Boolean.class)
145  {
146  return 0 == reader.readSByte()? Boolean.FALSE:Boolean.TRUE;
147  }
148  else if(reqClass == Byte.class)
149  {
150  return reader.readSByte();
151  }
152  else if(reqClass == Character.class)
153  {
154  return (char) reader.readSByte();
155  }
156  else if(reqClass == Short.class)
157  {
158  return reader.readSShort();
159  }
160  else if(reqClass == Integer.class)
161  {
162  return reader.readSInt();
163  }
164  else if(reqClass == Long.class)
165  {
166  return reader.readSLong();
167  }
168  else if(reqClass == Float.class)
169  {
170  return reader.readFloat();
171  }
172  else if(reqClass == Double.class)
173  {
174  return reader.readDouble();
175  }
176  else if(reqClass == String.class)
177  {
178  return reader.readString();
179  }
180  else if(reqClass == byte[].class)
181  {
182  return reader.readBlobRemain();
183  }
184  else if(reqClass == VSigned.class)
185  {
186  return new VSigned(reader.readVsNumber());
187  }
188  else if(reqClass == VUnsigned.class)
189  {
190  return new VUnsigned(reader.readVuNumber());
191  }
192  else if(reqClass == uint8_t.class)
193  {
194  return new uint8_t(reader.readUByte());
195  }
196  else if(reqClass == uint16_t.class)
197  {
198  return new uint16_t(reader.readUShort());
199  }
200  else if
201  (
202  reqClass.getCanonicalName().startsWith("eu.javaexperience.struct.GenericStruct")
203  &&
204  null != reqType
205  )
206  {
207  return tryExtractStruct(reqClass, reqType, reader);
208  }
209  else if(reqClass.isArray())
210  {
211  List ret = new ArrayList();
212  while(reader.hasUnprocessedBytes())
213  {
214  ret.add(readType(reader, reqClass.getComponentType()));
215  }
216 
217  return ret.toArray((Object[]) Array.newInstance(reqClass.getComponentType(), 1));
218  }
219  else if(reqClass.isEnum())
220  {
221  return reqClass.getEnumConstants()[(int) reader.readVuint()];
222  }
223 
224  return null;
225  }
226 
227  public static boolean isUartbusDataType(Class o)
228  {
229  return
230  Boolean.class.isAssignableFrom(o) ||
231  Byte.class.isAssignableFrom(o) ||
232  uint8_t.class.isAssignableFrom(o) ||
233  uint16_t.class.isAssignableFrom(o) ||
234  Short.class.isAssignableFrom(o) ||
235  byte[].class.isAssignableFrom(o) ||
236  Number.class.isAssignableFrom(o) ||
237  String.class.isAssignableFrom(o) ||
238  VSigned.class.isAssignableFrom(o) ||
239  VUnsigned.class.isAssignableFrom(o) ||
240  o.isEnum()||
241  o.getCanonicalName().startsWith("eu.javaexperience.struct.GenericStruct")||
242  (o.isArray() && isUartbusDataType(o.getComponentType()))
243  ;
244  }
245 
246  public static boolean isUartbusDataType(Object o)
247  {
248  return isUartbusDataType(o.getClass());
249  }
250 
251  public static void appendElements(PacketAssembler pa, Object... elements) throws IOException
252  {
253  for(Object o:elements)
254  {
255  if(null == o)
256  {
257  throw new NullPointerException("Can't serialize null");
258  }
259  else if(o instanceof Boolean)
260  {
261  pa.writeByte((byte)((Boolean.FALSE.equals(o))?0:1));
262  }
263  else if(o instanceof Byte)
264  {
265  pa.writeByte((Byte) o);
266  }
267  else if(o instanceof uint8_t)
268  {
269  pa.writeByte((((uint8_t)o).value & 0xff));
270  }
271  else if(o instanceof uint16_t)
272  {
273  pa.writeShort((((uint16_t)o).value));
274  }
275  //note: if you miss int8_t and int16_t it is because are the same as byte and short
276  else if(o instanceof Short)
277  {
278  pa.writeShort((Short)o);
279  }
280  else if(o instanceof byte[])
281  {
282  pa.write((byte[]) o);
283  }
284  else if(o instanceof String)
285  {
286  pa.writeString(o.toString());
287  }
288  else if(o instanceof VSigned)
289  {
290  pa.writePackedValue(true, ((VSigned) o).value);
291  }
292  else if(o instanceof VUnsigned)
293  {
294  pa.writePackedValue(true, ((VUnsigned) o).value);
295  }
296 
297  //keep this in clast case from the type of numbers
298  else if(o instanceof Number)
299  {
300  pa.writePackedValue(true, (Number) o);
301  }
302  else if(o.getClass().isEnum())
303  {
304  pa.write(UartbusTools.packInt(false, ((Enum)o).ordinal()));
305  }
306  else if
307  (
308  o.getClass().getCanonicalName().startsWith("eu.javaexperience.struct.GenericStruct")
309  )
310  {
311  //serialize all value
312  appendElements(pa, extractStruct(o));
313  }
314  else if(o.getClass().isArray())
315  {
316  int len = Array.getLength(o);
317  for(int i=0;i<len;++i)
318  {
319  Object add = Array.get(o, i);
320  appendElements(pa, add);
321  }
322  }
323  else
324  {
325  throw new RuntimeException("Can't serialize packet component ("+(null == o?"null":o.getClass())+"): "+o);
326  }
327  }
328  }
329 
330  protected static final TrackedLimitedResourcePool<PacketAssembler> PA_POOL = new TrackedLimitedResourcePool<PacketAssembler>(()->new PacketAssembler(), 1024);
331 
332  public static byte[] toPacket(int to, int from, Object... elements)
333  {
334  try(IssuedResource<PacketAssembler> res = PA_POOL.acquireResource())
335  {
336  PacketAssembler pa = res.getResource();
337  pa.writeAddressing(from, to);
338  appendElements(pa, elements);
339 
340  pa.appendCrc8();
341  return pa.done();
342  }
343  catch(Exception e)
344  {
345  Mirror.propagateAnyway(e);
346  return null;
347  }
348  }
349 
350  public static GetBy1<Boolean, UartbusPacketDispatch> createRequestPacketAcceptor
351  (
352  Integer targetAddress,
353  byte[] path
354  )
355  {
356  return p->
357  {
358  if
359  (
360  null != targetAddress
361  &&
362  !targetAddress.equals(p.getPacket().to)
363  )
364  {
365  return false;
366  }
367 
368  if
369  (
370  null != path
371  &&
372  0 != path.length
373  )
374  {
375  byte[] pl = p.getPayload();
376  if(pl.length < path.length)
377  {
378  return false;
379  }
380  for(int i=0;i<path.length;++i)
381  {
382  if(path[i] != pl[i])
383  {
384  return false;
385  }
386  }
387 
388  p.setDispatchByteIndex(path.length);
389  }
390 
391  return true;
392  };
393  }
394 
395  public static String loadString(UbRemoteString str)
396  {
397  return loadString(str, 16);
398  }
399 
400  public static String loadString(UbRemoteString str, int maxGetLength)
401  {
402  int len = str.getLength().value.intValue();
403 
404  StringBuilder sb = new StringBuilder();
405 
406  VUnsigned rlen = new VUnsigned(BigInteger.valueOf(maxGetLength));
407 
408  while(sb.length() < len)
409  {
410  String app = new String(str.getStringPart(new VUnsigned(sb.length()), rlen));
411  if(0 == app.length() || sb.length() >= len)
412  {
413  break;
414  }
415  sb.append(app);
416  }
417 
418  if(sb.length() < len)
419  {
420  throw new RuntimeException("Can't load the whole string.");
421  }
422 
423  return sb.toString();
424  }
425 }