mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
#1422 Resolves issue where MotoTRBO IP Site Connect and Capacity Plus voice group user message not decoding Radio & Talkgroup IDs correctly. Creates standalone application for viewing DMR messages from recordings. (#1442)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* 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
|
||||
@@ -21,6 +21,7 @@ package io.github.dsheirer.module.decode.dmr.message.data.lc;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.edac.CRCDMR;
|
||||
import io.github.dsheirer.edac.Checksum_5_DMR;
|
||||
import io.github.dsheirer.edac.ReedSolomon_12_9_4_DMR;
|
||||
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.FullLCMessage;
|
||||
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.GPSInformation;
|
||||
@@ -71,9 +72,23 @@ public class LCMessageFactory
|
||||
throw new IllegalArgumentException("Message cannot be null");
|
||||
}
|
||||
|
||||
//RS(12,9,4) can correct up to floor(4/2) = 1 bit error.
|
||||
boolean corrected = REED_SOLOMON_12_9_4_DMR.correctFullLinkControl(message,
|
||||
isTerminator ? TERMINATOR_LINK_CONTROL_CRC_MASK : VOICE_LINK_CONTROL_CRC_MASK);
|
||||
boolean valid = true;
|
||||
|
||||
if(message.size() == 77)
|
||||
{
|
||||
valid = Checksum_5_DMR.isValid(message);
|
||||
}
|
||||
else if(message.size() == 96)
|
||||
{
|
||||
//RS(12,9,4) can correct up to floor(4/2) = 1 bit error.
|
||||
valid = REED_SOLOMON_12_9_4_DMR.correctFullLinkControl(message,
|
||||
isTerminator ? TERMINATOR_LINK_CONTROL_CRC_MASK : VOICE_LINK_CONTROL_CRC_MASK);
|
||||
mLog.warn("Doing the reed solomon thing .... valid: " + valid);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Unrecognized Link Control Message Size: " + message.size());
|
||||
}
|
||||
|
||||
LCOpcode opcode = FullLCMessage.getOpcode(message);
|
||||
|
||||
@@ -118,7 +133,8 @@ public class LCMessageFactory
|
||||
break;
|
||||
}
|
||||
|
||||
flc.setValid(corrected);
|
||||
flc.setValid(valid);
|
||||
|
||||
return flc;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* 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
|
||||
@@ -93,7 +93,7 @@ public class FLCAssembler
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a fully-received messsage
|
||||
* Dispatches a fully-received message
|
||||
*/
|
||||
private FullLCMessage dispatch()
|
||||
{
|
||||
@@ -133,6 +133,7 @@ public class FLCAssembler
|
||||
for(int row = 0; row < 8; row++)
|
||||
{
|
||||
int rowErrorCount = Hamming16.checkAndCorrect(descrambled, row * 16);
|
||||
|
||||
errorCount += rowErrorCount;
|
||||
|
||||
if(errorCount > 1)
|
||||
@@ -179,6 +180,9 @@ public class FLCAssembler
|
||||
{
|
||||
extractedMessage.set(pointer++, descrambled.get(row * 16 + column));
|
||||
}
|
||||
|
||||
//Transfer the checksum parity bit from this row
|
||||
extractedMessage.set(70 + row, descrambled.get(row * 16 + 10));
|
||||
}
|
||||
|
||||
extractedMessage.setCorrectedBitCount(errorCount);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* 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
|
||||
@@ -99,4 +99,13 @@ public abstract class FullLCMessage extends LCMessage
|
||||
{
|
||||
return getMessage().get(ENCRYPTION_FLAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the reserved bit is set.
|
||||
* @return true if set
|
||||
*/
|
||||
public boolean isReservedBitSet()
|
||||
{
|
||||
return getMessage().get(RESERVED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* 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
|
||||
@@ -25,7 +25,6 @@ import io.github.dsheirer.identifier.radio.RadioIdentifier;
|
||||
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRRadio;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRTalkgroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -69,6 +68,7 @@ public class GroupVoiceChannelUser extends AbstractVoiceChannelUser
|
||||
sb.append(getRadio());
|
||||
sb.append(" TO:").append(getTalkgroup());
|
||||
sb.append(" ").append(getServiceOptions());
|
||||
sb.append(" MSG:").append(getMessage().toHexString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* 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
|
||||
@@ -28,20 +28,22 @@ import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver;
|
||||
import io.github.dsheirer.module.decode.dmr.channel.TimeslotFrequency;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRRadio;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRTalkgroup;
|
||||
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.AbstractVoiceChannelUser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Motorola Capacity Plus - Group Voice Channel User
|
||||
*/
|
||||
public class CapacityPlusGroupVoiceChannelUser extends AbstractVoiceChannelUser implements ITimeslotFrequencyReceiver
|
||||
public class CapacityPlusGroupVoiceChannelUser extends CapacityPlusVoiceChannelUser implements ITimeslotFrequencyReceiver
|
||||
{
|
||||
private static final int[] GROUP_ADDRESS = new int[]{40, 41, 42, 43, 44, 45, 46, 47};
|
||||
private static final int[] CAPACITY_PLUS_GROUP_ADDRESS = new int[]{40, 41, 42, 43, 44, 45, 46, 47};
|
||||
private static final int[] CONVENTIONAL_GROUP_ADDRESS = new int[]{24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
|
||||
private static final int[] VOICE_CHANNEL_REPEATER = new int[]{51, 52, 53, 54};
|
||||
private static final int[] VOICE_CHANNEL_TIMESLOT = new int[]{55};
|
||||
private static final int[] SOURCE_ADDRESS = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
|
||||
private static final int[] CAPACITY_PLUS_SOURCE_ADDRESS = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
|
||||
private static final int[] CONVENTIONAL_SOURCE_ADDRESS = new int[]{48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
|
||||
private static final int[] UNKNOWN = new int[]{72, 73, 74, 75, 76, 77, 78, 79};
|
||||
|
||||
private RadioIdentifier mRadio;
|
||||
@@ -69,20 +71,33 @@ public class CapacityPlusGroupVoiceChannelUser extends AbstractVoiceChannelUser
|
||||
sb.append("[CRC-ERROR] ");
|
||||
}
|
||||
|
||||
sb.append("FLC MOTOROLA CAP+ GROUP VOICE CHANNEL USER FM:");
|
||||
sb.append(getRadio());
|
||||
sb.append(" TO:").append(getTalkgroup());
|
||||
sb.append(" ON CHANNEL:");
|
||||
if(hasVoiceChannel())
|
||||
if(isEncrypted())
|
||||
{
|
||||
sb.append(getVoiceChannel());
|
||||
sb.append(" ENCRYPTED");
|
||||
}
|
||||
|
||||
if(isReservedBitSet())
|
||||
{
|
||||
sb.append(" RESERVED-BIT");
|
||||
}
|
||||
|
||||
if(getServiceOptions().isCapacityPlus())
|
||||
{
|
||||
sb.append("FLC MOTOROLA CAP+ GROUP VOICE CHANNEL USER");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("--");
|
||||
sb.append("FLC MOTOROLA CONV/IP SITE GROUP VOICE CHANNEL USER");
|
||||
}
|
||||
sb.append(" FM:").append(getRadio());
|
||||
sb.append(" TO:").append(getTalkgroup());
|
||||
|
||||
if(hasVoiceChannel())
|
||||
{
|
||||
sb.append(" ON CHANNEL:");
|
||||
sb.append(getVoiceChannel());
|
||||
}
|
||||
|
||||
sb.append(" UNK:").append(getUnknown());
|
||||
sb.append(" ").append(getServiceOptions());
|
||||
sb.append(" MSG:").append(getMessage().toHexString());
|
||||
return sb.toString();
|
||||
@@ -119,6 +134,7 @@ public class CapacityPlusGroupVoiceChannelUser extends AbstractVoiceChannelUser
|
||||
|
||||
/**
|
||||
* Rest timeslot
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getVoiceChannelTimeslot()
|
||||
@@ -131,7 +147,7 @@ public class CapacityPlusGroupVoiceChannelUser extends AbstractVoiceChannelUser
|
||||
*/
|
||||
public boolean hasVoiceChannel()
|
||||
{
|
||||
return getVoiceChannelRepeater() != 0;
|
||||
return getServiceOptions().isCapacityPlus() && getVoiceChannelRepeater() != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +157,14 @@ public class CapacityPlusGroupVoiceChannelUser extends AbstractVoiceChannelUser
|
||||
{
|
||||
if(mRadio == null)
|
||||
{
|
||||
mRadio = DMRRadio.createFrom(getMessage().getInt(SOURCE_ADDRESS));
|
||||
if(getServiceOptions().isCapacityPlus())
|
||||
{
|
||||
mRadio = DMRRadio.createFrom(getMessage().getInt(CAPACITY_PLUS_SOURCE_ADDRESS));
|
||||
}
|
||||
else
|
||||
{
|
||||
mRadio = DMRRadio.createFrom(getMessage().getInt(CONVENTIONAL_SOURCE_ADDRESS));
|
||||
}
|
||||
}
|
||||
|
||||
return mRadio;
|
||||
@@ -154,7 +177,14 @@ public class CapacityPlusGroupVoiceChannelUser extends AbstractVoiceChannelUser
|
||||
{
|
||||
if(mTalkgroup == null)
|
||||
{
|
||||
mTalkgroup = DMRTalkgroup.create(getMessage().getInt(GROUP_ADDRESS));
|
||||
if(getServiceOptions().isCapacityPlus())
|
||||
{
|
||||
mTalkgroup = DMRTalkgroup.create(getMessage().getInt(CAPACITY_PLUS_GROUP_ADDRESS));
|
||||
}
|
||||
else
|
||||
{
|
||||
mTalkgroup = DMRTalkgroup.create(getMessage().getInt(CONVENTIONAL_GROUP_ADDRESS));
|
||||
}
|
||||
}
|
||||
|
||||
return mTalkgroup;
|
||||
@@ -189,12 +219,13 @@ public class CapacityPlusGroupVoiceChannelUser extends AbstractVoiceChannelUser
|
||||
|
||||
/**
|
||||
* Applies the LSN to frequency map to the rest channel.
|
||||
*
|
||||
* @param timeslotFrequencies that match the logical timeslots
|
||||
*/
|
||||
@Override
|
||||
public void apply(List<TimeslotFrequency> timeslotFrequencies)
|
||||
{
|
||||
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies)
|
||||
for(TimeslotFrequency timeslotFrequency : timeslotFrequencies)
|
||||
{
|
||||
if(getVoiceChannel().getLogicalSlotNumber() == timeslotFrequency.getNumber())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* 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.lc.full.motorola;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.FullLCMessage;
|
||||
import io.github.dsheirer.module.decode.dmr.message.type.CapacityPlusServiceOptions;
|
||||
|
||||
/**
|
||||
* Any Capacity Plus Voice Channel User link control message that contains vendor-specific service options.
|
||||
*/
|
||||
public abstract class CapacityPlusVoiceChannelUser extends FullLCMessage
|
||||
{
|
||||
private static final int[] SERVICE_OPTIONS = new int[]{16, 17, 18, 19, 20, 21, 22, 23};
|
||||
|
||||
private CapacityPlusServiceOptions mServiceOptions;
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param message for the link control payload
|
||||
*/
|
||||
public CapacityPlusVoiceChannelUser(CorrectedBinaryMessage message, long timestamp, int timeslot)
|
||||
{
|
||||
super(message, timestamp, timeslot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Service options for the call
|
||||
*/
|
||||
public CapacityPlusServiceOptions getServiceOptions()
|
||||
{
|
||||
if(mServiceOptions == null)
|
||||
{
|
||||
mServiceOptions = new CapacityPlusServiceOptions(getMessage().getInt(SERVICE_OPTIONS));
|
||||
}
|
||||
|
||||
return mServiceOptions;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* 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
|
||||
@@ -28,22 +28,20 @@ import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver;
|
||||
import io.github.dsheirer.module.decode.dmr.channel.TimeslotFrequency;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRRadio;
|
||||
import io.github.dsheirer.module.decode.dmr.identifier.DMRTalkgroup;
|
||||
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.AbstractVoiceChannelUser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Motorola Capacity Plus - Wide Area (Multi-Site) Voice Channel User
|
||||
*/
|
||||
public class CapacityPlusWideAreaVoiceChannelUser extends AbstractVoiceChannelUser implements ITimeslotFrequencyReceiver
|
||||
public class CapacityPlusWideAreaVoiceChannelUser extends CapacityPlusVoiceChannelUser implements ITimeslotFrequencyReceiver
|
||||
{
|
||||
private static final int[] UNKNOWN_1 = new int[]{24, 25, 26, 27, 28, 29, 30, 31};
|
||||
private static final int[] GROUP_ADDRESS = new int[]{40, 41, 42, 43, 44, 45, 46, 47};
|
||||
private static final int[] REST_REPEATER = new int[]{51, 52, 53, 54};
|
||||
private static final int[] REST_TIMESLOT = new int[]{55};
|
||||
private static final int[] SOURCE_ADDRESS = new int[]{56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
|
||||
private static final int[] UNKNOWN_2 = new int[]{72, 73, 74, 75, 76, 77, 78, 79};
|
||||
private static final int[] UNKNOWN_3 = new int[]{72, 73, 74, 75, 76, 77, 78, 79};
|
||||
|
||||
private RadioIdentifier mRadio;
|
||||
private TalkgroupIdentifier mTalkgroup;
|
||||
@@ -70,6 +68,16 @@ public class CapacityPlusWideAreaVoiceChannelUser extends AbstractVoiceChannelUs
|
||||
sb.append("[CRC-ERROR] ");
|
||||
}
|
||||
|
||||
if(isEncrypted())
|
||||
{
|
||||
sb.append(" *ENCRYPTED*");
|
||||
}
|
||||
|
||||
if(isReservedBitSet())
|
||||
{
|
||||
sb.append(" *RESERVED-BIT*");
|
||||
}
|
||||
|
||||
sb.append("FLC MOTOROLA CAP+ WIDE-AREA VOICE CHANNEL USER FM:");
|
||||
sb.append(getRadio());
|
||||
sb.append(" TO:").append(getTalkgroup());
|
||||
@@ -102,7 +110,7 @@ public class CapacityPlusWideAreaVoiceChannelUser extends AbstractVoiceChannelUs
|
||||
*/
|
||||
public int getUnknown2()
|
||||
{
|
||||
return getMessage().getInt(UNKNOWN_2);
|
||||
return getMessage().getInt(UNKNOWN_3);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* 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.type;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Motorola Capacity Plus flavor of service options. Motorola uses the 2x reserved bits from the default implementation.
|
||||
*/
|
||||
public class CapacityPlusServiceOptions extends ServiceOptions
|
||||
{
|
||||
/**
|
||||
* Constructs an instance
|
||||
*
|
||||
* @param value of the service options bitmap
|
||||
*/
|
||||
public CapacityPlusServiceOptions(int value)
|
||||
{
|
||||
super(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserved bit 1 is used to signal if the system is IP Site Connect or Conventional (true) or Capacity Plus (false).
|
||||
* @return
|
||||
*/
|
||||
public boolean isCapacityPlus()
|
||||
{
|
||||
return !isReserved1();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the transmission is interruptible.
|
||||
* @return true if interruptible.
|
||||
*/
|
||||
public boolean isInterruptible()
|
||||
{
|
||||
return isReserved2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
List<String> flags = new ArrayList<>();
|
||||
|
||||
if(isEmergency())
|
||||
{
|
||||
flags.add("EMERGENCY");
|
||||
}
|
||||
|
||||
if(isEncrypted())
|
||||
{
|
||||
flags.add("ENCRYPTED");
|
||||
}
|
||||
|
||||
if(isBroadcastService())
|
||||
{
|
||||
flags.add("BROADCAST");
|
||||
}
|
||||
|
||||
if(isOpenVoiceCallMode())
|
||||
{
|
||||
flags.add("OVCM");
|
||||
}
|
||||
|
||||
if(isInterruptible())
|
||||
{
|
||||
flags.add("TXI CALL");
|
||||
}
|
||||
|
||||
if(getPriority() > 0)
|
||||
{
|
||||
flags.add("PRIORITY-" + getPriority());
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SERVICE OPTIONS [");
|
||||
if(!flags.isEmpty())
|
||||
{
|
||||
sb.append(Joiner.on(",").join(flags));
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* 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
|
||||
@@ -20,7 +20,6 @@
|
||||
package io.github.dsheirer.module.decode.dmr.message.type;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -31,6 +30,8 @@ public class ServiceOptions
|
||||
{
|
||||
private static final int EMERGENCY_MASK = 0x80;
|
||||
private static final int ENCRYPTION_MASK = 0x40;
|
||||
private static final int RESERVED_1 = 0x20;
|
||||
private static final int RESERVED_2 = 0x10;
|
||||
private static final int BROADCAST_SERVICE_MASK = 0x8;
|
||||
private static final int OPEN_VOICE_CALL_MODE_MASK = 0x4;
|
||||
private static final int PRIORITY_MASK = 0x3;
|
||||
@@ -77,6 +78,24 @@ public class ServiceOptions
|
||||
return isSet(OPEN_VOICE_CALL_MODE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if Reserved 1 bit is set
|
||||
* @return true if set
|
||||
*/
|
||||
public boolean isReserved1()
|
||||
{
|
||||
return isSet(RESERVED_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if Reserved 2 bit is set
|
||||
* @return true if set
|
||||
*/
|
||||
public boolean isReserved2()
|
||||
{
|
||||
return isSet(RESERVED_2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Priority of the communication
|
||||
* @return priority 0-3, 0 = lowest/routine, 3 = highest
|
||||
@@ -119,6 +138,16 @@ public class ServiceOptions
|
||||
flags.add("OVCM");
|
||||
}
|
||||
|
||||
if(isReserved1())
|
||||
{
|
||||
flags.add("RSVD1");
|
||||
}
|
||||
|
||||
if(isReserved2())
|
||||
{
|
||||
flags.add("RSVD2");
|
||||
}
|
||||
|
||||
if(getPriority() > 0)
|
||||
{
|
||||
flags.add("PRIORITY-" + getPriority());
|
||||
|
||||
Reference in New Issue
Block a user