-
Notifications
You must be signed in to change notification settings - Fork 240
/
Opcode.java
282 lines (251 loc) · 13.3 KB
/
Opcode.java
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.dmr.message.data.csbk;
import io.github.dsheirer.module.decode.dmr.message.type.Vendor;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.TreeMap;
/**
* Control Signalling Block (CSBK) Opcode enumeration
* ETSI TS 102 361-2 DMR Voice & Generic Services, Annex B
* ETSI TS 102 361-4 DMR Trunking Protocol, Annex B
*/
public enum Opcode
{
STANDARD_FEATURE_NOT_SUPPORTED(Vendor.STANDARD, 3, "FEATURE NOT SUPPORTED"),
STANDARD_UNIT_TO_UNIT_VOICE_SERVICE_REQUEST(Vendor.STANDARD, 4, "UNIT TO UNIT VOICE SERVICE REQUEST"),
STANDARD_UNIT_TO_UNIT_VOICE_SERVICE_RESPONSE(Vendor.STANDARD, 5, "UNIT TO UNIT VOICE SERVICE RESPONSE"),
STANDARD_CHANNEL_TIMING(Vendor.STANDARD, 7, "CHANNEL TIMING"),
STANDARD_ALOHA(Vendor.STANDARD, 25, "ALOHA"),
STANDARD_UNIFIED_DATA_TRANSPORT_OUTBOUND_HEADER(Vendor.STANDARD, 26, "UNIFIED DATA TRANSPORT OUTBOUND HEADER"),
STANDARD_UNIFIED_DATA_TRANSPORT_INBOUND_HEADER(Vendor.STANDARD, 27, "UNIFIED DATA TRANSPORT INBOUND HEADER"),
STANDARD_AHOY(Vendor.STANDARD, 28, "AHOY"),
STANDARD_ACTIVATION(Vendor.STANDARD, 30, "ACTIVATION"),
STANDARD_RANDOM_ACCESS_SERVICE_REQUEST(Vendor.STANDARD, 31, "RANDOM ACCESS SERVICE REQUEST"),
STANDARD_ACKNOWLEDGE_RESPONSE_OUTBOUND_TSCC(Vendor.STANDARD, 32, "ACKNOWLEDGE RESPONSE OUTBOUND TSCC"),
STANDARD_ACKNOWLEDGE_RESPONSE_INBOUND_TSCC(Vendor.STANDARD, 33, "ACKNOWLEDGE RESPONSE INBOUND TSCC"),
STANDARD_ACKNOWLEDGE_RESPONSE_OUTBOUND_PAYLOAD(Vendor.STANDARD, 34, "ACKNOWLEDGE RESPONSE OUTBOUND PAYLOAD"),
STANDARD_ACKNOWLEDGE_RESPONSE_INBOUND_PAYLOAD(Vendor.STANDARD, 35, "ACKNOWLEDGE RESPONSE INBOUND PAYLOAD"),
STANDARD_UNIFIED_DATA_TRANSPORT_FOR_DGNA_OUTBOUND_HEADER(Vendor.STANDARD, 36, "UNIFIED DATA TRANSPORT OUTBOUND HEADER"),
STANDARD_UNIFIED_DATA_TRANSPORT_FOR_DGNA_INBOUND_HEADER(Vendor.STANDARD, 37, "UNIFIED DATA TRANSPORT OUTBOUND HEADER"),
STANDARD_NEGATIVE_ACKNOWLEDGE_RESPONSE(Vendor.STANDARD, 38, "NEGATIVE ACKNOWLEDGE RESPONSE"),
STANDARD_ANNOUNCEMENT(Vendor.STANDARD, 40, "ANNOUNCEMENT"),
STANDARD_MAINTENANCE(Vendor.STANDARD, 42, "MAINTENANCE"),
STANDARD_CLEAR(Vendor.STANDARD, 46, "CLEAR"),
STANDARD_PROTECT(Vendor.STANDARD, 47, "PROTECT"),
STANDARD_PRIVATE_VOICE_CHANNEL_GRANT(Vendor.STANDARD, 48, "PRIVATE VOICE CHANNEL GRANT"),
STANDARD_TALKGROUP_VOICE_CHANNEL_GRANT(Vendor.STANDARD, 49, "TALKGROUP VOICE CHANNEL GRANT"),
STANDARD_BROADCAST_TALKGROUP_VOICE_CHANNEL_GRANT(Vendor.STANDARD, 50, "BROADCAST TALKGROUP VOICE CHANNEL GRANT"),
STANDARD_PRIVATE_DATA_CHANNEL_GRANT_SINGLE_ITEM(Vendor.STANDARD, 51, "PRIVATE DATA CHANNEL GRANT SINGLE ITEM"),
STANDARD_TALKGROUP_DATA_CHANNEL_GRANT_SINGLE_ITEM(Vendor.STANDARD, 52, "TALKGROUP DATA CHANNEL GRANT SINGLE ITEM"),
STANDARD_DUPLEX_PRIVATE_VOICE_CHANNEL_GRANT(Vendor.STANDARD, 53, "DUPLEX PRIVATE VOICE CHANNEL GRANT"),
STANDARD_DUPLEX_PRIVATE_DATA_CHANNEL_GRANT(Vendor.STANDARD, 54, "DUPLEX PRIVATE DATA CHANNEL GRANT"),
STANDARD_PRIVATE_DATA_CHANNEL_GRANT_MULTI_ITEM(Vendor.STANDARD, 55, "PRIVATE DATA CHANNEL GRANT MULTI ITEM"),
STANDARD_TALKGROUP_DATA_CHANNEL_GRANT_MULTI_ITEM(Vendor.STANDARD, 56, "TALKGROUP DATA CHANNEL GRANT MULTI ITEM"),
STANDARD_MOVE_TSCC(Vendor.STANDARD, 57, "MOVE TSCC"),
STANDARD_PREAMBLE(Vendor.STANDARD, 61, "PREAMBLE"),
MOTOROLA_CONPLUS_NEIGHBOR_REPORT(Vendor.MOTOROLA_CONNECT_PLUS, 1, "NEIGHBOR REPORT"),
MOTOROLA_CONPLUS_VOICE_CHANNEL_USER(Vendor.MOTOROLA_CONNECT_PLUS, 3, "VOICE CHANNEL USER"),
MOTOROLA_CONPLUS_DATA_CHANNEL_GRANT(Vendor.MOTOROLA_CONNECT_PLUS, 6, "DATA CHANNEL GRANT"),
MOTOROLA_CONPLUS_CSBKO_10(Vendor.MOTOROLA_CONNECT_PLUS, 10, "CSBKO 10"),
MOTOROLA_CONPLUS_TERMINATE_CHANNEL_GRANT(Vendor.MOTOROLA_CONNECT_PLUS, 12, "TERMINATE CHANNEL GRANT"),
MOTOROLA_CONPLUS_CSBKO_16(Vendor.MOTOROLA_CONNECT_PLUS, 16, "CSBKO 16"),
MOTOROLA_CONPLUS_REGISTRATION_REQUEST(Vendor.MOTOROLA_CONNECT_PLUS, 17, "REGISTRATION REQUEST"),
MOTOROLA_CONPLUS_REGISTRATION_RESPONSE(Vendor.MOTOROLA_CONNECT_PLUS, 18, "REGISTRATION RESPONSE"),
MOTOROLA_CONPLUS_TALKGROUP_AFFILIATION(Vendor.MOTOROLA_CONNECT_PLUS, 24, "TALKGROUP AFFILIATION"),
MOTOROLA_CONPLUS_DATA_WINDOW_ANNOUNCEMENT(Vendor.MOTOROLA_CONNECT_PLUS, 28, "ENHANCED DATA REVERT WINDOW ANNOUNCEMENT"),
MOTOROLA_CONPLUS_DATA_WINDOW_GRANT(Vendor.MOTOROLA_CONNECT_PLUS, 29, "ENHANCED DATA REVERT WINDOW GRANT"),
MOTOROLA_CAPMAX_GROUP_CHANNEL_USER(Vendor.MOTOROLA_CAPACITY_PLUS, 16, "GROUP CHANNEL USER"),
MOTOROLA_CAPMAX_ALOHA(Vendor.MOTOROLA_CAPACITY_PLUS, 25, "ALOHA"),
MOTOROLA_CAPMAX_GROUP_VOICE_CHANNEL_UPDATE(Vendor.MOTOROLA_CAPACITY_PLUS, 33, "TALKGROUP ACTIVE"),
MOTOROLA_CAPPLUS_CALL_ALERT(Vendor.MOTOROLA_CAPACITY_PLUS, 31, "CALL ALERT"),
MOTOROLA_CAPPLUS_CALL_ALERT_ACK(Vendor.MOTOROLA_CAPACITY_PLUS, 32, "CALL ALERT ACK"),
MOTOROLA_CAPPLUS_DATA_WINDOW_ANNOUNCEMENT(Vendor.MOTOROLA_CAPACITY_PLUS, 41, "ENHANCED DATA REVERT WINDOW ANNOUNCEMENT"),
MOTOROLA_CAPPLUS_DATA_WINDOW_GRANT(Vendor.MOTOROLA_CAPACITY_PLUS, 42, "ENHANCED DATA REVERT WINDOW GRANT"),
MOTOROLA_CAPPLUS_NEIGHBOR_REPORT(Vendor.MOTOROLA_CAPACITY_PLUS, 59, "NEIGHBOR REPORT"),
MOTOROLA_CAPPLUS_CSBKO_60(Vendor.MOTOROLA_CAPACITY_PLUS, 60, "CSBKO 60"),
MOTOROLA_CAPPLUS_PREAMBLE(Vendor.MOTOROLA_CAPACITY_PLUS, 61, "PREAMBLE"),
MOTOROLA_CAPPLUS_SITE_STATUS(Vendor.MOTOROLA_CAPACITY_PLUS, 62, "SITE STATUS"),
HYTERA_08_ACKNOWLEDGE(Vendor.HYTERA_8, 32, "HYTERA 08 ACKNOWLEDGE"),
HYTERA_08_ANNOUNCEMENT(Vendor.HYTERA_8, 40, "HYTERA 08 ANNOUNCEMENT"),
//CSBKO 44 & 47 observed on Tier3 interleaved in voice group call terminator sequence. 44 was continuously transmitted
//and 47 was only transmitted 3x times in succession in the middle of the terminators and CSBKO 44 messages.
HYTERA_08_CSBKO_44(Vendor.HYTERA_8, 44, "HYTERA 08 CSBKO 44"),
HYTERA_08_TRAFFIC_CHANNEL_TALKER_STATUS(Vendor.HYTERA_8, 47, "HYTERA 08 CSBKO 47"),
HYTERA_68_XPT_SITE_STATE(Vendor.HYTERA_68, 10, "HYTERA 68 XPT SITE STATE"),
HYTERA_68_ALOHA(Vendor.HYTERA_68, 25, "HYTERA 68 ALOHA"),
HYTERA_68_ACKNOWLEDGE(Vendor.HYTERA_68, 32, "HYTERA 68 ACKNOWLEDGE"),
HYTERA_68_ANNOUNCEMENT(Vendor.HYTERA_68, 40, "HYTERA 68 ANNOUNCEMENT"),
//Opcode 54 and/or 55 - See patent on Hytera call forwarding
HYTERA_68_XPT_PREAMBLE(Vendor.HYTERA_68, 61, "HYTERA 68 XPT PREAMBLE"),
HYTERA_68_CSBKO_62(Vendor.HYTERA_68, 62, "HYTERA 68 CSBKO 62"),
UNKNOWN(Vendor.UNKNOWN, -1, "UNKNOWN");
private final Vendor mVendor;
private final int mValue;
private final String mLabel;
/**
* Constructor
* @param vendor for the opcode
* @param value for the opcode
* @param label to display for the opcode
*/
Opcode(Vendor vendor, int value, String label)
{
mVendor = vendor;
mValue = value;
mLabel = label;
}
/**
* Vendor for this opcode
*/
public Vendor getVendor()
{
return mVendor;
}
/**
* Numeric value for the opcode
*/
public int getValue()
{
return mValue;
}
/**
* Pretty label for the opcode
*/
public String getLabel()
{
return mLabel;
}
@Override
public String toString()
{
return getLabel();
}
/**
* Indicates if this opcode is a data channel grant opcode
*/
public boolean isDataChannelGrantOpcode()
{
return DATA_CHANNEL_GRANTS.contains(this);
}
/**
* Data channel grant opcodes
*/
public static final EnumSet<Opcode> DATA_CHANNEL_GRANTS = EnumSet.of(STANDARD_PRIVATE_DATA_CHANNEL_GRANT_MULTI_ITEM,
STANDARD_PRIVATE_DATA_CHANNEL_GRANT_SINGLE_ITEM, STANDARD_DUPLEX_PRIVATE_DATA_CHANNEL_GRANT,
STANDARD_TALKGROUP_DATA_CHANNEL_GRANT_MULTI_ITEM, STANDARD_TALKGROUP_DATA_CHANNEL_GRANT_SINGLE_ITEM);
/**
* Data opcodes
*/
public static final EnumSet<Opcode> DATA_OPCODES = EnumSet.of(STANDARD_UNIFIED_DATA_TRANSPORT_OUTBOUND_HEADER,
STANDARD_UNIFIED_DATA_TRANSPORT_INBOUND_HEADER, STANDARD_UNIFIED_DATA_TRANSPORT_FOR_DGNA_OUTBOUND_HEADER,
STANDARD_UNIFIED_DATA_TRANSPORT_FOR_DGNA_INBOUND_HEADER, STANDARD_PREAMBLE);
/**
* Mobile request and response opcodes
*/
public static final EnumSet<Opcode> MOBILE_REQUEST_RESPONSE = EnumSet.of(STANDARD_UNIT_TO_UNIT_VOICE_SERVICE_REQUEST,
STANDARD_RANDOM_ACCESS_SERVICE_REQUEST);
/**
* Network request and response and announcement opcodes
*/
public static final EnumSet<Opcode> NETWORK_REQUEST_RESPONSE = EnumSet.of(STANDARD_FEATURE_NOT_SUPPORTED,
STANDARD_UNIT_TO_UNIT_VOICE_SERVICE_RESPONSE, STANDARD_AHOY, STANDARD_ACKNOWLEDGE_RESPONSE_OUTBOUND_TSCC,
STANDARD_ACKNOWLEDGE_RESPONSE_INBOUND_TSCC, STANDARD_ACKNOWLEDGE_RESPONSE_OUTBOUND_PAYLOAD,
STANDARD_ACKNOWLEDGE_RESPONSE_INBOUND_PAYLOAD, STANDARD_NEGATIVE_ACKNOWLEDGE_RESPONSE, STANDARD_CLEAR,
STANDARD_MOVE_TSCC, STANDARD_CHANNEL_TIMING,
STANDARD_ALOHA, STANDARD_ACTIVATION, STANDARD_ANNOUNCEMENT, STANDARD_MAINTENANCE, STANDARD_PROTECT);
/**
* Voice channel grant opcodes
*/
public static final EnumSet<Opcode> VOICE_CHANNEL_GRANTS = EnumSet.of(STANDARD_PRIVATE_VOICE_CHANNEL_GRANT,
STANDARD_TALKGROUP_VOICE_CHANNEL_GRANT, STANDARD_BROADCAST_TALKGROUP_VOICE_CHANNEL_GRANT,
STANDARD_DUPLEX_PRIVATE_VOICE_CHANNEL_GRANT);
/**
* Hytera opcodes
*/
public static final EnumSet<Opcode> HYTERA = EnumSet.of(HYTERA_08_ACKNOWLEDGE, HYTERA_08_ANNOUNCEMENT,
HYTERA_08_CSBKO_44, HYTERA_08_TRAFFIC_CHANNEL_TALKER_STATUS, HYTERA_68_XPT_SITE_STATE, HYTERA_68_ALOHA,
HYTERA_68_ACKNOWLEDGE, HYTERA_68_ANNOUNCEMENT, HYTERA_68_XPT_PREAMBLE, HYTERA_68_CSBKO_62);
/**
* Motorola Capacity Max opcodes
*/
public static final EnumSet<Opcode> MOTOROLA_CAPACITY_MAX = EnumSet.of(MOTOROLA_CAPMAX_ALOHA);
/**
* Motorola Capacity Plus opcodes
*/
public static final EnumSet<Opcode> MOTOROLA_CAPACITY_PLUS = EnumSet.of(MOTOROLA_CAPPLUS_CALL_ALERT,
MOTOROLA_CAPPLUS_CALL_ALERT_ACK, MOTOROLA_CAPPLUS_DATA_WINDOW_ANNOUNCEMENT,
MOTOROLA_CAPPLUS_DATA_WINDOW_GRANT, MOTOROLA_CAPPLUS_NEIGHBOR_REPORT, MOTOROLA_CAPPLUS_CSBKO_60,
MOTOROLA_CAPPLUS_PREAMBLE, MOTOROLA_CAPPLUS_SITE_STATUS);
/**
* Motorola Connect Plus opcodes
*/
public static final EnumSet<Opcode> MOTOROLA_CONNECT_PLUS = EnumSet.of(MOTOROLA_CONPLUS_NEIGHBOR_REPORT,
MOTOROLA_CONPLUS_VOICE_CHANNEL_USER, MOTOROLA_CONPLUS_DATA_CHANNEL_GRANT, MOTOROLA_CONPLUS_CSBKO_10,
MOTOROLA_CONPLUS_TERMINATE_CHANNEL_GRANT, MOTOROLA_CONPLUS_CSBKO_16, MOTOROLA_CONPLUS_REGISTRATION_REQUEST,
MOTOROLA_CONPLUS_REGISTRATION_RESPONSE, MOTOROLA_CONPLUS_TALKGROUP_AFFILIATION,
MOTOROLA_CONPLUS_DATA_WINDOW_ANNOUNCEMENT, MOTOROLA_CONPLUS_DATA_WINDOW_GRANT);
/**
* Indicates if the opcode is included in one of the enumset groupings above
* @return
*/
public boolean isGrouped()
{
return DATA_CHANNEL_GRANTS.contains(this) || DATA_OPCODES.contains(this) ||
MOBILE_REQUEST_RESPONSE.contains(this) || NETWORK_REQUEST_RESPONSE.contains(this) ||
VOICE_CHANNEL_GRANTS.contains(this) || HYTERA.contains(this) || MOTOROLA_CAPACITY_MAX.contains(this) ||
MOTOROLA_CAPACITY_PLUS.contains(this) || MOTOROLA_CONNECT_PLUS.contains(this);
}
/**
* Lookup map of vendors and opcode value to opcodes
*/
private static final Map<Vendor,Map<Integer,Opcode>> LOOKUP_MAP = new EnumMap<>(Vendor.class);
static
{
for(Opcode opcode : Opcode.values())
{
if(LOOKUP_MAP.containsKey(opcode.getVendor()))
{
LOOKUP_MAP.get(opcode.getVendor()).put(opcode.getValue(), opcode);
}
else
{
Map<Integer,Opcode> map = new TreeMap<>();
map.put(opcode.getValue(), opcode);
LOOKUP_MAP.put(opcode.getVendor(), map);
}
}
}
/**
* Lookup the opcode from the value for the specified vendor
*/
public static Opcode fromValue(int value, Vendor vendor)
{
if(LOOKUP_MAP.containsKey(vendor))
{
Map<Integer,Opcode> opcodeMap = LOOKUP_MAP.get(vendor);
if(opcodeMap.containsKey(value))
{
return opcodeMap.get(value);
}
}
return UNKNOWN;
}
}