mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
P25 work in progress
This commit is contained in:
@@ -220,7 +220,9 @@ public class CRCP25
|
||||
0x00080000l, 0x00100000l, 0x00200000l, 0x00400000l, 0x00800000l,
|
||||
0x01000000l, 0x02000000l, 0x04000000l, 0x08000000l, 0x10000000l,
|
||||
0x20000000l, 0x40000000l, 0x80000000l
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Performs CRC check and corrects single-bit errors against the message.
|
||||
|
||||
@@ -67,7 +67,7 @@ public enum DecoderType
|
||||
DecoderType.LTR_STANDARD,
|
||||
DecoderType.MPT1327,
|
||||
DecoderType.NBFM,
|
||||
// DecoderType.P25_PHASE1,
|
||||
DecoderType.P25_PHASE1,
|
||||
DecoderType.PASSPORT );
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ package decode.p25;
|
||||
|
||||
import instrument.Instrumentable;
|
||||
import instrument.tap.Tap;
|
||||
import instrument.tap.stream.DibitTap;
|
||||
import instrument.tap.stream.FloatTap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -36,9 +37,9 @@ import dsp.agc.RealAutomaticGainControl;
|
||||
import dsp.filter.ComplexFIRFilter;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.fsk.P25MessageFramer;
|
||||
import dsp.fsk.C4FMSlicer;
|
||||
import dsp.fsk.C4FMSymbolFilter;
|
||||
import dsp.fsk.P25MessageFramer;
|
||||
import dsp.nbfm.FMDiscriminator;
|
||||
|
||||
public class P25Decoder extends Decoder implements Instrumentable
|
||||
@@ -49,6 +50,7 @@ public class P25Decoder extends Decoder implements Instrumentable
|
||||
private static final String INSTRUMENT_INPUT_TO_AGC = "Tap Point: Input to AGC";
|
||||
private static final String INSTRUMENT_AGC_TO_SYMBOL_FILTER = "Tap Point: AGC to Symbol Filter";
|
||||
private static final String INSTRUMENT_SYMBOL_FILTER_TO_SLICER = "Tap Point: Symbol Filter to Slicer";
|
||||
private static final String INSTRUMENT_SLICER_OUTPUT = "Tap Point: Slicer Output";
|
||||
private List<Tap> mAvailableTaps;
|
||||
|
||||
private ComplexFIRFilter mBasebandFilter = new ComplexFIRFilter(
|
||||
@@ -125,6 +127,7 @@ public class P25Decoder extends Decoder implements Instrumentable
|
||||
mAvailableTaps.add( new FloatTap( INSTRUMENT_INPUT_TO_AGC, 0, 1.0f ) );
|
||||
mAvailableTaps.add( new FloatTap( INSTRUMENT_AGC_TO_SYMBOL_FILTER, 0, 1.0f ) );
|
||||
mAvailableTaps.add( new FloatTap( INSTRUMENT_SYMBOL_FILTER_TO_SLICER, 0, 0.1f ) );
|
||||
mAvailableTaps.add( new DibitTap( INSTRUMENT_SLICER_OUTPUT, 0, 0.1f ) );
|
||||
|
||||
mAvailableTaps.addAll( mSymbolFilter.getTaps() );
|
||||
}
|
||||
@@ -155,6 +158,10 @@ public class P25Decoder extends Decoder implements Instrumentable
|
||||
mSymbolFilter.setListener( symbolSlicer );
|
||||
symbolSlicer.setListener( mSlicer );
|
||||
break;
|
||||
case INSTRUMENT_SLICER_OUTPUT:
|
||||
DibitTap slicer = (DibitTap)tap;
|
||||
mSlicer.addListener( slicer );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +183,10 @@ public class P25Decoder extends Decoder implements Instrumentable
|
||||
case INSTRUMENT_SYMBOL_FILTER_TO_SLICER:
|
||||
mSymbolFilter.setListener( mSlicer );
|
||||
break;
|
||||
case INSTRUMENT_SLICER_OUTPUT:
|
||||
DibitTap slicerTap = (DibitTap)tap;
|
||||
mSlicer.removeListener( slicerTap );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
44
src/decode/p25/message/hdu/HDUMessage.java
Normal file
44
src/decode/p25/message/hdu/HDUMessage.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package decode.p25.message.hdu;
|
||||
|
||||
import alias.AliasList;
|
||||
import bits.BitSetBuffer;
|
||||
import crc.CRC;
|
||||
import decode.p25.message.P25Message;
|
||||
import decode.p25.reference.DataUnitID;
|
||||
|
||||
public class HDUMessage extends P25Message
|
||||
{
|
||||
public HDUMessage( BitSetBuffer message, DataUnitID duid,
|
||||
AliasList aliasList )
|
||||
{
|
||||
super( message, duid, aliasList );
|
||||
|
||||
/* NID CRC is checked in the message framer, thus a constructed message
|
||||
* means it passed the CRC */
|
||||
mCRC = new CRC[ 2 ];
|
||||
mCRC[ 0 ] = CRC.PASSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "NAC:" );
|
||||
sb.append( getNAC() );
|
||||
sb.append( " " );
|
||||
sb.append( getDUID().getLabel() );
|
||||
sb.append( " " );
|
||||
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/* Temporary override */
|
||||
public boolean isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
44
src/decode/p25/message/ldu/LDU1Message.java
Normal file
44
src/decode/p25/message/ldu/LDU1Message.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package decode.p25.message.ldu;
|
||||
|
||||
import alias.AliasList;
|
||||
import bits.BitSetBuffer;
|
||||
import crc.CRC;
|
||||
import decode.p25.message.P25Message;
|
||||
import decode.p25.reference.DataUnitID;
|
||||
|
||||
public class LDU1Message extends P25Message
|
||||
{
|
||||
public LDU1Message( BitSetBuffer message, DataUnitID duid,
|
||||
AliasList aliasList )
|
||||
{
|
||||
super( message, duid, aliasList );
|
||||
|
||||
/* NID CRC is checked in the message framer, thus a constructed message
|
||||
* means it passed the CRC */
|
||||
mCRC = new CRC[ 2 ];
|
||||
mCRC[ 0 ] = CRC.PASSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "NAC:" );
|
||||
sb.append( getNAC() );
|
||||
sb.append( " " );
|
||||
sb.append( getDUID().getLabel() );
|
||||
sb.append( " " );
|
||||
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/* Temporary override */
|
||||
public boolean isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
44
src/decode/p25/message/ldu/LDU2Message.java
Normal file
44
src/decode/p25/message/ldu/LDU2Message.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package decode.p25.message.ldu;
|
||||
|
||||
import alias.AliasList;
|
||||
import bits.BitSetBuffer;
|
||||
import crc.CRC;
|
||||
import decode.p25.message.P25Message;
|
||||
import decode.p25.reference.DataUnitID;
|
||||
|
||||
public class LDU2Message extends P25Message
|
||||
{
|
||||
public LDU2Message( BitSetBuffer message, DataUnitID duid,
|
||||
AliasList aliasList )
|
||||
{
|
||||
super( message, duid, aliasList );
|
||||
|
||||
/* NID CRC is checked in the message framer, thus a constructed message
|
||||
* means it passed the CRC */
|
||||
mCRC = new CRC[ 2 ];
|
||||
mCRC[ 0 ] = CRC.PASSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "NAC:" );
|
||||
sb.append( getNAC() );
|
||||
sb.append( " " );
|
||||
sb.append( getDUID().getLabel() );
|
||||
sb.append( " " );
|
||||
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/* Temporary override */
|
||||
public boolean isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public abstract class UnitToUnitChannelGrantExtended extends PDUMessage
|
||||
return mMessage.get( EMERGENCY_FLAG );
|
||||
}
|
||||
|
||||
public boolean isEncryptedChannel()
|
||||
public boolean isEncrypted()
|
||||
{
|
||||
return mMessage.get( ENCRYPTED_CHANNEL_FLAG );
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public class GroupDataChannelGrantExtended extends PDUMessage
|
||||
return mMessage.get( EMERGENCY_FLAG );
|
||||
}
|
||||
|
||||
public boolean isEncryptedChannel()
|
||||
public boolean isEncrypted()
|
||||
{
|
||||
return mMessage.get( ENCRYPTED_CHANNEL_FLAG );
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class GroupVoiceChannelGrantExplicit extends PDUMessage
|
||||
return mMessage.get( EMERGENCY_FLAG );
|
||||
}
|
||||
|
||||
public boolean isEncryptedChannel()
|
||||
public boolean isEncrypted()
|
||||
{
|
||||
return mMessage.get( ENCRYPTED_CHANNEL_FLAG );
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public class UnitToUnitVoiceChannelGrantUpdateExtended extends PDUMessage
|
||||
return mMessage.get( EMERGENCY_FLAG );
|
||||
}
|
||||
|
||||
public boolean isEncryptedChannel()
|
||||
public boolean isEncrypted()
|
||||
{
|
||||
return mMessage.get( ENCRYPTED_CHANNEL_FLAG );
|
||||
}
|
||||
|
||||
44
src/decode/p25/message/tdu/TDULCMessage.java
Normal file
44
src/decode/p25/message/tdu/TDULCMessage.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package decode.p25.message.tdu;
|
||||
|
||||
import alias.AliasList;
|
||||
import bits.BitSetBuffer;
|
||||
import crc.CRC;
|
||||
import decode.p25.message.P25Message;
|
||||
import decode.p25.reference.DataUnitID;
|
||||
|
||||
public class TDULCMessage extends P25Message
|
||||
{
|
||||
public TDULCMessage( BitSetBuffer message, DataUnitID duid,
|
||||
AliasList aliasList )
|
||||
{
|
||||
super( message, duid, aliasList );
|
||||
|
||||
/* NID CRC is checked in the message framer, thus a constructed message
|
||||
* means it passed the CRC */
|
||||
mCRC = new CRC[ 2 ];
|
||||
mCRC[ 0 ] = CRC.PASSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "NAC:" );
|
||||
sb.append( getNAC() );
|
||||
sb.append( " " );
|
||||
sb.append( getDUID().getLabel() );
|
||||
sb.append( " " );
|
||||
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/* Temporary override */
|
||||
public boolean isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import decode.p25.message.tsbk.osp.control.LocationRegistrationResponse;
|
||||
import decode.p25.message.tsbk.osp.control.MessageUpdate;
|
||||
import decode.p25.message.tsbk.osp.control.NetworkStatusBroadcast;
|
||||
import decode.p25.message.tsbk.osp.control.ProtectionParameterUpdate;
|
||||
import decode.p25.message.tsbk.osp.control.QueuedResponse;
|
||||
import decode.p25.message.tsbk.osp.control.RFSSStatusBroadcast;
|
||||
import decode.p25.message.tsbk.osp.control.RadioUnitMonitorCommand;
|
||||
import decode.p25.message.tsbk.osp.control.RoamingAddressCommand;
|
||||
@@ -125,6 +126,8 @@ public class TSBKMessageFactory
|
||||
case NETWORK_STATUS_BROADCAST:
|
||||
return new NetworkStatusBroadcast( message, duid,
|
||||
aliasList );
|
||||
case QUEUED_RESPONSE:
|
||||
return new QueuedResponse( message, duid, aliasList );
|
||||
case PROTECTION_PARAMETER_UPDATE:
|
||||
return new ProtectionParameterUpdate( message, duid,
|
||||
aliasList );
|
||||
|
||||
@@ -55,6 +55,19 @@ public class AuthenticationCommand extends TSBKMessage
|
||||
{
|
||||
return mMessage.getHex( TARGET_ID, 6 );
|
||||
}
|
||||
|
||||
public String getFullTargetID()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getWACN() );
|
||||
sb.append( "-" );
|
||||
sb.append( getSystemID() );
|
||||
sb.append( "-" );
|
||||
sb.append( getTargetID() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToID()
|
||||
|
||||
@@ -18,7 +18,7 @@ public enum DataUnitID
|
||||
PDU1 ( 12, 356, false, "PDU1 ", "Packet Data Unit" ),
|
||||
PDU2 ( 12, 452, false, "PDU2 ", "Packet Data Unit" ),
|
||||
PDU3 ( 12, 548, false, "PDU3 ", "Packet Data Unit" ),
|
||||
TDULC( 15, 372, false, "TDULC", "Terminator Data Unit With Link Control" ),
|
||||
TDULC( 15, 352, false, "TDULC", "Terminator Data Unit With Link Control" ),
|
||||
UNKN ( -1, 0, false, "UNKWN", "Unknown" );
|
||||
|
||||
private int mValue;
|
||||
|
||||
@@ -17,8 +17,12 @@ import crc.CRCP25;
|
||||
import decode.p25.P25Interleave;
|
||||
import decode.p25.TrellisHalfRate;
|
||||
import decode.p25.message.P25Message;
|
||||
import decode.p25.message.hdu.HDUMessage;
|
||||
import decode.p25.message.ldu.LDU1Message;
|
||||
import decode.p25.message.ldu.LDU2Message;
|
||||
import decode.p25.message.pdu.PDUMessage;
|
||||
import decode.p25.message.pdu.PDUMessageFactory;
|
||||
import decode.p25.message.tdu.TDULCMessage;
|
||||
import decode.p25.message.tdu.TDUMessage;
|
||||
import decode.p25.message.tsbk.TSBKMessage;
|
||||
import decode.p25.message.tsbk.TSBKMessageFactory;
|
||||
@@ -246,15 +250,15 @@ public class P25MessageFramer implements Listener<Dibit>
|
||||
break;
|
||||
case HDU:
|
||||
mComplete = true;
|
||||
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
|
||||
dispatch( new HDUMessage( mMessage.copy(), mDUID, mAliasList ) );
|
||||
break;
|
||||
case LDU1:
|
||||
mComplete = true;
|
||||
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
|
||||
dispatch( new LDU1Message( mMessage.copy(), mDUID, mAliasList ) );
|
||||
break;
|
||||
case LDU2:
|
||||
mComplete = true;
|
||||
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
|
||||
dispatch( new LDU2Message( mMessage.copy(), mDUID, mAliasList ) );
|
||||
break;
|
||||
case PDU0:
|
||||
/* Remove interleaving */
|
||||
@@ -368,7 +372,7 @@ public class P25MessageFramer implements Listener<Dibit>
|
||||
mComplete = true;
|
||||
break;
|
||||
case TDULC:
|
||||
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
|
||||
dispatch( new TDULCMessage( mMessage.copy(), mDUID, mAliasList ) );
|
||||
mComplete = true;
|
||||
break;
|
||||
case TSBK1:
|
||||
|
||||
@@ -22,6 +22,8 @@ import instrument.tap.Tap;
|
||||
import instrument.tap.TapViewPanel;
|
||||
import instrument.tap.stream.BinaryTap;
|
||||
import instrument.tap.stream.BinaryTapViewPanel;
|
||||
import instrument.tap.stream.DibitTap;
|
||||
import instrument.tap.stream.DibitTapViewPanel;
|
||||
import instrument.tap.stream.FloatTap;
|
||||
import instrument.tap.stream.FloatTapViewPanel;
|
||||
import instrument.tap.stream.SymbolEventTap;
|
||||
@@ -166,6 +168,9 @@ public class DecoderViewFrame extends JInternalFrame
|
||||
break;
|
||||
case STREAM_COMPLEX:
|
||||
break;
|
||||
case STREAM_DIBIT:
|
||||
panel = new DibitTapViewPanel( (DibitTap)tap );
|
||||
break;
|
||||
case STREAM_FLOAT:
|
||||
panel = new FloatTapViewPanel( (FloatTap)tap );
|
||||
break;
|
||||
|
||||
@@ -22,6 +22,7 @@ public enum TapType
|
||||
EVENT_SYNC_DETECT,
|
||||
STREAM_BINARY,
|
||||
STREAM_COMPLEX,
|
||||
STREAM_DIBIT,
|
||||
STREAM_FLOAT,
|
||||
STREAM_SYMBOL;
|
||||
}
|
||||
|
||||
60
src/instrument/tap/stream/DibitTap.java
Normal file
60
src/instrument/tap/stream/DibitTap.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package instrument.tap.stream;
|
||||
|
||||
import instrument.tap.TapListener;
|
||||
import instrument.tap.TapType;
|
||||
import sample.Listener;
|
||||
import dsp.fsk.Dibit;
|
||||
|
||||
public class DibitTap extends StreamTap implements Listener<Dibit>
|
||||
|
||||
{
|
||||
private Listener<Dibit> mListener;
|
||||
|
||||
public DibitTap( String name,
|
||||
int delay,
|
||||
float sampleRateRatio )
|
||||
{
|
||||
super( TapType.STREAM_DIBIT, name, delay, sampleRateRatio );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( Dibit dibit )
|
||||
{
|
||||
if( mListener != null )
|
||||
{
|
||||
mListener.receive( dibit );
|
||||
}
|
||||
|
||||
for( TapListener listener: mListeners )
|
||||
{
|
||||
listener.receive( dibit );
|
||||
}
|
||||
}
|
||||
|
||||
public void setListener( Listener<Dibit> listener )
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void removeListener( Listener<Dibit> listener )
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
190
src/instrument/tap/stream/DibitTapViewPanel.java
Normal file
190
src/instrument/tap/stream/DibitTapViewPanel.java
Normal file
@@ -0,0 +1,190 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package instrument.tap.stream;
|
||||
|
||||
import instrument.gui.SampleModel;
|
||||
import instrument.tap.Tap;
|
||||
import instrument.tap.TapViewPanel;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
|
||||
import dsp.fsk.Dibit;
|
||||
|
||||
public class DibitTapViewPanel extends TapViewPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Tap mTap;
|
||||
private List<Dibit> mSamples;
|
||||
private int mSampleCount;
|
||||
private int mOffset = 0;
|
||||
|
||||
public DibitTapViewPanel( DibitTap tap )
|
||||
{
|
||||
super( new SampleModel<Dibit>(), tap.getName() );
|
||||
|
||||
mTap = tap;
|
||||
mTap.addListener( getModel() );
|
||||
|
||||
getModel().setSampleCount(
|
||||
(int)( getModel().getSampleCount() * tap.getSampleRateRatio() ) );
|
||||
|
||||
getModel().setDelay( tap.getDelay() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update( Observable arg0, Object arg1 )
|
||||
{
|
||||
mSamples = (List<Dibit>)getModel().getSamples();
|
||||
mSampleCount = getModel().getSampleCount();
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void paintComponent( Graphics g )
|
||||
{
|
||||
super.paintComponent( g );
|
||||
|
||||
Graphics2D g2 = (Graphics2D)g;
|
||||
|
||||
int height = getHeight();
|
||||
int width = getWidth();
|
||||
|
||||
g2.setColor( Color.DARK_GRAY );
|
||||
|
||||
float middle = (float)height / 2.0f;
|
||||
|
||||
g2.drawLine( 0, (int)middle, width, (int)middle );
|
||||
|
||||
if( mSamples != null && mSamples.size() > 0 )
|
||||
{
|
||||
g2.setColor( getForeground() );
|
||||
|
||||
g2.drawString( mLabel, 5 , 15 );
|
||||
|
||||
for( int x = 1; x < mSamples.size(); x++ )
|
||||
{
|
||||
paintDibit( g, x, mSamples.get( x ) );
|
||||
}
|
||||
}
|
||||
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints a polyline representing a boolean value with a 0 or 1 label in
|
||||
* the middle of it
|
||||
*
|
||||
* @param graphics
|
||||
* @param index - index of the sample int the sample buffer
|
||||
* @param value - bit value, 0 or 1
|
||||
*/
|
||||
private void paintDibit( Graphics graphics, int index, Dibit value )
|
||||
{
|
||||
Graphics2D g2 = (Graphics2D)graphics;
|
||||
|
||||
Path2D.Float polyline =
|
||||
new Path2D.Float( Path2D.Float.WIND_EVEN_ODD, mSamples.size() );
|
||||
|
||||
float middleY = ( (float)getHeight() / 2.0f );
|
||||
|
||||
float indexWidth = (float)( getWidth() ) / (float)mSampleCount;
|
||||
|
||||
float startX = (float)index * indexWidth;
|
||||
float stopX = (float)(index + 1 ) * indexWidth;
|
||||
float fivePercent = indexWidth * .05f;
|
||||
float leftX = startX + fivePercent;
|
||||
float rightX = stopX - fivePercent;
|
||||
|
||||
/* Start */
|
||||
polyline.moveTo( startX, middleY );
|
||||
|
||||
/* Left horizonal segment */
|
||||
polyline.lineTo( leftX, middleY );
|
||||
|
||||
float y = middleY;
|
||||
|
||||
switch( value )
|
||||
{
|
||||
case D01_PLUS_3:
|
||||
y = middleY - ( middleY * 0.75f);
|
||||
break;
|
||||
case D00_PLUS_1:
|
||||
y = middleY - ( middleY * 0.25f);
|
||||
break;
|
||||
case D10_MINUS_1:
|
||||
y = middleY + ( middleY * 0.25f);
|
||||
break;
|
||||
case D11_MINUS_3:
|
||||
y = middleY + ( middleY * 0.75f);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Left vertical segment */
|
||||
polyline.lineTo( leftX, y );
|
||||
|
||||
/* Middle horizontal segment */
|
||||
polyline.lineTo( rightX, y );
|
||||
|
||||
/* Right vertical segment */
|
||||
polyline.lineTo( rightX, middleY );
|
||||
|
||||
/* Right horizontal segment */
|
||||
polyline.lineTo( stopX, middleY );
|
||||
|
||||
g2.draw( polyline );
|
||||
|
||||
/* Draw the bit value label */
|
||||
String bit = null;
|
||||
|
||||
switch( value )
|
||||
{
|
||||
case D00_PLUS_1:
|
||||
bit = "+1";
|
||||
break;
|
||||
case D01_PLUS_3:
|
||||
bit = "+3";
|
||||
break;
|
||||
case D10_MINUS_1:
|
||||
bit = "-1";
|
||||
break;
|
||||
case D11_MINUS_3:
|
||||
bit = "-3";
|
||||
break;
|
||||
}
|
||||
|
||||
FontMetrics fontMetrics = graphics.getFontMetrics( this.getFont() );
|
||||
|
||||
Rectangle2D label = fontMetrics.getStringBounds( bit, graphics );
|
||||
|
||||
float offsetX = (float)label.getWidth() / 2.0f;
|
||||
float offsetY = (float)label.getWidth() / 2.0f;
|
||||
|
||||
float middleX = startX + ( indexWidth / 2.0f );
|
||||
|
||||
graphics.drawString( bit,
|
||||
(int)( middleX - offsetX ),
|
||||
(int)( middleY - offsetY ) );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user