@ncd-io/node-red-enterprise-sensors 1.6.4 → 2.0.0

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.
@@ -0,0 +1,1024 @@
1
+ const { toMac, signInt, msbLsb } = require('../utils');
2
+
3
+ // --- 1. DEFINE LOCAL FUNCTIONS ---
4
+ // These are defined as local variables so they can call each other easily.
5
+ module.exports = (globalDevices) => {
6
+
7
+ const get_write_buffer_size = (firmware) => {
8
+ return 22;
9
+ };
10
+
11
+ const get_config_map = (firmware) => {
12
+ console.log('Generating sync map for firmware version', firmware);
13
+
14
+ return {
15
+ "core_version": {
16
+ "read_index": 3,
17
+ "descriptions": {
18
+ "title": "Core Version",
19
+ "main_caption": "The version of the core communication stack."
20
+ },
21
+ "validator": {
22
+ "type": "uint8"
23
+ },
24
+ "tags": [
25
+ "system"
26
+ ]
27
+ },
28
+ "firmware_version": {
29
+ "read_index": 4,
30
+ "descriptions": {
31
+ "title": "Firmware Version",
32
+ "main_caption": "The application-specific firmware version."
33
+ },
34
+ "validator": {
35
+ "type": "uint8"
36
+ },
37
+ "tags": [
38
+ "system"
39
+ ]
40
+ },
41
+ "sensor_type": {
42
+ "read_index": 5,
43
+ "descriptions": {
44
+ "title": "Sensor Type",
45
+ "main_caption": "The hardware identifier for the specific sensor model."
46
+ },
47
+ "validator": {
48
+ "type": "uint16be"
49
+ },
50
+ "tags": [
51
+ "system"
52
+ ]
53
+ },
54
+ "tx_lifetime_counter": {
55
+ "read_index": 7,
56
+ "descriptions": {
57
+ "title": "Sampling Interval",
58
+ "main_caption": "Set how often will the sensor transmit measurement data. Note: For this sensor, this value functions as the sampling interval rather than a traditional delay.",
59
+ "sub_caption": "Default value: 20 milliseconds."
60
+ },
61
+ "validator": {
62
+ "type": "uint32be"
63
+ },
64
+ "tags": [
65
+ "diagnostics"
66
+ ]
67
+ },
68
+ "hardware_id": {
69
+ "read_index": 11,
70
+ "length": 3,
71
+ "descriptions": {
72
+ "title": "Hardware ID",
73
+ "main_caption": "A unique 3-byte hardware identifier."
74
+ },
75
+ "validator": {
76
+ "type": "buffer"
77
+ },
78
+ "tags": [
79
+ "system"
80
+ ]
81
+ },
82
+ "network_id": {
83
+ "read_index": 14,
84
+ "write_index": 3,
85
+ "length": 2,
86
+ "descriptions": {
87
+ "title": "Network ID",
88
+ "main_caption": ""
89
+ },
90
+ "default_value": "7fff",
91
+ "validator": {
92
+ "type": "hex",
93
+ "length": 4
94
+ },
95
+ "html_id": "pan_id",
96
+ "tags": [
97
+ "communications"
98
+ ]
99
+ },
100
+ "destination_address": {
101
+ "read_index": 16,
102
+ "write_index": 5,
103
+ "length": 4,
104
+ "descriptions": {
105
+ "title": "Destination Address",
106
+ "main_caption": ""
107
+ },
108
+ "default_value": "0000ffff",
109
+ "validator": {
110
+ "type": "mac",
111
+ "length": 8
112
+ },
113
+ "html_id": "destination",
114
+ "tags": [
115
+ "communications"
116
+ ]
117
+ },
118
+ "node_id": {
119
+ "read_index": 20,
120
+ "write_index": 9,
121
+ "descriptions": {
122
+ "title": "Node ID",
123
+ "main_caption": ""
124
+ },
125
+ "default_value": "0",
126
+ "validator": {
127
+ "type": "uint8",
128
+ "min": 0,
129
+ "max": 255,
130
+ "generated": true
131
+ },
132
+ "html_id": "node_id",
133
+ "tags": [
134
+ "generic"
135
+ ]
136
+ },
137
+ "gyro_sample_rate": {
138
+ "read_index": 21,
139
+ "write_index": 10,
140
+ "descriptions": {
141
+ "title": "Set Gyroscope ODR",
142
+ "main_caption": ""
143
+ },
144
+ "default_value": 3,
145
+ "validator": {
146
+ "type": "uint8",
147
+ "min": 0,
148
+ "max": 3,
149
+ "generated": true
150
+ },
151
+ "options": {
152
+ "0": "125Hz",
153
+ "1": "250Hz",
154
+ "2": "500Hz",
155
+ "3": "1000Hz"
156
+ },
157
+ "html_id": "output_data_rate_103"
158
+ },
159
+ "acc_sample_rate": {
160
+ "read_index": 22,
161
+ "write_index": 11,
162
+ "descriptions": {
163
+ "title": "Set Accelerometer ODR",
164
+ "main_caption": ""
165
+ },
166
+ "default_value": 2,
167
+ "validator": {
168
+ "type": "uint8",
169
+ "min": 0,
170
+ "max": 4,
171
+ "generated": true
172
+ },
173
+ "options": {
174
+ "0": "8000Hz",
175
+ "1": "4000Hz",
176
+ "2": "1000Hz",
177
+ "3": "100Hz",
178
+ "4": "250Hz"
179
+ },
180
+ "html_id": "acc_output_data_rate_103"
181
+ },
182
+ "sampling_duration": {
183
+ "read_index": 23,
184
+ "write_index": 12,
185
+ "descriptions": {
186
+ "title": "Set Sampling Duration",
187
+ "main_caption": "Set the sampling duration in milliseconds, Example: a value of 1 = 50msec, 2 = 100msec, 100 = 5000msec"
188
+ },
189
+ "default_value": 1,
190
+ "validator": {
191
+ "type": "uint8",
192
+ "min": 1,
193
+ "max": 255,
194
+ "generated": true
195
+ },
196
+ "html_id": "sampling_duration_103"
197
+ },
198
+ "hpf_cutoff": {
199
+ "read_index": 24,
200
+ "write_index": 13,
201
+ "descriptions": {
202
+ "title": "Set HP Filter Cutoff",
203
+ "main_caption": "This setting will set the High Pass Filter freq to Sample Rate multiply by Selected Valu, Example: Sample Rate = 125 and Filter Coefficient = 0.00247 HPF freq (Hz) = 125 * 0.00247"
204
+ },
205
+ "default_value": 0,
206
+ "validator": {
207
+ "type": "uint8",
208
+ "min": 0,
209
+ "max": 6,
210
+ "generated": true
211
+ },
212
+ "options": {
213
+ "0": "Disabled",
214
+ "1": "0.00247",
215
+ "2": "0.00062084",
216
+ "3": "0.00015545",
217
+ "4": "0.00003862",
218
+ "5": "0.00000954",
219
+ "6": "0.00000238"
220
+ },
221
+ "html_id": "enable_hp_filter_cutoff_103"
222
+ },
223
+ "acc_fsr": {
224
+ "read_index": 25,
225
+ "write_index": 14,
226
+ "descriptions": {
227
+ "title": "Set Accelerometer FSR",
228
+ "main_caption": ""
229
+ },
230
+ "default_value": 0,
231
+ "validator": {
232
+ "type": "uint8",
233
+ "min": 0,
234
+ "max": 2,
235
+ "generated": true
236
+ },
237
+ "options": {
238
+ "0": "15g",
239
+ "1": "30g",
240
+ "2": "60g"
241
+ },
242
+ "html_id": "adxl_fsr_103"
243
+ },
244
+ "gyro_fsr": {
245
+ "read_index": 26,
246
+ "write_index": 15,
247
+ "descriptions": {
248
+ "title": "Set Gyroscope FSR",
249
+ "main_caption": ""
250
+ },
251
+ "default_value": 0,
252
+ "validator": {
253
+ "type": "uint8",
254
+ "min": 0,
255
+ "max": 3,
256
+ "generated": true
257
+ },
258
+ "options": {
259
+ "0": "250dsp",
260
+ "1": "500dps",
261
+ "2": "1000dps",
262
+ "3": "3000dps"
263
+ },
264
+ "html_id": "gyro_fsr_103"
265
+ },
266
+ "axis_enabled": {
267
+ "read_index": 27,
268
+ "write_index": 16,
269
+ "descriptions": {
270
+ "title": "Axes Enabled",
271
+ "main_caption": "New Command"
272
+ },
273
+ "validator": {
274
+ "type": "uint8"
275
+ },
276
+ "read_only": true,
277
+ },
278
+ "sampling_interval": {
279
+ "read_index": 28,
280
+ "write_index": 17,
281
+ "descriptions": {
282
+ "title": "Sampling Interval",
283
+ "main_caption": "Set how often will the sensor transmit measurement data."
284
+ },
285
+ "default_value": 1,
286
+ "validator": {
287
+ "type": "uint8",
288
+ "min": 0,
289
+ "max": 7,
290
+ "generated": true
291
+ },
292
+ "options": {
293
+ "0": "5 Minutes",
294
+ "1": "10 Minutes",
295
+ "2": "15 Minutes",
296
+ "3": "20 Minutes",
297
+ "4": "30 Minutes",
298
+ "5": "60 Minutes",
299
+ "6": "120 Minutes",
300
+ "7": "180 Minutes"
301
+ },
302
+ "html_id": "sampling_interval_101"
303
+ },
304
+ "accelerometer_threshold": {
305
+ "read_index": 29,
306
+ "write_index": 18,
307
+ "descriptions": {
308
+ "title": "Set Acceleration Threshold",
309
+ "main_caption": "Set a motion detection threshold for the sensor to trigger a data transmission. This is an interrupt-based configuration."
310
+ },
311
+ "default_value": 1,
312
+ "validator": {
313
+ "type": "uint8",
314
+ "min": 0,
315
+ "max": 255,
316
+ "generated": true
317
+ },
318
+ "html_id": "acc_threshold_103"
319
+ },
320
+ "enabled_sensors": {
321
+ "read_index": 30,
322
+ "write_index": 19,
323
+ "descriptions": {
324
+ "title": "Enable Sensor",
325
+ "main_caption": ""
326
+ },
327
+ "default_value": 2,
328
+ "validator": {
329
+ "type": "uint8",
330
+ "min": 0,
331
+ "max": 2,
332
+ "generated": true
333
+ },
334
+ "options": {
335
+ "0": "Accelerometer only",
336
+ "1": "Gyroscope only",
337
+ "2": "Both enabled"
338
+ },
339
+ "html_id": "enable_sensor_103"
340
+ },
341
+ "max_num_of_motion_tx_per_interval": {
342
+ "read_index": 31,
343
+ "write_index": 20,
344
+ "descriptions": {
345
+ "title": "Set Max Number Motion Tx Per Interval",
346
+ "main_caption": "Set Number of times it will send data due to motion triggers."
347
+ },
348
+ "default_value": 2,
349
+ "validator": {
350
+ "type": "uint8",
351
+ "min": 0,
352
+ "max": 255,
353
+ "generated": true
354
+ },
355
+ },
356
+ "send_raw_status": {
357
+ "read_index": 32,
358
+ "write_index": 21,
359
+ "descriptions": {
360
+ "title": "Set Raw On Motion Only",
361
+ "main_caption": ""
362
+ },
363
+ "validator": {
364
+ "type": "uint8",
365
+ "min": 0,
366
+ "max": 1,
367
+ "generated": true
368
+ },
369
+ "default_value": 0,
370
+ "html_id": "send_raw_on_motion_only_103"
371
+ },
372
+ "rtc": {
373
+ "read_index": 33,
374
+ "descriptions": {
375
+ "title": "Set RTC",
376
+ "main_caption": "Set the value for the Internal Real Time Clock."
377
+ },
378
+ "read_only": true,
379
+ }
380
+ };
381
+ };
382
+
383
+ const sync_parse = (rep_buffer) => {
384
+ let response = {};
385
+
386
+ // Get the map based on the sensor type byte
387
+ const sync_map = get_config_map(rep_buffer[4]);
388
+
389
+ for (const [key, config] of Object.entries(sync_map)) {
390
+ // Destructure 'type' from inside 'validator' and rename 'read_index' to 'idx'
391
+ const { read_index: idx, length, validator: { type } = {} } = config;
392
+
393
+ // If for some reason a config doesn't have a validator/type, skip it
394
+ if (!type) continue;
395
+
396
+ switch (type) {
397
+ case 'uint8':
398
+ response[key] = rep_buffer[idx];
399
+ break;
400
+ case 'uint16be':
401
+ response[key] = rep_buffer.readUInt16BE(idx);
402
+ break;
403
+ case 'uint32be':
404
+ response[key] = rep_buffer.readUInt32BE(idx);
405
+ break;
406
+ case 'buffer':
407
+ response[key] = rep_buffer.subarray(idx, idx + length);
408
+ break;
409
+ case 'hex':
410
+ response[key] = rep_buffer.subarray(idx, idx + length).toString('hex');
411
+ break;
412
+ case 'mac':
413
+ response[key] = rep_buffer.subarray(idx, idx + length).toString('hex');
414
+ break;
415
+ }
416
+ }
417
+ if(Object.hasOwn(response, 'destination_address') && response.destination_address.toLowerCase() === '00000000') {
418
+ console.log('##############################');
419
+ console.log('#########Dest Override########');
420
+ console.log('##############################');
421
+ response.destination_address = "0000ffff";
422
+ response.auto_raw_destination_address = "0000ffff";
423
+ };
424
+ return response;
425
+ };
426
+
427
+ const parse_fly = (frame) => {
428
+ let firmware = frame[2];
429
+ if(firmware > 1){
430
+ let frame_data = {};
431
+ switch(frame[12]){
432
+ case 0:
433
+ frame_data.gyro_odr = 125;
434
+ break;
435
+ case 1:
436
+ frame_data.gyro_odr = 250;
437
+ break;
438
+ case 2:
439
+ frame_data.gyro_odr = 500;
440
+ break;
441
+ case 3:
442
+ frame_data.gyro_odr = 1000;
443
+ break;
444
+ }
445
+ switch(frame[13]){
446
+ case 0:
447
+ frame_data.acc_odr = 8000;
448
+ break;
449
+ case 1:
450
+ frame_data.acc_odr = 4000;
451
+ break;
452
+ case 2:
453
+ frame_data.acc_odr = 2000;
454
+ break;
455
+ case 3:
456
+ frame_data.acc_odr = 1000;
457
+ break;
458
+ case 4:
459
+ frame_data.acc_odr = 100;
460
+ break;
461
+ }
462
+ switch(frame[15]){
463
+ case 0:
464
+ frame_data.hpf_cutoff = false;
465
+ break;
466
+ case 1:
467
+ frame_data.hpf_cutoff = 0.00247;
468
+ break;
469
+ case 2:
470
+ frame_data.hpf_cutoff = 0.00062084;
471
+ break;
472
+ case 3:
473
+ frame_data.hpf_cutoff = 0.00015545;
474
+ break;
475
+ case 4:
476
+ frame_data.hpf_cutoff = 0.00003862;
477
+ break;
478
+ case 5:
479
+ frame_data.hpf_cutoff = 0.00000954;
480
+ break;
481
+ case 6:
482
+ frame_data.hpf_cutoff = 0.00000238;
483
+ break;
484
+ }
485
+ switch(frame[16]){
486
+ case 0:
487
+ frame_data.fsr_acc = "15g";
488
+ break;
489
+ case 1:
490
+ frame_data.fsr_acc = "30g";
491
+ break;
492
+ case 2:
493
+ frame_data.fsr_acc = "60g";
494
+ break;
495
+ }
496
+ switch(frame[17]){
497
+ case 0:
498
+ frame_data.fsr_gyro = "250dps";
499
+ break;
500
+ case 1:
501
+ frame_data.fsr_gyro = "500dps";
502
+ break;
503
+ case 2:
504
+ frame_data.fsr_gyro = "1000dps";
505
+ break;
506
+ case 3:
507
+ frame_data.fsr_gyro = "2000dps";
508
+ break;
509
+ }
510
+ switch(frame[18]){
511
+ case 1:
512
+ frame_data.en_axis = "X Axis";
513
+ break;
514
+ case 2:
515
+ frame_data.en_axis = "Y Axis";
516
+ break;
517
+ case 3:
518
+ frame_data.en_axis = "X-Y Axes";
519
+ break;
520
+ case 4:
521
+ frame_data.en_axis = "Z Axis";
522
+ break;
523
+ case 5:
524
+ frame_data.en_axis = "X-Z Axes";
525
+ break;
526
+ case 6:
527
+ frame_data.en_axis = "Y-Z Axes";
528
+ break;
529
+ case 7:
530
+ frame_data.en_axis = "All Axes";
531
+ break;
532
+ }
533
+ switch(frame[19]){
534
+ case 0:
535
+ frame_data.sampling_interval = 5;
536
+ break;
537
+ case 1:
538
+ frame_data.sampling_interval = 10;
539
+ break;
540
+ case 2:
541
+ frame_data.sampling_interval = 15;
542
+ break;
543
+ case 3:
544
+ frame_data.sampling_interval = 20;
545
+ break;
546
+ case 4:
547
+ frame_data.sampling_interval = 30;
548
+ break;
549
+ case 5:
550
+ frame_data.sampling_interval = 60;
551
+ break;
552
+ case 6:
553
+ frame_data.sampling_interval = 120;
554
+ break;
555
+ case 7:
556
+ frame_data.sampling_interval = 180;
557
+ break;
558
+ }
559
+ switch(frame[21]){
560
+ case 0:
561
+ frame_data.en_sensors = "acc_only";
562
+ break;
563
+ case 1:
564
+ frame_data.en_sensors = "gyro_only";
565
+ break;
566
+ case 2:
567
+ frame_data.en_sensors = "both_enabled";
568
+ break;
569
+ }
570
+ frame_data.hpf_cutoff = (frame_data.hpf_cutoff)?((frame_data.hpf_cutoff * frame_data.acc_odr).toFixed(2) + 'Hz'):'disabled';
571
+ return {
572
+ 'firmware': firmware,
573
+ 'gyro_sample_rate': frame_data.gyro_odr + 'Hz',
574
+ 'acc_sample_rate': frame_data.acc_odr + 'Hz',
575
+ 'sampling_duration': (frame[14]* 50) + 'msec',
576
+ 'hpf_cutoff': frame_data.hpf_cutoff,
577
+ 'acc_fsr': frame_data.fsr_acc,
578
+ 'gyro_fsr': frame_data.fsr_gyro,
579
+ 'axis_enabled': frame_data.en_axis,
580
+ 'sampling_interval': frame_data.sampling_interval + 'min',
581
+ 'accelerometer_threshold': (frame[20]* 32) + "mg",
582
+ 'enabled_sensors': frame_data.en_sensors,
583
+ 'max_num_of_motion_tx_per_interval': frame[22],
584
+ 'rtc': [
585
+ String(frame[23]).padStart(2, '0'),
586
+ String(frame[24]).padStart(2, '0'),
587
+ String(frame[25]).padStart(2, '0')
588
+ ].join(':'),
589
+ 'hardware_id': frame.slice(26, 29),
590
+ 'report_rate': frame.slice(29, 33).reduce(msbLsb),
591
+ 'tx_life_counter': frame.slice(33, 37).reduce(msbLsb),
592
+ 'machine_values': {
593
+ 'firmware': frame[2],
594
+ 'gyro_sample_rate': frame[12],
595
+ 'acc_sample_rate': frame[13],
596
+ 'sampling_duration': frame[14],
597
+ 'hpf_cutoff': frame[15],
598
+ 'acc_fsr': frame[16],
599
+ 'gyro_fsr': frame[17],
600
+ 'axis_enabled': frame[18],
601
+ 'sampling_interval': frame[19],
602
+ 'accelerometer_threshold': frame[20],
603
+ 'enabled_sensors': frame[21],
604
+ 'max_num_of_motion_tx_per_interval': frame[22],
605
+ 'hour': frame[23],
606
+ 'minute': frame[24],
607
+ 'second': frame[25],
608
+ 'hardware_id': frame.slice(26, 29),
609
+ 'report_rate': frame.slice(29, 33),
610
+ 'tx_life_counter': frame.slice(33, 37)
611
+ }
612
+ }
613
+ }else{
614
+ let frame_data = {};
615
+ switch(frame[12]){
616
+ case 0:
617
+ frame_data.odr = 125;
618
+ break;
619
+ case 1:
620
+ frame_data.odr = 250;
621
+ break;
622
+ case 2:
623
+ frame_data.odr = 500;
624
+ break;
625
+ case 3:
626
+ frame_data.odr = 1000;
627
+ break;
628
+ }
629
+ switch(frame[15]){
630
+ case 0:
631
+ frame_data.fsr_acc = "10g";
632
+ break;
633
+ case 1:
634
+ frame_data.fsr_acc = "20g";
635
+ break;
636
+ case 2:
637
+ frame_data.fsr_acc = "40g";
638
+ break;
639
+ }
640
+ switch(frame[16]){
641
+ case 0:
642
+ frame_data.fsr_gyro = "250dps";
643
+ break;
644
+ case 1:
645
+ frame_data.fsr_gyro = "500dps";
646
+ break;
647
+ case 2:
648
+ frame_data.fsr_gyro = "1000dps";
649
+ break;
650
+ case 3:
651
+ frame_data.fsr_gyro = "2000dps";
652
+ break;
653
+ }
654
+ switch(frame[17]){
655
+ case 7:
656
+ frame_data.en_axis = "all";
657
+ break;
658
+ }
659
+ switch(frame[20]){
660
+ case 1:
661
+ frame_data.en_sensors = "gyro_only";
662
+ break;
663
+ case 2:
664
+ frame_data.en_sensors = "accel_only";
665
+ break;
666
+ case 3:
667
+ frame_data.en_sensors = "all_enabled";
668
+ break;
669
+ }
670
+ switch(frame[18]){
671
+ case 0:
672
+ frame_data.sampling_interval = 5;
673
+ break;
674
+ case 1:
675
+ frame_data.sampling_interval = 10;
676
+ break;
677
+ case 2:
678
+ frame_data.sampling_interval = 15;
679
+ break;
680
+ case 3:
681
+ frame_data.sampling_interval = 20;
682
+ break;
683
+ case 4:
684
+ frame_data.sampling_interval = 30;
685
+ break;
686
+ case 5:
687
+ frame_data.sampling_interval = 60;
688
+ break;
689
+ case 6:
690
+ frame_data.sampling_interval = 120;
691
+ break;
692
+ case 7:
693
+ frame_data.sampling_interval = 180;
694
+ break;
695
+ }
696
+ switch(frame[14]){
697
+ case 0:
698
+ frame_data.hpf_cutoff = 0.00247;
699
+ break;
700
+ case 1:
701
+ frame_data.hpf_cutoff = 0.00062084;
702
+ break;
703
+ case 2:
704
+ frame_data.hpf_cutoff = 0.00015545;
705
+ break;
706
+ case 3:
707
+ frame_data.hpf_cutoff = 0.00003862;
708
+ break;
709
+ case 4:
710
+ frame_data.hpf_cutoff = 0.00000954;
711
+ break;
712
+ case 5:
713
+ frame_data.hpf_cutoff = 0.00000238;
714
+ break;
715
+ }
716
+ return {
717
+ 'firmware': firmware,
718
+ 'sample_rate': frame_data.odr + 'Hz',
719
+ 'sampling_duration': (frame[13]* 50) + 'msec',
720
+ 'hpf_cutoff': (frame_data.hpf_cutoff * frame_data.odr).toFixed(2) + 'Hz',
721
+ 'acc_fsr': frame_data.fsr_acc,
722
+ 'gyro_fsr': frame_data.fsr_gyro,
723
+ 'axis_enabled': frame_data.en_axis,
724
+ 'sampling_interval': frame_data.sampling_interval + 'min',
725
+ 'accelerometer_threshold': (frame[19]* 32) + "mg",
726
+ 'enabled_sensors': frame_data.en_sensors,
727
+ 'rtc': [
728
+ String(frame[21]).padStart(2, '0'),
729
+ String(frame[22]).padStart(2, '0'),
730
+ String(frame[23]).padStart(2, '0')
731
+ ].join(':'),
732
+ 'hardware_id': frame.slice(24, 27),
733
+ 'report_rate': frame.slice(27, 31).reduce(msbLsb),
734
+ 'tx_life_counter': frame.slice(31, 35).reduce(msbLsb),
735
+ 'machine_values': {
736
+ 'firmware': frame[2],
737
+ 'odr': frame[12],
738
+ 'sampling_duration': frame[13],
739
+ 'hpf_cutoff': frame[14],
740
+ 'acc_fsr': frame[15],
741
+ 'gyro_fsr': frame[16],
742
+ 'axis_enabled': frame[17],
743
+ 'sampling_interval': frame[18],
744
+ 'accelerometer_threshold': frame[19],
745
+ 'enabled_sensors': frame[20],
746
+ 'hour': frame[21],
747
+ 'minute': frame[22],
748
+ 'second': frame[23],
749
+ 'hardware_id': frame.slice(24, 27),
750
+ 'report_rate': frame.slice(27, 31),
751
+ 'tx_life_counter': frame.slice(31, 35)
752
+ }
753
+ }
754
+ }
755
+ };
756
+
757
+ const parse = (payload, parsed, mac) => {
758
+ if(payload[9] === 0){ // mode raw
759
+ var sensor_type = payload[8];
760
+ var deviceAddr = mac;
761
+ var data = {};
762
+ switch(sensor_type){
763
+ case 1:
764
+ data.sensor_type = 'Accel';
765
+ switch(payload[11]){ // for ADXL382
766
+ case 0:
767
+ // data.odr = '8000Hz';
768
+ data.odr = 8000;
769
+ break;
770
+ case 1:
771
+ // data.odr = '4000Hz';
772
+ data.odr = 4000;
773
+ break;
774
+ case 2:
775
+ // data.odr = '2000Hz';
776
+ data.odr = 1000;
777
+ break;
778
+ case 3:
779
+ // data.odr = '1000Hz';
780
+ data.odr = 100;
781
+ break;
782
+ case 4:
783
+ // data.odr = '100Hz';
784
+ data.odr = 250;
785
+ break;
786
+ }
787
+ break;
788
+ case 2:
789
+ data.sensor_type = 'gyro';
790
+ switch(payload[11]){
791
+ case 0:
792
+ data.odr = '125Hz';
793
+ break;
794
+ case 1:
795
+ data.odr = '250Hz';
796
+ break;
797
+ case 2:
798
+ data.odr = '500Hz';
799
+ break;
800
+ case 3:
801
+ data.odr = '1000Hz';
802
+ break;
803
+ }
804
+ break;
805
+ }
806
+ switch(payload[10]){
807
+ case 1:
808
+ data.event_type = 'report';
809
+ break;
810
+ case 2:
811
+ data.event_type = 'motion';
812
+ break;
813
+ }
814
+
815
+ var mode = payload[9];
816
+ var odr = data.odr;
817
+ var en_axis = payload[12] & 7;
818
+ var fsr = payload[12] >> 3;
819
+ var hour = payload[13];
820
+ var minute = payload[14];
821
+ var device_temp = payload.slice(15, 17).reduce(msbLsb) / 100;
822
+ var external_temperature = payload.slice(17, 19).reduce(msbLsb) / 100;
823
+ var expected_packets = payload.slice(19, 21).reduce(msbLsb);
824
+ var current_packet = payload.slice(21, 23).reduce(msbLsb);
825
+ var data_start = 23;
826
+
827
+ if(globalDevices.hasOwnProperty(deviceAddr) || expected_packets == 1){
828
+ if(expected_packets != 1){
829
+ // if current packet is equal to last one (duplicated data). This does not apply to the last package
830
+ if (globalDevices[deviceAddr].last_packet_counter == current_packet){
831
+ console.log('Duplicated message')
832
+ return;
833
+ }
834
+ // if current packet is equal to 1 or last packet counter is higher thant current packet
835
+ if(current_packet == 1 || (globalDevices[deviceAddr].last_packet_counter > current_packet)){
836
+ // clear stream
837
+ delete globalDevices[deviceAddr];
838
+ // create new stream
839
+ globalDevices[deviceAddr] = {
840
+ // stream_size: expected_packets,
841
+ data: {},
842
+ odr: odr,
843
+ mo: mode,
844
+ en_axis: en_axis,
845
+ fsr: fsr,
846
+ hour: hour,
847
+ minute: minute,
848
+ device_temp: device_temp,
849
+ external_temp: external_temperature
850
+ }
851
+ globalDevices[deviceAddr].last_packet_counter = current_packet;
852
+ globalDevices[deviceAddr].data[current_packet] = payload.slice(data_start);
853
+ return;
854
+ }
855
+ else{
856
+ globalDevices[deviceAddr].last_packet_counter = current_packet;
857
+ globalDevices[deviceAddr].data[current_packet] = payload.slice(data_start);
858
+ }
859
+ }
860
+ else{
861
+ globalDevices[deviceAddr] = {
862
+ // stream_size: expected_packets,
863
+ data: {},
864
+ odr: odr,
865
+ mo: mode,
866
+ en_axis: en_axis,
867
+ fsr: fsr,
868
+ hour: hour,
869
+ minute: minute,
870
+ device_temp: device_temp,
871
+ external_temp: external_temperature
872
+ }
873
+ globalDevices[deviceAddr].last_packet_counter = current_packet;
874
+ globalDevices[deviceAddr].data[current_packet] = payload.slice(data_start);
875
+ }
876
+ }
877
+ else{
878
+
879
+ globalDevices[deviceAddr] = {
880
+ data: {},
881
+ odr: odr,
882
+ mo: mode,
883
+ en_axis: en_axis,
884
+ fsr: fsr,
885
+ hour: hour,
886
+ minute: minute,
887
+ device_temp: device_temp,
888
+ external_temp: external_temperature
889
+ }
890
+ globalDevices[deviceAddr].last_packet_counter = current_packet;
891
+ globalDevices[deviceAddr].data[current_packet] = payload.slice(data_start);
892
+ }
893
+ if(current_packet == expected_packets){
894
+ var raw_data = new Array();
895
+ for(const packet in globalDevices[deviceAddr].data){
896
+ raw_data = raw_data.concat(globalDevices[deviceAddr].data[packet]);
897
+ }
898
+ var label = 0;
899
+
900
+ var fft = new Array();
901
+ var fft_concat = {};
902
+
903
+ var en_axis_data = {};
904
+ en_axis_data.x_offset = 0;
905
+ en_axis_data.y_offset = 2;
906
+ en_axis_data.z_offset = 4;
907
+ en_axis_data.increment = 6;
908
+ fft_concat = {x: [], y: [], z: []};
909
+
910
+ /* Evaluate sensor type */
911
+ if(payload[8] == 1){ // accelerometer
912
+ var fsr_mult = 0.00732;
913
+ var fsr_text = "";
914
+ switch(globalDevices[deviceAddr].fsr){
915
+ case 0:
916
+ fsr_mult = 0.00732;
917
+ break;
918
+ case 1:
919
+ fsr_mult = 0.01464;
920
+ break;
921
+ case 2:
922
+ fsr_mult = 0.02929;
923
+ break;
924
+ }
925
+ switch(globalDevices[deviceAddr].fsr){
926
+ case 0:
927
+ // fsr_text = "15g";
928
+ fsr_text = 15;
929
+ break;
930
+ case 1:
931
+ // fsr_text = "30g";
932
+ fsr_text = 30;
933
+ break;
934
+ case 2:
935
+ // fsr_text = "60g";
936
+ fsr_text = 60;
937
+ break;
938
+ }
939
+ }else{ // gyro
940
+ var fsr_mult = 0.0076;
941
+ var fsr_text = "";
942
+ switch(globalDevices[deviceAddr].fsr){
943
+ case 0:
944
+ fsr_mult = 0.0076;
945
+ break;
946
+ case 1:
947
+ fsr_mult = 0.015;
948
+ break;
949
+ case 2:
950
+ fsr_mult = 0.0305;
951
+ break;
952
+ case 3:
953
+ fsr_mult = 0.061;
954
+ break;
955
+ }
956
+ switch(globalDevices[deviceAddr].fsr){
957
+ case 0:
958
+ fsr_text = "250dps";
959
+ break;
960
+ case 1:
961
+ fsr_text = "500dps";
962
+ break;
963
+ case 2:
964
+ fsr_text = "1000dps";
965
+ break;
966
+ case 3:
967
+ fsr_text = "2000dps";
968
+ break;
969
+ }
970
+ }
971
+
972
+ for(var i = 0; i < raw_data.length; i+=en_axis_data.increment){
973
+ label++;
974
+
975
+ if('x_offset' in en_axis_data){
976
+ fft_concat.x.push(parseFloat((signInt(((raw_data[i+en_axis_data.x_offset]<<8)+(raw_data[i+en_axis_data.x_offset+1])), 16)*fsr_mult).toFixed(5)));
977
+ }
978
+ if('y_offset' in en_axis_data){
979
+ fft_concat.y.push(parseFloat((signInt(((raw_data[i+en_axis_data.y_offset]<<8)+(raw_data[i+en_axis_data.y_offset+1])), 16)*fsr_mult).toFixed(5)));
980
+ }
981
+ if('z_offset' in en_axis_data){
982
+ fft_concat.z.push(parseFloat((signInt(((raw_data[i+en_axis_data.z_offset]<<8)+(raw_data[i+en_axis_data.z_offset+1])), 16)*fsr_mult).toFixed(5)));
983
+ }
984
+ }
985
+ var fft_concat_obj = {
986
+ mode: mode,
987
+ sensor_type: 103,
988
+ probe_type: data.sensor_type,
989
+ msg_type: data.event_type,
990
+ time_id: globalDevices[deviceAddr].hour +':'+ globalDevices[deviceAddr].minute,
991
+ mac_address: deviceAddr,
992
+ en_axis: globalDevices[deviceAddr].en_axis,
993
+ fsr: fsr_text,
994
+ odr: globalDevices[deviceAddr].odr,
995
+ device_temp: globalDevices[deviceAddr].device_temp,
996
+ external_temp: globalDevices[deviceAddr].external_temp,
997
+ total_samples: label,
998
+ fft_confidence : ((Object.keys(globalDevices[deviceAddr].data).length / expected_packets) * 100).toFixed(2) + '%',
999
+ data: fft_concat,
1000
+ raw_data: raw_data
1001
+ };
1002
+ sensor_data = fft_concat_obj;
1003
+ delete globalDevices[deviceAddr];
1004
+ return sensor_data;
1005
+ }
1006
+ else{
1007
+ return;
1008
+ }
1009
+ }
1010
+ };
1011
+
1012
+ // --- 2. EXPORT THE MODULE ---
1013
+ // Export the module with all the necessary functions and properties
1014
+ // that need to be called from outside the scrip
1015
+ return {
1016
+ type: 103,
1017
+ name: 'Custom Wireless Accelerometer Sensor',
1018
+ parse,
1019
+ get_write_buffer_size,
1020
+ get_config_map,
1021
+ sync_parse,
1022
+ parse_fly,
1023
+ };
1024
+ };