void rateMatchFunc(BitVector &in,BitVector &out, int eini) { int nin = in.size(); int nout = out.size(); if (nout == nin) { in.copyTo(out); return; } int eplus = 2 * nin; // eplus = a * Ni,j int eminus = 2 * (nout - nin); // eminus = a * abs(deltaNi,j) if (eminus < 0) { eminus = - eminus; } float e = eini; int m; // index of current bit, except zero-based as opposed to spec that is 1 based. char *inp = in.begin(); // cheating just a bit for efficiency. char *outp = out.begin(); char *outend = out.end(); if (nout < nin) { // Puncture bits as necessary. // Note from spec: loop termination Xi == Xij == number of bits before rate matching == nin. for (m=0; m < nin && outp < outend; m++) { e = e - eminus; if (e <= 0) { e = e + eplus; continue; // skip the bit. } *outp++ = inp[m]; } } else { // Repeat bits as necessary. for (m=0; m < nin && outp < outend; m++) { e = e - eminus; while (e <= 0) { if (outp >= outend) goto failed; *outp++ = inp[m]; // repeat the bit. e = e + eplus; } *outp++ = inp[m]; } } if (m != nin || outp != outend) { failed: LOG(ERR) << "rate matching mis-calculation, results:" <<LOGVAR(nin)<<LOGVAR(m)<<LOGVAR(nout)<<LOGVAR2(outp,outp-out.begin()) <<LOGVAR(e)<<LOGVAR(eplus)<<LOGVAR(eminus)<<LOGVAR(eini); } }
void TCHFACCHL1Encoder::dispatch() { // No downstream? That's a problem. assert(mDownstream); // Get right with the system clock. resync(); // If the channel is not active, wait for a multiframe and return. // Most channels do not need this, becuase they are entirely data-driven // from above. TCH/FACCH, however, must feed the interleaver on time. if (!active()) { mNextWriteTime += 26; gBTS.clock().wait(mNextWriteTime); return; } // Let previous data get transmitted. resync(); waitToSend(); // flag to control stealing bits bool currentFACCH = false; // Speech latency control. // Since Asterisk is local, latency should be small. OBJLOG(DEBUG) <<"TCHFACCHL1Encoder speechQ.size=" << mSpeechQ.size(); int maxQ = gConfig.getNum("GSM.MaxSpeechLatency"); while (mSpeechQ.size() > maxQ) delete mSpeechQ.read(); // Send, by priority: (1) FACCH, (2) TCH, (3) filler. if (L2Frame *fFrame = mL2Q.readNoBlock()) { OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder FACCH " << *fFrame; currentFACCH = true; // Copy the L2 frame into u[] for processing. // GSM 05.03 4.1.1. fFrame->LSB8MSB(); fFrame->copyTo(mU); // Encode u[] to c[], GSM 05.03 4.1.2 and 4.1.3. encode(); delete fFrame; OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder FACCH c[]=" << mC; // Flush the vocoder FIFO to limit latency. while (mSpeechQ.size()>0) delete mSpeechQ.read(); } else if (VocoderFrame *tFrame = mSpeechQ.readNoBlock()) { OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder TCH " << *tFrame; // Encode the speech frame into c[] as per GSM 05.03 3.1.2. encodeTCH(*tFrame); delete tFrame; OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder TCH c[]=" << mC; } else { // We have no ready data but must send SOMETHING. // This filler pattern was captured from a Nokia 3310, BTW. static const BitVector fillerC("110100001000111100000000111001111101011100111101001111000000000000110111101111111110100110101010101010101010101010101010101010101010010000110000000000000000000000000000000000000000001101001111000000000000000000000000000000000000000000000000111010011010101010101010101010101010101010101010101001000011000000000000000000110100111100000000111001111101101000001100001101001111000000000000000000011001100000000000000000000000000000000000000000000000000000000001"); fillerC.copyTo(mC); OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder filler FACCH=" << currentFACCH << " c[]=" << mC; } // Interleave c[] to i[]. LOG(INFO)<<"TCH START INTERLEAVE"; interleave(mOffset); LOG(INFO)<<"TCH START ENCRYPT"; encrypt(); LOG(INFO)<<"TCH START ENCRYPTed"; // "mapping on a burst" // Map c[] into outgoing normal bursts, marking stealing flags as needed. // GMS 05.03 3.1.4. ////////////////////////////////////////////////////////////////////////////////////////////////// /*for (int B=0; B<4; B++) { // set TDMA position mBurst.time(mNextWriteTime); // copy in the bits mI[B+mOffset].segment(0,57).copyToSegment(mBurst,3); mI[B+mOffset].segment(57,57).copyToSegment(mBurst,88); // stealing bits mBurst.Hu(currentFACCH); mBurst.Hl(mPreviousFACCH); // send OBJLOG(DEEPDEBUG) <<"TCHFACCHEncoder sending burst=" << mBurst; mDownstream->writeHighSide(mBurst); rollForward(); } */ for (int B=0; B<8; B++) { // set TDMA position mBurst.time(mNextWriteTime); // copy in the bits mE[B].segment(0,57).copyToSegment(mBurst,3); mE[B].segment(57,57).copyToSegment(mBurst,88); LOG(INFO) <<"TCHFACCHL1Decoder COPYTOSEGMENT"; // stealing bits mBurst.Hu(currentFACCH); mBurst.Hl(mPreviousFACCH); // send OBJLOG(DEEPDEBUG) <<"TCHFACCHEncoder sending burst=" << mBurst; mDownstream->writeHighSide(mBurst); rollForward(); } // Updaet the offset for the next transmission. if (mOffset==0) mOffset=4; else mOffset=0; // Save the stealing flag. mPreviousFACCH = currentFACCH; }