Merge pull request #1646 from DSheirer/1637-dmr-cap-plus-and-max-trunking

#1637 DMR Cap+/CapMax Channel Frequency Map / Trunking Issue
This commit is contained in:
Denny Sheirer
2023-08-31 07:10:21 -04:00
committed by GitHub
34 changed files with 327 additions and 369 deletions

View File

@@ -23,6 +23,7 @@ import io.github.dsheirer.buffer.INativeBufferProvider;
import io.github.dsheirer.controller.channel.event.ChannelStopProcessingRequest; import io.github.dsheirer.controller.channel.event.ChannelStopProcessingRequest;
import io.github.dsheirer.dsp.filter.design.FilterDesignException; import io.github.dsheirer.dsp.filter.design.FilterDesignException;
import io.github.dsheirer.eventbus.MyEventBus; import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.log.LoggingSuppressor;
import io.github.dsheirer.sample.Broadcaster; import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples; import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
@@ -65,6 +66,7 @@ import org.slf4j.LoggerFactory;
public class PolyphaseChannelManager implements ISourceEventProcessor public class PolyphaseChannelManager implements ISourceEventProcessor
{ {
private static final DecimalFormat FREQUENCY_FORMAT = new DecimalFormat("0.00000"); private static final DecimalFormat FREQUENCY_FORMAT = new DecimalFormat("0.00000");
private static final LoggingSuppressor LOGGING_SUPPRESSOR = new LoggingSuppressor(LoggerFactory.getLogger(PolyphaseChannelManager.class));
private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelManager.class); private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelManager.class);
private static final double MINIMUM_CHANNEL_BANDWIDTH = 25000.0; private static final double MINIMUM_CHANNEL_BANDWIDTH = 25000.0;
private static final double CHANNEL_OVERSAMPLING = 2.0; private static final double CHANNEL_OVERSAMPLING = 2.0;
@@ -203,7 +205,8 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
} }
catch(IllegalArgumentException iae) catch(IllegalArgumentException iae)
{ {
mLog.debug("Couldn't design final output low pass filter for polyphase channel source"); LOGGING_SUPPRESSOR.error(iae.getMessage(), 3, "Couldn't allocate channel. " + iae.getMessage());
channelSource = null;
} }
} }

View File

@@ -85,7 +85,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
private ToggleSwitch mUseCompressedTalkgroupsToggle; private ToggleSwitch mUseCompressedTalkgroupsToggle;
private Spinner<Integer> mTrafficChannelPoolSizeSpinner; private Spinner<Integer> mTrafficChannelPoolSizeSpinner;
private TableView<TimeslotFrequency> mTimeslotFrequencyTable; private TableView<TimeslotFrequency> mTimeslotFrequencyTable;
private IntegerTextField mLogicalSlotNumberField; private IntegerTextField mLogicalChannelNumberField;
private FrequencyField mDownlinkFrequencyField; private FrequencyField mDownlinkFrequencyField;
// private FrequencyField mUplinkFrequencyField; // private FrequencyField mUplinkFrequencyField;
private Button mAddTimeslotFrequencyButton; private Button mAddTimeslotFrequencyButton;
@@ -172,7 +172,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
GridPane.setConstraints(useCompressedTalkgroupsLabel, 7, row); GridPane.setConstraints(useCompressedTalkgroupsLabel, 7, row);
gridPane.getChildren().add(useCompressedTalkgroupsLabel); gridPane.getChildren().add(useCompressedTalkgroupsLabel);
Label timeslotTableLabel = new Label("Logical Slot Number (LSN) to Frequency Map. Required for: Connect Plus and Tier-III systems that don't use absolute frequencies"); Label timeslotTableLabel = new Label("Logical Channel Number (LCN) to Frequency Map. Required for: Connect Plus and Tier-III systems that don't use absolute frequencies. LSN = Logical Slot Number");
GridPane.setHalignment(timeslotTableLabel, HPos.LEFT); GridPane.setHalignment(timeslotTableLabel, HPos.LEFT);
GridPane.setConstraints(timeslotTableLabel, 0, ++row, 6, 1); GridPane.setConstraints(timeslotTableLabel, 0, ++row, 6, 1);
gridPane.getChildren().add(timeslotTableLabel); gridPane.getChildren().add(timeslotTableLabel);
@@ -194,17 +194,13 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
editorBox.setAlignment(Pos.CENTER_LEFT); editorBox.setAlignment(Pos.CENTER_LEFT);
editorBox.setSpacing(5); editorBox.setSpacing(5);
Label lsnLabel = new Label("LSN"); Label lcnLabel = new Label("LCN");
editorBox.getChildren().addAll(lsnLabel,getLogicalSlotNumberField()); editorBox.getChildren().addAll(lcnLabel, getLogicalChannelNumberField());
Label downlinkLabel = new Label("Frequency (MHz)"); Label downlinkLabel = new Label("Frequency (MHz)");
downlinkLabel.setPadding(new Insets(0,0,0,5)); downlinkLabel.setPadding(new Insets(0,0,0,5));
editorBox.getChildren().addAll(downlinkLabel,getDownlinkFrequencyField()); editorBox.getChildren().addAll(downlinkLabel,getDownlinkFrequencyField());
// Label uplinkLabel = new Label("Uplink");
// uplinkLabel.setPadding(new Insets(0,0,0,5));
// editorBox.getChildren().addAll(uplinkLabel,getUplinkFrequencyField());
GridPane.setConstraints(editorBox, 0, row, 4, 1); GridPane.setConstraints(editorBox, 0, row, 4, 1);
gridPane.getChildren().add(editorBox); gridPane.getChildren().add(editorBox);
@@ -287,20 +283,22 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
mTimeslotFrequencyTable = new TableView<>(FXCollections.observableArrayList(TimeslotFrequency.extractor())); mTimeslotFrequencyTable = new TableView<>(FXCollections.observableArrayList(TimeslotFrequency.extractor()));
mTimeslotFrequencyTable.setPrefHeight(100.0); mTimeslotFrequencyTable.setPrefHeight(100.0);
TableColumn<TimeslotFrequency,Number> numberColumn = new TableColumn("LSN"); TableColumn<TimeslotFrequency,Number> numberColumn = new TableColumn("LCN");
numberColumn.setPrefWidth(70); numberColumn.setPrefWidth(75);
numberColumn.setCellValueFactory(cellData -> cellData.getValue().getNumberProperty()); numberColumn.setCellValueFactory(cellData -> cellData.getValue().getNumberProperty());
mTimeslotFrequencyTable.getColumns().addAll(numberColumn); mTimeslotFrequencyTable.getColumns().addAll(numberColumn);
mTimeslotFrequencyTable.getSortOrder().add(numberColumn); mTimeslotFrequencyTable.getSortOrder().add(numberColumn);
TableColumn<TimeslotFrequency,Number> downlinkColumn = new TableColumn("Frequency (MHz)"); TableColumn<TimeslotFrequency,Number> downlinkColumn = new TableColumn("Frequency (MHz)");
downlinkColumn.setCellValueFactory(cellData -> cellData.getValue().getDownlinkMHz()); downlinkColumn.setCellValueFactory(cellData -> cellData.getValue().getDownlinkMHz());
downlinkColumn.setPrefWidth(175); downlinkColumn.setPrefWidth(150);
mTimeslotFrequencyTable.getColumns().addAll(downlinkColumn); mTimeslotFrequencyTable.getColumns().addAll(downlinkColumn);
// TableColumn<TimeslotFrequency,Number> uplinkColumn = new TableColumn("Uplink (MHz)"); TableColumn<TimeslotFrequency,String> lsnColumn = new TableColumn("IDs (TS1/TS2)");
// uplinkColumn.setCellValueFactory(cellData -> cellData.getValue().getUplinkMHz()); lsnColumn.setPrefWidth(225);
// mTimeslotFrequencyTable.getColumns().addAll(uplinkColumn); lsnColumn.setCellValueFactory(new PropertyValueFactory<>("logicalSlotNumbers"));
mTimeslotFrequencyTable.getColumns().addAll(lsnColumn);
mTimeslotFrequencyTable.getSelectionModel().selectedItemProperty() mTimeslotFrequencyTable.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> setTimeslot(newValue)); .addListener((observable, oldValue, newValue) -> setTimeslot(newValue));
@@ -317,20 +315,20 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
//Preserve the current modified flag state since setting values in the editor will change it. //Preserve the current modified flag state since setting values in the editor will change it.
boolean modified = modifiedProperty().get(); boolean modified = modifiedProperty().get();
getLogicalSlotNumberField().setDisable(timeslot == null); getLogicalChannelNumberField().setDisable(timeslot == null);
getDownlinkFrequencyField().setDisable(timeslot == null); getDownlinkFrequencyField().setDisable(timeslot == null);
// getUplinkFrequencyField().setDisable(timeslot == null); // getUplinkFrequencyField().setDisable(timeslot == null);
getDeleteTimeslotFrequencyButton().setDisable(timeslot == null); getDeleteTimeslotFrequencyButton().setDisable(timeslot == null);
if(timeslot != null) if(timeslot != null)
{ {
getLogicalSlotNumberField().set(timeslot.getNumber()); getLogicalChannelNumberField().set(timeslot.getNumber());
getDownlinkFrequencyField().set(timeslot.getDownlinkFrequency()); getDownlinkFrequencyField().set(timeslot.getDownlinkFrequency());
// getUplinkFrequencyField().set(timeslot.getUplinkFrequency()); // getUplinkFrequencyField().set(timeslot.getUplinkFrequency());
} }
else else
{ {
getLogicalSlotNumberField().set(0); getLogicalChannelNumberField().set(0);
getDownlinkFrequencyField().set(0); getDownlinkFrequencyField().set(0);
// getUplinkFrequencyField().set(0); // getUplinkFrequencyField().set(0);
} }
@@ -412,19 +410,19 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
return mDeleteTimeslotFrequencyButton; return mDeleteTimeslotFrequencyButton;
} }
private IntegerTextField getLogicalSlotNumberField() private IntegerTextField getLogicalChannelNumberField()
{ {
if(mLogicalSlotNumberField == null) if(mLogicalChannelNumberField == null)
{ {
mLogicalSlotNumberField = new IntegerTextField(); mLogicalChannelNumberField = new IntegerTextField();
mLogicalSlotNumberField.setDisable(true); mLogicalChannelNumberField.setDisable(true);
mLogicalSlotNumberField.setPrefWidth(65); mLogicalChannelNumberField.setPrefWidth(65);
mLogicalSlotNumberField.textProperty().addListener((observable, oldValue, newValue) -> { mLogicalChannelNumberField.textProperty().addListener((observable, oldValue, newValue) -> {
TimeslotFrequency selected = getTimeslotTable().getSelectionModel().getSelectedItem(); TimeslotFrequency selected = getTimeslotTable().getSelectionModel().getSelectedItem();
if(selected != null) if(selected != null)
{ {
Integer value = mLogicalSlotNumberField.get(); Integer value = mLogicalChannelNumberField.get();
if(value != null) if(value != null)
{ {
@@ -436,7 +434,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
}); });
} }
return mLogicalSlotNumberField; return mLogicalChannelNumberField;
} }
private FrequencyField getDownlinkFrequencyField() private FrequencyField getDownlinkFrequencyField()
@@ -610,8 +608,8 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
getTimeslotTable().setDisable(config == null); getTimeslotTable().setDisable(config == null);
getAddTimeslotFrequencyButton().setDisable(config == null); getAddTimeslotFrequencyButton().setDisable(config == null);
getDeleteTimeslotFrequencyButton().setDisable(true); getDeleteTimeslotFrequencyButton().setDisable(true);
getLogicalSlotNumberField().set(0); getLogicalChannelNumberField().set(0);
getLogicalSlotNumberField().setDisable(true); getLogicalChannelNumberField().setDisable(true);
getDownlinkFrequencyField().set(0); getDownlinkFrequencyField().set(0);
getDownlinkFrequencyField().setDisable(true); getDownlinkFrequencyField().setDisable(true);
// getUplinkFrequencyField().set(0); // getUplinkFrequencyField().set(0);

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer * Copyright (C) 2014-2023 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -41,13 +41,12 @@ import io.github.dsheirer.rrapi.type.Tag;
import io.github.dsheirer.rrapi.type.Talkgroup; import io.github.dsheirer.rrapi.type.Talkgroup;
import io.github.dsheirer.rrapi.type.Type; import io.github.dsheirer.rrapi.type.Type;
import io.github.dsheirer.rrapi.type.Voice; import io.github.dsheirer.rrapi.type.Voice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Utility class for decoding type, flavor and voice for systems and formatting talkgroups according to user preferences. * Utility class for decoding type, flavor and voice for systems and formatting talkgroups according to user preferences.
@@ -374,16 +373,10 @@ public class RadioReferenceDecoder
} }
} }
int lsn = (lcn - 1) * 2 + 1; TimeslotFrequency timeslotFrequency = new TimeslotFrequency();
TimeslotFrequency timeslot1Frequency = new TimeslotFrequency(); timeslotFrequency.setNumber(lcn);
timeslot1Frequency.setNumber(lsn); timeslotFrequency.setDownlinkFrequency((long)(siteFrequency.getFrequency() * 1E6));
timeslot1Frequency.setDownlinkFrequency((long)(siteFrequency.getFrequency() * 1E6)); frequencies.add(timeslotFrequency);
frequencies.add(timeslot1Frequency);
TimeslotFrequency timeslot2Frequency = new TimeslotFrequency();
timeslot2Frequency.setNumber(lsn + 1);
timeslot2Frequency.setDownlinkFrequency((long)(siteFrequency.getFrequency() * 1E6));
frequencies.add(timeslot2Frequency);
} }
return frequencies; return frequencies;

