/** * Determines if message bits 0 - 47 pass the Fleetsync CRC checksum * contained in bits 48 - 63, using a lookup table of CRC checksum values * derived from the CRC-15 value, and verifies the message has even parity */ public static CRC check( RadioLog.Common.SafeBitArray msg ) { CRC crc = CRC.UNKNOWN; int calculated = 1; //Starting value //Check even parity if( msg.Cardinality() % 2 == 0 ) { //Iterate bits that are set and XOR running checksum with lookup value for (int i = msg.nextSetBit( 0 ); i >= 0 && i < 48; i = msg.nextSetBit( i+1 ) ) { calculated ^= sCHECKSUMS[ i ]; } if( calculated == getChecksum( msg ) ) { crc = CRC.PASSED; } else { crc = CRC.FAILED_CRC; } } else { crc = CRC.FAILED_PARITY; } return crc; }
public P25MessageAssembler(P25MessageFramer framer) { mFramer = framer; mMessageLength = mDUID.getMessageLength(); mMessage = new RadioLog.Common.SafeBitArray(mMessageLength); reset(); }
/** * Sends instrumentation tap event to all registered listeners */ private void sendTapEvent(RadioLog.Common.SafeBitArray bitset, Shift shift, bool decision) { foreach (IListener <SymbolEvent> tap in mDecoder.GetListeners()) { SymbolEvent sEvent = new SymbolEvent(bitset.CloneFromIndexToIndex(0, mSymbolLength), mSymbolLength, decision, shift); tap.Receive(sEvent); } }
/** * Returns the integer value of the 15 bit crc checksum */ public static int getChecksum( RadioLog.Common.SafeBitArray msg ) { int retVal = 0; for( int x = 0; x < 15; x++ ) { if( msg[ x + 48 ] ) { retVal += 1<<( 14 - x ); } } return retVal; }
private Constellation getConstellation(RadioLog.Common.SafeBitArray message, int index) { int constellation = 0; for (int x = 0; x < 4; x++) { if (message[index + x]) { constellation += (1 << (3 - x)); } } return(Constellation.fromValue(constellation)); }
public static RadioLog.Common.SafeBitArray interleave(RadioLog.Common.SafeBitArray message, int start, int end) { RadioLog.Common.SafeBitArray original = message.CloneFromIndexToIndex(start, end); /* Clear block bits in source message */ message.ClearRange(start, end); /* Iterate only the set bits in the original message and apply * the deinterleave -- we don't have to evaluate the 0 bits */ for (int i = original.nextSetBit(0); i >= 0 && i < INTERLEAVE.Length; i = original.nextSetBit(i + 1)) { message.SetBit(start + INTERLEAVE[i]); } return(message); }
/** * Determines the errant bit positions and returns them in an array of * integer bit positions. * * Note: currently only detects single-bit errors * * @param msg to be checked for errors * @return - array of integer positions of bits that need flipped */ public static int[] findBitErrors( RadioLog.Common.SafeBitArray msg ) { int[] retVal = null; int checksum = getChecksum( msg ); //Remove the initial fill value (1) checksum ^= 1; //Iterate set message bits, removing their respective checksum value //from the transmitted checksum, to arrive at the remainder for (int i = msg.nextSetBit( 0 ); i >= 0 && i < 48; i = msg.nextSetBit( i+1 ) ) { checksum ^= sCHECKSUMS[ i ]; } //If at this point the checksum is 0, then we have a parity bit error if( checksum == 0 ) { retVal = new int[ 1 ]; retVal[ 0 ] = 63; } //Otherwise, try to lookup the syndrome for a single bit error else { for( int x = 0; x < 63; x++ ) { if( checksum == sCHECKSUMS[ x ] ) { //return this bit position retVal = new int[ 1 ]; retVal[ 0 ] = x; } } } return retVal; }
public static TSBKMessage getMessage(int system, RadioLog.Common.SafeBitArray buffer) { int opcode = buffer.getInt(TSBKMessage.OPCODE); int vendor = buffer.getInt(TSBKMessage.VENDOR_ID); switch (vendor) { case 0: //STANDARD { return(new TSBKMessage(system, buffer)); } case 144: //MOTOROLA { return(new TSBKMessage(system, buffer)); } default: { return(new TSBKMessage(system, buffer)); } } }
private CRC detectAndCorrect(int start, int end) { RadioLog.Common.SafeBitArray original = mMessage.CloneFromIndexToIndex(start, end); CRC retVal = CRCFleetsync.check(original); //Attempt to correct single-bit errors if (retVal == CRC.FAILED_PARITY) { int[] errorBitPositions = CRCFleetsync.findBitErrors(original); if (errorBitPositions != null) { foreach (int errorBitPosition in errorBitPositions) { mMessage.flip(start + errorBitPosition); } retVal = CRC.CORRECTED; } } return(retVal); }
public void decode(RadioLog.Common.SafeBitArray message, int start, int end) { /* load each of the nodes with deinterleaved constellations */ for (int index = 0; index < 49; index++) { Constellation c = getConstellation(message, index * 4); mConstellationNodes[index].setConstellation(c); } /* test to see if constellations are correct - otherwise correct them */ ConstellationNode firstNode = mConstellationNodes[0]; if (!firstNode.startsWith(Dibit.D0) || !firstNode.isCorrect()) { firstNode.correctTo(Dibit.D0); } /* clear constellations from original message */ message.ClearRange(start, end - start); /* replace with decoded values from the nodes */ for (int index = 0; index < 49; index++) { ConstellationNode node = mConstellationNodes[index]; if (node.firstBit()) { message.SetBit(start + (index * 2)); } if (node.secondBit()) { message.SetBit(start + (index * 2) + 1); } } }
public P25Message(RadioLog.Common.SafeBitArray message, Decoders.P25.Reference.DataUnitID duid) : base() { mMessage = message; mDUID = duid; }
public MessageAssembler(MessageFramer framer, int messageLength) { mFramer = framer; mMessage = new RadioLog.Common.SafeBitArray(messageLength); }
public FleetsyncMessage(RadioLog.Common.SafeBitArray message) { mMessage = message; checkParity(); }
public PDUMessage(RadioLog.Common.SafeBitArray message, Decoders.P25.Reference.DataUnitID duid) : base(message, duid) { }
public void dispose() { mMessage = null; }
private void checkComplete() { if (mDUID.Equals(Decoders.P25.Reference.DataUnitID.NID)) { int value = mMessage.getInt(Decoders.P25.Message.P25Message.DUID); Decoders.P25.Reference.DataUnitID duid = Decoders.P25.Reference.DataUnitID.fromValue(value); if (duid != Decoders.P25.Reference.DataUnitID.UNKN) { setDUID(duid); } else { mComplete = true; } } else if (mDUID.Equals(Decoders.P25.Reference.DataUnitID.HDU) || mDUID.Equals(Decoders.P25.Reference.DataUnitID.LDU1) || mDUID.Equals(Decoders.P25.Reference.DataUnitID.LDU2) || mDUID.Equals(Decoders.P25.Reference.DataUnitID.PDU2) || mDUID.Equals(Decoders.P25.Reference.DataUnitID.PDU3) || mDUID.Equals(Decoders.P25.Reference.DataUnitID.TDU) || mDUID.Equals(Decoders.P25.Reference.DataUnitID.TDULC) || mDUID.Equals(Decoders.P25.Reference.DataUnitID.UNKN)) { mComplete = true; mFramer.dispatch(new Decoders.P25.Message.P25Message(mMessage.Clone(), mDUID)); } else if (mDUID.Equals(Decoders.P25.Reference.DataUnitID.PDU1)) { int blocks = mMessage.getInt(Decoders.P25.Message.PDUMessage.PDU_HEADER_BLOCKS_TO_FOLLOW); int padBlocks = mMessage.getInt(Decoders.P25.Message.PDUMessage.PDU_HEADER_PAD_BLOCKS); int blockCount = blocks + padBlocks; if (blockCount == 24 || blockCount == 32) { setDUID(Decoders.P25.Reference.DataUnitID.PDU2); } else if (blockCount == 36 || blockCount == 48) { setDUID(Decoders.P25.Reference.DataUnitID.PDU3); } else { mFramer.dispatch(new Decoders.P25.Message.PDUMessage(mMessage.Clone(), mDUID)); mComplete = true; } } else if (mDUID.Equals(Decoders.P25.Reference.DataUnitID.TSBK1)) { /* Remove interleaving */ Decoders.P25.P25Interleave.deinterleave(mMessage, TSBK_BEGIN, TSBK_END); /* Remove trellis encoding */ mFramer.mHalfRate.decode(mMessage, TSBK_BEGIN, TSBK_END); /* Construct the message */ int tsbkSystem1 = mMessage.getInt(Decoders.P25.Message.P25Message.NAC); RadioLog.Common.SafeBitArray tsbkBuffer1 = new RadioLog.Common.SafeBitArray(mMessage.CloneFromIndexToIndex(TSBK_BEGIN, TSBK_DECODED_END), 96); Decoders.P25.Message.TSBKMessage tsbkMessage1 = Decoders.P25.Message.TSBKMessageFactory.getMessage(tsbkSystem1, tsbkBuffer1); if (tsbkMessage1.isLastBlock()) { mComplete = true; } else { setDUID(Decoders.P25.Reference.DataUnitID.TSBK2); mMessage.SetPointer(TSBK_BEGIN); } mFramer.dispatch(tsbkMessage1); } else if (mDUID.Equals(Decoders.P25.Reference.DataUnitID.TSBK2)) { /* Remove interleaving */ Decoders.P25.P25Interleave.deinterleave(mMessage, TSBK_BEGIN, TSBK_END); /* Remove trellis encoding */ mFramer.mHalfRate.decode(mMessage, TSBK_BEGIN, TSBK_END); /* Construct the message */ int tsbkSystem2 = mMessage.getInt(Decoders.P25.Message.P25Message.NAC); RadioLog.Common.SafeBitArray tsbkBuffer2 = new RadioLog.Common.SafeBitArray(mMessage.CloneFromIndexToIndex(TSBK_BEGIN, TSBK_DECODED_END), 98); Decoders.P25.Message.TSBKMessage tsbkMessage2 = Decoders.P25.Message.TSBKMessageFactory.getMessage(tsbkSystem2, tsbkBuffer2); if (tsbkMessage2.isLastBlock()) { mComplete = true; } else { setDUID(Decoders.P25.Reference.DataUnitID.TSBK3); mMessage.SetPointer(TSBK_BEGIN); } mFramer.dispatch(tsbkMessage2); } else if (mDUID.Equals(Decoders.P25.Reference.DataUnitID.TSBK3)) { /* Remove interleaving */ Decoders.P25.P25Interleave.deinterleave(mMessage, TSBK_BEGIN, TSBK_END); /* Remove trellis encoding */ mFramer.mHalfRate.decode(mMessage, TSBK_BEGIN, TSBK_END); /* Construct the message */ int tsbkSystem3 = mMessage.getInt(Decoders.P25.Message.P25Message.NAC); RadioLog.Common.SafeBitArray tsbkBuffer3 = new RadioLog.Common.SafeBitArray(mMessage.CloneFromIndexToIndex(TSBK_BEGIN, TSBK_DECODED_END), 96); Decoders.P25.Message.TSBKMessage tsbkMessage3 = Decoders.P25.Message.TSBKMessageFactory.getMessage(tsbkSystem3, tsbkBuffer3); mComplete = true; mFramer.dispatch(tsbkMessage3); } else { mComplete = true; } }
public TSBKMessage(int system, RadioLog.Common.SafeBitArray message) : base(message, Reference.DataUnitID.TSBK1) { // }