1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
| const assert = require('assert');
| const {
| Jh2028Decoder,
| crc8,
| } = require('../decoder');
| const {
| buildBloodPressurePayload,
| buildFrame,
| buildRealtimePayload,
| } = require('../tcp-simulator');
|
| describe('Jh2028Decoder', () => {
| it('parses realtime frame with little-endian fields and scale rules', () => {
| const decoder = new Jh2028Decoder({ alModelPath: './alModel.json' });
| const frame = buildFrame(1, 0x01, 0x00, buildRealtimePayload());
| const [result] = decoder.push(frame);
|
| assert.strictEqual(result.publish, true);
| assert.strictEqual(result.messageType, 'realtime');
| assert.deepStrictEqual(result.metric, {
| AF: 36.5,
| F: 36.8,
| A: 2000,
| C: 500,
| B: 250,
| K: 90,
| L: 500,
| D: 320,
| H: -100,
| o: 120,
| J: -80,
| U: 2048,
| G: 138,
| Na: 140,
| HCO3: 25,
| O2Sat: 98.7,
| Hct: 36.5,
| Hb: 13.2,
| Tblood: 36.7,
| ktv: 1.5,
| });
| });
|
| it('parses blood pressure frame and ignores mean pressure and irregular pulse', () => {
| const decoder = new Jh2028Decoder({ alModelPath: './alModel.json' });
| const frame = buildFrame(2, 0x01, 0x01, buildBloodPressurePayload());
| const [result] = decoder.push(frame);
|
| assert.strictEqual(result.publish, true);
| assert.strictEqual(result.messageType, 'blood-pressure');
| assert.deepStrictEqual(result.metric, {
| N: 120,
| O: 80,
| P: 76,
| });
| assert.deepStrictEqual(result.ignored, {
| irregularPulse: 0,
| meanPressure: 93,
| });
| });
|
| it('skips blood pressure error code frames', () => {
| const decoder = new Jh2028Decoder({ alModelPath: './alModel.json' });
| const frame = buildFrame(3, 0x01, 0x01, Buffer.from([2, 0, 0, 0, 0]));
| const [result] = decoder.push(frame);
|
| assert.strictEqual(result.publish, false);
| assert.strictEqual(result.ok, true);
| assert.strictEqual(result.reason, 'blood-pressure-error-code');
| assert.strictEqual(result.errorCode, 2);
| });
|
| it('rejects invalid CRC frames', () => {
| const decoder = new Jh2028Decoder({ alModelPath: './alModel.json' });
| const frame = Buffer.from(buildFrame(1, 0x01, 0x00, buildRealtimePayload()));
| frame[frame.length - 1] ^= 0xFF;
| const [result] = decoder.push(frame);
|
| assert.strictEqual(result.publish, false);
| assert.strictEqual(result.ok, false);
| assert.strictEqual(result.reason, 'crc-invalid');
| });
|
| it('handles sticky packets and split packets', () => {
| const decoder = new Jh2028Decoder({ alModelPath: './alModel.json' });
| const realtimeFrame = buildFrame(1, 0x01, 0x00, buildRealtimePayload());
| const bpFrame = buildFrame(2, 0x01, 0x01, buildBloodPressurePayload());
| const firstPart = realtimeFrame.slice(0, 10);
| const secondPart = Buffer.concat([realtimeFrame.slice(10), bpFrame]);
|
| assert.deepStrictEqual(decoder.push(firstPart), []);
| const results = decoder.push(secondPart);
|
| assert.strictEqual(results.length, 2);
| assert.strictEqual(results[0].messageType, 'realtime');
| assert.strictEqual(results[1].messageType, 'blood-pressure');
| });
|
| it('calculates CRC8 from the PDF algorithm', () => {
| const frameWithoutCrc = Buffer.from([0x55, 0xAA, 0x07, 0x01, 0x01, 0x7F]);
| assert.strictEqual(crc8(frameWithoutCrc), 0x1B);
| });
| });
|
|