View File

@@ -90,9 +90,9 @@ import io.github.dsheirer.module.decode.ip.mototrbo.xcmp.XCMPPacket;
import io.github.dsheirer.protocol.Protocol; import io.github.dsheirer.protocol.Protocol;
import io.github.dsheirer.source.tuner.channel.rotation.AddChannelRotationActiveStateRequest; import io.github.dsheirer.source.tuner.channel.rotation.AddChannelRotationActiveStateRequest;
import io.github.dsheirer.util.PacketUtil; import io.github.dsheirer.util.PacketUtil;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import org.jdesktop.swingx.mapviewer.GeoPosition; import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -111,7 +111,7 @@ public class DMRDecoderState extends TimeslotDecoderState
private DecodeEvent mCurrentCallEvent; private DecodeEvent mCurrentCallEvent;
private long mCurrentFrequency; private long mCurrentFrequency;
private boolean mIgnoreCRCChecksums; private boolean mIgnoreCRCChecksums;
private Map<Integer,DecodeEvent> mDetectedCallEventsMap = new TreeMap<>(); private Map<DMRChannel,DecodeEvent> mDetectedCallEventsMap = new HashMap<>();
private static final AddChannelRotationActiveStateRequest CAPACITY_PLUS_ACTIVE_STATE_REQUEST = private static final AddChannelRotationActiveStateRequest CAPACITY_PLUS_ACTIVE_STATE_REQUEST =
new AddChannelRotationActiveStateRequest(State.ACTIVE); new AddChannelRotationActiveStateRequest(State.ACTIVE);
@@ -417,7 +417,7 @@ public class DMRDecoderState extends TimeslotDecoderState
else else
{ {
DecodeEvent packetEvent = DMRDecodeEvent.builder(DecodeEventType.DATA_PACKET, packet.getTimestamp()) DecodeEvent packetEvent = DMRDecodeEvent.builder(DecodeEventType.DATA_PACKET, packet.getTimestamp())
.identifiers(getMergedIdentifierCollection(packet.getIdentifiers())) .identifiers(new IdentifierCollection(packet.getIdentifiers()))
.timeslot(getTimeslot()) .timeslot(getTimeslot())
.details(packet.toString()) .details(packet.toString())
.build(); .build();
@@ -429,7 +429,7 @@ public class DMRDecoderState extends TimeslotDecoderState
if (geoPosition != null) { if (geoPosition != null) {
PlottableDecodeEvent plottableDecodeEvent = PlottableDecodeEvent.plottableBuilder(DecodeEventType.GPS, packet.getTimestamp()) PlottableDecodeEvent plottableDecodeEvent = PlottableDecodeEvent.plottableBuilder(DecodeEventType.GPS, packet.getTimestamp())
.channel(getCurrentChannel()) .channel(getCurrentChannel())
.identifiers(getMergedIdentifierCollection(packet.getIdentifiers())) .identifiers(new IdentifierCollection(packet.getIdentifiers()))
.protocol(Protocol.LRRP) .protocol(Protocol.LRRP)
.location(geoPosition) .location(geoPosition)
.build(); .build();
@@ -735,21 +735,22 @@ public class DMRDecoderState extends TimeslotDecoderState
ChannelGrant dataGrant = (ChannelGrant)csbk; ChannelGrant dataGrant = (ChannelGrant)csbk;
DMRChannel channel = dataGrant.getChannel(); DMRChannel channel = dataGrant.getChannel();
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
if(hasTrafficChannelManager()) if(hasTrafficChannelManager())
{ {
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers, csbk.getOpcode(), mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers, csbk.getOpcode(),
csbk.getTimestamp(), csbk.isEncrypted()); csbk.getTimestamp(), csbk.isEncrypted());
} }
else else
{ {
DecodeEvent event = mDetectedCallEventsMap.get(channel.getValue()); DecodeEvent event = mDetectedCallEventsMap.get(channel);
if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers())) if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers()))
{ {
event = getDecodeEvent(csbk, DecodeEventType.DATA_CALL, channel, mergedIdentifiers); event = getDecodeEvent(csbk, DecodeEventType.DATA_CALL, channel,
mDetectedCallEventsMap.put(channel.getValue(), event); new IdentifierCollection(csbk.getIdentifiers()));
mDetectedCallEventsMap.put(channel, event);
} }
else else
{ {
@@ -768,21 +769,22 @@ public class DMRDecoderState extends TimeslotDecoderState
ChannelGrant tgGrant = (ChannelGrant)csbk; ChannelGrant tgGrant = (ChannelGrant)csbk;
DMRChannel channel = tgGrant.getChannel(); DMRChannel channel = tgGrant.getChannel();
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
if(hasTrafficChannelManager()) if(hasTrafficChannelManager())
{ {
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers, mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers,
csbk.getOpcode(), csbk.getTimestamp(), csbk.isEncrypted()); csbk.getOpcode(), csbk.getTimestamp(), csbk.isEncrypted());
} }
else else
{ {
DecodeEvent event = mDetectedCallEventsMap.get(channel.getValue()); DecodeEvent event = mDetectedCallEventsMap.get(channel);
if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers())) if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers()))
{ {
event = getDecodeEvent(csbk, DecodeEventType.CALL_GROUP, channel, mergedIdentifiers); event = getDecodeEvent(csbk, DecodeEventType.CALL_GROUP, channel,
mDetectedCallEventsMap.put(channel.getValue(), event); new IdentifierCollection(csbk.getIdentifiers()));
mDetectedCallEventsMap.put(channel, event);
} }
else else
{ {
@@ -800,21 +802,23 @@ public class DMRDecoderState extends TimeslotDecoderState
{ {
ChannelGrant channelGrant = (ChannelGrant)csbk; ChannelGrant channelGrant = (ChannelGrant)csbk;
DMRChannel channel = channelGrant.getChannel(); DMRChannel channel = channelGrant.getChannel();
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
if(hasTrafficChannelManager()) if(hasTrafficChannelManager())
{ {
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers, mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers,
csbk.getOpcode(), csbk.getTimestamp(), csbk.isEncrypted()); csbk.getOpcode(), csbk.getTimestamp(), csbk.isEncrypted());
} }
else else
{ {
DecodeEvent event = mDetectedCallEventsMap.get(channel.getValue()); DecodeEvent event = mDetectedCallEventsMap.get(channel);
if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers())) if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers()))
{ {
event = getDecodeEvent(csbk, DecodeEventType.CALL_UNIT_TO_UNIT, channel, mergedIdentifiers); event = getDecodeEvent(csbk, DecodeEventType.CALL_UNIT_TO_UNIT, channel,
mDetectedCallEventsMap.put(channel.getValue(), event); new IdentifierCollection(csbk.getIdentifiers()));
mDetectedCallEventsMap.put(channel, event);
} }
else else
{ {
@@ -845,21 +849,22 @@ public class DMRDecoderState extends TimeslotDecoderState
ConnectPlusDataChannelGrant cpdcg = (ConnectPlusDataChannelGrant)csbk; ConnectPlusDataChannelGrant cpdcg = (ConnectPlusDataChannelGrant)csbk;
DMRChannel channel = cpdcg.getChannel(); DMRChannel channel = cpdcg.getChannel();
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
if(hasTrafficChannelManager()) if(hasTrafficChannelManager())
{ {
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers, csbk.getOpcode(), mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers, csbk.getOpcode(),
csbk.getTimestamp(), csbk.isEncrypted()); csbk.getTimestamp(), csbk.isEncrypted());
} }
else else
{ {
DecodeEvent event = mDetectedCallEventsMap.get(channel.getValue()); DecodeEvent event = mDetectedCallEventsMap.get(channel);
if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers())) if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers()))
{ {
event = getDecodeEvent(csbk, DecodeEventType.DATA_CALL, channel, mergedIdentifiers); event = getDecodeEvent(csbk, DecodeEventType.DATA_CALL, channel,
mDetectedCallEventsMap.put(channel.getValue(), event); new IdentifierCollection(csbk.getIdentifiers()));
mDetectedCallEventsMap.put(channel, event);
} }
else else
{ {
@@ -875,7 +880,7 @@ public class DMRDecoderState extends TimeslotDecoderState
case MOTOROLA_CONPLUS_REGISTRATION_REQUEST: case MOTOROLA_CONPLUS_REGISTRATION_REQUEST:
DecodeEvent event = DMRDecodeEvent.builder(DecodeEventType.REQUEST, csbk.getTimestamp()) DecodeEvent event = DMRDecodeEvent.builder(DecodeEventType.REQUEST, csbk.getTimestamp())
.details("Registration Request") .details("Registration Request")
.identifiers(getMergedIdentifierCollection(csbk.getIdentifiers())) .identifiers(new IdentifierCollection(csbk.getIdentifiers()))
.timeslot(getTimeslot()) .timeslot(getTimeslot())
.build(); .build();
broadcast(event); broadcast(event);
@@ -884,7 +889,7 @@ public class DMRDecoderState extends TimeslotDecoderState
case MOTOROLA_CONPLUS_REGISTRATION_RESPONSE: case MOTOROLA_CONPLUS_REGISTRATION_RESPONSE:
DecodeEvent regRespEvent = DMRDecodeEvent.builder(DecodeEventType.RESPONSE, csbk.getTimestamp()) DecodeEvent regRespEvent = DMRDecodeEvent.builder(DecodeEventType.RESPONSE, csbk.getTimestamp())
.details("Registration Response") .details("Registration Response")
.identifiers(getMergedIdentifierCollection(csbk.getIdentifiers())) .identifiers(new IdentifierCollection(csbk.getIdentifiers()))
.timeslot(getTimeslot()) .timeslot(getTimeslot())
.build(); .build();
broadcast(regRespEvent); broadcast(regRespEvent);
@@ -896,21 +901,22 @@ public class DMRDecoderState extends TimeslotDecoderState
ConnectPlusVoiceChannelUser cpvcu = (ConnectPlusVoiceChannelUser)csbk; ConnectPlusVoiceChannelUser cpvcu = (ConnectPlusVoiceChannelUser)csbk;
DMRChannel channel = cpvcu.getChannel(); DMRChannel channel = cpvcu.getChannel();
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
if(hasTrafficChannelManager()) if(hasTrafficChannelManager())
{ {
IdentifierCollection mergedIdentifiers = getMergedIdentifierCollection(csbk.getIdentifiers());
mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers, csbk.getOpcode(), mTrafficChannelManager.processChannelGrant(channel, mergedIdentifiers, csbk.getOpcode(),
csbk.getTimestamp(), csbk.isEncrypted()); csbk.getTimestamp(), csbk.isEncrypted());
} }
else else
{ {
DecodeEvent detectedEvent = mDetectedCallEventsMap.get(channel.getValue()); DecodeEvent detectedEvent = mDetectedCallEventsMap.get(channel);
if(isStale(detectedEvent, csbk.getTimestamp(), csbk.getIdentifiers())) if(isStale(detectedEvent, csbk.getTimestamp(), csbk.getIdentifiers()))
{ {
detectedEvent = getDecodeEvent(csbk, DecodeEventType.CALL_GROUP, channel, mergedIdentifiers); detectedEvent = getDecodeEvent(csbk, DecodeEventType.CALL_GROUP, channel,
mDetectedCallEventsMap.put(channel.getValue(), detectedEvent); new IdentifierCollection(csbk.getIdentifiers()));
mDetectedCallEventsMap.put(channel, detectedEvent);
} }
else else
{ {
@@ -926,7 +932,7 @@ public class DMRDecoderState extends TimeslotDecoderState
case MOTOROLA_CONPLUS_TALKGROUP_AFFILIATION: case MOTOROLA_CONPLUS_TALKGROUP_AFFILIATION:
DecodeEvent affiliateEvent = DMRDecodeEvent.builder(DecodeEventType.AFFILIATE, csbk.getTimestamp()) DecodeEvent affiliateEvent = DMRDecodeEvent.builder(DecodeEventType.AFFILIATE, csbk.getTimestamp())
.details("TALKGROUP AFFILIATION") .details("TALKGROUP AFFILIATION")
.identifiers(getMergedIdentifierCollection(csbk.getIdentifiers())) .identifiers(new IdentifierCollection(csbk.getIdentifiers()))
.timeslot(getTimeslot()) .timeslot(getTimeslot())
.build(); .build();
broadcast(affiliateEvent); broadcast(affiliateEvent);
@@ -939,18 +945,18 @@ public class DMRDecoderState extends TimeslotDecoderState
} }
private DecodeEvent getDecodeEvent(CSBKMessage csbk, DecodeEventType decodeEventType, DMRChannel channel, private DecodeEvent getDecodeEvent(CSBKMessage csbk, DecodeEventType decodeEventType, DMRChannel channel,
IdentifierCollection mergedIdentifiers) { IdentifierCollection identifierCollection) {
return DMRDecodeEvent.builder(decodeEventType, csbk.getTimestamp()) return DMRDecodeEvent.builder(decodeEventType, csbk.getTimestamp())
.channel(channel) .channel(channel)
.details(csbk.getOpcode().getLabel()) .details(csbk.getOpcode().getLabel())
.identifiers(mergedIdentifiers) .identifiers(identifierCollection)
.timeslot(getTimeslot()) .timeslot(getTimeslot())
.build(); .build();
} }
private DecodeEvent getDecodeEvent(CSBKMessage csbk, DecodeEventType decodeEventType, String details) { private DecodeEvent getDecodeEvent(CSBKMessage csbk, DecodeEventType decodeEventType, String details) {
return DMRDecodeEvent.builder(decodeEventType, csbk.getTimestamp()) return DMRDecodeEvent.builder(decodeEventType, csbk.getTimestamp())
.identifiers(getMergedIdentifierCollection(csbk.getIdentifiers())) .identifiers(new IdentifierCollection(csbk.getIdentifiers()))
.timeslot(getTimeslot()) .timeslot(getTimeslot())
.details(details) .details(details)
.build(); .build();

View File

@@ -127,19 +127,19 @@ public class DMRMessageProcessor implements Listener<IMessage>
} }
} }
//Enrich messages that carry DMR Logical Slot Number channels with LCN to frequency mappings //Enrich messages that carry DMR Logical Channel Numbers with LCN to frequency mappings
if(message instanceof ITimeslotFrequencyReceiver) if(message instanceof ITimeslotFrequencyReceiver)
{ {
ITimeslotFrequencyReceiver receiver = (ITimeslotFrequencyReceiver)message; ITimeslotFrequencyReceiver receiver = (ITimeslotFrequencyReceiver)message;
int[] lsns = receiver.getLogicalSlotNumbers(); int[] lcns = receiver.getLogicalChannelNumbers();
List<TimeslotFrequency> timeslotFrequencies = new ArrayList<>(); List<TimeslotFrequency> timeslotFrequencies = new ArrayList<>();
for(int lsn: lsns) for(int lcn: lcns)
{ {
if(mTimeslotFrequencyMap.containsKey(lsn)) if(mTimeslotFrequencyMap.containsKey(lcn))
{ {
timeslotFrequencies.add(mTimeslotFrequencyMap.get(lsn)); timeslotFrequencies.add(mTimeslotFrequencyMap.get(lcn));
} }
} }

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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/>
* * *****************************************************************************
* *
* 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; package io.github.dsheirer.module.decode.dmr;
@@ -41,14 +38,13 @@ import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.ConnectPlusCo
import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.ConnectPlusTrafficChannel; import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.ConnectPlusTrafficChannel;
import io.github.dsheirer.module.decode.dmr.message.type.Model; import io.github.dsheirer.module.decode.dmr.message.type.Model;
import io.github.dsheirer.module.decode.dmr.message.type.SystemIdentityCode; import io.github.dsheirer.module.decode.dmr.message.type.SystemIdentityCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Tracks the network configuration details of a DMR network from the broadcast messages * Tracks the network configuration details of a DMR network from the broadcast messages
@@ -250,7 +246,7 @@ public class DMRNetworkConfigurationMonitor
ConnectPlusNeighborReport cpnr = (ConnectPlusNeighborReport)csbk; ConnectPlusNeighborReport cpnr = (ConnectPlusNeighborReport)csbk;
mNeighborSites.addAll(cpnr.getNeighbors()); mNeighborSites.addAll(cpnr.getNeighbors());
} }
if(mBrand == null) if(mBrand == null || mBrand != BRAND_MOTOROLA_CONNECT_PLUS)
{ {
mBrand = BRAND_MOTOROLA_CONNECT_PLUS; mBrand = BRAND_MOTOROLA_CONNECT_PLUS;
} }

View File

@@ -98,7 +98,7 @@ public class DMRTrafficChannelManager extends TrafficChannelManager implements I
private List<Channel> mManagedTrafficChannels; private List<Channel> mManagedTrafficChannels;
private Map<Long,Channel> mAllocatedTrafficChannelFrequencyMap = new ConcurrentHashMap<>(); private Map<Long,Channel> mAllocatedTrafficChannelFrequencyMap = new ConcurrentHashMap<>();
private Map<Integer,DMRChannelGrantEvent> mLSNGrantEventMap = new ConcurrentHashMap<>(); private Map<DMRChannel,DMRChannelGrantEvent> mChannelGrantEventMap = new ConcurrentHashMap<>();
private Listener<ChannelEvent> mChannelEventListener; private Listener<ChannelEvent> mChannelEventListener;
private Listener<IDecodeEvent> mDecodeEventListener; private Listener<IDecodeEvent> mDecodeEventListener;
@@ -322,9 +322,7 @@ public class DMRTrafficChannelManager extends TrafficChannelManager implements I
public void processChannelGrant(DMRChannel channel, IdentifierCollection identifierCollection, public void processChannelGrant(DMRChannel channel, IdentifierCollection identifierCollection,
Opcode opcode, long timestamp, boolean encrypted) Opcode opcode, long timestamp, boolean encrypted)
{ {
int lsn = channel.getValue(); DMRChannelGrantEvent event = mChannelGrantEventMap.get(channel);
DMRChannelGrantEvent event = mLSNGrantEventMap.get(lsn);
DecodeEventType decodeEventType = getEventType(opcode, identifierCollection, encrypted); DecodeEventType decodeEventType = getEventType(opcode, identifierCollection, encrypted);
if(isStale(event, timestamp, identifierCollection)) //Create new event if(isStale(event, timestamp, identifierCollection)) //Create new event
@@ -335,7 +333,7 @@ public class DMRTrafficChannelManager extends TrafficChannelManager implements I
.identifiers(identifierCollection) .identifiers(identifierCollection)
.build(); .build();
mLSNGrantEventMap.put(lsn, event); mChannelGrantEventMap.put(channel, event);
} }
else //Update current event else //Update current event
@@ -355,7 +353,7 @@ public class DMRTrafficChannelManager extends TrafficChannelManager implements I
.identifiers(identifierCollection) .identifiers(identifierCollection)
.build(); .build();
mLSNGrantEventMap.put(lsn, event); mChannelGrantEventMap.put(channel, event);
broadcast(event); broadcast(event);
} }
} }
@@ -643,37 +641,37 @@ public class DMRTrafficChannelManager extends TrafficChannelManager implements I
*/ */
private void removeCallEvents(long frequency) private void removeCallEvents(long frequency)
{ {
List<Integer> lsnsToRemove = new ArrayList<>(); List<DMRChannel> channelsToRemove = new ArrayList<>();
for(Map.Entry<Integer,DMRChannelGrantEvent> entry: mLSNGrantEventMap.entrySet()) for(Map.Entry<DMRChannel,DMRChannelGrantEvent> entry: mChannelGrantEventMap.entrySet())
{ {
if(entry.getValue().getChannelDescriptor().getDownlinkFrequency() == frequency) if(entry.getKey().getDownlinkFrequency() == frequency)
{ {
lsnsToRemove.add(entry.getKey()); channelsToRemove.add(entry.getKey());
} }
} }
for(Integer lsn: lsnsToRemove) for(DMRChannel channel: channelsToRemove)
{ {
mLSNGrantEventMap.remove(lsn); mChannelGrantEventMap.remove(channel);
} }
} }
private void updateCallEventDetails(long frequency, String detailFragment) private void updateCallEventDetails(long frequency, String detailFragment)
{ {
List<Integer> lsnsToUpdate = new ArrayList<>(); List<DMRChannel> channelsToUpdate = new ArrayList<>();
for(Map.Entry<Integer,DMRChannelGrantEvent> entry: mLSNGrantEventMap.entrySet()) for(Map.Entry<DMRChannel,DMRChannelGrantEvent> entry: mChannelGrantEventMap.entrySet())
{ {
if(entry.getValue().getChannelDescriptor().getDownlinkFrequency() == frequency) if(entry.getValue().getChannelDescriptor().getDownlinkFrequency() == frequency)
{ {
lsnsToUpdate.add(entry.getKey()); channelsToUpdate.add(entry.getKey());
} }
} }
for(Integer lsn: lsnsToUpdate) for(DMRChannel channel: channelsToUpdate)
{ {
DMRChannelGrantEvent event = mLSNGrantEventMap.get(lsn); DMRChannelGrantEvent event = mChannelGrantEventMap.get(channel);
if(event != null) if(event != null)
{ {

View File

@@ -26,6 +26,8 @@ import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.identifier.integer.IntegerIdentifier; import io.github.dsheirer.identifier.integer.IntegerIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
import io.github.dsheirer.protocol.Protocol; import io.github.dsheirer.protocol.Protocol;
import java.util.List;
import java.util.Objects;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
/** /**
@@ -33,8 +35,9 @@ import org.apache.commons.lang3.Validate;
* *
* Note: timeslots are tracked as 1 and 2 * Note: timeslots are tracked as 1 and 2
*/ */
public abstract class DMRChannel extends IntegerIdentifier implements IChannelDescriptor public abstract class DMRChannel extends IntegerIdentifier implements IChannelDescriptor, ITimeslotFrequencyReceiver
{ {
private TimeslotFrequency mTimeslotFrequency;
private int mTimeslot; private int mTimeslot;
/** /**
@@ -56,13 +59,23 @@ public abstract class DMRChannel extends IntegerIdentifier implements IChannelDe
} }
/** /**
* Repeater number or channel number for the channel. * Repeater number aka Logical Channel Number (LCN) for the channel.
*/ */
public int getChannel() public int getChannelNumber()
{ {
return getValue(); return getValue();
} }
/**
* Convenience method to format the single channel number as an array for TimeslotFrequency matching.
* @return channel number as an integer array.
*/
public int[] getLogicalChannelNumbers()
{
return new int[]{getChannelNumber()};
}
/** /**
* Timeslot for the channel. * Timeslot for the channel.
* @return timeslot as zero-based index with values in range: 0 or 1. * @return timeslot as zero-based index with values in range: 0 or 1.
@@ -95,7 +108,7 @@ public abstract class DMRChannel extends IntegerIdentifier implements IChannelDe
@Override @Override
public String toString() public String toString()
{ {
return "CHAN:" + getChannel() + ":" + getTimeslot(); return "CHAN:" + getChannelNumber() + ":" + getTimeslot();
} }
/** /**
@@ -115,4 +128,72 @@ public abstract class DMRChannel extends IntegerIdentifier implements IChannelDe
{ {
throw new IllegalArgumentException("This method is not supported"); throw new IllegalArgumentException("This method is not supported");
} }
@Override
public long getDownlinkFrequency()
{
if(mTimeslotFrequency != null)
{
return mTimeslotFrequency.getDownlinkFrequency();
}
return 0;
}
@Override
public long getUplinkFrequency()
{
if(mTimeslotFrequency != null)
{
return mTimeslotFrequency.getUplinkFrequency();
}
return 0;
}
/**
* Sets the lsn to frequency mapper value.
* @param timeslotFrequency to set
*/
public void setTimeslotFrequency(TimeslotFrequency timeslotFrequency)
{
mTimeslotFrequency = timeslotFrequency;
}
@Override
public void apply(List<TimeslotFrequency> timeslotFrequencies)
{
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies)
{
if(timeslotFrequency.getChannelNumber() == getChannelNumber())
{
setTimeslotFrequency(timeslotFrequency);
return;
}
}
}
@Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(!(o instanceof DMRChannel that))
{
return false;
}
if(!super.equals(o))
{
return false;
}
return getTimeslot() == that.getTimeslot();
}
@Override
public int hashCode()
{
return Objects.hash(super.hashCode(), getTimeslot());
}
} }

View File

@@ -19,8 +19,6 @@
package io.github.dsheirer.module.decode.dmr.channel; package io.github.dsheirer.module.decode.dmr.channel;
import java.util.List;
/** /**
* DMR Logical Slot Number (LSN) channel. * DMR Logical Slot Number (LSN) channel.
* *
@@ -44,10 +42,8 @@ import java.util.List;
* 15: 8/1 * 15: 8/1
* 16: 8/2 * 16: 8/2
*/ */
public class DMRLsn extends DMRChannel implements ITimeslotFrequencyReceiver public class DMRLsn extends DMRChannel
{ {
private TimeslotFrequency mTimeslotFrequency;
/** /**
* Constructs an instance * Constructs an instance
* *
@@ -61,7 +57,7 @@ public class DMRLsn extends DMRChannel implements ITimeslotFrequencyReceiver
@Override @Override
public String toString() public String toString()
{ {
return "LSN:" + getLsn(); return "LSN:" + getLsn() + " LCN:" + getChannelNumber();
} }
/** /**
@@ -70,65 +66,7 @@ public class DMRLsn extends DMRChannel implements ITimeslotFrequencyReceiver
*/ */
public int getLsn() public int getLsn()
{ {
return ((getChannel() - 1) * 2) + getTimeslot(); return ((getChannelNumber() - 1) * 2) + getTimeslot();
} }
@Override
public long getDownlinkFrequency()
{
if(mTimeslotFrequency != null)
{
return mTimeslotFrequency.getDownlinkFrequency();
}
return 0;
}
@Override
public long getUplinkFrequency()
{
if(mTimeslotFrequency != null)
{
return mTimeslotFrequency.getUplinkFrequency();
}
return 0;
}
@Override
public int[] getLogicalSlotNumbers()
{
return new int[]{getLsn()};
}
/**
* Sets the lsn to frequency mapper value.
* @param timeslotFrequency to set
*/
public void setTimeslotFrequency(TimeslotFrequency timeslotFrequency)
{
mTimeslotFrequency = timeslotFrequency;
}
@Override
public void apply(List<TimeslotFrequency> timeslotFrequencies)
{
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies)
{
if(timeslotFrequency.getNumber() == getLsn())
{
setTimeslotFrequency(timeslotFrequency);
return;
}
}
}
public static void main(String[] args)
{
for(int x = 1; x <= 16; x++)
{
DMRLsn lsn = new DmrRestLsn(x);
System.out.println(lsn);
}
}
} }

View File

@@ -24,14 +24,12 @@ package io.github.dsheirer.module.decode.dmr.channel;
*/ */
public class DMRTier3Channel extends DMRChannel public class DMRTier3Channel extends DMRChannel
{ {
private TimeslotFrequency mTimeslotFrequency;
/** /**
* Constructs an instance. Note: radio reference uses a one based index, so we add a value of one to the * Constructs an instance. Note: radio reference uses a one based index, so we add a value of one to the
* calculated logical slot value for visual compatibility for users. * calculated logical slot value for visual compatibility for users.
* *
* @param channel number or repeater number * @param channel number or repeater number
* @param logicalSlotNumber - zero based index. * @param timeslot either 1 or 2.
*/ */
public DMRTier3Channel(int channel, int timeslot) public DMRTier3Channel(int channel, int timeslot)
{ {
@@ -39,42 +37,12 @@ public class DMRTier3Channel extends DMRChannel
} }
/** /**
* Downlink frequency * Tier III Channel ID
* @return value in Hertz, or 0 if this channel doesn't have a timeslot frequency mapping * @return channel ID
*/ */
@Override public int getChannelId()
public long getDownlinkFrequency()
{ {
if(mTimeslotFrequency != null) return getChannelNumber() * 2 + getTimeslot();
{
return mTimeslotFrequency.getDownlinkFrequency();
}
return 0;
}
/**
* Uplink frequency
* @return value in Hertz, or 0 if this channel doesn't have a timeslot frequency mapping
*/
@Override
public long getUplinkFrequency()
{
if(mTimeslotFrequency != null)
{
return mTimeslotFrequency.getUplinkFrequency();
}
return 0;
}
/**
* Sets the timeslot frequency mapping
* @param timeslotFrequency
*/
public void setTimeslotFrequency(TimeslotFrequency timeslotFrequency)
{
mTimeslotFrequency = timeslotFrequency;
} }
/** /**
@@ -83,7 +51,8 @@ public class DMRTier3Channel extends DMRChannel
public String toString() public String toString()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(" LCN:").append(getValue()); sb.append(" LCN:").append(getChannelNumber());
sb.append(" CHANID:").append(getChannelId());
return sb.toString(); return sb.toString();
} }
} }

View File

@@ -24,9 +24,9 @@ import java.util.List;
public interface ITimeslotFrequencyReceiver public interface ITimeslotFrequencyReceiver
{ {
/** /**
* Provides the logical slot number(s) that require a matching timeslot frequency mapping * Provides the logical channel number(s) that require a matching timeslot frequency mapping
*/ */
public int[] getLogicalSlotNumbers(); public int[] getLogicalChannelNumbers();
/** /**
* Applies the list of timeslot frequency mappings to the implementer * Applies the list of timeslot frequency mappings to the implementer

View File

@@ -31,7 +31,7 @@ import javafx.beans.property.SimpleLongProperty;
import javafx.util.Callback; import javafx.util.Callback;
/** /**
* Maps a logical slot number (LSN) to a pair of channel frequency values * Maps a logical channel number (LCN) to a pair of channel frequency values
*/ */
public class TimeslotFrequency public class TimeslotFrequency
{ {
@@ -100,7 +100,10 @@ public class TimeslotFrequency
} }
/** /**
* Logical slot number (LSN) as a 1-index based counter * Logical channel number (LCN) as a 1-index based counter
*
* Note: lsn (logical slot number) is a legacy name for this field. The field currently holds the LCN or logical
* channel number. To avoid breaking serialization, we leave this field labeled as lsn.
*/ */
@JacksonXmlProperty(isAttribute = true, localName = "lsn") @JacksonXmlProperty(isAttribute = true, localName = "lsn")
public int getNumber() public int getNumber()
@@ -109,12 +112,52 @@ public class TimeslotFrequency
} }
/** /**
* Sets the logical slot number (LSN) as a 1-index start * Logical channel number which is the same value as getNumber.
* @param lsn where LSN 1 is the first slot, 2 the second, etc * @return
*/ */
public void setNumber(int lsn) @JsonIgnore
public int getChannelNumber()
{ {
mNumberProperty.set(lsn); return getNumber();
}
@JsonIgnore
public String getLogicalSlotNumbers()
{
StringBuilder sb = new StringBuilder();
int channel = getChannelNumber();
if(channel > 0)
{
if(channel < 32) //Connect Plus uses 5-bits for LSN for a maximum value of 31
{
//Cap+ & Con+ Logical Slot Numbers
int lsn1 = (channel - 1) * 2 + 1;
int lsn2 = (channel - 1) * 2 + 2;
sb.append("LSN:").append(lsn1).append("/").append(lsn2).append(" or ");
}
//Tier III channel IDs
int chanId1 = channel * 2 + 1;
int chanId2 = channel * 2 + 2;
sb.append("Tier3 Chan:").append(chanId1).append("/").append(chanId2);
}
else
{
sb.append("(empty)");
}
return sb.toString();
}
/**
* Sets the logical channel number (LCN) as a 1-index start
* @param lcn where LCN 1 is logical slot numbers (LSN) 1 and 2, LCN2=LSN3/4, etc.
*/
public void setNumber(int lcn)
{
mNumberProperty.set(lcn);
} }
/** /**
@@ -160,7 +203,7 @@ public class TimeslotFrequency
@Override @Override
public String toString() public String toString()
{ {
return "TIMESLOT LSN:" + getNumber() + " DOWNLINK:" + getDownlinkFrequency(); return "LCN:" + getNumber() + " DOWNLINK:" + getDownlinkFrequency();
} }
/** /**

View File

@@ -299,9 +299,9 @@ public class CapacityPlusNeighbors extends CSBKMessage implements ITimeslotFrequ
} }
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
return getRestChannel().getLogicalSlotNumbers(); return getRestChannel().getLogicalChannelNumbers();
} }
/** /**
@@ -312,13 +312,7 @@ public class CapacityPlusNeighbors extends CSBKMessage implements ITimeslotFrequ
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
for(TimeslotFrequency timeslotFrequency : timeslotFrequencies) getRestChannel().apply(timeslotFrequencies);
{
if(timeslotFrequency.getNumber() == getRestChannel().getValue())
{
getRestChannel().setTimeslotFrequency(timeslotFrequency);
}
}
} }
@Override @Override

View File

@@ -299,9 +299,9 @@ public class CapacityPlusSiteStatus extends CSBKMessage implements ITimeslotFreq
* Logical slot numbers that require slot to frequency mappings. * Logical slot numbers that require slot to frequency mappings.
*/ */
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
return getRestChannel().getLogicalSlotNumbers(); return getRestChannel().getLogicalChannelNumbers();
} }
/** /**
@@ -312,13 +312,7 @@ public class CapacityPlusSiteStatus extends CSBKMessage implements ITimeslotFreq
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
for(TimeslotFrequency timeslotFrequency : timeslotFrequencies) getRestChannel().apply(timeslotFrequencies);
{
if(getRestChannel().getValue() == timeslotFrequency.getNumber())
{
getRestChannel().setTimeslotFrequency(timeslotFrequency);
}
}
} }
@Override @Override

View File

@@ -40,7 +40,7 @@ public class ConnectPlusDataChannelGrant extends CSBKMessage implements ITimeslo
{ {
private static final int[] TARGET_ADDRESS = new int[]{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, private static final int[] TARGET_ADDRESS = new int[]{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39}; 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] REPEATER = new int[]{40, 41, 42, 43, 44}; private static final int[] LOGICAL_SLOT_NUMBER = new int[]{40, 41, 42, 43, 44};
//Analysis: this field correlates to UNKNOWN_FIELD_1(bits: 40-48) in ConnectPlusTerminateChannelGrant. //Analysis: this field correlates to UNKNOWN_FIELD_1(bits: 40-48) in ConnectPlusTerminateChannelGrant.
private static final int[] UNKNOWN_FIELD = new int[]{48, 49, 50, 51, 52, 53, 54, 55}; private static final int[] UNKNOWN_FIELD = new int[]{48, 49, 50, 51, 52, 53, 54, 55};
@@ -109,11 +109,11 @@ public class ConnectPlusDataChannelGrant extends CSBKMessage implements ITimeslo
} }
/** /**
* Channel grant repeater number * Channel grant logical slot number
*/ */
public int getRepeater() public int getLsn()
{ {
return getMessage().getInt(REPEATER); return getMessage().getInt(LOGICAL_SLOT_NUMBER) - 1; //Don't change this ... always subtract 1 to get the repeater LSN
} }
/** /**
@@ -123,16 +123,16 @@ public class ConnectPlusDataChannelGrant extends CSBKMessage implements ITimeslo
{ {
if(mDmrLsn == null) if(mDmrLsn == null)
{ {
mDmrLsn = new DMRLsn(getRepeater()); mDmrLsn = new DMRLsn(getLsn());
} }
return mDmrLsn; return mDmrLsn;
} }
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
return getChannel().getLogicalSlotNumbers(); return getChannel().getLogicalChannelNumbers();
} }
/** /**
@@ -142,13 +142,7 @@ public class ConnectPlusDataChannelGrant extends CSBKMessage implements ITimeslo
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies) getChannel().apply(timeslotFrequencies);
{
if(timeslotFrequency.getNumber() == getChannel().getValue())
{
getChannel().setTimeslotFrequency(timeslotFrequency);
}
}
} }
@Override @Override

View File

@@ -45,7 +45,7 @@ public class ConnectPlusOTAAnnouncement extends CSBKMessage implements ITimeslot
private static final int[] VERSION = new int[]{24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; private static final int[] VERSION = new int[]{24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] UNKNOWN = new int[]{40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, private static final int[] UNKNOWN = new int[]{40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62}; 57, 58, 59, 60, 61, 62};
private static final int[] DATA_REPEATER = new int[]{63, 64, 65, 66, 67}; private static final int[] LOGICAL_SLOT_NUMBER = new int[]{63, 64, 65, 66, 67};
private DMRLsn mDataChannel; private DMRLsn mDataChannel;
private List<Identifier> mIdentifiers; private List<Identifier> mIdentifiers;
@@ -99,11 +99,11 @@ public class ConnectPlusOTAAnnouncement extends CSBKMessage implements ITimeslot
} }
/** /**
* Data repeater number * Data logical slot numberrepeater number
*/ */
public int getDataRepeater() public int getDataLsn()
{ {
return getMessage().getInt(DATA_REPEATER); return getMessage().getInt(LOGICAL_SLOT_NUMBER) - 1; //Leave this as minus 1
} }
/** /**
@@ -113,16 +113,16 @@ public class ConnectPlusOTAAnnouncement extends CSBKMessage implements ITimeslot
{ {
if(mDataChannel == null) if(mDataChannel == null)
{ {
mDataChannel = new DMRLsn(getDataRepeater()); mDataChannel = new DMRLsn(getDataLsn());
} }
return mDataChannel; return mDataChannel;
} }
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
return getDataChannel().getLogicalSlotNumbers(); return getDataChannel().getLogicalChannelNumbers();
} }
/** /**
@@ -133,13 +133,7 @@ public class ConnectPlusOTAAnnouncement extends CSBKMessage implements ITimeslot
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
for(TimeslotFrequency timeslotFrequency : timeslotFrequencies) getDataChannel().apply(timeslotFrequencies);
{
if(timeslotFrequency.getNumber() == getDataChannel().getValue())
{
getDataChannel().setTimeslotFrequency(timeslotFrequency);
}
}
} }
@Override @Override

View File

@@ -44,7 +44,7 @@ public class ConnectPlusVoiceChannelUser extends CSBKMessage implements ITimeslo
32, 33, 34, 35, 36, 37, 38, 39}; 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] GROUP_ADDRESS = new int[]{40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, private static final int[] GROUP_ADDRESS = new int[]{40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63}; 56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] TRAFFIC_CHANNEL_REPEATER = new int[]{64, 65, 66, 67, 68}; private static final int[] LOGICAL_SLOT_NUMBER = new int[]{64, 65, 66, 67, 68};
private static final int[] UNKNOWN_FIELD = new int[]{72, 73, 74, 75, 76, 77, 78, 79}; private static final int[] UNKNOWN_FIELD = new int[]{72, 73, 74, 75, 76, 77, 78, 79};
private RadioIdentifier mRadio; private RadioIdentifier mRadio;
@@ -126,9 +126,9 @@ public class ConnectPlusVoiceChannelUser extends CSBKMessage implements ITimeslo
/** /**
* Traffic channel repeater * Traffic channel repeater
*/ */
public int getTrafficChannelRepeater() public int getTrafficLsn()
{ {
return getMessage().getInt(TRAFFIC_CHANNEL_REPEATER); return getMessage().getInt(LOGICAL_SLOT_NUMBER) - 1; //Always leave as minus 1
} }
/** /**
@@ -138,16 +138,16 @@ public class ConnectPlusVoiceChannelUser extends CSBKMessage implements ITimeslo
{ {
if(mDmrLsn == null) if(mDmrLsn == null)
{ {
mDmrLsn = new DMRLsn(getTrafficChannelRepeater()); mDmrLsn = new DMRLsn(getTrafficLsn());
} }
return mDmrLsn; return mDmrLsn;
} }
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
return getChannel().getLogicalSlotNumbers(); return getChannel().getLogicalChannelNumbers();
} }
/** /**
@@ -157,13 +157,7 @@ public class ConnectPlusVoiceChannelUser extends CSBKMessage implements ITimeslo
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies) getChannel().apply(timeslotFrequencies);
{
if(timeslotFrequency.getNumber() == getChannel().getValue())
{
getChannel().setTimeslotFrequency(timeslotFrequency);
}
}
} }
@Override @Override

View File

@@ -25,7 +25,6 @@ import io.github.dsheirer.identifier.integer.IntegerIdentifier;
import io.github.dsheirer.identifier.radio.RadioIdentifier; import io.github.dsheirer.identifier.radio.RadioIdentifier;
import io.github.dsheirer.module.decode.dmr.DMRSyncPattern; import io.github.dsheirer.module.decode.dmr.DMRSyncPattern;
import io.github.dsheirer.module.decode.dmr.channel.DMRChannel; import io.github.dsheirer.module.decode.dmr.channel.DMRChannel;
import io.github.dsheirer.module.decode.dmr.channel.DMRLsn;
import io.github.dsheirer.module.decode.dmr.channel.DMRTier3Channel; import io.github.dsheirer.module.decode.dmr.channel.DMRTier3Channel;
import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver; 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.channel.TimeslotFrequency;
@@ -224,11 +223,11 @@ public class Clear extends CSBKMessage implements ITimeslotFrequencyReceiver
* Logical Slot Number(s) for channels contained in this message * Logical Slot Number(s) for channels contained in this message
*/ */
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
if(getMoveToChannel() instanceof DMRLsn dmrLsn) if(getMoveToChannel() != null)
{ {
return dmrLsn.getLogicalSlotNumbers(); return getMoveToChannel().getLogicalChannelNumbers();
} }
return new int[0]; return new int[0];
@@ -241,17 +240,9 @@ public class Clear extends CSBKMessage implements ITimeslotFrequencyReceiver
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
if(getMoveToChannel() instanceof DMRTier3Channel) if(getMoveToChannel() != null)
{ {
DMRTier3Channel channel = (DMRTier3Channel)getMoveToChannel(); getMoveToChannel().apply(timeslotFrequencies);
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies)
{
if(channel.getValue() == timeslotFrequency.getNumber())
{
channel.setTimeslotFrequency(timeslotFrequency);
}
}
} }
} }

