commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r10089 - in openbts/trunk: Control GSM SIP apps


From: dburgess00
Subject: [Commit-gnuradio] r10089 - in openbts/trunk: Control GSM SIP apps
Date: Sat, 29 Nov 2008 15:46:56 -0700 (MST)

Author: dburgess00
Date: 2008-11-29 15:46:56 -0700 (Sat, 29 Nov 2008)
New Revision: 10089

Added:
   openbts/trunk/Control/DCCHDispatch.cpp
Removed:
   openbts/trunk/Control/FACCHDispatch.cpp
   openbts/trunk/Control/SDCCHDispatch.cpp
Modified:
   openbts/trunk/Control/CallControl.cpp
   openbts/trunk/Control/ControlCommon.h
   openbts/trunk/Control/Makefile.am
   openbts/trunk/Control/MobilityManagement.cpp
   openbts/trunk/Control/PagerTest.cpp
   openbts/trunk/Control/RadioResource.cpp
   openbts/trunk/GSM/GSMCommon.cpp
   openbts/trunk/GSM/GSMCommon.h
   openbts/trunk/GSM/GSML2LAPDm.cpp
   openbts/trunk/GSM/GSML3Message.h
   openbts/trunk/GSM/GSML3RRElements.cpp
   openbts/trunk/GSM/GSML3RRElements.h
   openbts/trunk/GSM/GSML3RRMessages.cpp
   openbts/trunk/GSM/GSML3RRMessages.h
   openbts/trunk/SIP/SIPInterface.cpp
   openbts/trunk/apps/OpenBTS850.cpp
   openbts/trunk/apps/OpenBTS900.cpp
Log:
Support very early assignment for mobile-terminating calls.
Merge in from branches/developers/dburgess00/veryearly/, r10066:10088.
Includes fixes for #316, #327.


Modified: openbts/trunk/Control/CallControl.cpp
===================================================================
--- openbts/trunk/Control/CallControl.cpp       2008-11-29 06:27:41 UTC (rev 
10088)
+++ openbts/trunk/Control/CallControl.cpp       2008-11-29 22:46:56 UTC (rev 
10089)
@@ -456,15 +456,20 @@
 
 
 /**
-       This function starts MOC to the point of TCH assignment. 
+       This function starts MOC on the SDCCH to the point of TCH assignment. 
        @param req The CM Service Request that started all of this.
-       @param SDCCH The SDCCH used to initiate call setup.
+       @param LCH The logical used to initiate call setup.
 */
-void Control::MOCStarter(const L3CMServiceRequest* req, SDCCHLogicalChannel 
*SDCCH)
+void Control::MOCStarter(const L3CMServiceRequest* req, LogicalChannel *LCH)
 {
+       assert(LCH);
        assert(req);
        CLDCOUT("MOC: " << *req);
 
+       // Determine if very early assignment already happened.
+       bool veryEarly=false;
+       if (LCH->type()==FACCHType) veryEarly=true;
+
        // FIXME -- At this point, verify the that subscriber has access to 
this service.
        // If the subscriber isn't authorized, send a CM Service Reject with
        // cause code, 0x41, "requested service option not subscribed",
@@ -478,25 +483,28 @@
                // FIXME -- This is quick-and-dirty, not following GSM 04.08 5.
                CERR("WARNING -- (ControlLayer) MOC setup with no IMSI");
                // Cause 0x60 "Invalid mandatory information"
-               SDCCH->send(L3CMServiceReject(L3RejectCause(0x60)));
-               SDCCH->send(L3ChannelRelease());
+               LCH->send(L3CMServiceReject(L3RejectCause(0x60)));
+               LCH->send(L3ChannelRelease());
                // The SIP side and transaction record don't exist yet.
                // So we're done.
                return;
        }
 
-       // Allocate a TCH for the call.
-       TCHFACCHLogicalChannel *TCH = allocateTCH(SDCCH);
-       // It's OK to just return on failure; allocateTCH cleaned up already.
-       if (TCH==NULL) return;
+       // Allocate a TCH for the call, if we don't have it already.
+       TCHFACCHLogicalChannel *TCH = NULL;
+       if (!veryEarly) {
+               TCH = allocateTCH(dynamic_cast<SDCCHLogicalChannel*>(LCH));
+               // It's OK to just return on failure; allocateTCH cleaned up 
already.
+               if (TCH==NULL) return;
+       }
 
        // Let the phone know we're going ahead with the transaction.
        CLDCOUT("MOC: sending CMServiceAccept")
-       SDCCH->send(L3CMServiceAccept());
+       LCH->send(L3CMServiceAccept());
 
        // Get the Setup message.
        // GSM 04.08 5.2.1.2
-       const L3Setup *setup = dynamic_cast<const L3Setup*>(getMessage(SDCCH));
+       const L3Setup *setup = dynamic_cast<const L3Setup*>(getMessage(LCH));
        if (setup==NULL) throw UnexpectedMessage();
        CLDCOUT("MOC: " << *setup);
        // Pull out the L3 short transaction information now.
@@ -506,8 +514,8 @@
                // FIXME -- This is quick-and-dirty, not following GSM 04.08 5.
                CERR("WARNING -- (ControlLayer) MOC setup with no number");
                // Cause 0x60 "Invalid mandatory information"
-               SDCCH->send(L3ReleaseComplete(0,L3TI,L3Cause(0x60)));
-               SDCCH->send(L3ChannelRelease());
+               LCH->send(L3ReleaseComplete(0,L3TI,L3Cause(0x60)));
+               LCH->send(L3ChannelRelease());
                // The SIP side and transaction record don't exist yet.
                // So we're done.
                return;
@@ -527,16 +535,16 @@
                setup->calledPartyBCDNumber());
        transaction.SIP().User(IMSI);
        transaction.Q931State(TransactionEntry::MOCInitiated);
-       SDCCH->transactionID(transaction.ID());
-       TCH->transactionID(transaction.ID());
+       LCH->transactionID(transaction.ID());
+       if (!veryEarly) TCH->transactionID(transaction.ID());
        CLDCOUT("MOC: transaction: " << transaction);
        gTransactionTable.add(transaction);
 
        // At this point, we have enough information start the SIP call setup.
        // We have 2 seconds to repsond to the MS.  ITU-T Q.931 Table 9-1, T303.
 
-       // Now start a call by contacting asterisk. engine methods will return 
their 
-       // current state.       
+       // Now start a call by contacting asterisk.
+       // Engine methods will return their current state.      
        // The remote party will start ringing soon.
        CLDCOUT("MOC: starting SIP (INVITE) Calling "<<bcd_digits);
        unsigned basePort = allocateRTPPorts();
@@ -548,14 +556,30 @@
        delete setup;
 
        // The transaction is moving on to the MOCController.
+       // If we need a TCH assignment, we do it here.
        gTransactionTable.update(transaction);
        CLDCOUT("MOC: transaction: " << transaction);
-       // This call also opens the TCH.
-       assignTCHF(SDCCH,TCH);
+       if (veryEarly) {
+               // For very early assignment, we need a mode change.
+               static const L3ChannelMode mode(L3ChannelMode::SpeechV1);
+               LCH->send(L3ChannelModeModify(LCH->channelDescription(),mode));
+               const L3ChannelModeModifyAcknowledge *ack =
+                       
dynamic_cast<L3ChannelModeModifyAcknowledge*>(getMessage(LCH));
+               if (!ack) throw UnexpectedMessage();
+               // Cause 0x06 is "channel unacceptable"
+               if (ack->mode() != mode) return 
abortCall(transaction,LCH,L3Cause(0x06));
+               
MOCController(transaction,dynamic_cast<TCHFACCHLogicalChannel*>(LCH));
+       } else {
+               // For late assignment, send the TCH assignment now.
+               // This dispatcher on the next channel will continue the 
transaction.
+               assignTCHF(dynamic_cast<SDCCHLogicalChannel*>(LCH),TCH);
+       }
 }
 
 
 
