/* * Copyright 2008, 2009 Free Software Foundation, Inc. * * This software is distributed under the terms of the GNU Affero Public License. * See the COPYING file in the main directory for details. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifndef FECVECTORS_H #define FECVECTORS_H #include "Vector.h" #include class BitVector; class SoftVector; /** Shift-register (LFSR) generator. */ class Generator { private: uint64_t mCoeff; ///< polynomial coefficients. LSB is zero exponent. uint64_t mState; ///< shift register state. LSB is most recent. uint64_t mMask; ///< mask for reading state unsigned mLen; ///< number of bits used in shift register unsigned mLen_1; ///< mLen - 1 public: Generator(uint64_t wCoeff, unsigned wLen) :mCoeff(wCoeff),mState(0), mMask((1ULL<>(mLen_1)) & 0x01; mState = (mState<<1) ^ (inBit & 0x01); if (fb) mState ^= mCoeff; } /** Update the generator state by one cycle. This is in the .h for inlining. */ void encoderShift(unsigned inBit) { const unsigned fb = ((mState>>(mLen_1)) ^ inBit) & 0x01; mState <<= 1; if (fb) mState ^= mCoeff; } }; /** Parity (CRC-type) generator and checker based on a Generator. */ class Parity : public Generator { protected: unsigned mCodewordSize; public: Parity(uint64_t wCoefficients, unsigned wParitySize, unsigned wCodewordSize) :Generator(wCoefficients, wParitySize), mCodewordSize(wCodewordSize) { } /** Compute the parity word and write it into the target segment. */ void writeParityWord(const BitVector& data, BitVector& parityWordTarget, bool invert=true); /** Compute the syndrome of a received sequence. */ uint64_t syndrome(const BitVector& receivedCodeword); }; /** Class to represent convolutional coders/decoders of rate 1/2, memory length 4. This is the "workhorse" coder for most GSM channels. */ class ViterbiR2O4 { private: /**name Lots of precomputed elements so the compiler can optimize like hell. */ //@{ /**@name Core values. */ //@{ static const unsigned mIRate = 2; ///< reciprocal of rate static const unsigned mOrder = 4; ///< memory length of generators //@} /**@name Derived values. */ //@{ static const unsigned mIStates = 0x01 << mOrder; ///< number of states, number of survivors static const uint32_t mSMask = mIStates-1; ///< survivor mask static const uint32_t mCMask = (mSMask<<1) | 0x01; ///< candidate mask static const uint32_t mOMask = (0x01< { public: /**@name Constructors. */ //@{ /**@name Casts of Vector constructors. */ //@{ BitVector(char* wData, char* wStart, char* wEnd) :Vector(wData,wStart,wEnd) { } BitVector(size_t len=0):Vector(len) {} BitVector(const Vector& source):Vector(source) {} BitVector(Vector& source):Vector(source) {} BitVector(const Vector& source1, const Vector source2):Vector(source1,source2) {} //@} /** Construct from a string of "0" and "1". */ BitVector(const char* valString); //@} /** Index a single bit. */ bool bit(size_t index) const { // We put this code in .h for fast inlining. const char *dp = mStart+index; assert(dp::segment(start,span)); } BitVector head(size_t span) { return segment(0,span); } const BitVector head(size_t span) const { return segment(0,span); } BitVector tail(size_t start) { return segment(start,size()-start); } const BitVector tail(size_t start) const { return segment(start,size()-start); } //@} void zero() { fill(0); } /**@name FEC operations. */ //@{ /** Calculate the syndrome of the vector with the given Generator. */ uint64_t syndrome(Generator& gen) const; /** Calculate the parity word for the vector with the given Generator. */ uint64_t parity(Generator& gen) const; /** Encode the signal with the GSM rate 1/2 convolutional encoder. */ void encode(const ViterbiR2O4& encoder, BitVector& target); //@} /** Invert 0<->1. */ void invert(); /**@name Byte-wise operations. */ //@{ /** Reverse an 8-bit vector. */ void reverse8(); /** Reverse groups of 8 within the vector (byte reversal). */ void LSB8MSB(); //@} /**@name Serialization and deserialization. */ //@{ uint64_t peekField(size_t readIndex, unsigned length) const; uint64_t peekFieldReversed(size_t readIndex, unsigned length) const; uint64_t readField(size_t& readIndex, unsigned length) const; uint64_t readFieldReversed(size_t& readIndex, unsigned length) const; void fillField(size_t writeIndex, uint64_t value, unsigned length); void fillFieldReversed(size_t writeIndex, uint64_t value, unsigned length); void writeField(size_t& writeIndex, uint64_t value, unsigned length); void writeFieldReversed(size_t& writeIndex, uint64_t value, unsigned length); void write0(size_t& writeIndex) { writeField(writeIndex,0,1); } void write1(size_t& writeIndex) { writeField(writeIndex,1,1); } //@} /** Sum of bits. */ unsigned sum() const; /** Reorder bits, dest[i] = this[map[i]]. */ void map(const unsigned *map, size_t mapSize, BitVector& dest) const; /** Reorder bits, dest[map[i]] = this[i]. */ void unmap(const unsigned *map, size_t mapSize, BitVector& dest) const; /** Pack into a char array. */ void pack(unsigned char*) const; /** Unpack from a char array. */ void unpack(const unsigned char*); /** Make a hexdump string. */ void hex(std::ostream&) const; std::string hexstr() const; /** Unpack from a hexdump string. * @returns true on success, false on error. */ bool unhex(const char*); void set(BitVector other) // That's right. No ampersand. { clear(); mData=other.mData; mStart=other.mStart; mEnd=other.mEnd; other.mData=NULL; } void settfb(int i, int j) const { mStart[i] = j; } }; std::ostream& operator<<(std::ostream&, const BitVector&); /** The SoftVector class is used to represent a soft-decision signal. Values 0..1 represent probabilities that a bit is "true". */ class SoftVector: public Vector { public: /** Build a SoftVector of a given length. */ SoftVector(size_t wSize=0):Vector(wSize) {} /** Construct a SoftVector from a C string of "0", "1", and "X". */ SoftVector(const char* valString); /** Construct a SoftVector from a BitVector. */ SoftVector(const BitVector& source); /** Wrap a SoftVector around a block of floats. The block will be delete[]ed upon desctuction. */ SoftVector(float *wData, unsigned length) :Vector(wData,length) {} SoftVector(float* wData, float* wStart, float* wEnd) :Vector(wData,wStart,wEnd) { } /** Casting from a Vector. Note that this is NOT pass-by-reference. */ SoftVector(Vector source) :Vector(source) {} /**@name Casts and overrides of Vector operators. */ //@{ SoftVector segment(size_t start, size_t span) { float* wStart = mStart + start; float* wEnd = wStart + span; assert(wEnd<=mEnd); return SoftVector(NULL,wStart,wEnd); } SoftVector alias() { return segment(0,size()); } const SoftVector segment(size_t start, size_t span) const { return (SoftVector)(Vector::segment(start,span)); } SoftVector head(size_t span) { return segment(0,span); } const SoftVector head(size_t span) const { return segment(0,span); } SoftVector tail(size_t start) { return segment(start,size()-start); } const SoftVector tail(size_t start) const { return segment(start,size()-start); } //@} /** Decode soft symbols with the GSM rate-1/2 Viterbi decoder. */ void decode(ViterbiR2O4 &decoder, BitVector& target) const; // (pat) How good is the SoftVector in the sense of the bits being solid? // Result of 1 is perfect and 0 means all the bits were 0.5 // If plow is non-NULL, also return the lowest energy bit. float getEnergy(float *low=0) const; /** Fill with "unknown" values. */ void unknown() { fill(0.5F); } /** Return a hard bit value from a given index by slicing. */ bool bit(size_t index) const { const float *dp = mStart+index; assert(dp0.5F; } /** Slice the whole signal into bits. */ BitVector sliced() const; }; std::ostream& operator<<(std::ostream&, const SoftVector&); #endif // vim: ts=4 sw=4