View File

@@ -88,7 +88,8 @@ public class MoveTSCC extends CSBKMessage
if(multiBlock != null) if(multiBlock != null)
{ {
mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 0); //Timeslot hard-coded to 1 since this is a control channel.
mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 1);
} }
} }

View File

@@ -84,8 +84,8 @@ public class AdjacentSiteInformation extends Announcement
if(multiBlock != null) if(multiBlock != null)
{ {
//Timeslot hard-coded to zero for control channel //Timeslot hard-coded to one for control channel
mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 0); mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 1);
} }
} }

View File

@@ -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 * 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 * it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@ import io.github.dsheirer.module.decode.dmr.message.data.SlotType;
import io.github.dsheirer.module.decode.dmr.message.data.mbc.MBCContinuationBlock; import io.github.dsheirer.module.decode.dmr.message.data.mbc.MBCContinuationBlock;
import io.github.dsheirer.module.decode.dmr.message.type.AbsoluteChannelParameters; import io.github.dsheirer.module.decode.dmr.message.type.AbsoluteChannelParameters;
import io.github.dsheirer.module.decode.dmr.message.type.DataType; import io.github.dsheirer.module.decode.dmr.message.type.DataType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -56,7 +55,8 @@ public class AnnounceChannelFrequency extends Announcement
if(multiBlock != null) if(multiBlock != null)
{ {
mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 0); //Timeslot hard-coded to one
mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 1);
} }
} }