+
+
 /**
        Continue MOC process on the TCH.
        @param transaction The call state and SIP interface.
@@ -565,6 +589,7 @@
 {
        CLDCOUT("MOC: transaction: " << transaction);
        unsigned L3TI = transaction.TIValue();
+       assert(TCH);
 
        // Once we can start SIP call setup, send Call Proceeding.
        CLDCOUT("MOC: Sending Call Proceeding ");
@@ -682,16 +707,24 @@
 
 
 
-void Control::MTCStarter(const L3PagingResponse *resp, 
-                                               SDCCHLogicalChannel *SDCCH)
+void Control::MTCStarter(const L3PagingResponse *resp, LogicalChannel *LCH)
 {
        assert(resp);
-       CLDCOUT("MTC: " << *resp);
+       assert(LCH);
+       CLDCOUT("MTC on " << LCH->type() << ": " << *resp);
 
+       // Determine if very early assigment already happened.
+       bool veryEarly = false;
+       if (LCH->type()==FACCHType) veryEarly=true;
+
        // Allocate a TCH for the call.
-       TCHFACCHLogicalChannel *TCH = allocateTCH(SDCCH);
-       // The orphaned transaction will be cleared at the next findByMobileID 
call.
-       if (TCH==NULL) return;
+       TCHFACCHLogicalChannel *TCH = NULL;
+       if (!veryEarly) {
+               TCH = allocateTCH(dynamic_cast<SDCCHLogicalChannel*>(LCH));
+               // It's OK to just return on failure; allocateTCH cleaned up 
already.
+               // The orphaned transaction will be cleared at the next 
findByMobileID call.
+               if (TCH==NULL) return;
+       }
 
        // Find the transction table entry that was created when the phone was 
paged.
        CLDCOUT("MTC: find TransactionEntry for " << resp->mobileIdentity());
@@ -701,13 +734,13 @@
                return;
        }
        CLDCOUT("MTC: transaction: "<< transaction);
-       TCH->transactionID(transaction.ID());   
-       SDCCH->transactionID(transaction.ID()); 
+       if (!veryEarly) TCH->transactionID(transaction.ID());   
+       LCH->transactionID(transaction.ID());   
        unsigned L3TI = transaction.TIValue();
 
        // GSM 04.08 5.2.2.1
        CLDCOUT("MTC: sending GSM Setup");
-       SDCCH->send(L3Setup(0,L3TI));
+       LCH->send(L3Setup(0,L3TI));
        transaction.T303().set();
        transaction.Q931State(TransactionEntry::CallPresent);
 
@@ -715,31 +748,47 @@
        CLDCOUT("MTC: wait for GSM Call Confirmed")
        while (transaction.Q931State()!=TransactionEntry::MTCConfirmed) {
                if (transaction.SIP().MTCSendTrying()==SIP::Fail) {
-                       TCH->send(RELEASE);
-                       return abortCall(transaction,SDCCH,L3Cause(0x7F));
+                       LCH->send(RELEASE);
+                       // Cause 0x03 is "no route to destination"
+                       return abortCall(transaction,LCH,L3Cause(0x03));
                }
                // FIXME -- What's the proper timeout here?
                // It's the SIP TRYING timeout, whatever that is.
-               if (updateGSMSignalling(transaction,SDCCH,1000)) {
+               if (updateGSMSignalling(transaction,LCH,1000)) {
                        CLDCOUT("MTC: Release from GSM side");
-                       TCH->send(RELEASE);
+                       LCH->send(RELEASE);
                        return;
                }
                // Check for SIP cancel, too.
                if (transaction.SIP().MTCWaitForACK()==SIP::Fail) {
-                       TCH->send(RELEASE);
-                       return abortCall(transaction,SDCCH,L3Cause(0x7F));
+                       LCH->send(RELEASE);
+                       // Cause 0x10 is "normal clearing"
+                       return abortCall(transaction,LCH,L3Cause(0x10));
                }
        }
 
        // The transaction is moving to the MTCController.
        gTransactionTable.update(transaction);
        CLDCOUT("MTC: transaction: " << transaction);
-       assignTCHF(SDCCH,TCH);
+       if (veryEarly) {
+               // For very early assignment, we need a mode change.
+               static const L3ChannelMode mode(L3ChannelMode::SpeechV1);
+               LCH->send(L3ChannelModeModify(LCH->channelDescription(),mode));
+               const L3ChannelModeModifyAcknowledge *ack =
+                       
dynamic_cast<L3ChannelModeModifyAcknowledge*>(getMessage(LCH));
+               if (!ack) throw UnexpectedMessage();
+               // Cause 0x06 is "channel unacceptable"
+               if (ack->mode() != mode) return 
abortCall(transaction,LCH,L3Cause(0x06));
+               
MTCController(transaction,dynamic_cast<TCHFACCHLogicalChannel*>(LCH));
+       }
+       else {
+               // For late assignment, send the TCH assignment now.
+               // This dispatcher on the next channel will continue the 
transaction.
+               assignTCHF(dynamic_cast<SDCCHLogicalChannel*>(LCH),TCH);
+       }
 }
 
 
-
 void Control::MTCController(TransactionEntry& transaction, 
TCHFACCHLogicalChannel* TCH)
 {
        // Early Assignment Mobile Terminated Call. 
@@ -747,6 +796,7 @@
 
        CLDCOUT("MTC: transaction: " << transaction);
        unsigned L3TI = transaction.TIValue();
+       assert(TCH);
 
        // Get the alerting message.
        CLDCOUT("MTC:: waiting for GSM Alerting and Connect");

Modified: openbts/trunk/Control/ControlCommon.h
===================================================================
--- openbts/trunk/Control/ControlCommon.h       2008-11-29 06:27:41 UTC (rev 
10088)
+++ openbts/trunk/Control/ControlCommon.h       2008-11-29 22:46:56 UTC (rev 
10089)
@@ -47,6 +47,7 @@
 #include <GSML3CommonElements.h>
 #include <GSML3MMElements.h>
 #include <GSML3CCElements.h>
+#include <GSML3RRMessages.h>
 #include <SIPEngine.h>
 
 
@@ -142,28 +143,36 @@
 
 /address@hidden Functions for mobility manangement operations. */
 //@{
-void CMServiceResponder(const GSM::L3CMServiceRequest* cmsrq, 
GSM::SDCCHLogicalChannel* SDCCH);
+void CMServiceResponder(const GSM::L3CMServiceRequest* cmsrq, 
GSM::LogicalChannel* DCCH);
 void IMSIDetachController(const GSM::L3IMSIDetachIndication* idi, 
GSM::SDCCHLogicalChannel* SDCCH);
 void LocationUpdatingController(const GSM::L3LocationUpdatingRequest* lur, 
GSM::SDCCHLogicalChannel* SDCCH);
 //@}
 
 /address@hidden Functions for radio resource operations. */
 //@{
+/** Decode RACH bits and send an immediate assignment. */
 void AccessGrantResponder(unsigned requestReference, const GSM::Time& when);
