/* * Copyright 2008, 2009, 2014 Free Software Foundation, Inc. * Copyright 2014 Range Networks, Inc. * * 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 . * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. */ #ifndef BITVECTORS_H #define BITVECTORS_H #include "Vector.h" #include #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); }; // (pat) Nov 2013. I rationalized the behavior of BitVector and added assertions to core dump code // that relied on the bad aspects of the original behavior. See comments at VectorBase. class BitVector : public VectorBase { public: /**@name Constructors. */ //@{ /**@name Casts of Vector constructors. */ BitVector(VectorDataType wData, char* wStart, char* wEnd) : VectorBase(wData, wStart, wEnd) {} // The one and only copy-constructor. BitVector(const BitVector&other) : VectorBase() { VECTORDEBUG("BitVector(%p)",(void*)&other); if (other.getData()) { this->clone(other); } else { this->makeAlias(other); } } // (pat) Removed default value for len and added 'explicit'. Please do not remove 'explicit'; // it prevents auto-conversion of int to BitVector in constructors. // Previous code was often ambiguous, especially for L3Frame and descendent constructors, leading to latent bugs. explicit BitVector(size_t len) { this->vInit(len); } BitVector() { this->vInit(0); } /** Build a BitVector by concatenation. */ BitVector(const BitVector& other1, const BitVector& other2) : VectorBase() { assert(this->getData() == 0); this->vConcat(other1,other2); } /** Construct from a string of "0" and "1". */ // (pat) Characters that are not '0' or '1' map to '0'. BitVector(const char* valString); //@} /**@name Casts and overrides of Vector operators. */ //@{ // (pat) Please DO NOT add a const anywhere in this method. Use cloneSegment instead. BitVector segment(size_t start, size_t span) { char* wStart = this->begin() + start; char* wEnd = wStart + span; assert(wEnd<=this->end()); #if BITVECTOR_REFCNTS return BitVector(mData,wStart,wEnd); #else return BitVector(NULL,wStart,wEnd); #endif } // (pat) Historically the BitVector segment method had const and non-const versions with different behavior. // I changed the name of the const version to cloneSegment and replaced all uses throughout OpenBTS. const BitVector cloneSegment(size_t start, size_t span) const { BitVector seg = const_cast(this)->segment(start,span); // (pat) We are depending on the Return Value Optimization not to invoke the copy-constructor on the result, // which would result in its immediate destruction while we are still using it. BitVector result; result.clone(seg); return result; } BitVector alias() const { return const_cast(this)->segment(0,size()); } BitVector head(size_t span) { return segment(0,span); } BitVector tail(size_t start) { return segment(start,size()-start); } // (pat) Please do NOT put the const version of head and tail back in, because historically they were messed up. // Use cloneSegment instead. //const BitVector head(size_t span) const { return segment(0,span); } //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; //@} /** 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; /* Roman: This is here for debugging */ void pack2(unsigned char*) const; // Same as pack but return a string. std::string packToString() 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*); // For this method, 'other' should have been run through the copy-constructor already // (unless it was newly created, ie foo.dup(L2Frame(...)), in which case we are screwed anyway) // so the call to makeAlias is redundant. // This only works if other is already an alias. void dup(BitVector other) { assert(!this->getData()); makeAlias(other); assert(this->mStart == other.mStart); } void dup(BitVector &other) { makeAlias(other); assert(this->mStart == other.mStart); } #if 0 void operator=(const BitVector& other) { printf("BitVector::operator=\n"); assert(0); //this->dup(other); } #endif bool operator==(const BitVector &other) const; /** Copy to dst, not including those indexed in puncture. */ void copyPunctured(BitVector &dst, const unsigned *puncture, const size_t plth); /** Index a single bit. */ // (pat) Cant have too many ways to do this, I guess. bool bit(size_t index) const { // We put this code in .h for fast inlining. const char *dp = this->begin()+index; assert(dpend()); return (*dp) & 0x01; } char& operator[](size_t index) { assert(this->mStart+indexmEnd); return this->mStart[index]; } const char& operator[](size_t index) const { assert(this->mStart+indexmEnd); return this->mStart[index]; } /** Set a bit */ void settfb(size_t index, int value) { char *dp = this->mStart+index; assert(dpmEnd); *dp = value; } typedef char* iterator; typedef const char* const_iterator; }; // (pat) BitVector2 was an intermediate step in fixing BitVector but is no longer needed. #define BitVector2 BitVector 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); } //@} // (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; float getSNR() 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; /** Copy to dst, adding in 0.5 for those indexed in puncture. */ void copyUnPunctured(SoftVector &dst, const unsigned *puncture, const size_t plth); /** Return a soft bit. */ float softbit(size_t index) const { const float *dp = mStart+index; assert(dp