View File

@@ -86,8 +86,8 @@ public class AnnounceWithdrawTSCC extends Announcement
if(multiBlock != null) if(multiBlock != null)
{ {
//Control channel timeslot hard-coded to 0 //Control channel timeslot hard-coded to 1
mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 0); mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 1);
} }
} }

View File

@@ -23,7 +23,6 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.dmr.DMRSyncPattern; import io.github.dsheirer.module.decode.dmr.DMRSyncPattern;
import io.github.dsheirer.module.decode.dmr.channel.DMRChannel; import io.github.dsheirer.module.decode.dmr.channel.DMRChannel;
import io.github.dsheirer.module.decode.dmr.channel.DMRLsn;
import io.github.dsheirer.module.decode.dmr.channel.DMRTier3Channel; import io.github.dsheirer.module.decode.dmr.channel.DMRTier3Channel;
import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver; 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.channel.TimeslotFrequency;
@@ -90,7 +89,8 @@ public class VoteNowAdvice extends Announcement implements ITimeslotFrequencyRec
if(multiBlock != null) if(multiBlock != null)
{ {
mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 0); //Timeslot hard-coded to one for control channel
mAbsoluteChannelParameters = new AbsoluteChannelParameters(multiBlock.getMessage(), 0, 1);
} }
} }
@@ -239,11 +239,11 @@ public class VoteNowAdvice extends Announcement implements ITimeslotFrequencyRec
* Logical Slot Number(s) for channels contained in this message * Logical Slot Number(s) for channels contained in this message
*/ */
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
if(getChannel() instanceof DMRLsn dmrLsn) if(getChannel() != null)
{ {
return dmrLsn.getLogicalSlotNumbers(); return getChannel().getLogicalChannelNumbers();
} }
return new int[0]; return new int[0];
@@ -256,17 +256,9 @@ public class VoteNowAdvice extends Announcement implements ITimeslotFrequencyRec
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
if(getChannel() instanceof DMRTier3Channel) if(getChannel() != null)
{ {
DMRTier3Channel channel = (DMRTier3Channel)getChannel(); getChannel().apply(timeslotFrequencies);
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies)
{
if(channel.getValue() == timeslotFrequency.getNumber())
{
channel.setTimeslotFrequency(timeslotFrequency);
}
}
} }
} }
} }

