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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
//! Decode various trunking-related packet fields.

use util::{slice_u16, slice_u24, slice_u32};

/// Options that can be requested/granted by a service.
pub struct ServiceOptions(u8);

impl ServiceOptions {
    /// Create a new `ServiceOptions` based on the given byte.
    pub fn new(opts: u8) -> ServiceOptions { ServiceOptions(opts) }

    /// Whether the service should be processed as an emergency.
    pub fn emergency(&self) -> bool { self.0 >> 7 == 1 }
    /// Whether the channel should be encrypted.
    pub fn protected(&self) -> bool { self.0 >> 6 & 1 == 1 }
    /// Whether the channel should be full duplex for simultaneous transmit and receive
    /// (otherwise fall back to half duplex.)
    pub fn full_duplex(&self) -> bool { self.0 >> 5 & 1 == 1 }
    /// Whether the service should be packet switched (otherwise fall back to circuit
    /// switched.)
    pub fn packet_switched(&self) -> bool { self.0 >> 4 & 1 == 1 }
    /// Priority assigned to service, with 1 as lowest and 7 as highest.
    pub fn prio(&self) -> u8 { self.0 & 0x7 }
}

/// Uniquely identifies a channel within a site.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Channel(u16);

impl Channel {
    /// Create a new `Channel` from the given 16 bits.
    pub fn new(bytes: &[u8]) -> Channel { Channel(slice_u16(bytes)) }

    /// Channel ID whose parameters to use.
    pub fn id(&self) -> u8 { (self.0 >> 12) as u8 }
    /// Individual channel number within the channel.
    pub fn number(&self) -> u16 { self.0 & 0xFFF }
}

/// Identifies which group a message belongs to.
///
/// In a production P25 system, users can set their radios to receive one or more
/// talkgroups, and the radio will only unsquelch if one of those talkgroups is seen.
/// Additionally, the user directs each transmission to a talkgroup selected on the
/// radio.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "ser", derive(Serialize))]
pub enum TalkGroup {
    /// Includes nobody.
    Nobody,
    /// Default talkgroup when no other is selected.
    Default,
    /// Includes everybody.
    Everbody,
    /// Specific group of users.
    Other(u16),
}

impl TalkGroup {
    /// Parse a talkgroup from the given 16 bit slice.
    pub fn new(bytes: &[u8]) -> TalkGroup {
        Self::from_bits(slice_u16(bytes))
    }

    /// Parse a talkgroup from the given 16 bits.
    pub fn from_bits(bits: u16) -> TalkGroup {
        use self::TalkGroup::*;

        match bits {
            0x0000 => Nobody,
            0x0001 => Default,
            0xFFFF => Everbody,
            _ => Other(bits),
        }
    }
}

/// Supported services of a control channel.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct SystemServices(u8);

impl SystemServices {
    /// Create a new `SystemServices` from the given byte.
    pub fn new(ssc: u8) -> Self { SystemServices(ssc) }

    /// Whether channel can also operate as a traffic channel in busy conditions.
    pub fn is_composite(&self) -> bool { self.0 & 0x01 != 0 }
    /// Whether channel only transmits updates (and doesn't accept data, voice, etc.
    /// service requests.)
    pub fn updates_only(&self) -> bool { self.0 & 0x02 != 0 }
    /// Whether channel operates only as backup to a primary control channel.
    pub fn is_backup(&self) -> bool { self.0 & 0x04 != 0 }
    /// Supports data service requests.
    pub fn has_data(&self) -> bool { self.0 & 0x10 != 0 }
    /// Supports voice service requests.
    pub fn has_voice(&self) -> bool { self.0 & 0x20 != 0 }
    /// Supports registration requests.
    pub fn has_registration(&self) -> bool { self.0 & 0x40 != 0 }
    /// Supports authentication requests.
    pub fn has_auth(&self) -> bool { self.0 & 0x80 != 0 }
}

/// Maps channel identifiers (maximum 16 per control channel) to their tuning parameters.
#[derive(Default)]
pub struct ChannelParamsMap([Option<ChannelParams>; 16]);