-void PagingResponseHandler(const GSM::L3PagingResponse*, 
GSM::SDCCHLogicalChannel*);
+/** Find and compelte the in-process transaction associated with a paging 
repsonse. */
+void PagingResponseHandler(const GSM::L3PagingResponse*, GSM::LogicalChannel*);
+/** Find and compelte the in-process transaction associated with a completed 
assignment. */
+void AssignmentCompleteHandler(const GSM::L3AssignmentComplete*, 
GSM::TCHFACCHLogicalChannel*);
 //@}
 
 /address@hidden Functions for call control operations. */
 //@{
 /address@hidden MOC */
 //@{
-void MOCStarter(const GSM::L3CMServiceRequest* req, GSM::SDCCHLogicalChannel 
*SDCCH);
-void MOCController(TransactionEntry& transaction, GSM::TCHFACCHLogicalChannel* 
TCHFACCH);
+/** Run the MOC to the point of alerting, doing early assignment if needed. */
+void MOCStarter(const GSM::L3CMServiceRequest*, GSM::LogicalChannel*);
+/** Complete the MOC connection. */
+void MOCController(TransactionEntry&, GSM::TCHFACCHLogicalChannel*);
 //@}
 /address@hidden MTC */
 //@{
-void MTCStarter(const GSM::L3PagingResponse *resp, GSM::SDCCHLogicalChannel 
*SDCCH);
-void MTCController(TransactionEntry& transaction, GSM::TCHFACCHLogicalChannel* 
TCHFACCH);
+/** Run the MTC to the point of alerting, doing early assignment if needed. */
+void MTCStarter(const GSM::L3PagingResponse*, GSM::LogicalChannel*);
+/** Complete the MTC connection. */
+void MTCController(TransactionEntry&, GSM::TCHFACCHLogicalChannel*);
 //@}
 /address@hidden MOSMS */
 //@{
@@ -186,6 +195,7 @@
 //@{
 void FACCHDispatcher(GSM::TCHFACCHLogicalChannel *TCHFACCH);
 void SDCCHDispatcher(GSM::SDCCHLogicalChannel *SDCCH);
+void DCCHDispatcher(GSM::LogicalChannel *DCCH);
 //@}
 
 
@@ -199,6 +209,7 @@
        private:
 
        // FIXME -- We need to support channel type.  See tracker item #316.
+       GSM::ChannelType mType;                 ///< The needed channel type.
        GSM::L3MobileIdentity mID;              ///< The mobile ID.
        Timeval mExpiration;                    ///< The expiration time for 
this entry.
 
@@ -209,13 +220,16 @@
                @param wID The ID to be paged.
                @param wLife The number of milliseconds to keep paging.
        */
-       PagingEntry(const GSM::L3MobileIdentity& wID, unsigned wLife)
-               :mID(wID),mExpiration(wLife)
+       PagingEntry(const GSM::L3MobileIdentity& wID, GSM::ChannelType wType, 
unsigned wLife)
+               :mID(wID),mType(wType),mExpiration(wLife)
        {}
 
        /** Access the ID. */
        const GSM::L3MobileIdentity& ID() const { return mID; }
 
+       /** Access the channel type needed. */
+       const GSM::ChannelType type() const { return mType; }
+
        /** Renew the timer. */
        void renew(unsigned wLife) { mExpiration = Timeval(wLife); }
 
@@ -252,9 +266,10 @@
        /**
                Add a mobile ID to the paging list.
                @param addID The mobile ID to be paged.
+               @param chanType The channel type to be requested.
                @param wLife The paging duration in ms, default based on SIP 
INVITE retry preiod.
        */
-       void addID(const GSM::L3MobileIdentity& addID, unsigned wLife=4000);
+       void addID(const GSM::L3MobileIdentity& addID, GSM::ChannelType 
chanType, unsigned wLife=4000);
 
        private:
 