View File

@@ -104,7 +104,7 @@ public class BroadcastTalkgroupVoiceChannelGrant extends ChannelGrant
sb.append(" BROADCAST TALKGROUP VOICE CHANNEL GRANT FM:").append(getSourceRadio()); sb.append(" BROADCAST TALKGROUP VOICE CHANNEL GRANT FM:").append(getSourceRadio());
sb.append(" TO:").append(getDestinationTalkgroup()); sb.append(" TO:").append(getDestinationTalkgroup());
sb.append(" CHAN:").append(getChannel()); sb.append(" ").append(getChannel());
return sb.toString(); return sb.toString();
} }

View File

@@ -22,7 +22,6 @@ package io.github.dsheirer.module.decode.dmr.message.data.csbk.standard.grant;
import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.module.decode.dmr.DMRSyncPattern; import io.github.dsheirer.module.decode.dmr.DMRSyncPattern;
import io.github.dsheirer.module.decode.dmr.channel.DMRChannel; import io.github.dsheirer.module.decode.dmr.channel.DMRChannel;
import io.github.dsheirer.module.decode.dmr.channel.DMRLsn;
import io.github.dsheirer.module.decode.dmr.channel.DMRTier3Channel; import io.github.dsheirer.module.decode.dmr.channel.DMRTier3Channel;
import io.github.dsheirer.module.decode.dmr.channel.ITimeslotFrequencyReceiver; 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.channel.TimeslotFrequency;
@@ -158,11 +157,11 @@ public abstract class ChannelGrant extends CSBKMessage implements ITimeslotFrequ
* Logical Slot Number(s) for channels contained in this message * Logical Slot Number(s) for channels contained in this message
*/ */
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
if(getChannel() instanceof DMRLsn dmrLsn) if(getChannel() != null)
{ {
return dmrLsn.getLogicalSlotNumbers(); return getChannel().getLogicalChannelNumbers();
} }
return new int[0]; return new int[0];
@@ -175,17 +174,9 @@ public abstract class ChannelGrant extends CSBKMessage implements ITimeslotFrequ
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
if(getChannel() instanceof DMRTier3Channel) if(getChannel() != null)
{ {
DMRTier3Channel channel = (DMRTier3Channel)getChannel(); getChannel().apply(timeslotFrequencies);
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies)
{
if(channel.getValue() == timeslotFrequency.getNumber())
{
channel.setTimeslotFrequency(timeslotFrequency);
}
}
} }
} }
} }