impl ChannelParamsMap {
    /// Update the map with the given channel parameters.
    pub fn update(&mut self, upd: &ChannelParamsUpdate) {
        self.0[upd.id() as usize] = Some(upd.params());
    }

    /// Try to retrieve channel parameters for the given channel ID.
    pub fn lookup(&self, id: u8) -> Option<ChannelParams> {
        self.0[id as usize]
    }
}

/// Computes TX/RX frequencies and bandwidth for channel numbers within a site.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ChannelParams {
    /// Base frequency in Hz.
    base: u32,
    /// Channel spacing in Hz.
    spacing: u32,
    /// Transmit frequency offset in Hz.
    offset: i32,
    /// Channel bandwidth in Hz.
    pub bandwidth: u32,
}

impl ChannelParams {
    /// Create a new `ChannelParams` from the given base frequency (5Hz steps), bandwidth
    /// (125Hz steps), TX offset (250kHz steps), and inter-channel spacing (125Hz steps.)
    pub fn new(base: u32, bandwidth: u16, offset: u16, spacing: u16) -> ChannelParams {
        // The MSB denotes the sign and the lower byte is the actual offset.
        let off = (offset as i32 & 0xFF) * 250_000;

        ChannelParams {
            base: base * 5,
            spacing: spacing as u32 * 125,
            offset: if offset >> 8 == 0 { -off } else { off },
            bandwidth: bandwidth as u32 * 125,
        }
    }

    /// Receive frequency for the given channel number in Hz.
    pub fn rx_freq(&self, ch: u16) -> u32 {
        self.base + self.spacing * ch as u32
    }

    /// Transmit frequency for the given channel number in Hz.
    pub fn tx_freq(&self, ch: u16) -> u32 {
        self.rx_freq(ch) + self.offset as u32
    }
}

/// Options for a P25 site.
pub struct SiteOptions(u8);

impl SiteOptions {
    /// Create a new `SiteOptions` from the given 4-bit word.
    pub fn new(opts: u8) -> SiteOptions {
        assert!(opts >> 4 == 0);
        SiteOptions(opts)
    }

    /// Whether site is "conventional", with no trunking.
    pub fn conventional(&self) -> bool { self.0 & 0b1000 != 0 }
    /// Whether site is in a failure state.
    pub fn failing(&self) -> bool { self.0 & 0b100 != 0 }
    /// Whether this information is up-to-date (whether broadcasting site is in
    /// communication with adjacent site.)
    pub fn current(&self) -> bool { self.0 & 0b10 != 0 }
    /// Whether site has active network connection with RFSS controller and can
    /// communicate with other sites.
    pub fn networked(&self) -> bool { self.0 & 1 != 0 }
}

/// Updates subscribers about new or ongoing talkgroup conversations.
///
/// Note that this can be used for both `GroupVoiceUpdate` and `GroupDataUpdate`.
pub struct GroupTrafficUpdate<'a>(&'a [u8]);

impl<'a> GroupTrafficUpdate<'a> {
    /// Create a new `GroupTrafficUpdate` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { GroupTrafficUpdate(payload) }

    /// Retrieve the set of active talkgroups included in the update along with the
    /// parameters for tuning to the traffic channel of each.
    pub fn updates(&self) -> [(Channel, TalkGroup); 2] {
        [
            (Channel::new(&self.0[0..=1]), TalkGroup::new(&self.0[2..=3])),
            (Channel::new(&self.0[4..=5]), TalkGroup::new(&self.0[6..=7])),
        ]
    }
}

/// Advertisement of an adjacent/nearby site within the same WACN (Wide Area Communication
/// Network.)
pub struct AdjacentSite<'a>(&'a [u8]);

impl<'a> AdjacentSite<'a> {
    /// Create a new `AdjacentSite` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { AdjacentSite(payload) }

