aboutsummaryrefslogtreecommitdiffstats
path: root/lib/decoding/openbts/BitVector.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/decoding/openbts/BitVector.h')
-rw-r--r--lib/decoding/openbts/BitVector.h432
1 files changed, 432 insertions, 0 deletions
diff --git a/lib/decoding/openbts/BitVector.h b/lib/decoding/openbts/BitVector.h
new file mode 100644
index 0000000..c8782eb
--- /dev/null
+++ b/lib/decoding/openbts/BitVector.h
@@ -0,0 +1,432 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <stdint.h>
+#include <stdio.h>
+
+
+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<<wLen)-1),
+ mLen(wLen),mLen_1(wLen-1)
+ { assert(wLen<64); }
+
+ void clear() { mState=0; }
+
+ /**@name Accessors */
+ //@{
+ uint64_t state() const { return mState & mMask; }
+ unsigned size() const { return mLen; }
+ //@}
+
+ /**
+ Calculate one bit of a syndrome.
+ This is in the .h for inlining.
+ */
+ void syndromeShift(unsigned inBit)
+ {
+ const unsigned fb = (mState>>(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<char>
+{
+ public:
+ /**@name Constructors. */
+ //@{
+
+ /**@name Casts of Vector constructors. */
+ BitVector(VectorDataType wData, char* wStart, char* wEnd) : VectorBase<char>(wData, wStart, wEnd) {}
+
+ // The one and only copy-constructor.
+ BitVector(const BitVector&other) : VectorBase<char>() {
+ 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<char>()
+ {
+ 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<BitVector*>(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<BitVector*>(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(dp<this->end());
+ return (*dp) & 0x01;
+ }
+
+ char& operator[](size_t index)
+ {
+ assert(this->mStart+index<this->mEnd);
+ return this->mStart[index];
+ }
+
+ const char& operator[](size_t index) const
+ {
+ assert(this->mStart+index<this->mEnd);
+ return this->mStart[index];
+ }
+
+ /** Set a bit */
+ void settfb(size_t index, int value)
+ {
+ char *dp = this->mStart+index;
+ assert(dp<this->mEnd);
+ *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<float> {
+
+ public:
+
+ /** Build a SoftVector of a given length. */
+ SoftVector(size_t wSize=0):Vector<float>(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<float>(wData,length)
+ {}
+
+ SoftVector(float* wData, float* wStart, float* wEnd)
+ :Vector<float>(wData,wStart,wEnd)
+ { }
+
+ /**
+ Casting from a Vector<float>.
+ Note that this is NOT pass-by-reference.
+ */
+ SoftVector(Vector<float> source)
+ :Vector<float>(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<float>::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(dp<mEnd);
+ return (*dp)>0.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<mEnd);
+ return *dp;
+ }
+
+ /** Set a soft bit */
+ void settfb(size_t index, float value)
+ {
+ float *dp = mStart+index;
+ assert(dp<mEnd);
+ *dp = value;
+ }
+};
+
+
+
+std::ostream& operator<<(std::ostream&, const SoftVector&);
+
+
+
+
+#endif
+// vim: ts=4 sw=4