View File

@@ -103,7 +103,7 @@ public class DuplexPrivateDataChannelGrant extends ChannelGrant
sb.append(" DUPLEX PRIVATE DATA CHANNEL GRANT FM:").append(getSourceRadio()); sb.append(" DUPLEX PRIVATE DATA CHANNEL GRANT FM:").append(getSourceRadio());
sb.append(" TO:").append(getDestinationRadio()); sb.append(" TO:").append(getDestinationRadio());
sb.append(" CHAN:").append(getChannel()); sb.append(" ").append(getChannel());
return sb.toString(); return sb.toString();
} }

View File

@@ -103,7 +103,7 @@ public class DuplexPrivateVoiceChannelGrant extends ChannelGrant
sb.append(" DUPLEX PRIVATE VOICE CHANNEL GRANT FM:").append(getSourceRadio()); sb.append(" DUPLEX PRIVATE VOICE CHANNEL GRANT FM:").append(getSourceRadio());
sb.append(" TO:").append(getDestinationRadio()); sb.append(" TO:").append(getDestinationRadio());
sb.append(" CHAN:").append(getChannel()); sb.append(" ").append(getChannel());
return sb.toString(); return sb.toString();
} }

View File

@@ -108,7 +108,7 @@ public class PrivateDataChannelGrant extends ChannelGrant
sb.append(" PRIVATE DATA CHANNEL GRANT FM:").append(getSourceRadio()); sb.append(" PRIVATE DATA CHANNEL GRANT FM:").append(getSourceRadio());
sb.append(" TO:").append(getDestinationRadio()); sb.append(" TO:").append(getDestinationRadio());
sb.append(" CHAN:").append(getChannel()); sb.append(" ").append(getChannel());
return sb.toString(); return sb.toString();
} }