    /// Location registration area of adjacent site, which determines whether a subscriber
    /// must update the network before roaming to the site.
    pub fn area(&self) -> u8 { self.0[0] }
    /// Description of adjacent site.
    pub fn opts(&self) -> SiteOptions { SiteOptions::new(self.0[1] >> 4) }
    /// System ID of adjacent site within WACN.
    pub fn system(&self) -> u16 { slice_u16(&self.0[1..=2]) & 0xFFF }
    /// RF Subsystem ID of adjacent site within the System.
    pub fn rfss(&self) -> u8 { self.0[3] }
    /// Site ID of adjacent site within the RFSS.
    pub fn site(&self) -> u8 { self.0[4] }
    /// Channel information for computing TX/RX frequencies.
    pub fn channel(&self) -> Channel { Channel::new(&self.0[5..=6]) }
    /// Services supported by the adjacent site.
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[7]) }
}

/// Advertisement of parameters used to calculate TX/RX frequencies within the given
/// associated channel.
pub struct ChannelParamsUpdate<'a>(&'a [u8]);

impl<'a> ChannelParamsUpdate<'a> {
    /// Create a new `ChannelParamsUpdate` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { ChannelParamsUpdate(payload) }

    /// Channel ID associated with the enclosed parameters (can be up to 16 per control
    /// channel.)
    pub fn id(&self) -> u8 { self.0[0] >> 4 }

    /// Parameters for the associated channel.
    pub fn params(&self) -> ChannelParams {
        ChannelParams::new(self.base(), self.bandwidth(), self.offset(), self.spacing())
    }

    /// Bandwidth in steps of 125Hz.
    fn bandwidth(&self) -> u16 {
        (self.0[0] as u16 & 0xF) << 5 | (self.0[1] >> 3) as u16
    }

    /// Offset of TX frequency from base RX frequency in steps of 250kHz.
    fn offset(&self) -> u16 {
        (self.0[1] as u16 & 0x7) << 6 | (self.0[2] >> 2) as u16
    }

    /// Spacing between individual channel numbers in steps of 125Hz.
    fn spacing(&self) -> u16 {
        (self.0[2] as u16 & 0x3) << 8 | self.0[3] as u16
    }

    /// Base RX frequency in steps of 5Hz.
    fn base(&self) -> u32 { slice_u32(&self.0[4..=7]) }
}

/// Advertisement of one or more alternative control channels for the current site.
pub struct AltControlChannel<'a>(&'a [u8]);

impl<'a> AltControlChannel<'a> {
    /// Create a new `AltControlChannel` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { AltControlChannel(payload) }

    /// RF Subsystem ID of current site within System.
    pub fn rfss(&self) -> u8 { self.0[0] }
    /// Site ID of current site within RFSS.
    pub fn site(&self) -> u8 { self.0[1] }

    /// Retrieve alternative sites, with each site's tuning parameters and supported
    /// services.
    pub fn alts(&self) -> [(Channel, SystemServices); 2] {
        [
            (Channel::new(&self.0[2..=3]), SystemServices::new(self.0[4])),
            (Channel::new(&self.0[5..=6]), SystemServices::new(self.0[7])),
        ]
    }
}

/// Site and RFSS information of current control channel.
pub struct RfssStatusBroadcast<'a>(&'a [u8]);

impl<'a> RfssStatusBroadcast<'a> {
    /// Create a new `RfssStatusBroadcast` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { RfssStatusBroadcast(payload) }

    /// Location registration area of current site.
    pub fn area(&self) -> u8 { self.0[0] }
    /// Whether the site is networked with the RFSS controller, which determines if it can
    /// communicate with other sites.
    pub fn networked(&self) -> bool { self.0[1] & 0b10000 != 0 }
    /// System ID of current site within WACN.
    pub fn system(&self) -> u16 { slice_u16(&self.0[1..=2]) & 0xFFF }
    /// RF Subsystem ID of current site within System.
    pub fn rfss(&self) -> u8 { self.0[3] }
    /// Site ID of current site within RFSS.
    pub fn site(&self) -> u8 { self.0[4] }
    /// Channel information for computing TX/RX frequencies.
    pub fn channel(&self) -> Channel { Channel::new(&self.0[5..=6]) }
    /// Services supported by the current site.
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[7]) }
}

