void PDCHL1Downlink::mchResync() { // If the encoder's clock is far from the current BTS clock, // get it caught up to something reasonable. Time now = gBTS.time(); int32_t delta = mchNextWriteTime-now; GPRSLOG(8) << "PDCHL1Downlink" <<LOGVAR(mchNextWriteTime) <<LOGVAR(now)<< LOGVAR(delta); if ((delta<0) || (delta>(51*26))) { mchNextWriteTime = now; //mchNextWriteTime.TN(now.TN()); // unneeded? mchNextWriteTime.rollForward(mchMapping.frameMapping(mchTotalBursts),mchMapping.repeatLength()); GPRSLOG(2) <<"PDCHL1Downlink RESYNC" << LOGVAR(mchNextWriteTime) << LOGVAR(now); } }
void PDCHL1Downlink::bugFixIdleFrame() { // DEBUG: We are only using this function to fix this problem for now. if (gFixIdleFrame) { // For this debug purpose, the mssage is sent on the next frame // TODO: debug purpose only! This only works for one channel! //Time tnext(gBSNNext.FN()); //gBTS.clock().wait(tnext); } // Did we make it in time? { Time tnow = gBTS.time(); int fn = tnow.FN(); int mfn = (fn / 13); // how many 13-multiframes int rem = (fn - (mfn*13)); // how many blocks within the last multiframe. int tbsn = mfn * 3 + ((rem==12) ? 2 : (rem/4)); GPRSLOG(2) <<"idleframe"<<LOGVAR(fn)<<LOGVAR(tbsn)<<LOGVAR(rem); } /*** if (mchIdleFrame.size() == 0) { RLCMsgPacketDownlinkDummyControlBlock *dummymsg = new RLCMsgPacketDownlinkDummyControlBlock(); mchIdleFrame.set(BitVector(RLCBlockSizeInBits[ChannelCodingCS1])); dummymsg->write(mchIdleFrame); delete dummymsg; } send1Frame(mchIdleFrame,ChannelCodingCS1,true); ***/ }
void BSSGWriteLowSide(NSMsg *ulmsg) { if (gBSSG.mbsTestQ) { // For testing, deliver messages to this queue instead: gBSSG.mbsTestQ->write(ulmsg); } else { GPRSLOG(1) << "BSSG ===> writelowside " <<ulmsg->str()<<timestr(); gBSSG.mbsTxQ.write(ulmsg); // normal mode; block is headed for the SGSN. } }
void PDCHL1FEC::mchStart() { getRadio()->setSlot(TN(),Transceiver::IGPRS); // Load up the GPRS filler idle burst tables in the transceiver. // We could use any consecutive bsn, but lets use ones around the current time // just to make sure they get through in case someone is triaging somewhere. // Sending all 12 blocks is 2x overkill because the modulus in Transceiver::setModulus // for type IGPRS is set the same as type I which is only 26, not 52. RLCBSN_t bsn = FrameNumber2BSN(gBTS.time().FN()) + 1; for (int i = 0; i < 12; i++, bsn = bsn + 1) { GPRSLOG(1) <<"sendIdleFrame"<<LOGVAR2("TN",TN())<<LOGVAR(bsn)<<LOGVAR(i); mchDownlink->sendIdleFrame(bsn); } mchOldFec->setGPRS(true,this); debug_test(); }
static int opensock(uint32_t sgsnIp, int sgsnPort /*,int bssgPort*/ ) { //int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sockfd < 0) { LOG(ERR) << "Could not create socket for BSSGP"; return -1; } /****** { // We dont want to bind here. connect will pick a port for us. int32_t bssgIp = INADDR_ANY; struct sockaddr_in myAddr; memset(&myAddr,0,sizeof(myAddr)); // be safe. myAddr.sin_family = AF_INET; myAddr.sin_addr.s_addr = htonl(bssgIp); myAddr.sin_port = htons(bssgPort); if (0 != bind(sockfd,(sockaddr*)&myAddr,sizeof(myAddr))) { LOG(ERR) << "Could not bind NS socket to" << LOGVAR(bssgIp) << LOGVAR(bssgPort) << LOGVAR(errno); close(sockfd); return -1; } } ****/ struct sockaddr_in sgsnAddr; memset(&sgsnAddr,0,sizeof(sgsnAddr)); sgsnAddr.sin_family = AF_INET; sgsnAddr.sin_addr.s_addr = sgsnIp; // This is already in network order. sgsnAddr.sin_port = htons(sgsnPort); if (0 != connect(sockfd,(sockaddr*)&sgsnAddr,sizeof(sgsnAddr))) { LOG(ERR) << "Could not connect NS socket to" << LOGVAR(sgsnIp) << LOGVAR(sgsnPort) << LOGVAR(errno); close(sockfd); return -1; } else { GPRSLOG(1) << "connected to SGSN at "<< inet_ntoa(sgsnAddr.sin_addr) <<" port "<<sgsnPort; } return sockfd; }
// OLD: Send this loop an NS_BLOCK message to kill this thread off; // and we dont normally use that NS message. // There is a BSSG-level BVC_BLOCK message that we would use to do a temporary data block. void *sendServiceLoop(void *arg) { BSSGMain *bssgp = (BSSGMain*)arg; NSPDUType::type nstype = NSPDUType::NS_RESET; // init to anything. do { NSMsg *ulmsg = bssgp->mbsTxQ.read(); // It is already wrapped up in an NS protocol. int msgsize = ulmsg->size(); ssize_t result = send(bssgp->mbsSGSockfd,ulmsg->begin(),msgsize,0); nstype = ulmsg->getNSPDUType(); int debug_level = 1; //(nstype == NSPDUType::NS_UNITDATA) ? 1 : 4; if (GPRS::GPRSDebug & debug_level) { GPRSLOG(debug_level) << "BSSG ===> sendServiceLoop sent " <<nstype<<LOGVAR(msgsize)<<ulmsg->str()<<timestr(); } if (result != msgsize) { LOG(ERR) << "BSSGP invalid send result" << LOGVAR(result) << LOGVAR(msgsize); } delete ulmsg; } while (bssgp->mbsIsOpen /*&& nstype != NSPDUType::NS_BLOCK*/); return NULL; }
bool BSSGMain::BSSGReset() { // BSSG starts out blocked until it receives a reset. mbsBlocked = true; mbsResetReceived = false; mbsResetAckReceived = false; // Start communication with SGSN. // Initiate NS Reset procedure: GSM 08.16 7.3 // We are supposed to send NS_STATUS, but it doesnt matter with our sgsn. BSSGWriteLowSide(NsFactory(NSPDUType::NS_RESET)); BSSGWriteLowSide(NsFactory(NSPDUType::NS_UNBLOCK)); // Wait a bit for the sgsn to respond. // Note: The first time we talk to the SGSN it sends us an NS_RESET, // but if OpenBTS crashes, the second time it inits it doesnt send NS_RESET, // which may be a bug in the SGSN, but in any event we dont want // to wait for a RESET msg. for (int i = 0; 1; i++) { if (mbsResetAckReceived && !mbsBlocked) { break; } Utils::sleepf(0.1); if (i >= 40) { // wait 4 seconds GPRSLOG(1) << LOGVAR(mbsResetReceived) <<LOGVAR(mbsResetAckReceived) <<LOGVAR(mbsBlocked); LOG(INFO) << "SGSN failed to respond\n"; return false; } } // GSM 08.18 8.4: Reset the BVC. You must do this after verifying NS layer is working. // Must reset each BVCI separately. // I'm not going to bother to check for acks - if the NS protocol inited, // the sgsn is fine and this will init ok too. BSSGWriteLowSide(BVCFactory(BSPDUType::BVC_RESET,BVCI::SIGNALLING)); BSSGWriteLowSide(BVCFactory(BSPDUType::BVC_RESET,gBSSG.mbsBVCI)); return true; }
void NsRecvMsg(unsigned char *data, int nsize) { NSPDUType::type nstype = (NSPDUType::type) data[0]; // We dont need to see all the keep alive messages. if (nstype != NSPDUType::NS_UNITDATA) { GPRSLOG(4) << "BSSG NsRecvMsg "<<nstype<<LOGVAR(nsize); } switch (nstype) { case NSPDUType::NS_UNITDATA: { int bvci = getntohs(&data[2]); if (bvci == BVCI::SIGNALLING) { GPRSLOG(4) << "BSSG <=== signalling "<<nstype<<LOGVAR(nsize) <<timestr(); BsRecvSignallingMsg(data, nsize); } else if (bvci == BVCI::PTM) { GPRSLOG(4) << "BSSG <=== "<<nstype<<LOGVAR(nsize)<<" ignored" <<timestr(); // Not implemented } else { // Send data to the MAC // We left the NS header intact. BSSGDownlinkMsg *dlmsg = new BSSGDownlinkMsg(data,nsize); //GPRSLOG(1) << "BSSG <=== queued "<<dlmsg->str() <<timestr(); GPRSLOG(1) << "BSSG <=== queued size="<<dlmsg->size() <<timestr(); gBSSG.mbsRxQ.write(dlmsg); } break; } case NSPDUType::NS_RESET: gBSSG.mbsResetReceived = true; BSSGWriteLowSide(NsFactory(NSPDUType::NS_RESET_ACK)); break; case NSPDUType::NS_RESET_ACK: gBSSG.mbsResetAckReceived = true; break; case NSPDUType::NS_BLOCK: gBSSG.mbsBlocked = true; BSSGWriteLowSide(NsFactory(NSPDUType::NS_BLOCK_ACK)); break; case NSPDUType::NS_BLOCK_ACK: // ignored. break; case NSPDUType::NS_UNBLOCK: gBSSG.mbsBlocked = false; BSSGWriteLowSide(NsFactory(NSPDUType::NS_UNBLOCK_ACK)); break; case NSPDUType::NS_UNBLOCK_ACK: gBSSG.mbsBlocked = false; // ignored. break; case NSPDUType::NS_STATUS: // This happens when the sgsn is stopped and restarted. // It probably happens for other reasons too, but lets just // assume that is what happened and reset the BSSG link. gBSSG.BSSGReset(); break; case NSPDUType::NS_ALIVE: gBSSG.mbsAliveReceived = true; BSSGWriteLowSide(NsFactory(NSPDUType::NS_ALIVE_ACK)); break; case NSPDUType::NS_ALIVE_ACK: gBSSG.mbsAliveAckReceived = true; break; default: LOG(INFO) << "unrecognized NS message received, type "<<nstype; break; } }
// Dispatch an RLC block on this downlink. // This must run once for every Radio Block (4 TDMA frames or so) sent. // It should be kept only as far enough ahead of the physical layer so that it never stalls. // Based on: TCHFACCHL1Encoder::dispatch() void PDCHL1Downlink::dlService() { // Get right with the system clock. // NO: mchResync(); static int debugCntTotal = 0, debugCntDummy = 0; debugCntTotal++; if ((GPRSDebug&512) || debugCntTotal % 1024 == 0) { GPRSLOG(2) << "dlService sent total="<<debugCntTotal<<" dummy="<<debugCntDummy <<" "<<this->parent(); } // If gFixIdleFrame only send blocks on the even BSNs, // and send idle frames on the odd BSNs, to make SURE that the // RRBP and USF fields are cleared. // This means that only the odd uplink BSNs will be used for uplink data. // I also modified makeReservationInt to make the RRBP uplink reservations // only on even frames, since they will be clear of data, but // that is overkill for debugging. // For reservations all we care is that the downlink RRBP field // occurs only on even frames - // the associated uplink block will be 3-7 blocks downtime from that, // so could land on either even or odd frames. if (gFixIdleFrame && (gBSNNext & 1)) { return; } // I think we have to check active because the radio can get turned on/off // completely without our knowledge. // If this happens, the TBFs will expire, so we should probably destroy // the entire GPRS machinery and start over when we get turned back on. //if (! active()) { // mNextWriteTime += 52; // Wait for a PCH multiframe. // gBTS.clock().wait(mNextWriteTime); // return; //} // Look for a data block to send. // We did not queue these up in advance because the data that the engine // wants to send may change every time it receives an ack/nack message. //TBFList_t &list = gL2MAC.macTBFs; //TBFList_t::iterator itr = list.begin(), e = list.end(); //for ( ; itr != e; itr++) { //TBF *tbf = *itr; TBF *tbf; TBFList_t::iterator itr; for (RListIterator<TBF*> itrl(gL2MAC.macTBFs); itrl.next(tbf,itr); ) { if (!tbf->canUseDownlink(this)) { GPRSLOG(4) <<"dlService"<<tbf<<" state "<<tbf->mtGetState() <<" reqch:"<<tbf->mtMS->msPacch << " can not use downlink:"<<this->parent(); continue; } TBFState::type oldstate = tbf->mtGetState(); if (tbf->mtServiceDownlink(this)) { GPRSLOG(2) <<"dlService"<<tbf<<LOGVAR(oldstate)<<" state="<<tbf->mtGetState() <<" reqch:"<<tbf->mtMS->msPacch <<" using ch:"<<this->parent(); // Move this tbf to end of the list so we may service someone else next time. // TODO: If the tbf is using extended dynamic uplink, all ganged // uplink channels are reserved at once, and so we are not sharing // the other ganged uplinks with other TBFs that want to use them unless // those TBFs also share this channel. gL2MAC.macTBFs.erase(itr); gL2MAC.macTBFs.push_back(tbf); if (gFixIdleFrame) { bugFixIdleFrame(); } return; } } // If nothing else, send a dummy message. // We have to allocate it because we allocate all messages. // Note that this message will have the MAC header fields USF and RRBP set by send1MsgFrame. RLCMsgPacketDownlinkDummyControlBlock *dummymsg = new RLCMsgPacketDownlinkDummyControlBlock(); send1MsgFrame(NULL,dummymsg,0,MsgTransNone,NULL); debugCntDummy++; if (gFixIdleFrame) { bugFixIdleFrame(); } }
// WARNING: This func runs in a separate thread. void PDCHL1Uplink::writeLowSideRx(const RxBurst &inBurst) { float low, avg = inBurst.getEnergy(&low); //if (avg > 0.7) { OBJLOG(DEBUG) << "PDCHL1Uplink " << inBurst; } //ScopedLock lock(testlock); int burstfn = inBurst.time().FN(); int mfn = (burstfn / 13); // how many 13-multiframes int rem = (burstfn - (mfn*13)); // how many blocks within the last multiframe. int B = rem % 4; if (avg > 0.5) { GPRSLOG(256) << "FEC:"<<LOGVAR(B)<<" "<<inBurst<<LOGVAR(avg); } ChannelCodingType cc; BitVector *result = decodeLowSide(inBurst,B,mchCS14Dec,&cc); if (B == 3) { int burst_fn=burstfn-3; // First fn in rlc block. RLCBSN_t bsn = FrameNumber2BSN(burst_fn); if (GPRSDebug) { PDCHL1FEC *pdch = parent(); short *qbits = mchCS14Dec.qbits; BitVector cshead(mchCS14Dec.mC.head(12).sliced()); RLCBlockReservation *res = mchParent->getReservation(bsn); int thisUsf = pdch->getUsf(bsn-2); // If we miss a reservation or usf, print it: int missedRes = avg>0.4 && !result && (res||thisUsf); if (missedRes || (GPRSDebug & (result?4:256))) { std::ostringstream ss; char buf[30]; ss <<"writeLowSideRx "<<parent() <<(result?" === good" : "=== bad") << (res?" res:" : "") <<(res ? res->str() : "") //<<LOGVAR(cshead) //<<LOGVAR2("cs",(int)mchCS14Dec.getCS()) <<LOGVAR(cc) <<LOGVAR2("revusf",decodeUSF(mchCS14Dec.mC)) <<LOGVAR(burst_fn)<<LOGVAR(bsn) <<LOGVAR2("RSSI",inBurst.RSSI()) <<LOGVAR2("TE",inBurst.timingError()) // But lets print out the USFs bracketing this on either side. <<getAnsweringUsfText(buf,bsn) //<<" AnsweringUsf="<<pdch->getUsf(bsn-2)<<" "<<pdch->getUsf(bsn-1) //<<" ["<<pdch->getUsf(bsn)<<"] "<<pdch->getUsf(bsn+1)<<" "<<pdch->getUsf(bsn+2) <<" qbits="<<qbits[0]<<qbits[1]<<qbits[2]<<qbits[3] <<qbits[4]<<qbits[5]<<qbits[6]<<qbits[7] <<LOGVAR(low)<<LOGVAR(avg) ; if (missedRes) { for (int i = 0; i < 4; i++) { // There was an unanswered reservation or usf. avg = mchCS14Dec.mI[i].getEnergy(&low); GPRSLOG(1) << "energy["<<i<<"]:"<<LOGVAR(avg)<<LOGVAR(low)<<" " <<mchCS14Dec.mI[i]; } } GLOG(DEBUG)<<ss.str(); // Make sure we see a decoder failure if it reoccurs. if (missedRes) std::cout <<ss.str() <<"\n"; } } // if GPRSDebug if (result) { // Check clock skew for debugging purposes. static int cnt = 0; if (bsn >= gBSNNext-1) { if (cnt++ % 32 == 0) { GLOG(ERR) << "Incoming burst at frame:"<<burst_fn <<" is not sufficiently ahead of clock:"<<gBSNNext.FN(); if (GPRSDebug) { std::cout << "Incoming burst at frame:"<<burst_fn <<" is not sufficiently ahead of clock:"<<gBSNNext.FN()<<"\n"; } } } countGoodFrame(); // The four frame radio block has been decoded and is in mD. if (gConfig.getBool("Control.GSMTAP.GPRS")) { // Send to GSMTAP. Untested. gWriteGSMTAP(ARFCN(),TN(),gBSNNext.FN(), //GSM::TDMA_PACCH, frame2GsmTapType(*result), false, // not SACCH true, // this is an uplink. *result); // The data. } mchUplinkData.write(new RLCRawBlock(bsn,*result,inBurst.RSSI(),inBurst.timingError(),cc)); } else { countBadFrame(); } } else { // We dont have a full 4 bursts yet, and we rarely care about these // intermediate results, but here is a way to see them: GPRSLOG(64) <<"writeLowSideRx "<<parent()<<LOGVAR(burstfn)<<LOGVAR(B) <<" RSSI=" <<inBurst.RSSI() << " timing=" << inBurst.timingError(); } }
// Return true if we send a block on the downlink. bool PDCHL1Downlink::send1MsgFrame( TBF *tbf, // The TBF sending the message, or NULL for an idle frame. RLCDownlinkMessage *msg, // The message. int makeres, // 0 = no res, 1 = optional res, 2 = required res. MsgTransactionType mttype, // Type of reservation unsigned *pcounter) // If non-null, incremented if a reservation is made. { if (! setMACFields(msg,mchParent,msg->mTBF,makeres,mttype,pcounter)) { delete msg; // oh well. return false; // This allows some other tbf to try to use this downlink block. } bool dummy = msg->mMessageType == RLCDownlinkMessage::PacketDownlinkDummyControlBlock; bool idle = dummy && msg->isMacUnused(); if (idle && 0 == gConfig.getNum("GPRS.SendIdleFrames")) { delete msg; // Let the transceiver send an idle frame. return false; // This return value will not be checked. } if (tbf) { tbf->talkedDown(); } // Convert to a BitVector. Messages always use CS-1 encoding. BitVector tobits(RLCBlockSizeInBits[ChannelCodingCS1]); msg->write(tobits); // The possible downlink debug things we want to see are: // 2: Only non-dummy messages. // 32: include messages with non-idle MAC header, means mUSF or mSP. // 1024: all messages including dummy ones. if (GPRSDebug) { if ((!dummy && (GPRSDebug&2)) || (!idle && (GPRSDebug&32)) || (GPRSDebug&1024)) { ByteVector content(tobits); GPRSLOG(2|32|1024) << "send1MsgFrame "<<parent() <<" "<<msg->mTBF<< " "<<msg->str() << " " <<LOGVAR2("content",content); // The res is unrelated to the message, and confusing, so dont print it: //<<" "<<(res ? res->str() : ""); } } #if 0 // The below is what went out in release 3.0: if (GPRSDebug & (1|32)) { //RLCBlockReservation *res = mchParent->getReservation(gBSNNext); //std::ostringstream ssres; //if (res) ssres << res; if (! idle || (GPRSDebug & 1024)) { //ostringstream bits; //tobits.hex(bits); //GPRSLOG(1) << "send1MsgFrame "<<msg->mTBF<< " "<<msg->str() << "\nbits:"<<tobits.hexstr(); ByteVector content(tobits); GPRSLOG(1) << "send1MsgFrame "<<parent()<<" "<<msg->mTBF<< " "<<msg->str() <<" " << LOGVAR2("content",content); // This res is unrelated to the message, and confusing, so dont print it: //<<" "<<(res ? res->str() : ""); } else if (msg->mUSF) { GPRSLOG(32) << "send1MsgFrame "<<parent()<<" "<<msg->mTBF<< " "<<msg->str() <<" "; //<<" "<<(res ? res->str() : ""); } } #endif delete msg; send1Frame(tobits,ChannelCodingCS1,idle); return true; }
// Return true if we send a block on the downlink. bool PDCHL1Downlink::send1DataFrame( //SVGDBG RLCDownEngine *engdown, RLCDownlinkDataBlock *block, // block to send. int makeres, // 0 = no res, 1 = optional res, 2 = required res. MsgTransactionType mttype, // Type of reservation unsigned *pcounter) { //ScopedLock lock(testlock); TBF *tbf = engdown->getTBF(); if (! setMACFields(block,mchParent,tbf,makeres,mttype,pcounter)) { return false; } // The rest of the RLC header is already set, but we did not know the tfi // when we created the RLCDownlinkDataBlocks (because tbf not yet attached) // so set tfi now that we know. Update 8-2012: Above comment is stale because we // make the RLCDownlinkBlocks on the fly now. block->mTFI = tbf->mtTFI; // block->mPR = 1; // DEBUG test; made no diff. tbf->talkedDown(); BitVector tobits = block->getBitVector(); // tobits deallocated when this function exits. if (block->mChannelCoding == 0) { devassert(tobits.size() == 184); } if (GPRSDebug & 1) { RLCBlockReservation *res = mchParent->getReservation(gBSNNext); std::ostringstream sshdr; block->text(sshdr,false); //block->RLCDownlinkDataBlockHeader::text(sshdr); ByteVector content(tobits); GPRSLOG(1) << "send1DataFrame "<<parent()<<" "<<tbf<<LOGVAR(tbf->mtExpectedAckBSN) << " "<<sshdr.str() <<" "<<(res ? res->str() : "") << LOGVAR2("content",content); //<< " enc="<<tbf->mtChannelCoding <<" "<<os.str() << "\nbits:" <<bits.str(); //<<" " <<block->str() <<"\nbits:" <<tobits.hexstr(); } #if FEC_DEBUG BitVector copybits; copybits.clone(tobits); #endif send1Frame(tobits,block->mChannelCoding,0); #if FEC_DEBUG BitVector *result = debugDecoder.getResult(); devassert(result); devassert(copybits == tobits); if (result && !(*result == tobits)) { int diffbit = -1; char thing[500]; for (int i = 0; i < (int)result->size(); i++) { thing[i] = '-'; if (result->bit(i) != tobits.bit(i)) { if (diffbit == -1) diffbit = i; thing[i] = '0' + result->bit(i); } } thing[result->size()] = 0; GPRSLOG(1) <<"encoding error" <<LOGVAR2("cs",(int)debugDecoder.getCS()) <<LOGVAR(diffbit) <<LOGVAR2("in:size",tobits.size()) <<LOGVAR2("out:size",result->size()) <<"\n"<<tobits <<"\n"<<*result <<"\n"<<thing; } else { //GPRSLOG(1) <<"encoding ok" <<LOGVAR2("cs",(int)debugDecoder.getCS()); } #endif return true; }