View File

@@ -102,7 +102,7 @@ public class PrivateVoiceChannelGrant extends ChannelGrant
sb.append(" PRIVATE VOICE CHANNEL GRANT FM:").append(getSourceRadio()); sb.append(" PRIVATE VOICE CHANNEL GRANT FM:").append(getSourceRadio());
sb.append(" TO:").append(getDestinationRadio()); sb.append(" TO:").append(getDestinationRadio());
sb.append(" CHAN:").append(getChannel()); sb.append(" ").append(getChannel());
return sb.toString(); return sb.toString();
} }

View File

@@ -110,7 +110,7 @@ public class TalkgroupDataChannelGrant extends ChannelGrant
sb.append(" TALKGROUP DATA CHANNEL GRANT FM:").append(getSourceRadio()); sb.append(" TALKGROUP DATA CHANNEL GRANT FM:").append(getSourceRadio());
sb.append(" TO:").append(getDestinationTalkgroup()); sb.append(" TO:").append(getDestinationTalkgroup());
sb.append(" CHAN:").append(getChannel()); sb.append(" ").append(getChannel());
return sb.toString(); return sb.toString();
} }

View File

@@ -104,7 +104,7 @@ public class TalkgroupVoiceChannelGrant extends ChannelGrant
sb.append(" TALKGROUP VOICE CHANNEL GRANT FM:").append(getSourceRadio()); sb.append(" TALKGROUP VOICE CHANNEL GRANT FM:").append(getSourceRadio());
sb.append(" TO:").append(getDestinationTalkgroup()); sb.append(" TO:").append(getDestinationTalkgroup());
sb.append(" CHAN:").append(getChannel()); sb.append(" ").append(getChannel());
return sb.toString(); return sb.toString();
} }