Copied: openbts/trunk/Control/DCCHDispatch.cpp (from rev 10088, 
openbts/branches/developers/dburgess00/veryearly/Control/DCCHDispatch.cpp)
===================================================================
--- openbts/trunk/Control/DCCHDispatch.cpp                              (rev 0)
+++ openbts/trunk/Control/DCCHDispatch.cpp      2008-11-29 22:46:56 UTC (rev 
10089)
@@ -0,0 +1,179 @@
+/address@hidden Idle-mode dispatcher for dedicated control channels. */
+
+/*
+* Copyright 2008 Free Software Foundation, Inc.
+*
+* This software is distributed under the terms of the GNU Public License.
+* See the COPYING 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 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+
+
+#include "ControlCommon.h"
+#include <GSMLogicalChannel.h>
+#include <GSML3MMMessages.h>
+#include <GSML3RRMessages.h>
+#include <SIPUtility.h>
+#include <SIPInterface.h>
+
+using namespace std;
+using namespace GSM;
+using namespace Control;
+
+
+
+
+/**
+       Dispatch the appropriate controller for a Mobility Management message.
+       @param req A pointer to the initial message.
+       @param DCCH A pointer to the logical channel for the transaction.
+*/
+void DCCHDispatchMM(const L3MMMessage* req, LogicalChannel *DCCH)
+{
+       assert(req);
+       L3MMMessage::MessageType MTI = (L3MMMessage::MessageType)req->MTI();
+       switch (MTI) {
+               case L3MMMessage::LocationUpdatingRequest:
+                       LocationUpdatingController(dynamic_cast<const 
L3LocationUpdatingRequest*>(req),
+                                                                       
dynamic_cast<SDCCHLogicalChannel*>(DCCH));
+                       break;
+               case L3MMMessage::IMSIDetachIndication:
+                       IMSIDetachController(dynamic_cast<const 
L3IMSIDetachIndication*>(req),
+                                                                       
dynamic_cast<SDCCHLogicalChannel*>(DCCH));
+                       break;
+               case L3MMMessage::CMServiceRequest:
+                       CMServiceResponder(dynamic_cast<const 
L3CMServiceRequest*>(req),DCCH);
+                       break;
+               default:
+                       CERR("NOTICE -- (ControlLayer) unhandled MM message " 
<< MTI << " on " << DCCH->type());
+                       throw UnsupportedMessage();
+       }
+}
+
+
+/**
+       Dispatch the appropriate controller for a Radio Resource message.
+       @param req A pointer to the initial message.
+       @param DCCH A pointer to the logical channel for the transaction.
+*/
+void DCCHDispatchRR(const L3RRMessage* req, LogicalChannel *DCCH)
+{
+       CLDCOUT("DCCHDispatchRR: cheking MTI"<< 
(L3RRMessage::MessageType)req->MTI() )
+
+       assert(req);
+       L3RRMessage::MessageType MTI = (L3RRMessage::MessageType)req->MTI();
+       switch (MTI) {
+               case L3RRMessage::PagingResponse:
+                       PagingResponseHandler(dynamic_cast<const 
L3PagingResponse*>(req),DCCH);
+                       break;
+               case L3RRMessage::AssignmentComplete:
+                       AssignmentCompleteHandler(dynamic_cast<const 
L3AssignmentComplete*>(req),
+                                                                               
dynamic_cast<TCHFACCHLogicalChannel*>(DCCH));
+                       break;
+               default:
+                       CERR("NOTICE -- (ControlLayer) unhandled RR message " 
<< MTI << " on " << DCCH->type());
+                       throw UnsupportedMessage();
+       }
+}
+
+
+
+
+
+
+/** Example of a closed-loop, persistent-thread control function for the DCCH. 
*/
+void Control::DCCHDispatcher(LogicalChannel *DCCH)
+{
+       while (1) {
+               try {
+                       // Wait for a transaction to start.
+                       CLDCOUT("DCCHDisptacher waiting for " << DCCH->type() 
<< " ESTABLISH");
+                       while (!waitForPrimitive(DCCH,ESTABLISH)) {}
+                       // Pull the first message and dispatch a new 
transaction.
+                       const L3Message *message = getMessage(DCCH);
+                       CLDCOUT("DCCHDispatcher got " << *message);
+                       // Each protocol has it's own sub-dispatcher.
+                       switch (message->PD()) {
+                               case L3MobilityManagementPD:
+                                       DCCHDispatchMM(dynamic_cast<const 
L3MMMessage*>(message),DCCH);
+                                       break;
+                               case L3RadioResourcePD:
+                                       DCCHDispatchRR(dynamic_cast<const 
L3RRMessage*>(message),DCCH);
+                                       break;
+                               default:
+                                       CERR("NOTICE -- (ControlLayer) 
unhandled protocol " 
+                                               << message->PD() << " on DCCH");
+                                       throw UnsupportedMessage();
+                       }
+                       delete message;
+               }
+
+               // Catch the various error cases.
+
+               catch (ChannelReadTimeout except) {
+                       clearTransactionHistory(except.transactionID());
+                       CERR("NOTICE -- ChannelReadTimeout");
+                       // Cause 0x03 means "abnormal release, timer expired".
+                       DCCH->send(L3ChannelRelease(0x03));
+               }
+               catch (UnexpectedPrimitive except) {
+                       clearTransactionHistory(except.transactionID());
+                       CERR("NOTICE -- UnexpectedPrimitive");
+                       // Cause 0x62 means "message type not not compatible 
with protocol state".
+                       DCCH->send(L3ChannelRelease(0x62));
+               }
+               catch (UnexpectedMessage except) {
+                       clearTransactionHistory(except.transactionID());
+                       CERR("NOTICE -- UnexpectedMessage");
+                       // Cause 0x62 means "message type not not compatible 
with protocol state".
+                       DCCH->send(L3ChannelRelease(0x62));
+               }
+               catch (UnsupportedMessage except) {
+                       clearTransactionHistory(except.transactionID());
+                       CERR("NOTICE -- UnsupportedMessage");
+                       // Cause 0x61 means "message type not implemented".
+                       DCCH->send(L3ChannelRelease(0x61));
+               }
+               catch (Q931TimerExpired except) {
+                       clearTransactionHistory(except.transactionID());
+                       CERR("NOTICE -- Q.931 T3xx timer expired");
+                       // Cause 0x03 means "abnormal release, timer expired".
+                       DCCH->send(L3ChannelRelease(0x03));
+               }
+               catch (SIP::SIPTimeout) {
+                       CERR("NOTICE -- Uncaught SIP Timeout");
+                       // Cause 0x03 means "abnormal release, timer expired".
+                       DCCH->send(L3ChannelRelease(0x03));
+               }
+               catch (SIP::SIPError) {
+                       CERR("NOTICE -- Uncaught SIP Error");
+                       // Cause 0x01 means "abnormal release, unspecified".
+                       DCCH->send(L3ChannelRelease(0x01));
+               }
+
+               CLDCOUT("DCCHDisptacher waiting for " << DCCH->type() << " 
RELEASE");
+               //FIXME -- What's the GSM 04.08 Txxx value for this?
+               // Probably N200 * T200
+               waitForPrimitive(DCCH,RELEASE,20000);
+       }
+}
+
+
+
+
+// vim: ts=4 sw=4

Deleted: openbts/trunk/Control/FACCHDispatch.cpp

Modified: openbts/trunk/Control/Makefile.am
===================================================================
--- openbts/trunk/Control/Makefile.am   2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/Control/Makefile.am   2008-11-29 22:46:56 UTC (rev 10089)
@@ -31,10 +31,9 @@
 libcontrol_la_SOURCES = \
        CallControl.cpp \
        ControlCommon.cpp \
-       FACCHDispatch.cpp \
        MobilityManagement.cpp \
        RadioResource.cpp \
-       SDCCHDispatch.cpp
+       DCCHDispatch.cpp
 
 PagerTest_SOURCES = PagerTest.cpp
 PagerTest_LDADD = \

Modified: openbts/trunk/Control/MobilityManagement.cpp
===================================================================
--- openbts/trunk/Control/MobilityManagement.cpp        2008-11-29 06:27:41 UTC 
(rev 10088)
+++ openbts/trunk/Control/MobilityManagement.cpp        2008-11-29 22:46:56 UTC 
(rev 10089)
@@ -52,24 +52,24 @@
 
 
 /** Controller for CM Service requests, dispatches out to multiple possible 
transaction controllers. */
-void Control::CMServiceResponder(const L3CMServiceRequest* cmsrq, 
SDCCHLogicalChannel* SDCCH)
+void Control::CMServiceResponder(const L3CMServiceRequest* cmsrq, 
LogicalChannel* DCCH)
 {
        assert(cmsrq);
        CLDCOUT("CMServiceResponder " << *cmsrq);
        switch (cmsrq->serviceType().type()) {
                case L3CMServiceType::MobileOriginatedCall:
-                       MOCStarter(cmsrq,SDCCH);
+                       MOCStarter(cmsrq,DCCH);
                        break;
 #ifdef SMS
                case L3CMServiceType::ShortMessage:
-                       ShortMessageServiceStarter(cmsrq, SDCCH);
+                       ShortMessageServiceStarter(cmsrq, 
dynamic_cast<SDCCHLogicalChannel*>(SDCCH));
                        break;
 #endif
                default:
                        CLDCOUT("CMServiceResponder service not supported");
                        // Cause 0x20 means "serivce not supported".
-                       SDCCH->send(L3CMServiceReject(0x20));
-                       SDCCH->send(L3ChannelRelease());
+                       DCCH->send(L3CMServiceReject(0x20));
+                       DCCH->send(L3ChannelRelease());
        }
 }
 

Modified: openbts/trunk/Control/PagerTest.cpp
===================================================================
--- openbts/trunk/Control/PagerTest.cpp 2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/Control/PagerTest.cpp 2008-11-29 22:46:56 UTC (rev 10089)
@@ -59,9 +59,9 @@
        pager.start();
 
        while (1) {
-               pager.addID(L3MobileIdentity(random()));
-               pager.addID(L3MobileIdentity(random()));
-               pager.addID(L3MobileIdentity("123456789012345"));
+               pager.addID(L3MobileIdentity(random()),GSM::AnyDCCHType);
+               pager.addID(L3MobileIdentity(random()),GSM::AnyDCCHType);
+               
pager.addID(L3MobileIdentity("123456789012345"),GSM::AnyDCCHType);
                sleep(random() % 2);
        }
 }

Modified: openbts/trunk/Control/RadioResource.cpp
===================================================================
--- openbts/trunk/Control/RadioResource.cpp     2008-11-29 06:27:41 UTC (rev 
10088)
+++ openbts/trunk/Control/RadioResource.cpp     2008-11-29 22:46:56 UTC (rev 
10089)
@@ -75,6 +75,52 @@
 //@}
 
 