/// WACN (Wide Area Communication Network) and System ID information of current control
/// channel.
pub struct NetworkStatusBroadcast<'a>(&'a [u8]);

impl<'a> NetworkStatusBroadcast<'a> {
    /// Create a new `NetworkStatusBroadcast` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { NetworkStatusBroadcast(payload) }

    /// Location registration area of site.
    pub fn area(&self) -> u8 { self.0[0] }
    /// WACN ID within the communications network.
    pub fn wacn(&self) -> u32 { slice_u24(&self.0[1..=3]) >> 4 }
    /// System ID of site within WACN.
    pub fn system(&self) -> u16 { slice_u16(&self.0[3..=4]) & 0xFFF }
    /// Channel information for computing TX/RX frequencies.
    pub fn channel(&self) -> Channel { Channel::new(&self.0[5..=6]) }
    /// Services supported by the current site.
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[7]) }
}

/// Registration response.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "ser", derive(Serialize))]
pub enum RegResponse {
    /// Registration is accepted.
    Accept,
    /// RFSS was unable to verify registration.
    Fail,
    /// Registration isn't allowed at this location.
    Deny,
    /// Denied temporarily, but user may retry registration.
    Refuse,
}

impl RegResponse {
    /// Try to parse a registration response from the given 2 bits.
    pub fn from_bits(bits: u8) -> RegResponse {
        use self::RegResponse::*;

        assert!(bits >> 2 == 0);

        match bits {
            0b00 => Accept,
            0b01 => Fail,
            0b10 => Deny,
            0b11 => Refuse,
            _ => unreachable!(),
        }
    }
}

/// Request for a target unit to call a source unit.
pub struct UnitCallAlert<'a>(&'a [u8]);

impl<'a> UnitCallAlert<'a> {
    /// Create a new `UnitCallAlert` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { UnitCallAlert(payload) }

    /// Target unit.
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[2..=4]) }
    /// Requesting unit.
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[5..=7]) }
}

/// Signals a target unit that a unit-to-unit all has been requested.
pub struct UnitCallRequest<'a>(&'a [u8]);

impl<'a> UnitCallRequest<'a> {
    /// Create a new `UnitCallRequest` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { UnitCallRequest(payload) }

    /// Options requested/granted for resulting channel.
    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[0]) }
    /// Target unit.
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[2..=4]) }
    /// Requesting unit.
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[5..=7]) }
}

/// Alerts a unit of a call from the public phone network.
pub struct PhoneAlert<'a>(&'a [u8]);

impl<'a> PhoneAlert<'a> {
    /// Create a new `PhoneAlert` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { PhoneAlert(payload) }

    /// The 10-digit phone number of the calling party, as encoded bytes.
    pub fn digits(&self) -> &[u8] { &self.0[0..=4] }
    /// Unit the call is for.
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[5..=7]) }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_channel_params() {
        // Example from the standard.
        let p = ChannelParams::new(170201250, 0x64, 0b010110100, 0x32);
        assert_eq!(p.base, 851_006_250);
        assert_eq!(p.spacing, 6_250);
        assert_eq!(p.offset, -45_000_000);
        assert_eq!(p.bandwidth, 12_500);
        assert_eq!(p.rx_freq(0b1001), 851_062_500);
    }

    #[test]
    fn test_group_traffic_updates() {
        let buf = [
            0b10001000,
            0b01110111,
            0b11111111,
            0b11111111,
            0b10010001,
            0b00000001,
            0b10101010,
            0b10101010,
        ];

        let u = GroupTrafficUpdate(&buf[..]).updates();

        assert_eq!(u[0].0.id(), 0b1000);
        assert_eq!(u[0].0.number(), 0b100001110111);
        assert_eq!(u[0].1, TalkGroup::Everbody);
        assert_eq!(u[1].0.id(), 0b1001);
        assert_eq!(u[1].0.number(), 0b000100000001);
        assert_eq!(u[1].1, TalkGroup::Other(0b1010101010101010));
    }
}