View File

@@ -176,9 +176,9 @@ public class CapacityPlusWideAreaVoiceChannelUser extends CapacityPlusVoiceChann
* Exposes the rest channel logical slot number so that a LSN to frequency map can be applied to this message. * Exposes the rest channel logical slot number so that a LSN to frequency map can be applied to this message.
*/ */
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
return getRestChannel().getLogicalSlotNumbers(); return getRestChannel().getLogicalChannelNumbers();
} }
/** /**
@@ -189,12 +189,6 @@ public class CapacityPlusWideAreaVoiceChannelUser extends CapacityPlusVoiceChann
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
for(TimeslotFrequency timeslotFrequency : timeslotFrequencies) getRestChannel().apply(timeslotFrequencies);
{
if(getRestChannel().getValue() == timeslotFrequency.getNumber())
{
getRestChannel().setTimeslotFrequency(timeslotFrequency);
}
}
} }
} }

View File

@@ -105,9 +105,9 @@ public class CapacityPlusRestChannel extends ShortLCMessage implements ITimeslot
* Exposes the rest channel logical slot number so that a LSN to frequency map can be applied to this message. * Exposes the rest channel logical slot number so that a LSN to frequency map can be applied to this message.
*/ */
@Override @Override
public int[] getLogicalSlotNumbers() public int[] getLogicalChannelNumbers()
{ {
return getRestChannel().getLogicalSlotNumbers(); return getRestChannel().getLogicalChannelNumbers();
} }
/** /**
@@ -117,13 +117,7 @@ public class CapacityPlusRestChannel extends ShortLCMessage implements ITimeslot
@Override @Override
public void apply(List<TimeslotFrequency> timeslotFrequencies) public void apply(List<TimeslotFrequency> timeslotFrequencies)
{ {
for(TimeslotFrequency timeslotFrequency: timeslotFrequencies) getRestChannel().apply(timeslotFrequencies);
{
if(getRestChannel().getValue() == timeslotFrequency.getNumber())
{
getRestChannel().setTimeslotFrequency(timeslotFrequency);
}
}
} }
@Override @Override

View File

@@ -221,7 +221,7 @@ public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain
sb.append(","); sb.append(",");
} }
if(identifier.getForm() == Form.TALKGROUP) if(identifier.getForm() == Form.TALKGROUP || identifier.getForm() == Form.RADIO || identifier.getForm() == Form.PATCH_GROUP)
{ {
sb.append(mUserPreferences.getTalkgroupFormatPreference().format(identifier)); sb.append(mUserPreferences.getTalkgroupFormatPreference().format(identifier));
} }