diff --git a/src/module/decode/DecoderFactory.java b/src/module/decode/DecoderFactory.java index 459aad25..df6ac8f7 100644 --- a/src/module/decode/DecoderFactory.java +++ b/src/module/decode/DecoderFactory.java @@ -271,7 +271,8 @@ public class DecoderFactory if( channelType == ChannelType.STANDARD ) { - long timeout = p25Config.getCallTimeout() * 1000; //convert to milliseconds + //Set call timeout to 3 seconds for P25 traffic channels + long timeout = 3000; modules.add( new TrafficChannelManager( resourceManager, decodeConfig, recordConfig, system, site, diff --git a/src/module/decode/p25/DecodeConfigP25Phase1.java b/src/module/decode/p25/DecodeConfigP25Phase1.java index aa19583f..1e92f540 100644 --- a/src/module/decode/p25/DecodeConfigP25Phase1.java +++ b/src/module/decode/p25/DecodeConfigP25Phase1.java @@ -18,6 +18,7 @@ package module.decode.p25; import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlTransient; import module.decode.DecoderType; import module.decode.config.DecodeConfiguration; @@ -27,7 +28,7 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration { private P25_LSMDecoder.Modulation mModulation = Modulation.C4FM; - private int mCallTimeout = DEFAULT_CALL_TIMEOUT_SECONDS; + private int mCallTimeout = 1; private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT; public DecodeConfigP25Phase1() @@ -52,8 +53,13 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration { mModulation = modulation; } - - @XmlAttribute( name="call_timeout" ) + + /** + * Note: this field is now deprecated. + * @return + */ + @XmlTransient + @Deprecated public int getCallTimeout() { return mCallTimeout; @@ -63,16 +69,9 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration * Sets the call timeout value in seconds ( 10 - 600 ); * @param timeout */ + @Deprecated public void setCallTimeout( int timeout ) { - if( CALL_TIMEOUT_MINIMUM <= timeout && timeout <= CALL_TIMEOUT_MAXIMUM ) - { - mCallTimeout = timeout; - } - else - { - mCallTimeout = DEFAULT_CALL_TIMEOUT_SECONDS; - } } diff --git a/src/module/decode/p25/P25CallEvent.java b/src/module/decode/p25/P25CallEvent.java index 3813d46b..b9e24858 100644 --- a/src/module/decode/p25/P25CallEvent.java +++ b/src/module/decode/p25/P25CallEvent.java @@ -75,6 +75,22 @@ public class P25CallEvent extends CallEvent { return mFrequency; } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + + sb.append( "P25 " ); + sb.append( getCallEventType().name() ); + sb.append( " CHAN[" ); + sb.append( getChannel() ); + sb.append( "] TO[" ); + sb.append( getToID() ); + sb.append( "] FROM[" ); + sb.append( getFromID() ); + + return sb.toString(); + } public static class Builder { diff --git a/src/module/decode/p25/P25DecoderState.java b/src/module/decode/p25/P25DecoderState.java index 82b7fd24..215fe76e 100644 --- a/src/module/decode/p25/P25DecoderState.java +++ b/src/module/decode/p25/P25DecoderState.java @@ -31,6 +31,7 @@ import module.decode.DecoderType; import module.decode.event.CallEvent; import module.decode.event.CallEvent.CallEventType; import module.decode.p25.P25Decoder.Modulation; +import module.decode.p25.message.IAdjacentSite; import module.decode.p25.message.IBandIdentifier; import module.decode.p25.message.P25Message; import module.decode.p25.message.hdu.HDUMessage; @@ -67,6 +68,7 @@ import module.decode.p25.message.pdu.osp.voice.UnitToUnitVoiceChannelGrantExtend import module.decode.p25.message.pdu.osp.voice.UnitToUnitVoiceChannelGrantUpdateExtended; import module.decode.p25.message.tdu.TDUMessage; import module.decode.p25.message.tdu.lc.AdjacentSiteStatusBroadcast; +import module.decode.p25.message.tdu.lc.AdjacentSiteStatusBroadcastExplicit; import module.decode.p25.message.tdu.lc.GroupVoiceChannelUpdate; import module.decode.p25.message.tdu.lc.GroupVoiceChannelUpdateExplicit; import module.decode.p25.message.tdu.lc.NetworkStatusBroadcast; @@ -146,16 +148,14 @@ public class P25DecoderState extends DecoderState private RFSSStatusBroadcast mRFSSStatusMessage; private RFSSStatusBroadcastExtended mRFSSStatusMessageExtended; private SNDCPDataChannelAnnouncementExplicit mSNDCPDataChannel; - private HashMap mNeighborMap = - new HashMap(); private Set mSecondaryControlChannels = new TreeSet<>(); - private HashMap mBands = - new HashMap(); + private Map mBands = new HashMap<>(); + private Map mRegistrations = new HashMap<>(); + private Map mNeighborMap = new HashMap<>(); - private HashMap mRegistrations = new HashMap(); private String mLastCommandEventID; private String mLastPageEventID; private String mLastQueryEventID; @@ -291,7 +291,7 @@ public class P25DecoderState extends DecoderState hasEvent = true; } } - else if( event.getFromID() == null ) + else { hasEvent = true; } @@ -390,15 +390,10 @@ public class P25DecoderState extends DecoderState } /** - * Terminator Data Unit, or default message if the CRC failed for a longer - * message. We process these as continuation events. + * Terminator Data Unit */ private void processTDU( TDUMessage tdu ) { -// if( mCurrentCallEvent == null ) -// { -// broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) ); -// } } /** @@ -457,10 +452,11 @@ public class P25DecoderState extends DecoderState case ADJACENT_SITE_STATUS_BROADCAST: if( tdulc instanceof AdjacentSiteStatusBroadcast ) { - AdjacentSiteStatusBroadcast assb = - (AdjacentSiteStatusBroadcast)tdulc; + IAdjacentSite ias = (IAdjacentSite)tdulc; - updateSystem( assb.getSystemID() ); + mNeighborMap.put( ias.getUniqueID(), ias ); + + updateSystem( ias.getSystemID() ); } else { @@ -468,7 +464,14 @@ public class P25DecoderState extends DecoderState } break; case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT: - /* This message doesn't provide anything we need for channel state */ + if( tdulc instanceof AdjacentSiteStatusBroadcastExplicit ) + { + IAdjacentSite ias = (IAdjacentSite)tdulc; + + mNeighborMap.put( ias.getUniqueID(), ias ); + + updateSystem( ias.getSystemID() ); + } break; case CALL_ALERT: if( tdulc instanceof module.decode.p25.message.tdu.lc.CallAlert ) @@ -620,7 +623,8 @@ public class P25DecoderState extends DecoderState mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.GROUP_CALL ) .aliasList( getAliasList() ) .channel( mCurrentChannel ) - .details( ( gvcuser.isEncrypted() ? "ENCRYPTED " : "" ) + + .details( "TDULC GROUP VOICE CHANNEL USER" + + ( gvcuser.isEncrypted() ? "ENCRYPTED " : "" ) + ( gvcuser.isEmergency() ? "EMERGENCY " : "") ) .frequency( mCurrentChannelFrequency ) .from( from ) @@ -1006,10 +1010,11 @@ public class P25DecoderState extends DecoderState case ADJACENT_SITE_STATUS_BROADCAST: if( ldu instanceof module.decode.p25.message.ldu.lc.AdjacentSiteStatusBroadcast ) { - module.decode.p25.message.ldu.lc.AdjacentSiteStatusBroadcast assb = - (module.decode.p25.message.ldu.lc.AdjacentSiteStatusBroadcast)ldu; + IAdjacentSite ias = (IAdjacentSite)ldu; - updateSystem( assb.getSystemID() ); + mNeighborMap.put( ias.getUniqueID(), ias ); + + updateSystem( ias.getSystemID() ); } else { @@ -1018,7 +1023,18 @@ public class P25DecoderState extends DecoderState break; case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT: - /* This message doesn't provide anything we need for channel state */ + if( ldu instanceof module.decode.p25.message.ldu.lc.AdjacentSiteStatusBroadcastExplicit ) + { + IAdjacentSite ias = (IAdjacentSite)ldu; + + mNeighborMap.put( ias.getUniqueID(), ias ); + + updateSystem( ias.getSystemID() ); + } + else + { + logAlternateVendorMessage( ldu ); + } break; case CALL_ALERT: if( ldu instanceof module.decode.p25.message.ldu.lc.CallAlert ) @@ -1509,10 +1525,14 @@ public class P25DecoderState extends DecoderState switch( tsbk.getOpcode() ) { case ADJACENT_STATUS_BROADCAST: - AdjacentStatusBroadcast neighborMessage = - (AdjacentStatusBroadcast)tsbk; - - mNeighborMap.put( neighborMessage.getUniqueID(), neighborMessage ); + if( tsbk instanceof AdjacentStatusBroadcast ) + { + IAdjacentSite ias = (IAdjacentSite)tsbk; + + mNeighborMap.put( ias.getUniqueID(), ias ); + + updateSystem( ias.getSystemID() ); + } break; case ACKNOWLEDGE_RESPONSE: processTSBKResponse( tsbk ); @@ -1627,24 +1647,10 @@ public class P25DecoderState extends DecoderState */ private void processPDU( PDUMessage pdu ) { - broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.DATA ) ); - - if( pdu instanceof NetworkStatusBroadcastExtended ) - { - mNetworkStatusExtended = (NetworkStatusBroadcastExtended)pdu; - } - else if( pdu instanceof ProtectionParameterBroadcast ) - { - mProtectionParameterBroadcast = - (ProtectionParameterBroadcast)pdu; - } - else if( pdu instanceof RFSSStatusBroadcastExtended ) - { - mRFSSStatusMessageExtended = (RFSSStatusBroadcastExtended)pdu; - } - if( pdu instanceof PDUConfirmedMessage ) { + broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.DATA ) ); + PDUConfirmedMessage pduc = (PDUConfirmedMessage)pdu; switch( pduc.getPDUType() ) @@ -1747,13 +1753,27 @@ public class P25DecoderState extends DecoderState else { /* These are alternate trunking control blocks in PDU format */ + broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) ); + switch( pdu.getOpcode() ) { + case GROUP_DATA_CHANNEL_GRANT: + case GROUP_VOICE_CHANNEL_GRANT: + case INDIVIDUAL_DATA_CHANNEL_GRANT: + case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT: + case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT: + case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE: + processPDUChannelGrant( pdu ); + break; case ADJACENT_STATUS_BROADCAST: - AdjacentStatusBroadcastExtended asbe = - (AdjacentStatusBroadcastExtended)pdu; - - updateSystem( asbe.getSystemID() ); + if( pdu instanceof AdjacentStatusBroadcastExtended ) + { + IAdjacentSite ias = (IAdjacentSite)pdu; + + mNeighborMap.put( ias.getUniqueID(), ias ); + + updateSystem( ias.getSystemID() ); + } break; case CALL_ALERT: if( pdu instanceof CallAlertExtended ) @@ -1823,77 +1843,6 @@ public class P25DecoderState extends DecoderState logAlternateVendorMessage( pdu ); } break; - case GROUP_DATA_CHANNEL_GRANT: - if( pdu instanceof GroupDataChannelGrantExtended ) - { - GroupDataChannelGrantExtended gdcge = - (GroupDataChannelGrantExtended)pdu; - - CallEvent callEvent = new P25CallEvent.Builder( CallEventType.DATA_CALL ) - .aliasList( getAliasList() ) - .channel( gdcge.getTransmitChannel() ) - .details( ( gdcge.isEncrypted() ? "ENCRYPTED" : "" ) + - ( gdcge.isEmergency() ? " EMERGENCY" : "") ) - .frequency( gdcge.getDownlinkFrequency() ) - .from( gdcge.getSourceAddress() ) - .to( gdcge.getGroupAddress() ) - .build(); - - broadcast( new TrafficChannelAllocationEvent( this, callEvent ) ); - } - else - { - logAlternateVendorMessage( pdu ); - } - break; - case GROUP_VOICE_CHANNEL_GRANT: - if( pdu instanceof GroupVoiceChannelGrantExplicit ) - { - GroupVoiceChannelGrantExplicit gvcge = - (GroupVoiceChannelGrantExplicit)pdu; - - CallEvent callEvent = new P25CallEvent.Builder( CallEventType.CALL ) - .aliasList( getAliasList() ) - .channel( gvcge.getTransmitChannel() ) - .details( ( gvcge.isEncrypted() ? "ENCRYPTED" : "" ) + - ( gvcge.isEmergency() ? " EMERGENCY" : "") ) - .frequency( gvcge.getDownlinkFrequency() ) - .from( gvcge.getSourceAddress() ) - .to( gvcge.getGroupAddress() ) - .build(); - - broadcast( new TrafficChannelAllocationEvent( this, callEvent ) ); - } - else - { - logAlternateVendorMessage( pdu ); - } - break; - case INDIVIDUAL_DATA_CHANNEL_GRANT: - if( pdu instanceof IndividualDataChannelGrantExtended ) - { - IndividualDataChannelGrantExtended idcge = - (IndividualDataChannelGrantExtended)pdu; - - CallEvent callEvent = new P25CallEvent.Builder( CallEventType.DATA_CALL ) - .aliasList( getAliasList() ) - .channel( idcge.getTransmitChannel() ) - .details( ( idcge.isEncrypted() ? "ENCRYPTED" : "" ) + - ( idcge.isEmergency() ? " EMERGENCY" : "") ) - .frequency( idcge.getDownlinkFrequency() ) - .from( idcge.getSourceWACN() + "-" + - idcge.getSourceSystemID() + "-" + - idcge.getSourceAddress() ) - .to( idcge.getTargetAddress() ) - .build(); - - broadcast( new TrafficChannelAllocationEvent( this, callEvent ) ); - } - else - { - logAlternateVendorMessage( pdu ); - } - break; case MESSAGE_UPDATE: if( pdu instanceof MessageUpdateExtended ) { @@ -1912,14 +1861,36 @@ public class P25DecoderState extends DecoderState logAlternateVendorMessage( pdu ); } break; + case NETWORK_STATUS_BROADCAST: + if( pdu instanceof NetworkStatusBroadcastExtended ) + { + mNetworkStatusExtended = (NetworkStatusBroadcastExtended)pdu; + } + else + { + logAlternateVendorMessage( pdu ); + } + break; + case PROTECTION_PARAMETER_BROADCAST: + if( pdu instanceof ProtectionParameterBroadcast ) + { + mProtectionParameterBroadcast = + (ProtectionParameterBroadcast)pdu; + } + else + { + logAlternateVendorMessage( pdu ); + } + break; case RFSS_STATUS_BROADCAST: if( pdu instanceof RFSSStatusBroadcastExtended ) { - RFSSStatusBroadcastExtended rsbe = (RFSSStatusBroadcastExtended)pdu; + mRFSSStatusMessageExtended = (RFSSStatusBroadcastExtended)pdu; - updateNAC( rsbe.getNAC() ); - updateSystem( rsbe.getSystemID() ); - updateSite( rsbe.getRFSubsystemID() + "-" + rsbe.getSiteID() ); + updateNAC( mRFSSStatusMessageExtended.getNAC() ); + updateSystem( mRFSSStatusMessageExtended.getSystemID() ); + updateSite( mRFSSStatusMessageExtended.getRFSubsystemID() + + "-" + mRFSSStatusMessageExtended.getSiteID() ); } else { @@ -2019,22 +1990,6 @@ public class P25DecoderState extends DecoderState logAlternateVendorMessage( pdu ); } break; - case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT: - TelephoneInterconnectChannelGrantExplicit ticge = - (TelephoneInterconnectChannelGrantExplicit)pdu; - - CallEvent callEvent = new P25CallEvent.Builder( CallEventType.TELEPHONE_INTERCONNECT ) - .aliasList( getAliasList() ) - .channel( ticge.getTransmitChannel() ) - .details( ( ticge.isEncrypted() ? "ENCRYPTED" : "" ) + - ( ticge.isEmergency() ? " EMERGENCY" : "") + - " CALL TIMER:" + ticge.getCallTimer() ) - .frequency( ticge.getDownlinkFrequency() ) - .from( ticge.getAddress() ) - .build(); - - broadcast( new TrafficChannelAllocationEvent( this, callEvent ) ); - break; case UNIT_REGISTRATION_RESPONSE: if( pdu instanceof UnitRegistrationResponseExtended ) { @@ -2095,60 +2050,253 @@ public class P25DecoderState extends DecoderState logAlternateVendorMessage( pdu ); } break; - case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT: - if( pdu instanceof UnitToUnitVoiceChannelGrantExtended ) - { - UnitToUnitVoiceChannelGrantExtended uuvcge = - (UnitToUnitVoiceChannelGrantExtended)pdu; - - CallEvent uuCallEvent = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL ) - .aliasList( getAliasList() ) - .channel( uuvcge.getTransmitChannel() ) - .details( ( uuvcge.isEncrypted() ? "ENCRYPTED" : "" ) + - ( uuvcge.isEmergency() ? " EMERGENCY" : "") ) - .frequency( uuvcge.getDownlinkFrequency() ) - .from( uuvcge.getSourceWACN() + "-" + - uuvcge.getSourceSystemID() + "-" + - uuvcge.getSourceID() ) - .to( uuvcge.getTargetAddress() ) - .build(); - - broadcast( new TrafficChannelAllocationEvent( this, uuCallEvent ) ); - } - else - { - logAlternateVendorMessage( pdu ); - } - break; - case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE: - if( pdu instanceof UnitToUnitVoiceChannelGrantUpdateExtended ) - { - UnitToUnitVoiceChannelGrantUpdateExtended uuvcgue = - (UnitToUnitVoiceChannelGrantUpdateExtended)pdu; - - broadcast( new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL ) - .aliasList( getAliasList() ) - .channel( uuvcgue.getTransmitChannel() ) - .details( ( uuvcgue.isEncrypted() ? "ENCRYPTED" : "" ) + - ( uuvcgue.isEmergency() ? " EMERGENCY" : "") ) - .frequency( uuvcgue.getDownlinkFrequency() ) - .from( uuvcgue.getSourceWACN() + "-" + - uuvcgue.getSourceSystemID() + "-" + - uuvcgue.getSourceID() ) - .to( uuvcgue.getTargetAddress() ) - .build() ); - } - else - { - logAlternateVendorMessage( pdu ); - } - break; default: break; } } } + private void processPDUChannelGrant( PDUMessage pdu ) + { + String channel = null; + String from = null; + String to = null; + + switch( pdu.getOpcode() ) + { + case GROUP_DATA_CHANNEL_GRANT: + if( pdu instanceof GroupDataChannelGrantExtended ) + { + GroupDataChannelGrantExtended gdcge = + (GroupDataChannelGrantExtended)pdu; + + channel = gdcge.getTransmitChannel(); + from = gdcge.getSourceAddress(); + to = gdcge.getGroupAddress(); + + if( hasCallEvent( channel, from, to ) ) + { + updateCallEvent( channel, from, to ); + } + else + { + P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.DATA_CALL ) + .aliasList( getAliasList() ) + .channel( channel ) + .details( ( gdcge.isEncrypted() ? "ENCRYPTED" : "" ) + + ( gdcge.isEmergency() ? " EMERGENCY" : "") ) + .frequency( gdcge.getDownlinkFrequency() ) + .from( from ) + .to( to ) + .build(); + + registerCallEvent( callEvent ); + broadcast( callEvent ); + } + } + else + { + logAlternateVendorMessage( pdu ); + } + + /* We don't allocate traffic channels for data */ + break; + case GROUP_VOICE_CHANNEL_GRANT: + if( pdu instanceof GroupVoiceChannelGrantExplicit ) + { + GroupVoiceChannelGrantExplicit gvcge = + (GroupVoiceChannelGrantExplicit)pdu; + + channel = gvcge.getTransmitChannel(); + from = gvcge.getSourceAddress(); + to = gvcge.getGroupAddress(); + + if( hasCallEvent( channel, from, to ) ) + { + updateCallEvent( channel, from, to ); + } + else + { + P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.GROUP_CALL ) + .aliasList( getAliasList() ) + .channel( channel ) + .details( ( gvcge.isEncrypted() ? "ENCRYPTED" : "" ) + + ( gvcge.isEmergency() ? " EMERGENCY" : "") ) + .frequency( gvcge.getDownlinkFrequency() ) + .from( from ) + .to( to ) + .build(); + + registerCallEvent( callEvent ); + broadcast( callEvent ); + } + + broadcast( new TrafficChannelAllocationEvent( this, + mChannelCallMap.get( channel ) ) ); + } + else + { + logAlternateVendorMessage( pdu ); + } + break; + case INDIVIDUAL_DATA_CHANNEL_GRANT: + if( pdu instanceof IndividualDataChannelGrantExtended ) + { + IndividualDataChannelGrantExtended idcge = + (IndividualDataChannelGrantExtended)pdu; + + channel = idcge.getTransmitChannel(); + from = idcge.getSourceWACN() + "-" + + idcge.getSourceSystemID() + "-" + + idcge.getSourceAddress(); + to = idcge.getTargetAddress(); + + if( hasCallEvent( channel, from, to ) ) + { + updateCallEvent( channel, from, to ); + } + else + { + P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.DATA_CALL ) + .aliasList( getAliasList() ) + .channel( channel ) + .details( ( idcge.isEncrypted() ? "ENCRYPTED" : "" ) + + ( idcge.isEmergency() ? " EMERGENCY" : "") ) + .frequency( idcge.getDownlinkFrequency() ) + .from( from ) + .to( to ) + .build(); + + registerCallEvent( callEvent ); + broadcast( callEvent ); + } + + //We don't allocate traffic channels for data + } + else + { + logAlternateVendorMessage( pdu ); + } + break; + case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT: + TelephoneInterconnectChannelGrantExplicit ticge = + (TelephoneInterconnectChannelGrantExplicit)pdu; + + channel = ticge.getTransmitChannel(); + + //We don't know if the subscriber is calling or being called, so + //we use the same address in both from/to fields + from = ticge.getAddress(); + to = ticge.getAddress(); + + if( hasCallEvent( channel, from, to ) ) + { + updateCallEvent( channel, from, to ); + } + else + { + P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.TELEPHONE_INTERCONNECT ) + .aliasList( getAliasList() ) + .channel( channel ) + .details( ( ticge.isEncrypted() ? "ENCRYPTED" : "" ) + + ( ticge.isEmergency() ? " EMERGENCY" : "") + + " CALL TIMER:" + ticge.getCallTimer() ) + .frequency( ticge.getDownlinkFrequency() ) + .from( from ) + .to( to ) + .build(); + + registerCallEvent( callEvent ); + broadcast( callEvent ); + } + + broadcast( new TrafficChannelAllocationEvent( this, + mChannelCallMap.get( channel ) ) ); + break; + case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT: + if( pdu instanceof UnitToUnitVoiceChannelGrantExtended ) + { + UnitToUnitVoiceChannelGrantExtended uuvcge = + (UnitToUnitVoiceChannelGrantExtended)pdu; + + channel = uuvcge.getTransmitChannel(); + from = uuvcge.getSourceWACN() + "-" + + uuvcge.getSourceSystemID() + "-" + + uuvcge.getSourceID(); + to = uuvcge.getTargetAddress(); + + if( hasCallEvent( channel, from, to ) ) + { + updateCallEvent( channel, from, to ); + } + else + { + P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL ) + .aliasList( getAliasList() ) + .channel( channel ) + .details( ( uuvcge.isEncrypted() ? "ENCRYPTED" : "" ) + + ( uuvcge.isEmergency() ? " EMERGENCY" : "") ) + .frequency( uuvcge.getDownlinkFrequency() ) + .from( from ) + .to( to ) + .build(); + + registerCallEvent( callEvent ); + broadcast( callEvent ); + } + + broadcast( new TrafficChannelAllocationEvent( this, + mChannelCallMap.get( channel ) ) ); + } + else + { + logAlternateVendorMessage( pdu ); + } + break; + case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE: + if( pdu instanceof UnitToUnitVoiceChannelGrantUpdateExtended ) + { + UnitToUnitVoiceChannelGrantUpdateExtended uuvcgue = + (UnitToUnitVoiceChannelGrantUpdateExtended)pdu; + + channel = uuvcgue.getTransmitChannel(); + from = uuvcgue.getSourceWACN() + "-" + + uuvcgue.getSourceSystemID() + "-" + + uuvcgue.getSourceID(); + to = uuvcgue.getTargetAddress(); + + if( hasCallEvent( channel, from, to ) ) + { + updateCallEvent( channel, from, to ); + } + else + { + P25CallEvent callEvent = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL ) + .aliasList( getAliasList() ) + .channel( channel ) + .details( ( uuvcgue.isEncrypted() ? "ENCRYPTED" : "" ) + + ( uuvcgue.isEmergency() ? " EMERGENCY" : "") ) + .frequency( uuvcgue.getDownlinkFrequency() ) + .from( from ) + .to( to ) + .build(); + + registerCallEvent( callEvent ); + broadcast( callEvent ); + } + + broadcast( new TrafficChannelAllocationEvent( this, + mChannelCallMap.get( channel ) ) ); + + } + else + { + logAlternateVendorMessage( pdu ); + } + break; + } + } + private void processTSBKCommand( TSBKMessage message ) { switch( message.getOpcode() ) @@ -2573,7 +2721,7 @@ public class P25DecoderState extends DecoderState channel = gdcg.getChannel(); from = gdcg.getSourceAddress(); to = gdcg.getGroupAddress(); - + if( hasCallEvent( channel, from, to ) ) { updateCallEvent( channel, from, to ); @@ -3277,11 +3425,11 @@ public class P25DecoderState extends DecoderState } else { - for( AdjacentStatusBroadcast neighbor: mNeighborMap.values() ) + for( IAdjacentSite neighbor: mNeighborMap.values() ) { - sb.append( "\nNAC:\t" + neighbor.getNAC() ); + sb.append( "\nNAC:\t" + ((P25Message)neighbor).getNAC() ); sb.append( "\nSYSTEM:\t" + neighbor.getSystemID() ); - sb.append( "\nLRA:\t" + neighbor.getLocationRegistrationArea() ); + sb.append( "\nLRA:\t" + neighbor.getLRA() ); String neighborID = neighbor.getRFSS() + "-" + neighbor.getSiteID(); sb.append( "\nRFSS-SITE:\t" + neighborID ); @@ -3298,10 +3446,11 @@ public class P25DecoderState extends DecoderState sb.append( "\nPCCH:\tDNLINK " + mFrequencyFormatter.format( (double)neighbor.getDownlinkFrequency() / 1E6d ) + - " [" + neighbor.getIdentifier() + "-" + neighbor.getChannel() + "]" ); + " [" + neighbor.getDownlinkChannel() + "]" ); sb.append( "\n\tUPLINK:" + mFrequencyFormatter.format( - (double)neighbor.getUplinkFrequency() / 1E6d ) + "\n" ); - sb.append( "\nSERVICES:\t" + Service.getServices( neighbor.getSystemServiceClass() ) ); + (double)neighbor.getUplinkFrequency() / 1E6d ) + + " [" + neighbor.getDownlinkChannel() + "]\n" ); + sb.append( "\nSERVICES:\t" + neighbor.getSystemServiceClass() ); sb.append( "\n----------------------------------------------------" ); } } @@ -3367,6 +3516,8 @@ public class P25DecoderState extends DecoderState { TrafficChannelAllocationEvent allocationEvent = (TrafficChannelAllocationEvent)event; + + mCurrentCallEvent = (P25CallEvent)allocationEvent.getCallEvent(); mCurrentChannel = allocationEvent.getCallEvent().getChannel(); broadcast( ChangedAttribute.CHANNEL_NUMBER ); diff --git a/src/module/decode/p25/P25Editor.java b/src/module/decode/p25/P25Editor.java index 6858109d..e66fbb79 100644 --- a/src/module/decode/p25/P25Editor.java +++ b/src/module/decode/p25/P25Editor.java @@ -43,8 +43,6 @@ public class P25Editor extends DecodeEditor private static final long serialVersionUID = 1L; private JComboBox mComboModulation; - private JLabel mCallTimeoutLabel; - private JSlider mCallTimeout; private JLabel mTrafficChannelPoolSizeLabel; private JSlider mTrafficChannelPoolSize; @@ -67,32 +65,6 @@ public class P25Editor extends DecodeEditor add( new JLabel( "Modulation:" ) ); add( mComboModulation, "wrap" ); - mCallTimeout = new JSlider( JSlider.HORIZONTAL, - DecodeConfiguration.CALL_TIMEOUT_MINIMUM, - DecodeConfiguration.CALL_TIMEOUT_MAXIMUM, - DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS ); - - mCallTimeout.setMajorTickSpacing( 90 ); - mCallTimeout.setMinorTickSpacing( 10 ); - mCallTimeout.setPaintTicks( true ); - - mCallTimeout.setLabelTable( mCallTimeout.createStandardLabels( 100, 100 ) ); - mCallTimeout.setPaintLabels( true ); - - mCallTimeoutLabel = new JLabel( "Call Timeout: " + mCallTimeout.getValue() + " " ); - - mCallTimeout.addChangeListener( new ChangeListener() - { - @Override - public void stateChanged( ChangeEvent e ) - { - mCallTimeoutLabel.setText( "Call Timeout: " + mCallTimeout.getValue() ); - } - } ); - - add( mCallTimeoutLabel ); - add( mCallTimeout, "wrap,grow" ); - mTrafficChannelPoolSize = new JSlider( JSlider.HORIZONTAL, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM, @@ -150,8 +122,6 @@ public class P25Editor extends DecodeEditor config.setModulation( (Modulation)mComboModulation.getSelectedItem() ); - config.setCallTimeout( mCallTimeout.getValue() ); - config.setTrafficChannelPoolSize( mTrafficChannelPoolSize.getValue() ); } @@ -162,8 +132,6 @@ public class P25Editor extends DecodeEditor mComboModulation.setSelectedItem( config.getModulation() ); - mCallTimeout.setValue( config.getCallTimeout() ); - mTrafficChannelPoolSize.setValue( config.getTrafficChannelPoolSize() ); } } diff --git a/src/module/decode/p25/message/IAdjacentSite.java b/src/module/decode/p25/message/IAdjacentSite.java new file mode 100644 index 00000000..ea9e4ef6 --- /dev/null +++ b/src/module/decode/p25/message/IAdjacentSite.java @@ -0,0 +1,20 @@ +package module.decode.p25.message; + +/** + * Interface for adjacent site (ie neighbor) messages + */ +public interface IAdjacentSite +{ + public String getUniqueID(); + public String getRFSS(); + public String getSystemID(); + public String getSiteID(); + public String getLRA(); + public String getSystemServiceClass(); + + public String getDownlinkChannel(); + public long getDownlinkFrequency(); + + public String getUplinkChannel(); + public long getUplinkFrequency(); +} diff --git a/src/module/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcast.java b/src/module/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcast.java index b123ee9d..1f45e760 100644 --- a/src/module/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcast.java +++ b/src/module/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcast.java @@ -1,16 +1,17 @@ package module.decode.p25.message.ldu.lc; +import module.decode.p25.message.IAdjacentSite; import module.decode.p25.message.IBandIdentifier; import module.decode.p25.message.IdentifierReceiver; import module.decode.p25.message.ldu.LDU1Message; +import module.decode.p25.message.tsbk.osp.control.SystemService; import module.decode.p25.reference.LinkControlOpcode; -import module.decode.p25.reference.Service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AdjacentSiteStatusBroadcast extends LDU1Message - implements IdentifierReceiver + implements IdentifierReceiver, IAdjacentSite { private final static Logger mLog = LoggerFactory.getLogger( AdjacentSiteStatusBroadcast.class ); @@ -46,20 +47,33 @@ public class AdjacentSiteStatusBroadcast extends LDU1Message sb.append( getMessageStub() ); - sb.append( " LRA:" + getLocationRegistrationArea() ); + sb.append( " LRA:" + getLRA() ); sb.append( " SYS:" + getSystemID() ); - sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + sb.append( " SITE:" + getRFSS() + "-" + getSiteID() ); sb.append( " CHAN:" + getChannel() ); - sb.append( " " + Service.getServices( getSystemServiceClass() ).toString() ); + sb.append( " " + getSystemServiceClass() ); return sb.toString(); } - public String getLocationRegistrationArea() + public String getUniqueID() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getSystemID() ); + sb.append( ":" ); + sb.append( getRFSS() ); + sb.append( ":" ); + sb.append( getSiteID() ); + + return sb.toString(); + } + + public String getLRA() { return mMessage.getHex( LRA, 2 ); } @@ -69,7 +83,7 @@ public class AdjacentSiteStatusBroadcast extends LDU1Message return mMessage.getHex( SYSTEM_ID, 3 ); } - public String getRFSubsystemID() + public String getRFSS() { return mMessage.getHex( RFSS_ID, 2 ); } @@ -94,9 +108,9 @@ public class AdjacentSiteStatusBroadcast extends LDU1Message return mMessage.getInt( CHANNEL ); } - public int getSystemServiceClass() + public String getSystemServiceClass() { - return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + return SystemService.toString( mMessage.getInt( SYSTEM_SERVICE_CLASS ) ); } @Override @@ -114,13 +128,26 @@ public class AdjacentSiteStatusBroadcast extends LDU1Message return identifiers; } + - public long getDownlinkFrequency() + @Override + public String getDownlinkChannel() + { + return getChannel(); + } + + @Override + public String getUplinkChannel() + { + return getChannel(); + } + + public long getDownlinkFrequency() { return calculateDownlink( mIdentifierUpdate, getChannelNumber() ); } - public long getUplinkFrequencyB() + public long getUplinkFrequency() { return calculateUplink( mIdentifierUpdate, getChannelNumber() ); } diff --git a/src/module/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcastExplicit.java b/src/module/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcastExplicit.java index 16c3e056..5008728f 100644 --- a/src/module/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcastExplicit.java +++ b/src/module/decode/p25/message/ldu/lc/AdjacentSiteStatusBroadcastExplicit.java @@ -1,5 +1,8 @@ package module.decode.p25.message.ldu.lc; +import module.decode.p25.message.IAdjacentSite; +import module.decode.p25.message.IBandIdentifier; +import module.decode.p25.message.IdentifierReceiver; import module.decode.p25.message.ldu.LDU1Message; import module.decode.p25.reference.LinkControlOpcode; @@ -7,6 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AdjacentSiteStatusBroadcastExplicit extends LDU1Message + implements IdentifierReceiver, IAdjacentSite { private final static Logger mLog = LoggerFactory.getLogger( AdjacentSiteStatusBroadcastExplicit.class ); @@ -22,6 +26,9 @@ public class AdjacentSiteStatusBroadcastExplicit extends LDU1Message public static final int[] RECEIVE_CHANNEL = { 724,725,730,731,732,733,734, 735,740,741,742,743 }; + private IBandIdentifier mTransmitBand; + private IBandIdentifier mReceiveBand; + public AdjacentSiteStatusBroadcastExplicit( LDU1Message message ) { super( message ); @@ -40,27 +47,45 @@ public class AdjacentSiteStatusBroadcastExplicit extends LDU1Message sb.append( getMessageStub() ); - sb.append( " LRA:" + getLocationRegistrationArea() ); + sb.append( " LRA:" + getLRA() ); - sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + sb.append( " SITE:" + getRFSS() + "-" + getSiteID() ); - sb.append( " DNLINK:" + getTransmitChannelNumber() ); + sb.append( " DNLINK:" + getDownlinkChannel() ); - sb.append( " UPLINK:" + getReceiveChannelNumber() ); + sb.append( " UPLINK:" + getUplinkChannel() ); return sb.toString(); } - public String getLocationRegistrationArea() + public String getUniqueID() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getSystemID() ); + sb.append( ":" ); + sb.append( getRFSS() ); + sb.append( ":" ); + sb.append( getSiteID() ); + + return sb.toString(); + } + + public String getLRA() { return mMessage.getHex( LRA, 2 ); } - public String getRFSubsystemID() + public String getRFSS() { return mMessage.getHex( RFSS_ID, 2 ); } + public String getSystemID() + { + return "***"; + } + public String getSiteID() { return mMessage.getHex( SITE_ID, 2 ); @@ -76,7 +101,7 @@ public class AdjacentSiteStatusBroadcastExplicit extends LDU1Message return mMessage.getInt( TRANSMIT_CHANNEL ); } - public String getTransmitChannelNumber() + public String getDownlinkChannel() { return getTransmitIdentifier() + "-" + getTransmitChannel(); } @@ -91,8 +116,50 @@ public class AdjacentSiteStatusBroadcastExplicit extends LDU1Message return mMessage.getInt( RECEIVE_CHANNEL ); } - public String getReceiveChannelNumber() + public String getUplinkChannel() { return getReceiveIdentifier() + "-" + getReceiveChannel(); } + + @Override + public String getSystemServiceClass() + { + return "[]"; + } + + public long getDownlinkFrequency() + { + return calculateDownlink( mTransmitBand, getTransmitChannel() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mReceiveBand, getReceiveChannel() ); + } + + @Override + public void setIdentifierMessage( int identifier, IBandIdentifier message ) + { + if( identifier == getTransmitIdentifier() ) + { + mTransmitBand = message; + } + + if( identifier == getReceiveIdentifier() ) + { + mReceiveBand = message; + } + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 2 ]; + + identifiers[ 0 ] = getTransmitIdentifier(); + identifiers[ 1 ] = getReceiveIdentifier(); + + return identifiers; + } + } diff --git a/src/module/decode/p25/message/pdu/PDUMessage.java b/src/module/decode/p25/message/pdu/PDUMessage.java index 78c703ad..6981d673 100644 --- a/src/module/decode/p25/message/pdu/PDUMessage.java +++ b/src/module/decode/p25/message/pdu/PDUMessage.java @@ -45,7 +45,19 @@ public class PDUMessage extends P25Message sb.append( "NAC:" ); sb.append( getNAC() ); sb.append( " " ); - sb.append( getDUID().getLabel() ); + + switch( getFormat() ) + { + case ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL: + sb.append( "ATSBK" ); + break; + case UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL: + sb.append( "**** UNCONFIRMED MULTI-BLOCK TRUNKING CONTROL" ); + break; + default: + sb.append( getDUID().getLabel() ); + break; + } if( vendor == Vendor.STANDARD ) { diff --git a/src/module/decode/p25/message/pdu/PDUMessageFactory.java b/src/module/decode/p25/message/pdu/PDUMessageFactory.java index bafef26b..26b25b1c 100644 --- a/src/module/decode/p25/message/pdu/PDUMessageFactory.java +++ b/src/module/decode/p25/message/pdu/PDUMessageFactory.java @@ -66,6 +66,7 @@ public class PDUMessageFactory return new GroupDataChannelGrantExtended( message, duid, aliasList ); case GROUP_VOICE_CHANNEL_GRANT: + return new GroupVoiceChannelGrantExplicit( message, duid, aliasList ); case INDIVIDUAL_DATA_CHANNEL_GRANT: @@ -123,7 +124,6 @@ public class PDUMessageFactory case UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL: return new PDUMessage( message, duid, aliasList ); - default: return new PDUMessage( message, duid, aliasList ); } diff --git a/src/module/decode/p25/message/pdu/osp/control/AdjacentStatusBroadcastExtended.java b/src/module/decode/p25/message/pdu/osp/control/AdjacentStatusBroadcastExtended.java index e4d2a5a4..1334c1ab 100644 --- a/src/module/decode/p25/message/pdu/osp/control/AdjacentStatusBroadcastExtended.java +++ b/src/module/decode/p25/message/pdu/osp/control/AdjacentStatusBroadcastExtended.java @@ -1,5 +1,6 @@ package module.decode.p25.message.pdu.osp.control; +import module.decode.p25.message.IAdjacentSite; import module.decode.p25.message.IBandIdentifier; import module.decode.p25.message.IdentifierReceiver; import module.decode.p25.message.pdu.PDUMessage; @@ -11,7 +12,7 @@ import bits.BinaryMessage; import edac.CRCP25; public class AdjacentStatusBroadcastExtended extends PDUMessage - implements IdentifierReceiver + implements IdentifierReceiver, IAdjacentSite { public static final int[] LRA = { 88,89,90,91,92,93,94,95 }; public static final int[] SYSTEM_ID = { 100,101,102,103,104,105,106,107,108, @@ -57,11 +58,11 @@ public class AdjacentStatusBroadcastExtended extends PDUMessage sb.append( getMessageStub() ); - sb.append( " LRA:" + getLocationRegistrationArea() ); + sb.append( " LRA:" + getLRA() ); sb.append( " SYS:" + getSystemID() ); - sb.append( " RFSS:" + getRFSubsystemID() ); + sb.append( " RFSS:" + getRFSS() ); sb.append( " SITE:" + getSiteID() ); @@ -73,28 +74,29 @@ public class AdjacentStatusBroadcastExtended extends PDUMessage sb.append( " UP:" + getUplinkFrequency() ); - sb.append( " SYS SVC CLASS:" + - SystemService.toString( getSystemServiceClass() ) ); + sb.append( " SYS SVC CLASS:" + getSystemServiceClass() ); return sb.toString(); } - - public String getLocationRegistrationArea() - { - return mMessage.getHex( LRA, 2 ); - } - + public String getUniqueID() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getSystemID() ); + sb.append( ":" ); + sb.append( getRFSS() ); + sb.append( ":" ); + sb.append( getSiteID() ); + + return sb.toString(); + } + public String getSystemID() { return mMessage.getHex( SYSTEM_ID, 3 ); } - public String getRFSubsystemID() - { - return mMessage.getHex( RF_SUBSYSTEM_ID, 2 ); - } - public String getSiteID() { return mMessage.getHex( SITE_ID, 2 ); @@ -120,11 +122,6 @@ public class AdjacentStatusBroadcastExtended extends PDUMessage return mMessage.getInt( RECEIVE_CHANNEL ); } - public int getSystemServiceClass() - { - return mMessage.getInt( SYSTEM_SERVICE_CLASS ); - } - public long getDownlinkFrequency() { return calculateDownlink( mTransmitIdentifierProvider, getTransmitChannel() ); @@ -158,4 +155,34 @@ public class AdjacentStatusBroadcastExtended extends PDUMessage return idens; } + + @Override + public String getRFSS() + { + return mMessage.getHex( RF_SUBSYSTEM_ID, 2 ); + } + + @Override + public String getLRA() + { + return mMessage.getHex( LRA, 2 ); + } + + @Override + public String getSystemServiceClass() + { + return SystemService.toString( mMessage.getInt( SYSTEM_SERVICE_CLASS ) ); + } + + @Override + public String getDownlinkChannel() + { + return getTransmitIdentifier() + "-" + getTransmitChannel(); + } + + @Override + public String getUplinkChannel() + { + return getReceiveIdentifier() + "-" + getReceiveChannel(); + } } diff --git a/src/module/decode/p25/message/pdu/osp/voice/GroupVoiceChannelGrantExplicit.java b/src/module/decode/p25/message/pdu/osp/voice/GroupVoiceChannelGrantExplicit.java index 7b9105d7..87e5e649 100644 --- a/src/module/decode/p25/message/pdu/osp/voice/GroupVoiceChannelGrantExplicit.java +++ b/src/module/decode/p25/message/pdu/osp/voice/GroupVoiceChannelGrantExplicit.java @@ -77,6 +77,9 @@ public class GroupVoiceChannelGrantExplicit extends PDUMessage sb.append( " CHAN UP:" + getReceiveChannelIdentifier() + "-" + getReceiveChannelNumber() ); sb.append( " " + getUplinkFrequency() ); + sb.append( " " ); + sb.append( mMessage.toString() ); + return sb.toString(); } diff --git a/src/module/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcast.java b/src/module/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcast.java index 154d3af0..58935d2f 100644 --- a/src/module/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcast.java +++ b/src/module/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcast.java @@ -1,7 +1,9 @@ package module.decode.p25.message.tdu.lc; +import module.decode.p25.message.IAdjacentSite; import module.decode.p25.message.IBandIdentifier; import module.decode.p25.message.IdentifierReceiver; +import module.decode.p25.message.tsbk.osp.control.SystemService; import module.decode.p25.reference.LinkControlOpcode; import module.decode.p25.reference.Service; @@ -9,7 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AdjacentSiteStatusBroadcast extends TDULinkControlMessage - implements IdentifierReceiver + implements IdentifierReceiver, IAdjacentSite { private final static Logger mLog = LoggerFactory.getLogger( AdjacentSiteStatusBroadcast.class ); @@ -45,20 +47,33 @@ public class AdjacentSiteStatusBroadcast extends TDULinkControlMessage sb.append( getMessageStub() ); - sb.append( " LRA:" + getLocationRegistrationArea() ); + sb.append( " LRA:" + getLRA() ); sb.append( " SYS:" + getSystemID() ); - sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + sb.append( " SITE:" + getRFSS() + "-" + getSiteID() ); sb.append( " CHAN:" + getChannel() ); - sb.append( " " + Service.getServices( getSystemServiceClass() ).toString() ); + sb.append( " " + getSystemServiceClass() ); return sb.toString(); } - public String getLocationRegistrationArea() + public String getUniqueID() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getSystemID() ); + sb.append( ":" ); + sb.append( getRFSS() ); + sb.append( ":" ); + sb.append( getSiteID() ); + + return sb.toString(); + } + + public String getLRA() { return mMessage.getHex( LRA, 2 ); } @@ -68,7 +83,7 @@ public class AdjacentSiteStatusBroadcast extends TDULinkControlMessage return mMessage.getHex( SYSTEM_ID, 3 ); } - public String getRFSubsystemID() + public String getRFSS() { return mMessage.getHex( RFSS_ID, 2 ); } @@ -88,14 +103,26 @@ public class AdjacentSiteStatusBroadcast extends TDULinkControlMessage return getIdentifier() + "-" + getChannelNumber(); } + @Override + public String getDownlinkChannel() + { + return getChannel(); + } + + @Override + public String getUplinkChannel() + { + return getChannel(); + } + public int getChannelNumber() { return mMessage.getInt( CHANNEL ); } - public int getSystemServiceClass() + public String getSystemServiceClass() { - return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + return SystemService.toString( mMessage.getInt( SYSTEM_SERVICE_CLASS ) ); } @Override @@ -119,7 +146,7 @@ public class AdjacentSiteStatusBroadcast extends TDULinkControlMessage return calculateDownlink( mIdentifierUpdate, getChannelNumber() ); } - public long getUplinkFrequencyB() + public long getUplinkFrequency() { return calculateUplink( mIdentifierUpdate, getChannelNumber() ); } diff --git a/src/module/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcastExplicit.java b/src/module/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcastExplicit.java index ad3f83f0..630c0075 100644 --- a/src/module/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcastExplicit.java +++ b/src/module/decode/p25/message/tdu/lc/AdjacentSiteStatusBroadcastExplicit.java @@ -1,11 +1,15 @@ package module.decode.p25.message.tdu.lc; +import module.decode.p25.message.IAdjacentSite; +import module.decode.p25.message.IBandIdentifier; +import module.decode.p25.message.IdentifierReceiver; import module.decode.p25.reference.LinkControlOpcode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AdjacentSiteStatusBroadcastExplicit extends TDULinkControlMessage + implements IdentifierReceiver, IAdjacentSite { private final static Logger mLog = LoggerFactory.getLogger( AdjacentSiteStatusBroadcastExplicit.class ); @@ -21,6 +25,9 @@ public class AdjacentSiteStatusBroadcastExplicit extends TDULinkControlMessage public static final int[] RECEIVE_CHANNEL = { 164,165,166,167,168,169,170, 171,184,185,186,187 }; + private IBandIdentifier mTransmitBand; + private IBandIdentifier mReceiveBand; + public AdjacentSiteStatusBroadcastExplicit( TDULinkControlMessage source ) { super( source ); @@ -39,32 +46,56 @@ public class AdjacentSiteStatusBroadcastExplicit extends TDULinkControlMessage sb.append( getMessageStub() ); - sb.append( " LRA:" + getLocationRegistrationArea() ); + sb.append( " LRA:" + getLRA() ); - sb.append( " SITE:" + getRFSubsystemID() + "-" + getSiteID() ); + sb.append( " SITE:" + getRFSS() + "-" + getSiteID() ); - sb.append( " DNLINK:" + getTransmitChannelNumber() ); + sb.append( " DNLINK:" + getDownlinkChannel() ); - sb.append( " UPLINK:" + getReceiveChannelNumber() ); + sb.append( " UPLINK:" + getUplinkChannel() ); return sb.toString(); } - public String getLocationRegistrationArea() + public String getUniqueID() + { + StringBuilder sb = new StringBuilder(); + + sb.append( getSystemID() ); + sb.append( ":" ); + sb.append( getRFSS() ); + sb.append( ":" ); + sb.append( getSiteID() ); + + return sb.toString(); + } + + public String getLRA() { return mMessage.getHex( LRA, 2 ); } - public String getRFSubsystemID() + public String getRFSS() { return mMessage.getHex( RFSS_ID, 2 ); } + public String getSystemID() + { + return "***"; + } + public String getSiteID() { return mMessage.getHex( SITE_ID, 2 ); } + @Override + public String getSystemServiceClass() + { + return "[]"; + } + public int getTransmitIdentifier() { return mMessage.getInt( TRANSMIT_IDENTIFIER ); @@ -75,7 +106,7 @@ public class AdjacentSiteStatusBroadcastExplicit extends TDULinkControlMessage return mMessage.getInt( TRANSMIT_CHANNEL ); } - public String getTransmitChannelNumber() + public String getDownlinkChannel() { return getTransmitIdentifier() + "-" + getTransmitChannel(); } @@ -90,8 +121,43 @@ public class AdjacentSiteStatusBroadcastExplicit extends TDULinkControlMessage return mMessage.getInt( RECEIVE_CHANNEL ); } - public String getReceiveChannelNumber() + public String getUplinkChannel() { return getReceiveIdentifier() + "-" + getReceiveChannel(); } + + public long getDownlinkFrequency() + { + return calculateDownlink( mTransmitBand, getTransmitChannel() ); + } + + public long getUplinkFrequency() + { + return calculateUplink( mReceiveBand, getReceiveChannel() ); + } + + @Override + public void setIdentifierMessage( int identifier, IBandIdentifier message ) + { + if( identifier == getTransmitIdentifier() ) + { + mTransmitBand = message; + } + + if( identifier == getReceiveIdentifier() ) + { + mReceiveBand = message; + } + } + + @Override + public int[] getIdentifiers() + { + int[] identifiers = new int[ 2 ]; + + identifiers[ 0 ] = getTransmitIdentifier(); + identifiers[ 1 ] = getReceiveIdentifier(); + + return identifiers; + } } diff --git a/src/module/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java b/src/module/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java index 227bbcc3..49744f78 100644 --- a/src/module/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java +++ b/src/module/decode/p25/message/tsbk/osp/control/AdjacentStatusBroadcast.java @@ -1,5 +1,6 @@ package module.decode.p25.message.tsbk.osp.control; +import module.decode.p25.message.IAdjacentSite; import module.decode.p25.message.IBandIdentifier; import module.decode.p25.message.IdentifierReceiver; import module.decode.p25.message.tsbk.TSBKMessage; @@ -8,7 +9,8 @@ import module.decode.p25.reference.Opcode; import alias.AliasList; import bits.BinaryMessage; -public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierReceiver +public class AdjacentStatusBroadcast extends TSBKMessage + implements IdentifierReceiver, IAdjacentSite { public static final int[] LOCATION_REGISTRATION_AREA = { 80,81,82,83,84,85, 86,87 }; @@ -47,7 +49,7 @@ public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierRe sb.append( getMessageStub() ); - sb.append( " LRA:" + getLocationRegistrationArea() ); + sb.append( " LRA:" + getLRA() ); sb.append( " SYS:" + getSystemID() ); @@ -79,12 +81,24 @@ public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierRe sb.append( " ACTIVE-NETWORK-CONN" ); } - sb.append( SystemService.toString( getSystemServiceClass() ) ); + sb.append( getSystemServiceClass() ); return sb.toString(); } - public String getLocationRegistrationArea() + @Override + public String getDownlinkChannel() + { + return getIdentifier() + "-" + getChannel(); + } + + @Override + public String getUplinkChannel() + { + return getIdentifier() + "-" + getChannel(); + } + + public String getLRA() { return mMessage.getHex( LOCATION_REGISTRATION_AREA, 2 ); } @@ -147,9 +161,9 @@ public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierRe return mMessage.getInt( IDENTIFIER ); } - public int getSystemServiceClass() + public String getSystemServiceClass() { - return mMessage.getInt( SYSTEM_SERVICE_CLASS ); + return SystemService.toString( mMessage.getInt( SYSTEM_SERVICE_CLASS ) ); } public long getDownlinkFrequency() @@ -161,6 +175,7 @@ public class AdjacentStatusBroadcast extends TSBKMessage implements IdentifierRe { return calculateUplink( mIdentifierUpdate, getChannel() ); } + @Override public void setIdentifierMessage( int identifier, IBandIdentifier message ) diff --git a/src/module/decode/state/ChannelState.java b/src/module/decode/state/ChannelState.java index 81fe70da..a3218dd8 100644 --- a/src/module/decode/state/ChannelState.java +++ b/src/module/decode/state/ChannelState.java @@ -309,26 +309,45 @@ public class ChannelState extends Module implements ICallEventProvider, switch( state ) { case CONTROL: + //Don't allow traffic channels to be control channels, + //otherwise they won't get call tear down + if( mChannelType != ChannelType.TRAFFIC ) + { + broadcast( SquelchState.SQUELCH ); + updateFadeTimeout(); + startMonitor(); + mState = state; + broadcast( ChangedAttribute.CHANNEL_STATE ); + } + break; case DATA: case ENCRYPTED: broadcast( SquelchState.SQUELCH ); updateFadeTimeout(); startMonitor(); + mState = state; + broadcast( ChangedAttribute.CHANNEL_STATE ); break; case CALL: broadcast( SquelchState.UNSQUELCH ); updateFadeTimeout(); startMonitor(); + mState = state; + broadcast( ChangedAttribute.CHANNEL_STATE ); break; case FADE: broadcast( SquelchState.SQUELCH ); updateResetTimeout(); startMonitor(); + mState = state; + broadcast( ChangedAttribute.CHANNEL_STATE ); break; case END: broadcast( SquelchState.SQUELCH ); broadcast( new DecoderStateEvent( this, Event.RESET, State.IDLE ) ); broadcast( new MetadataReset() ); + mState = state; + broadcast( ChangedAttribute.CHANNEL_STATE ); break; case IDLE: broadcast( SquelchState.SQUELCH ); @@ -350,14 +369,13 @@ public class ChannelState extends Module implements ICallEventProvider, mTrafficChannelCallEvent = null; } } + + mState = state; + broadcast( ChangedAttribute.CHANNEL_STATE ); break; default: break; } - - mState = state; - - broadcast( ChangedAttribute.CHANNEL_STATE ); } }