+/**
+       Determine the channel type needed.
+       This is based on GSM 04.08 Table 9.3 and 9.3a.
+       The following is assumed about the global BTS capabilities:
+       - We do not support "new establishment causes" and NECI is 0.
+       - We do not support call reestablishment.
+       - We do not support GPRS.
+       @param RA The request reference from the channel request message.
+       @return channel type code, undefined if not a supported service
+*/
+ChannelType decodeChannelNeeded(unsigned RA)
+{
+       // These values assume NECI is 0.
+       // This code is formatted so that it lines up easily with GSM 04.08 
Table 9.9.
+       //
+       if ((RA>>5) == 0x05) return TCHFType;                   // emergency 
call
+       //
+       // skip re-establishment cases
+       //
+       // "Answer to paging"
+       if ((RA>>5) == 0x04) return SDCCHType;                  // answer to 
paging, any channel
+       if ((RA>>4) == 0x01) return SDCCHType;                  // answer to 
paging, SDCCH
+       if ((RA>>4) == 0x02) return TCHFType;                   // answer to 
paging, TCH/F
+       if ((RA>>4) == 0x03) return TCHFType;                   // answer to 
paging, TCH/F or TCH/H
+       //
+       if ((RA>>5) == 0x07) return SDCCHType;                  // MOC or SDCCH 
procedures
+       //
+       if ((RA>>4) == 0x04) return TCHFType;                   // MOC
+       //
+       // skip originating data call cases
+       //
+       if ((RA>>5) == 0x00) return SDCCHType;                  // location 
updating
+       //
+       if ((RA>>4) == 0x00) return SDCCHType;                  // location 
updating
+       //
+       // skip packet (GPRS) cases
+       //
+       // skip LMU case
+       //
+       // skip reserved cases
+       //
+       // Anything else falls through to here.
+       return UndefinedCHType;
+}
+
+
 void Control::AccessGrantResponder(unsigned RA, const GSM::Time& when)
 {
        // RR Establishment.
@@ -82,35 +128,31 @@
        // GSM 04.08 3.3.1.1.3.
        // Given a request reference, try to allocate a channel
        // and send the assignment to the handset on the CCCH.
+       // This GSM's version of medium access control.
        // Papa Legba, open that door...
 
        CLDCOUT("AccessGrantResponder RA=" << RA << " when=" << when);
 
        // FIXME -- Check "when" against current clock to see if we're too late.
 
-       // Check the request type to see if it's a service we don't even 
support.
+       // Determine the channel type needed.
+       ChannelType chanNeeded = decodeChannelNeeded(RA);
+
+       // Allocate the channel.
+       LogicalChannel *LCH = NULL;
+       if (chanNeeded==TCHFType) LCH = gBTS.getTCH();
+       if (chanNeeded==SDCCHType) LCH = gBTS.getSDCCH();
        // If we don't support it, ignore it.
-       if ((RA&0xe0)==0x70) return;    // GPRS
-       if ((RA&0xe0)==0x60) return;    // TCH/H reestablishment & some 
reserved codes
-       if (RA==0x67) return;                   // LMU
-       if (RA==0xef) return;                   // reserved
+       if (LCH==NULL) return;
 
        // Get an AGCH to send on.
        CCCHLogicalChannel *AGCH = gBTS.getAGCH();
        assert(AGCH);
 
-       // FIXME -- We are ASSUMING that SDCCH is OK.
-       // The truth is that we should decode according GSM 04.08 9.1.8, Table 
9.9a.
-
-       // Get an SDCCH to assign to.
-       SDCCHLogicalChannel *SDCCH = gBTS.getSDCCH();
-
        // Nothing available?
-       if (!SDCCH) {
+       if (!LCH) {
                // Rejection, GSM 04.08 3.3.1.1.3.2.
-               // Emergency calls are not subject to T3122 hold-off.
-               // They are not handled as a special case because the
-               // MS will ignore the T3122 setting.
+               // BTW, emergency calls are not subject to T3122 hold-off.
                CERR("NOTICE -- Access Grant CONGESTION");
                unsigned waitTime = curT3122()/1000;
                CLDCOUT("AccessGrantResponder: assginment reject, wait time " 
<< waitTime);
@@ -123,10 +165,10 @@
        // Assignment, GSM 04.08 3.3.1.1.3.1.
        // Create the ImmediateAssignment message.
        // For most of the message, default IE values are correct.
-       const L3ImmediateAssignment 
assign(L3RequestReference(RA,when),SDCCH->channelDescription());
+       const L3ImmediateAssignment 
assign(L3RequestReference(RA,when),LCH->channelDescription());
        CLDCOUT("AccessGrantResponder sending " << assign);
        AGCH->send(assign);
-       SDCCH->open();
+       // This was opened by the gBTS.getXXX() method.  LCH->open();
 
        // Reset exponential back-off upon successful allocation.
        restoreT3122();
@@ -136,8 +178,10 @@
 
 
 
-void Control::PagingResponseHandler(const L3PagingResponse* resp, 
SDCCHLogicalChannel* SDCCH)
+void Control::PagingResponseHandler(const L3PagingResponse* resp, 
LogicalChannel* DCCH)
 {
+       assert(resp);
+       assert(DCCH);
        CLDCOUT("PagingResponseHandler " << *resp);
 
        // FIXME -- Delete the Mobile ID from the paging list to free up CCCH 
bandwidth.
@@ -146,9 +190,10 @@
        // if not a legitimate reason, need to release the channel.
 
        // FIXME -- Check the transaction table to see if the call is still 
valid.
+
 #ifndef PAGERTEST
        // For now, assume MTC.
-       MTCStarter(resp, SDCCH);
+       MTCStarter(resp, DCCH);
 #else
        COUT("starting MTC...");
 #endif
@@ -156,12 +201,42 @@
 
 
 
+void Control::AssignmentCompleteHandler(const L3AssignmentComplete *confirm, 
TCHFACCHLogicalChannel *TCH)
+{
+       assert(TCH);
+       assert(confirm);
 
+       // Check the transaction table to know what to do next.
+       TransactionEntry transaction;
+       if (!gTransactionTable.find(TCH->transactionID(),transaction)) {
+               CLDCOUT("NOTICE -- Assignment Complete from channel with no 
transaction");
+               throw UnexpectedMessage();
+       }
+       CLDCOUT("AssignmentCompleteHandler 
service="<<transaction.service().type());
+       // These "controller" functions don't return until the call is cleared.
+       switch (transaction.service().type()) {
+               case L3CMServiceType::MobileOriginatedCall:
+                       MOCController(transaction,TCH);
+                       break;
+               case L3CMServiceType::MobileTerminatedCall:
+                       MTCController(transaction,TCH);
+                       break;
+               default:
+                       CLDCOUT("NOTICE -- request for unsupported service " << 
transaction.service());
+                       throw UnsupportedMessage();
+       }
+       // If we got here, the call is cleared.
+       clearTransactionHistory(TCH->transactionID());
+}
 
 
 
 
-void Pager::addID(const L3MobileIdentity& newID, unsigned wLife)
+
+
+
+
+void Pager::addID(const L3MobileIdentity& newID, ChannelType chanType, 
unsigned wLife)
 {
        // Add a mobile ID to the paging list for a given lifetime.
 
@@ -180,7 +255,7 @@
        }
        // If this ID is new, put it in the list.
        if (!renewed) {
-               mPageIDs.push_back(PagingEntry(newID,wLife));
+               mPageIDs.push_back(PagingEntry(newID,chanType,wLife));
                CLDCOUT("Pager::addID " << newID << " added to table");
        }
        // Signal in case the paging loop is waiting for new entries.
@@ -210,22 +285,25 @@
        // Page remaining entries, two at a time if possible.
        list<PagingEntry>::iterator lp = mPageIDs.begin();
        while (lp != mPageIDs.end()) {
-               // HACK -- Just pick the minimum load channel.
-               // FIXME -- This completely ignores the paging goups, GSM 04.08 
10.5.2.11 and GSM 05.02 6.5.2.
-               GSM::CCCHLogicalChannel *PCH = gBTS.getPCH();
+               // FIXME -- This completely ignores the paging groups, GSM 
04.08 10.5.2.11 and GSM 05.02 6.5.2.
+               CCCHLogicalChannel *PCH = gBTS.getPCH();
                assert(PCH);
-               const L3MobileIdentity& id1 = lp->ID(); ++lp;
+               const L3MobileIdentity& id1 = lp->ID();
+               ChannelType type1 = lp->type();
+               ++lp;
                if (lp==mPageIDs.end()) {
                        // Just one ID left?
                        //CLDCOUT("Pager::pageAll paging " << id1);
-                       PCH->send(L3PagingRequestType1(id1));
+                       PCH->send(L3PagingRequestType1(id1,type1));
                        numPaged++;
                        break;
                }
                // Page by pairs when possible.
-               const L3MobileIdentity& id2 = lp->ID(); ++lp;
+               const L3MobileIdentity& id2 = lp->ID();
+               ChannelType type2 = lp->type();
+               ++lp;
                //CLDCOUT("Pager::pageAll paging " << id1 << " and " << id2);
-               PCH->send(L3PagingRequestType1(id1,id2));
+               PCH->send(L3PagingRequestType1(id1,type1,id2,type2));
                numPaged += 2;
        }
        

Deleted: openbts/trunk/Control/SDCCHDispatch.cpp

Modified: openbts/trunk/GSM/GSMCommon.cpp
===================================================================
--- openbts/trunk/GSM/GSMCommon.cpp     2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/GSM/GSMCommon.cpp     2008-11-29 22:46:56 UTC (rev 10089)
@@ -274,8 +274,10 @@
                case SACCHType: os << "SACCH"; break;
                case TCHFType: os << "TCH/F"; break;
                case TCHHType: os << "TCH/H"; break;
-               case LoopbackFullType: os << "LoopbackFull"; break;
-               case LoopbackHalfType: os << "LoopbackHalf"; break;
+               case AnyTCHType: os << "any TCH"; break;
+               case LoopbackFullType: os << "Loopback Full"; break;
+               case LoopbackHalfType: os << "Loopback Half"; break;
+               case AnyDCCHType: os << "any DCCH"; break;
                default: os << "?" << (int)val << "?";
        }
        return os;

Modified: openbts/trunk/GSM/GSMCommon.h
===================================================================
--- openbts/trunk/GSM/GSMCommon.h       2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/GSM/GSMCommon.h       2008-11-29 22:46:56 UTC (rev 10089)
@@ -185,12 +185,14 @@
        //@{
        TCHFType,               ///< full-rate traffic
        TCHHType,               ///< half-rate traffic
+       AnyTCHType,             ///< any TCH type
        //@}
        ///@name Special internal channel types.
        //@{
        LoopbackFullType,               ///< loopback testing
        LoopbackHalfType,               ///< loopback testing
-       UndefinedCHType,        ///< undefined
+       AnyDCCHType,                    ///< any dedicated control channel
+       UndefinedCHType,                ///< undefined
        //@}
 };
 

Modified: openbts/trunk/GSM/GSML2LAPDm.cpp
===================================================================
--- openbts/trunk/GSM/GSML2LAPDm.cpp    2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/GSM/GSML2LAPDm.cpp    2008-11-29 22:46:56 UTC (rev 10089)
@@ -43,6 +43,7 @@
 using namespace std;
 using namespace GSM;
 
+//#define NDEBUG
 
 
 ostream& GSM::operator<<(ostream& os, L2LAPDm::LAPDState state)

Modified: openbts/trunk/GSM/GSML3Message.h
===================================================================
--- openbts/trunk/GSM/GSML3Message.h    2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/GSM/GSML3Message.h    2008-11-29 22:46:56 UTC (rev 10089)
@@ -102,7 +102,7 @@
                It can't be pure virtual because it is not needed by all 
subclasses.
        */
        virtual void writeBody(L3Frame& dest, size_t &writePosition) const
-       { abort(); }
+       { CERR("unimplemented L3Message::writeBody"); abort(); }
 
        /**
                The parseBody() method starts processing at the first byte 
following the
@@ -111,7 +111,7 @@
                It can't be pure virtual because it is not needed by all 
subclasses.
        */
        virtual void parseBody(const L3Frame& source, size_t &readPosition)
-       { abort(); }
+       { CERR("unimplemented L3Message::parseBody"); abort(); }
 
 
        public:
@@ -201,7 +201,7 @@
          @param rp Bit index of read position (updated by read).
        */
        virtual void parseV(const L3Frame& src, size_t &rp )
-       { abort(); }
+       { CERR("unimplemented L3ProtocolElement::parseV"); abort(); }
 
        /**
          The parseV method decodes L3 message bits from variable-length value 
parts.
@@ -213,7 +213,7 @@
          @param expectedLength Length of available field, in bytes.
        */
        virtual void parseV(const L3Frame& src, size_t &rp, size_t 
expectedLength)
-       { abort(); }
+       { CERR("unimplemented L3ProtocolElement::parseV"); abort(); }
 
 
        /**
@@ -250,7 +250,7 @@
                @param wp The write index (updated by write).
        */
        virtual void writeV(L3Frame& dest, size_t &wp) const
-       { abort(); }
+       { CERR("unimplemented L3ProtocolElement::writeV"); abort(); }
 
        /**
                Write LV format.

Modified: openbts/trunk/GSM/GSML3RRElements.cpp
===================================================================
--- openbts/trunk/GSM/GSML3RRElements.cpp       2008-11-29 06:27:41 UTC (rev 
10088)
+++ openbts/trunk/GSM/GSML3RRElements.cpp       2008-11-29 22:46:56 UTC (rev 
10089)
@@ -111,6 +111,7 @@
 }
 
 
+
 void L3ControlChannelDescription::text(ostream& os) const
 {
        os << "ATT=" << mATT;
@@ -298,6 +299,7 @@
 
 void L3ChannelDescription::writeV( L3Frame &dest, size_t &wp ) const 
 {
+       // GSM 04.08 10.5.2.5
 //                                     Channel Description Format (non-hopping)
 //                     7      6      5      4      3     2      1      0
 //       [         TSC       ][ H=0 ][ SPARE(0,0)][ ARFCN[9:8] ]  Octet 3
@@ -305,7 +307,7 @@
 //
 
        // HACK -- Hard code for non-hopping.
-
+       assert(mHFlag==0);
        dest.writeField(wp,mTypeAndOffset,5);
        dest.writeField(wp,mTN,3);
        dest.writeField(wp,mTSC,3);
@@ -314,6 +316,24 @@
 }
 
 
+
+void L3ChannelDescription::parseV(const L3Frame& src, size_t &rp)
+{
+       // GSM 04.08 10.5.2.5
+       mTypeAndOffset = (TypeAndOffset)src.readField(rp,5);
+       mTN = src.readField(rp,3);
+       mTSC = src.readField(rp,3);
+       mHFlag = src.readField(rp,1);
+       if (mHFlag) {
+               mMAIO = src.readField(rp,6);
+               mHSN = src.readField(rp,6);
+       } else {
+               rp += 2;        // skip 2 spare bits
+               mARFCN = src.readField(rp,10);
+       }
+}
+
+
 void L3ChannelDescription::text(std::ostream& os) const
 {
 
@@ -405,6 +425,13 @@
        dest.writeField(wp, mMode, 8);
 }
 
+void L3ChannelMode::parseV(const L3Frame& src, size_t& rp)
+{
+       mMode = (Mode)src.readField(rp,8);
+}
+
+
+
 ostream& GSM::operator<<(ostream& os, L3ChannelMode::Mode mode)
 {
        switch (mode) {

Modified: openbts/trunk/GSM/GSML3RRElements.h
===================================================================
--- openbts/trunk/GSM/GSML3RRElements.h 2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/GSM/GSML3RRElements.h 2008-11-29 22:46:56 UTC (rev 10089)
@@ -100,7 +100,7 @@
        unsigned mCELL_RESELECT_HYSTERESIS;
        unsigned mMS_TXPWR_MAX_CCH;
        unsigned mACS;
-       unsigned mNECI;
+       static const unsigned mNECI = 0;        // new establishment causes not 
supported
        unsigned mRXLEV_ACCESS_MIN;
 
        public:
@@ -112,7 +112,6 @@
                mCELL_RESELECT_HYSTERESIS=6;            // 8 dB reselect
                mMS_TXPWR_MAX_CCH=0;                            // a high power 
level in all bands
                mACS=0;                                                         
// no additional relesect parameters
-               mNECI=0;                                                        
// new establishment causes not supported
                mRXLEV_ACCESS_MIN=0;                            // lowest 
allowed access level
        }
 
@@ -388,10 +387,18 @@
                mARFCN(wARFCN),
                mMAIO(0),mHSN(0)
        { }
+
+       /** Blank initializer */
+       L3ChannelDescription()
+               :mTypeAndOffset(TDMA_MISC),
+               mTN(0),mTSC(0),mHFlag(0),mARFCN(0),mMAIO(0),mHSN(0)
+       { }
        
 
        void writeV( L3Frame &dest, size_t &wp ) const;
 
+       void parseV(const L3Frame& src, size_t &rp);
+
        size_t lengthV() const  { return 3; }
 
        void text(std::ostream&) const;
@@ -538,7 +545,11 @@
                mMode(wMode)
        {}
 
+       bool operator==(const L3ChannelMode& other) const { return 
mMode==other.mMode; }
+       bool operator!=(const L3ChannelMode& other) const { return 
mMode!=other.mMode; }
+
        void writeV(L3Frame& dest, size_t &wp) const;
+       void parseV(const L3Frame& src, size_t& wp);
        size_t lengthV() const { return 1; }
        void text(std::ostream&) const;
 

Modified: openbts/trunk/GSM/GSML3RRMessages.cpp
===================================================================
--- openbts/trunk/GSM/GSML3RRMessages.cpp       2008-11-29 06:27:41 UTC (rev 
10088)
+++ openbts/trunk/GSM/GSML3RRMessages.cpp       2008-11-29 22:46:56 UTC (rev 
10089)
@@ -121,6 +121,7 @@
                case L3RRMessage::AssignmentFailure: return new 
L3AssignmentFailure();
                case L3RRMessage::RRStatus: return new L3RRStatus();
                case L3RRMessage::PagingResponse: return new L3PagingResponse();
+               case L3RRMessage::ChannelModeModifyAcknowledge: return new 
L3ChannelModeModifyAcknowledge();
                default:
                        CERR("WARNING -- no L3 RR factory support for " << MTI);
                        return NULL;
@@ -143,6 +144,23 @@
 
 
 
+/**
+This is a local function to map the GSM::ChannelType enum
+to one of the codes from GMS 04.07 10.5.2.8.
+*/
+unsigned channelNeededCode(ChannelType wType)
+{
+       switch (wType) {
+               case AnyDCCHType: return 0;
+               case SDCCHType: return 1;
+               case TCHFType: return 2;
+               case AnyTCHType: return 3;
+               default: abort();
+       }
+}
+
+
+
 size_t L3PagingRequestType1::bodyLength() const
 {
        int sz = mMobileIDs.size();
@@ -154,14 +172,25 @@
 }
 
 
+
 void L3PagingRequestType1::writeBody(L3Frame& dest, size_t &wp) const
 {
+       // See GSM 04.08 9.1.22.
+       // Page Mode Page Mode M V 1/2 10.5.2.26    
+       // Channels Needed  M V 1/2 
+       // Mobile Identity 1 M LV 2-9 10.5.1.4    
+       // 0x17 Mobile Identity 2 O TLV  3-10 10.5.1.4    
+
        int sz = mMobileIDs.size();
        assert(sz<=2);
-       // Remember for reverse orders of 1/2-octet fields.
+       // Remember to reverse orders of 1/2-octet fields.
        // Because GSM transmits LSB-first within each byte.
-       dest.writeField(wp,0x0,4);              // "any channel", GSM 04.08 
Table 10.5.29
-       dest.writeField(wp,0x0,4);              // "normal paging", GSM 04.08 
Table 10.5.63
+       // channel needed codes
+       dest.writeField(wp,channelNeededCode(mChannelsNeeded[1]),2);
+       dest.writeField(wp,channelNeededCode(mChannelsNeeded[0]),2);
+       // "normal paging", GSM 04.08 Table 10.5.63
+       dest.writeField(wp,0x0,4);
+       // the actual mobile IDs
        mMobileIDs[0].writeLV(dest,wp);
        if (sz>1) mMobileIDs[1].writeTLV(0x17,dest,wp);
 }
@@ -172,7 +201,7 @@
        L3RRMessage::text(os);
        os << " mobileIDs=(";
        for (unsigned i=0; i<mMobileIDs.size(); i++) {
-               os << "(" << mMobileIDs[i] << "),";
+               os << "(" << mMobileIDs[i] << "," << mChannelsNeeded[i] << "),";
        }
        os << ")";
 }
@@ -500,5 +529,34 @@
 
 
 
+void L3ChannelModeModify::writeBody(L3Frame &dest, size_t& wp) const
+{
+       mDescription.writeV(dest,wp);
+       mMode.writeV(dest,wp);
+}
 
+
+void L3ChannelModeModify::text(ostream& os) const
+{
+       L3RRMessage::text(os);
+       os << "description=(" << mDescription << ")";
+       os << " mode=(" << mMode << ")";
+}
+
+
+void L3ChannelModeModifyAcknowledge::parseBody(const L3Frame &src, size_t& rp)
+{
+       mDescription.parseV(src,rp);
+       mMode.parseV(src,rp);
+}
+
+
+void L3ChannelModeModifyAcknowledge::text(ostream& os) const
+{
+       L3RRMessage::text(os);
+       os << "description=(" << mDescription << ")";
+       os << " mode=(" << mMode << ")";
+}
+
+
 // vim: ts=4 sw=4

Modified: openbts/trunk/GSM/GSML3RRMessages.h
===================================================================
--- openbts/trunk/GSM/GSML3RRMessages.h 2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/GSM/GSML3RRMessages.h 2008-11-29 22:46:56 UTC (rev 10089)
@@ -95,12 +95,12 @@
                ///@name miscellaneous
                //@{
                ChannelModeModify=0x10,
+               RRStatus=0x12,
+               ChannelModeModifyAcknowledge=0x17,
                ClassmarkChange=0x16,
+               MeasurementReport = 0x15,
                GPRSSuspensionRequest=0x34,
-               RRStatus=0x12,
                //@}
-               /// reporting
-               MeasurementReport = 0x15,
                ///@name special cases -- assigned >8-bit codes to avoid 
conflicts
                //@{
                SynchronizationChannelInformation=0x100,
@@ -141,6 +141,7 @@
        private:
 
        std::vector<L3MobileIdentity> mMobileIDs;
+       ChannelType mChannelsNeeded[2];
 
 
        public:
@@ -150,19 +151,30 @@
        {
                // The empty paging request is a single untyped mobile ID.
                mMobileIDs.push_back(L3MobileIdentity());
+               mChannelsNeeded[0]=AnyDCCHType;
+               mChannelsNeeded[1]=AnyDCCHType;
        }
 
-       L3PagingRequestType1(const L3MobileIdentity& wId)
+       L3PagingRequestType1(const L3MobileIdentity& wId, ChannelType wType)
                :L3RRMessage()
-       { mMobileIDs.push_back(wId); }
+       {
+               mMobileIDs.push_back(wId);
+               mChannelsNeeded[0]=wType;
+               mChannelsNeeded[1]=AnyDCCHType;
+       }
 
-       L3PagingRequestType1(const L3MobileIdentity& wId1, const 
L3MobileIdentity& wId2)
+       L3PagingRequestType1(const L3MobileIdentity& wId1, ChannelType wType1,
+                       const L3MobileIdentity& wId2, ChannelType wType2)
                :L3RRMessage()
        {
                mMobileIDs.push_back(wId1);
+               mChannelsNeeded[0]=wType1;
                mMobileIDs.push_back(wId2);
+               mChannelsNeeded[1]=wType2;
        }
 
+       unsigned chanCode(ChannelType) const;
+
        size_t bodyLength() const;
 
        int MTI() const { return PagingRequestType1; }
@@ -672,7 +684,60 @@
 
 
 
+/** GSM 04.08 9.1.5 */
+class L3ChannelModeModify : public L3RRMessage {
 
+       private:
+
+       L3ChannelDescription mDescription;
+       L3ChannelMode mMode;
+
+       public:
+
+       L3ChannelModeModify(const L3ChannelDescription& wDescription,
+                                               const L3ChannelMode& wMode)
+               :L3RRMessage(),
+               mDescription(wDescription),
+               mMode(wMode)
+       {}
+
+       int MTI() const { return (int) ChannelModeModify; }
+
+       size_t bodyLength() const
+               { return mDescription.lengthV() + mMode.lengthV(); }
+
+       void writeBody(L3Frame&, size_t&) const;
+
+       void text(std::ostream&) const;
+};
+
+
+/** GSM 04.08 9.1.6 */
+class L3ChannelModeModifyAcknowledge : public L3RRMessage {
+
+       private:
+
+       L3ChannelDescription mDescription;
+       L3ChannelMode mMode;
+
+       public:
+
+       const L3ChannelDescription& description() const { return mDescription; }
+       const L3ChannelMode& mode() const { return mMode; }
+
+       int MTI() const { return (int) ChannelModeModifyAcknowledge; }
+
+       size_t bodyLength() const
+               { return mDescription.lengthV() + mMode.lengthV(); }
+
+       void parseBody(const L3Frame&, size_t&);
+
+       void text(std::ostream&) const;
+};
+
+
+
+
 }; // GSM
 
 

Modified: openbts/trunk/SIP/SIPInterface.cpp
===================================================================
--- openbts/trunk/SIP/SIPInterface.cpp  2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/SIP/SIPInterface.cpp  2008-11-29 22:46:56 UTC (rev 10089)
@@ -43,9 +43,17 @@
 using namespace Control;
 
 
+/**
+       The channel type to request in paging.
+       Request SDCCHType for early assignment or
+       TCHFType for very early assignment.
+*/
+const GSM::ChannelType RequiredChannel = GSM::TCHFType;
+//const GSM::ChannelType RequiredChannel = GSM::SDCCHType;
 
 
 
+
 // SIPMessageMap method definitions.
 
 void SIPMessageMap::write(const std::string& call_id, osip_message_t * msg)
@@ -193,7 +201,7 @@
        if(msg->sip_method == NULL){ return false; }
        if( strcmp(msg->sip_method,"INVITE") != 0) {return false;}
 
-       // FIXME -- Check gBTS for TCH and SDCCH availability.  Bug #130.
+       // FIXME -- Check gBTS for TCH availability, bug #330.
        // Respond with a congestion message if none are available.
 
        // Get call_id from invite message.
@@ -219,18 +227,13 @@
                        return false;
                }
                DCOUT("SIPInterface::checkInvite: repeated SIP invite, 
repaging") 
-               gBTS.pager().addID(mobile_id);  
+               gBTS.pager().addID(mobile_id,RequiredChannel);  
                transaction.T3113().set();
                gTransactionTable.update(transaction);
                osip_free(to_uri);
                return false;
        }
 
-       // FIXME -- At this point, check for the mobile_id in the transaction 
table.
-       // Bug #131.
-       // If it's there, it could mean the phone's already busy, depending on 
the state.
-       // Respond with Busy.
-
        // Add an entry to the SIP Map.
        mSIPMap.add(call_id_string);
 
@@ -254,7 +257,7 @@
        
        // Add to paging list.
        DCOUT("SIPInterface::checkInvite: new SIP invite, initial paging") 
-       gBTS.pager().addID(mobile_id);  
+       gBTS.pager().addID(mobile_id,RequiredChannel);  
 
        osip_free(to_uri);
        return true;

Modified: openbts/trunk/apps/OpenBTS850.cpp
===================================================================
--- openbts/trunk/apps/OpenBTS850.cpp   2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/apps/OpenBTS850.cpp   2008-11-29 22:46:56 UTC (rev 10089)
@@ -116,7 +116,7 @@
                SDCCH[i].downstream(radio);
                SDCCH[i].open();
                gBTS.addSDCCH(&SDCCH[i]);
-               
SDCCHControlThread[i].start((void*(*)(void*))Control::SDCCHDispatcher,&SDCCH[i]);
+               
SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&SDCCH[i]);
        }
 
        // TCHs
