@robotical/raftjs 2.0.4 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,23 +7,32 @@
7
7
  //
8
8
  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9
9
 
10
- import { DeviceTypePollRespMetadata } from "./RaftDeviceInfo";
10
+ import { CustomFunctionDefinition, DeviceTypePollRespMetadata } from "./RaftDeviceInfo";
11
+
12
+ type CustomAttrJsFn = (
13
+ buf: Uint8Array,
14
+ attrValues: Record<string, number[]>,
15
+ attrValueVecs: number[][],
16
+ pollRespMetadata: DeviceTypePollRespMetadata,
17
+ msgBuffer: Uint8Array,
18
+ msgBufIdx: number,
19
+ numMsgBytes: number
20
+ ) => void;
11
21
 
12
22
  export default class CustomAttrHandler {
23
+
24
+ private _jsFunctionCache = new Map<string, CustomAttrJsFn>();
13
25
 
14
26
  public handleAttr(pollRespMetadata: DeviceTypePollRespMetadata, msgBuffer: Uint8Array, msgBufIdx: number): number[][] {
15
27
 
16
- // Implement the pseudo-code:
17
- // int N=(buf[0]+32-buf[2])%32;int k=3;int i=0;while(i<N){out.Red=(buf[k]<<16)|(buf[k+1]<<8)|buf[k+2];out.IR=(buf[k+3]<<16)|(buf[k+4]<<8)|buf[k+5];k+=6;i++;next;}
18
-
19
- // Number of bytes in the each message
28
+ // Number of bytes in each message
20
29
  const numMsgBytes = pollRespMetadata.b;
21
30
 
22
31
  // Create a vector for each attribute in the metadata
23
- const attrValueVecs: [][] = [];
32
+ const attrValueVecs: number[][] = [];
24
33
 
25
34
  // Reference to each vector by attribute name
26
- const attrValues: { [key: string]: number[] } = {};
35
+ const attrValues: Record<string, number[]> = {};
27
36
 
28
37
  // Add attributes to the vector
29
38
  for (let attrIdx = 0; attrIdx < pollRespMetadata.a.length; attrIdx++) {
@@ -31,41 +40,78 @@ export default class CustomAttrHandler {
31
40
  attrValues[pollRespMetadata.a[attrIdx].n] = attrValueVecs[attrIdx];
32
41
  }
33
42
 
34
- // Custom code for each device type
35
- if (pollRespMetadata.c!.n === "max30101_fifo") {
36
- // Hex dump msgBuffer
37
- // console.log(`CustomAttrHandler handleAttr ${pollRespMetadata.c!.n} msgBuffer: ${msgBuffer.toString('hex')}`);
38
- const buf = msgBuffer.slice(msgBufIdx);
39
- if (buf.length < numMsgBytes) {
40
- return [];
43
+ const customFnDef = pollRespMetadata.c;
44
+ if (!customFnDef) {
45
+ return attrValueVecs;
46
+ }
47
+
48
+ // Provide the message buffer sliced to the data portion
49
+ const buf = msgBuffer.slice(msgBufIdx);
50
+ if (buf.length < numMsgBytes) {
51
+ return [];
52
+ }
53
+
54
+ // Execute supplied JS implementation if provided
55
+ if (customFnDef.j && customFnDef.j.trim().length > 0) {
56
+ const jsFn = this.getOrCompileJsFunction(customFnDef);
57
+ if (!jsFn) {
58
+ return attrValueVecs;
59
+ }
60
+ try {
61
+ jsFn(buf, attrValues, attrValueVecs, pollRespMetadata, msgBuffer, msgBufIdx, numMsgBytes);
62
+ } catch (err) {
63
+ console.error(`CustomAttrHandler JS function ${customFnDef.n} execution failed`, err);
41
64
  }
65
+ return attrValueVecs;
66
+ }
42
67
 
68
+ // Custom code for each device type handled natively
69
+ if (customFnDef.n === "max30101_fifo") {
43
70
  // Generated code ...
44
- const N=(buf[0]+32-buf[2])%32;
45
- let k=3;
46
- let i=0;
47
- while (i<N) {
48
- attrValues['Red'].push(0); attrValues['Red'][attrValues['Red'].length-1] =(buf[k]<<16)|(buf[k+1]<<8)|buf[k+2];
49
- attrValues['IR'].push(0); attrValues['IR'][attrValues['IR'].length-1] =(buf[k+3]<<16)|(buf[k+4]<<8)|buf[k+5];
50
- k+=6;
71
+ const N = (buf[0] + 32 - buf[2]) % 32;
72
+ let k = 3;
73
+ let i = 0;
74
+ while (i < N) {
75
+ attrValues["Red"].push(0);
76
+ attrValues["Red"][attrValues["Red"].length - 1] = (buf[k] << 16) | (buf[k + 1] << 8) | buf[k + 2];
77
+ attrValues["IR"].push(0);
78
+ attrValues["IR"][attrValues["IR"].length - 1] = (buf[k + 3] << 16) | (buf[k + 4] << 8) | buf[k + 5];
79
+ k += 6;
51
80
  i++;
52
- ;
53
- }
54
- } else if (pollRespMetadata.c!.n === "gravity_o2_calc") {
55
- // Get the buffer
56
- const buf = msgBuffer.slice(msgBufIdx);
57
- if (buf.length < numMsgBytes) {
58
- return [];
59
81
  }
60
-
61
- // Implement the pseudo-code:
62
- // float key = 20.9/120.0; float val = key * (buf[0] + (buf[1]/10.0) + (buf[2]/100.0)); out.oxygen = val;
82
+ } else if (customFnDef.n === "gravity_o2_calc") {
63
83
  const key = 20.9 / 120.0;
64
- const val = key * (buf[0] + (buf[1] / 10.0) + (buf[2] / 100.0));
65
-
66
- // Add the value to the oxygen attribute
67
- attrValues['oxygen'].push(val);
84
+ const val = key * (buf[0] + buf[1] / 10.0 + buf[2] / 100.0);
85
+ attrValues["oxygen"].push(val);
68
86
  }
69
87
  return attrValueVecs;
70
88
  }
89
+
90
+ private getOrCompileJsFunction(customFnDef: CustomFunctionDefinition): CustomAttrJsFn | null {
91
+ if (!customFnDef.j) {
92
+ return null;
93
+ }
94
+ const cacheKey = `${customFnDef.n}::${customFnDef.j}`;
95
+ const cachedFn = this._jsFunctionCache.get(cacheKey);
96
+ if (cachedFn) {
97
+ return cachedFn;
98
+ }
99
+ try {
100
+ const compiledFn = new Function(
101
+ "buf",
102
+ "attrValues",
103
+ "attrValueVecs",
104
+ "pollRespMetadata",
105
+ "msgBuffer",
106
+ "msgBufIdx",
107
+ "numMsgBytes",
108
+ customFnDef.j
109
+ ) as CustomAttrJsFn;
110
+ this._jsFunctionCache.set(cacheKey, compiledFn);
111
+ return compiledFn;
112
+ } catch (err) {
113
+ console.error(`CustomAttrHandler failed to compile JS function ${customFnDef.n}`, err);
114
+ return null;
115
+ }
116
+ }
71
117
  }
@@ -73,11 +73,13 @@ export interface DeviceTypeAttribute {
73
73
  vf?: boolean | number; // Display attribute value in the device info panel
74
74
  vft?: string; // Attribute validity based on the value of another named attribute
75
75
  lut?: Array<LUTRow>; // Lookup table for the attribute value - each row is a lookup table for a range of values e.g. [{"r":"0x20-0x30","v":0},{"r":"1,2,3","v":42},{r:"","v":1}]
76
+ resolution?: string;
76
77
  }
77
78
 
78
79
  export interface CustomFunctionDefinition {
79
80
  n: string; // Function name
80
81
  c: string; // Function pseudo-code
82
+ j?: string; // Optional JavaScript implementation
81
83
  }
82
84
 
83
85
  export interface DeviceTypePollRespMetadata {