asterix-parser 1.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.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/build/src/main/app.d.ts +8 -0
- package/build/src/main/app.js +66 -0
- package/build/src/main/data/uap/cat021.d.ts +6 -0
- package/build/src/main/data/uap/cat021.js +216 -0
- package/build/src/main/util/common.d.ts +27 -0
- package/build/src/main/util/common.js +79 -0
- package/build/src/main/util/preprocess.d.ts +33 -0
- package/build/src/main/util/preprocess.js +82 -0
- package/build/src/main/util/process/cat021.d.ts +13 -0
- package/build/src/main/util/process/cat021.js +1785 -0
- package/build/src/main/util/varlen/cat021.d.ts +9 -0
- package/build/src/main/util/varlen/cat021.js +235 -0
- package/build/src/test/app.test.d.ts +1 -0
- package/build/src/test/app.test.js +14 -0
- package/jest.config.js +9 -0
- package/package.json +43 -0
- package/tsconfig.json +15 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 chung5072
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# asterix-parser
|
|
2
|
+
### 기능
|
|
3
|
+
**asterix-validator를 활용한 Asterix 데이터 파싱 모듈**
|
|
4
|
+
|
|
5
|
+
- 모듈로 확인할 수 있는 내용
|
|
6
|
+
- 배열 내의 객체 형태로 Asterix 데이터 파싱 결과.
|
|
7
|
+
- 현재 구현된 내용: Category 021
|
|
8
|
+
|
|
9
|
+
**기술 스택**
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
### 사용 예시
|
|
16
|
+
```
|
|
17
|
+
parse("확인하고_싶은_데이터_문자열");
|
|
18
|
+
```
|
|
19
|
+
**결과 구조**
|
|
20
|
+
```
|
|
21
|
+
/* typescript */
|
|
22
|
+
[
|
|
23
|
+
{
|
|
24
|
+
'021_010_SAC': 01,
|
|
25
|
+
'021_010_SIC': 01,
|
|
26
|
+
},
|
|
27
|
+
...
|
|
28
|
+
]
|
|
29
|
+
```
|
|
30
|
+
**예시**
|
|
31
|
+
```
|
|
32
|
+
console.log(parse("3E0006800102"));
|
|
33
|
+
```
|
|
34
|
+
---
|
|
35
|
+
### 참고 링크
|
|
36
|
+
[Asterix CAT021](https://www.eurocontrol.int/publication/cat021-eurocontrol-specification-surveillance-data-exchange-asterix-part-12-category-21)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parse = void 0;
|
|
4
|
+
const asterix_validator_1 = require("asterix-validator");
|
|
5
|
+
const preprocess_1 = require("./util/preprocess");
|
|
6
|
+
const cat021_1 = require("./util/varlen/cat021");
|
|
7
|
+
const cat021_2 = require("./util/process/cat021");
|
|
8
|
+
/**
|
|
9
|
+
* Asterix 데이터 파싱
|
|
10
|
+
* @param input 16진수 문자열 데이터
|
|
11
|
+
* @returns 파싱 결과
|
|
12
|
+
*/
|
|
13
|
+
const parse = (input) => {
|
|
14
|
+
// 데이터 확인
|
|
15
|
+
const { category, length, bitArr } = (0, asterix_validator_1.inputData)(input); // 카테도리, 데이터 길이, 바이트 값
|
|
16
|
+
// 데이터 순회 인덱스
|
|
17
|
+
let pos = 3;
|
|
18
|
+
const records = [];
|
|
19
|
+
const record = {};
|
|
20
|
+
// 패킷 데이터 순회
|
|
21
|
+
while (pos < length) {
|
|
22
|
+
const { fieldSpec, recordIndex } = (0, preprocess_1.getFieldSpec)(category, bitArr, pos);
|
|
23
|
+
// 현재 레코드 안에서 움직일 포인터를 하나 만듭니다.
|
|
24
|
+
let currentPos = recordIndex;
|
|
25
|
+
for (const [dataItem, length] of Object.entries(fieldSpec)) {
|
|
26
|
+
if (dataItem === 'SPARE') {
|
|
27
|
+
// 사용하지 않는 데이터 아이템 넘김
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
let diLength = 0;
|
|
31
|
+
if (length !== -1) {
|
|
32
|
+
// 고정 길이
|
|
33
|
+
diLength = length;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// 가변 길이
|
|
37
|
+
switch (category) {
|
|
38
|
+
case 21: {
|
|
39
|
+
diLength = (0, cat021_1.cat021VarLen)(bitArr, currentPos, dataItem);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
default:
|
|
43
|
+
diLength = 0;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
record[dataItem] = diLength;
|
|
48
|
+
switch (category) {
|
|
49
|
+
case 21: {
|
|
50
|
+
(0, cat021_2.cat021Process)(record, bitArr, currentPos, dataItem, diLength);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
default:
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
// 포인터 이동
|
|
57
|
+
currentPos += diLength;
|
|
58
|
+
}
|
|
59
|
+
// 다음 레코드는 마지막으로 읽은 위치(currentPos)부터 시작
|
|
60
|
+
pos = currentPos;
|
|
61
|
+
// 객체 복사 후 삽입
|
|
62
|
+
records.push(Object.assign({}, record));
|
|
63
|
+
}
|
|
64
|
+
return records;
|
|
65
|
+
};
|
|
66
|
+
exports.parse = parse;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CAT021_UAP = void 0;
|
|
4
|
+
const CAT021_UAP = {
|
|
5
|
+
1: {
|
|
6
|
+
1: {
|
|
7
|
+
dataItem: "di010",
|
|
8
|
+
length: 2
|
|
9
|
+
},
|
|
10
|
+
2: {
|
|
11
|
+
dataItem: "di040",
|
|
12
|
+
length: -1
|
|
13
|
+
},
|
|
14
|
+
3: {
|
|
15
|
+
dataItem: "di161",
|
|
16
|
+
length: 2
|
|
17
|
+
},
|
|
18
|
+
4: {
|
|
19
|
+
dataItem: "di015",
|
|
20
|
+
length: 1
|
|
21
|
+
},
|
|
22
|
+
5: {
|
|
23
|
+
dataItem: "di071",
|
|
24
|
+
length: 3
|
|
25
|
+
},
|
|
26
|
+
6: {
|
|
27
|
+
dataItem: "di130",
|
|
28
|
+
length: 6
|
|
29
|
+
},
|
|
30
|
+
7: {
|
|
31
|
+
dataItem: "di131",
|
|
32
|
+
length: 8
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
2: {
|
|
36
|
+
1: {
|
|
37
|
+
dataItem: "di072",
|
|
38
|
+
length: 3
|
|
39
|
+
},
|
|
40
|
+
2: {
|
|
41
|
+
dataItem: "di150",
|
|
42
|
+
length: 2
|
|
43
|
+
},
|
|
44
|
+
3: {
|
|
45
|
+
dataItem: "di151",
|
|
46
|
+
length: 2
|
|
47
|
+
},
|
|
48
|
+
4: {
|
|
49
|
+
dataItem: "di080",
|
|
50
|
+
length: 3
|
|
51
|
+
},
|
|
52
|
+
5: {
|
|
53
|
+
dataItem: "di073",
|
|
54
|
+
length: 3
|
|
55
|
+
},
|
|
56
|
+
6: {
|
|
57
|
+
dataItem: "di074",
|
|
58
|
+
length: 4
|
|
59
|
+
},
|
|
60
|
+
7: {
|
|
61
|
+
dataItem: "di075",
|
|
62
|
+
length: 3
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
3: {
|
|
66
|
+
1: {
|
|
67
|
+
dataItem: "di076",
|
|
68
|
+
length: 4
|
|
69
|
+
},
|
|
70
|
+
2: {
|
|
71
|
+
dataItem: "di140",
|
|
72
|
+
length: 2
|
|
73
|
+
},
|
|
74
|
+
3: {
|
|
75
|
+
dataItem: "di090",
|
|
76
|
+
length: -1
|
|
77
|
+
},
|
|
78
|
+
4: {
|
|
79
|
+
dataItem: "di210",
|
|
80
|
+
length: 1
|
|
81
|
+
},
|
|
82
|
+
5: {
|
|
83
|
+
dataItem: "di070",
|
|
84
|
+
length: 2
|
|
85
|
+
},
|
|
86
|
+
6: {
|
|
87
|
+
dataItem: "di230",
|
|
88
|
+
length: 2
|
|
89
|
+
},
|
|
90
|
+
7: {
|
|
91
|
+
dataItem: "di145",
|
|
92
|
+
length: 2
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
4: {
|
|
96
|
+
1: {
|
|
97
|
+
dataItem: "di152",
|
|
98
|
+
length: 2
|
|
99
|
+
},
|
|
100
|
+
2: {
|
|
101
|
+
dataItem: "di200",
|
|
102
|
+
length: 1
|
|
103
|
+
},
|
|
104
|
+
3: {
|
|
105
|
+
dataItem: "di155",
|
|
106
|
+
length: 2
|
|
107
|
+
},
|
|
108
|
+
4: {
|
|
109
|
+
dataItem: "di157",
|
|
110
|
+
length: 2
|
|
111
|
+
},
|
|
112
|
+
5: {
|
|
113
|
+
dataItem: "di160",
|
|
114
|
+
length: 4
|
|
115
|
+
},
|
|
116
|
+
6: {
|
|
117
|
+
dataItem: "di165",
|
|
118
|
+
length: 2
|
|
119
|
+
},
|
|
120
|
+
7: {
|
|
121
|
+
dataItem: "di077",
|
|
122
|
+
length: 3
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
5: {
|
|
126
|
+
1: {
|
|
127
|
+
dataItem: "di170",
|
|
128
|
+
length: 6
|
|
129
|
+
},
|
|
130
|
+
2: {
|
|
131
|
+
dataItem: "di020",
|
|
132
|
+
length: 1
|
|
133
|
+
},
|
|
134
|
+
3: {
|
|
135
|
+
dataItem: "di220",
|
|
136
|
+
length: -1
|
|
137
|
+
},
|
|
138
|
+
4: {
|
|
139
|
+
dataItem: "di146",
|
|
140
|
+
length: 2
|
|
141
|
+
},
|
|
142
|
+
5: {
|
|
143
|
+
dataItem: "di148",
|
|
144
|
+
length: 2
|
|
145
|
+
},
|
|
146
|
+
6: {
|
|
147
|
+
dataItem: "di110",
|
|
148
|
+
length: -1
|
|
149
|
+
},
|
|
150
|
+
7: {
|
|
151
|
+
dataItem: "di016",
|
|
152
|
+
length: 1
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
6: {
|
|
156
|
+
1: {
|
|
157
|
+
dataItem: "di008",
|
|
158
|
+
length: 1
|
|
159
|
+
},
|
|
160
|
+
2: {
|
|
161
|
+
dataItem: "di271",
|
|
162
|
+
length: -1
|
|
163
|
+
},
|
|
164
|
+
3: {
|
|
165
|
+
dataItem: "di132",
|
|
166
|
+
length: 1
|
|
167
|
+
},
|
|
168
|
+
4: {
|
|
169
|
+
dataItem: "di250",
|
|
170
|
+
length: -1
|
|
171
|
+
},
|
|
172
|
+
5: {
|
|
173
|
+
dataItem: "di260",
|
|
174
|
+
length: 7
|
|
175
|
+
},
|
|
176
|
+
6: {
|
|
177
|
+
dataItem: "di400",
|
|
178
|
+
length: 1
|
|
179
|
+
},
|
|
180
|
+
7: {
|
|
181
|
+
dataItem: "di295",
|
|
182
|
+
length: -1
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
7: {
|
|
186
|
+
1: {
|
|
187
|
+
dataItem: "SPARE",
|
|
188
|
+
length: 0
|
|
189
|
+
},
|
|
190
|
+
2: {
|
|
191
|
+
dataItem: "SPARE",
|
|
192
|
+
length: 0
|
|
193
|
+
},
|
|
194
|
+
3: {
|
|
195
|
+
dataItem: "SPARE",
|
|
196
|
+
length: 0
|
|
197
|
+
},
|
|
198
|
+
4: {
|
|
199
|
+
dataItem: "SPARE",
|
|
200
|
+
length: 0
|
|
201
|
+
},
|
|
202
|
+
5: {
|
|
203
|
+
dataItem: "SPARE",
|
|
204
|
+
length: 0
|
|
205
|
+
},
|
|
206
|
+
6: {
|
|
207
|
+
dataItem: "RE",
|
|
208
|
+
length: -1
|
|
209
|
+
},
|
|
210
|
+
7: {
|
|
211
|
+
dataItem: "SP",
|
|
212
|
+
length: -1
|
|
213
|
+
},
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
exports.CAT021_UAP = CAT021_UAP;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 비트가 켜져있는지 확인
|
|
3
|
+
* @param bits 비트 데이터
|
|
4
|
+
* @param fieldPos 확인하고자 하는 필드 위치
|
|
5
|
+
* @param headerLen 어떤 필드가 존재하는지 알려주는 primary octet
|
|
6
|
+
* @returns fieldPos의 비트가 켜져있는지
|
|
7
|
+
*/
|
|
8
|
+
declare const isBitSet: (bits: number, fieldPos: number, headerLen: number) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* 특정 범위 내부에서 비트가 1인 위치의 값을 전부 합침
|
|
11
|
+
* 시작 인덱스 >= 값 >= 끝 인덱스
|
|
12
|
+
* @param bits 비트 데이터
|
|
13
|
+
* @param startIndex 범위의 시작 인덱스
|
|
14
|
+
* @param endIndex 범위의 끝 인덱스
|
|
15
|
+
* @param pow 계산할 제곱값
|
|
16
|
+
* @returns 범위 값
|
|
17
|
+
*/
|
|
18
|
+
declare const octetOfRange: (bits: number, startIndex: number, endIndex: number, pow: number) => number;
|
|
19
|
+
/**
|
|
20
|
+
* 2의 보수 처리
|
|
21
|
+
* @param octets 보수 처리 전의 값
|
|
22
|
+
* @param bitCount 범위 최대치 위치
|
|
23
|
+
* @returns 보수 처리 후 값
|
|
24
|
+
*/
|
|
25
|
+
declare const twosCompliment: (octets: number, bitCount: number) => number;
|
|
26
|
+
declare const getChar: (key: number) => string;
|
|
27
|
+
export { isBitSet, octetOfRange, twosCompliment, getChar };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getChar = exports.twosCompliment = exports.octetOfRange = exports.isBitSet = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 비트가 켜져있는지 확인
|
|
6
|
+
* @param bits 비트 데이터
|
|
7
|
+
* @param fieldPos 확인하고자 하는 필드 위치
|
|
8
|
+
* @param headerLen 어떤 필드가 존재하는지 알려주는 primary octet
|
|
9
|
+
* @returns fieldPos의 비트가 켜져있는지
|
|
10
|
+
*/
|
|
11
|
+
const isBitSet = (bits, fieldPos, headerLen) => {
|
|
12
|
+
const totalBits = headerLen * 7;
|
|
13
|
+
// fieldPos는 1부터 시작
|
|
14
|
+
const shift = totalBits - fieldPos;
|
|
15
|
+
return (shift >= 0) && ((bits & (1 << shift)) != 0);
|
|
16
|
+
};
|
|
17
|
+
exports.isBitSet = isBitSet;
|
|
18
|
+
/**
|
|
19
|
+
* 특정 범위 내부에서 비트가 1인 위치의 값을 전부 합침
|
|
20
|
+
* 시작 인덱스 >= 값 >= 끝 인덱스
|
|
21
|
+
* @param bits 비트 데이터
|
|
22
|
+
* @param startIndex 범위의 시작 인덱스
|
|
23
|
+
* @param endIndex 범위의 끝 인덱스
|
|
24
|
+
* @param pow 계산할 제곱값
|
|
25
|
+
* @returns 범위 값
|
|
26
|
+
*/
|
|
27
|
+
const octetOfRange = (bits, startIndex, endIndex, pow) => {
|
|
28
|
+
let result = 0;
|
|
29
|
+
for (let index = startIndex; index >= endIndex; index--, pow--) {
|
|
30
|
+
if ((bits & (1 << index)) !== 0) {
|
|
31
|
+
result |= (1 << pow);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
exports.octetOfRange = octetOfRange;
|
|
37
|
+
/**
|
|
38
|
+
* 2의 보수 처리
|
|
39
|
+
* @param octets 보수 처리 전의 값
|
|
40
|
+
* @param bitCount 범위 최대치 위치
|
|
41
|
+
* @returns 보수 처리 후 값
|
|
42
|
+
*/
|
|
43
|
+
const twosCompliment = (octets, bitCount) => {
|
|
44
|
+
// 최상위 비트를 부호 비트로 식별
|
|
45
|
+
const signBit = 1 << (bitCount - 1);
|
|
46
|
+
// 최대값 범위 계산
|
|
47
|
+
const maxRange = 1 << bitCount;
|
|
48
|
+
// 음수 변환 조건
|
|
49
|
+
// 부호 비트가 1이면 음수로 변환
|
|
50
|
+
return (octets >= signBit) ? (octets - maxRange) : octets;
|
|
51
|
+
};
|
|
52
|
+
exports.twosCompliment = twosCompliment;
|
|
53
|
+
// 배열 선언
|
|
54
|
+
const CHAR_ARRAY = new Array(58);
|
|
55
|
+
// 초기화 로직 - A-Z (인덱스 1-26)
|
|
56
|
+
const startCharA = 'A'.charCodeAt(0);
|
|
57
|
+
for (let i = 1; i <= 26; i++) {
|
|
58
|
+
CHAR_ARRAY[i] = String.fromCharCode(startCharA + i - 1);
|
|
59
|
+
}
|
|
60
|
+
// 초기화 로직 - 0-9 (인덱스 48-57)
|
|
61
|
+
const startChar0 = '0'.charCodeAt(0);
|
|
62
|
+
for (let i = 48; i <= 57; i++) {
|
|
63
|
+
CHAR_ARRAY[i] = String.fromCharCode(startChar0 + i - 48);
|
|
64
|
+
}
|
|
65
|
+
const getChar = (key) => {
|
|
66
|
+
// 혹시라도 소수점이 들어올 경우를 대비해 정수로 변환 (Java의 (int)key 대응)
|
|
67
|
+
const intKey = Math.floor(key);
|
|
68
|
+
// 배열 범위 확인
|
|
69
|
+
if (intKey < 0 || intKey >= CHAR_ARRAY.length) {
|
|
70
|
+
return "";
|
|
71
|
+
}
|
|
72
|
+
const result = CHAR_ARRAY[intKey];
|
|
73
|
+
// 할당되지 않은 인덱스(undefined) 처리 (Java의 null 체크 대응)
|
|
74
|
+
if (result === undefined) {
|
|
75
|
+
return "";
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
};
|
|
79
|
+
exports.getChar = getChar;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type FieldSpec = {
|
|
2
|
+
[dataItem: string]: number;
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* UAP 정보를 통해 FieldSpec을 반환하는 함수
|
|
6
|
+
* @param category 카테고리
|
|
7
|
+
* @param data 바이트 데이터
|
|
8
|
+
* @param pos 데이터 순회 인덱스
|
|
9
|
+
* @returns FieldSpec과 다음 인덱스
|
|
10
|
+
*/
|
|
11
|
+
declare const getFieldSpec: (category: number, bitArr: Uint8Array, pos: number) => {
|
|
12
|
+
fieldSpec: FieldSpec;
|
|
13
|
+
recordIndex: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* FX 비트를 체크하여 확장되는 헤더를 읽고 { 비트조합, 헤더길이 }를 반환
|
|
17
|
+
* @param bitArr 비트 데이터
|
|
18
|
+
* @param recordIndex record 시작 인덱스
|
|
19
|
+
* @returns { 비트 조합, 헤더 길이 }
|
|
20
|
+
*/
|
|
21
|
+
declare const parseIndicator: (bitArr: Uint8Array, recordIndex: number) => {
|
|
22
|
+
bits: number;
|
|
23
|
+
headerLen: number;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* SP과 RE에서 사용
|
|
27
|
+
* @param bitArr Asterix 바이트 데이터
|
|
28
|
+
* @param currentPos 데이터 아이템 시작 인덱스
|
|
29
|
+
* @param length 데이터 길이
|
|
30
|
+
* @returns 문자열
|
|
31
|
+
*/
|
|
32
|
+
declare const getHexString: (bitArr: number[] | Uint8Array, currentPos: number, length: number) => string;
|
|
33
|
+
export { FieldSpec, getFieldSpec, parseIndicator, getHexString };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getHexString = exports.parseIndicator = exports.getFieldSpec = void 0;
|
|
4
|
+
const cat021_1 = require("../data/uap/cat021");
|
|
5
|
+
/**
|
|
6
|
+
* UAP 정보를 통해 FieldSpec을 반환하는 함수
|
|
7
|
+
* @param category 카테고리
|
|
8
|
+
* @param data 바이트 데이터
|
|
9
|
+
* @param pos 데이터 순회 인덱스
|
|
10
|
+
* @returns FieldSpec과 다음 인덱스
|
|
11
|
+
*/
|
|
12
|
+
const getFieldSpec = (category, bitArr, pos) => {
|
|
13
|
+
const fieldSpec = {};
|
|
14
|
+
// 행 번호
|
|
15
|
+
let block = 1;
|
|
16
|
+
// * 현재 바이트의 마지막 비트가 0일 때까지 반복
|
|
17
|
+
while (true) {
|
|
18
|
+
const currentByte = bitArr[pos++];
|
|
19
|
+
for (let bit = 7; bit >= 1; bit--) {
|
|
20
|
+
// * 해당 비트가 0이면 data item이 없다는 뜻이므로 넘김
|
|
21
|
+
if ((currentByte & (1 << bit)) === 0) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
// 열 번호
|
|
25
|
+
const frn = 7 - bit + 1;
|
|
26
|
+
if (category === 21) {
|
|
27
|
+
const dataItem = cat021_1.CAT021_UAP[block][frn].dataItem;
|
|
28
|
+
const length = cat021_1.CAT021_UAP[block][frn].length;
|
|
29
|
+
fieldSpec[dataItem] = length;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// * 마지막 비트가 0이면 종료
|
|
33
|
+
if ((currentByte & 1) === 0) {
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
block++;
|
|
37
|
+
}
|
|
38
|
+
const recordIndex = pos;
|
|
39
|
+
return { fieldSpec, recordIndex };
|
|
40
|
+
};
|
|
41
|
+
exports.getFieldSpec = getFieldSpec;
|
|
42
|
+
/**
|
|
43
|
+
* FX 비트를 체크하여 확장되는 헤더를 읽고 { 비트조합, 헤더길이 }를 반환
|
|
44
|
+
* @param bitArr 비트 데이터
|
|
45
|
+
* @param recordIndex record 시작 인덱스
|
|
46
|
+
* @returns { 비트 조합, 헤더 길이 }
|
|
47
|
+
*/
|
|
48
|
+
const parseIndicator = (bitArr, recordIndex) => {
|
|
49
|
+
let hasExtension = true;
|
|
50
|
+
let bits = 0;
|
|
51
|
+
let headerLen = 0;
|
|
52
|
+
while (hasExtension) {
|
|
53
|
+
const currentByte = bitArr[recordIndex++];
|
|
54
|
+
hasExtension = (currentByte & 1) != 0;
|
|
55
|
+
// FX 비트를 제거한 후 합침
|
|
56
|
+
bits = (bits << 7) | (currentByte >> 1);
|
|
57
|
+
headerLen++;
|
|
58
|
+
}
|
|
59
|
+
return { bits, headerLen };
|
|
60
|
+
};
|
|
61
|
+
exports.parseIndicator = parseIndicator;
|
|
62
|
+
/**
|
|
63
|
+
* SP과 RE에서 사용
|
|
64
|
+
* @param bitArr Asterix 바이트 데이터
|
|
65
|
+
* @param currentPos 데이터 아이템 시작 인덱스
|
|
66
|
+
* @param length 데이터 길이
|
|
67
|
+
* @returns 문자열
|
|
68
|
+
*/
|
|
69
|
+
const getHexString = (bitArr, currentPos, length) => {
|
|
70
|
+
const hexArray = "0123456789abcdef";
|
|
71
|
+
const result = [];
|
|
72
|
+
for (let i = 0; i < length; i++) {
|
|
73
|
+
// 배열 범위를 벗어나는지 체크 (안전장치, 필요 없으면 생략 가능)
|
|
74
|
+
if (currentPos + i >= bitArr.length)
|
|
75
|
+
break;
|
|
76
|
+
const v = bitArr[currentPos + i] & 0xFF;
|
|
77
|
+
result.push(hexArray[v >> 4]);
|
|
78
|
+
result.push(hexArray[v & 0x0F]);
|
|
79
|
+
}
|
|
80
|
+
return result.join('');
|
|
81
|
+
};
|
|
82
|
+
exports.getHexString = getHexString;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type Record = {
|
|
2
|
+
[dataItem: string]: {};
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* CAT 021 파싱
|
|
6
|
+
* @param record 단일 Record 파싱 결과
|
|
7
|
+
* @param bitArr Asterix 바이트 데이터
|
|
8
|
+
* @param currentPos 데이터 아이템 시작 인덱스
|
|
9
|
+
* @param dataItem 데이터 아이템 이름
|
|
10
|
+
* @param diLength 데이터 아이템 길이
|
|
11
|
+
*/
|
|
12
|
+
declare const cat021Process: (record: Record, bitArr: Uint8Array, currentPos: number, dataItem: string, diLength: number) => void;
|
|
13
|
+
export { Record, cat021Process };
|