@@ -134,7 +134,7 @@
                TCH[i].downstream(radio);
                TCH[i].open();
                gBTS.addTCH(&TCH[i]);
-               
TCHControlThread[i].start((void*(*)(void*))Control::FACCHDispatcher,&TCH[i]);
+               
TCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&TCH[i]);
        }
 
        // Set up the pager.

Modified: openbts/trunk/apps/OpenBTS900.cpp
===================================================================
--- openbts/trunk/apps/OpenBTS900.cpp   2008-11-29 06:27:41 UTC (rev 10088)
+++ openbts/trunk/apps/OpenBTS900.cpp   2008-11-29 22:46:56 UTC (rev 10089)
@@ -114,7 +114,7 @@
        Thread SDCCHControlThread[4];
        for (int i=0; i<4; i++) {
                SDCCH[i].downstream(radio);
-               
SDCCHControlThread[i].start((void*(*)(void*))Control::SDCCHDispatcher,&SDCCH[i]);
+               
SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&SDCCH[i]);
                SDCCH[i].open();
                gBTS.addSDCCH(&SDCCH[i]);
        }
@@ -132,7 +132,7 @@
        Thread TCHControlThread[7];
        for (int i=0; i<7; i++) {
                TCH[i].downstream(radio);
-               
TCHControlThread[i].start((void*(*)(void*))Control::FACCHDispatcher,&TCH[i]);
+               
TCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&TCH[i]);
                TCH[i].open();
                gBTS.addTCH(&TCH[i]);
        }





reply via email to

[Prev in Thread] Current Thread [Next in Thread]