commit-gnuradio
[Top][All Lists]
Advanced

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

[Commit-gnuradio] r11667 - in openbts/trunk: . CLI CommonLibs Control GS


From: dburgess00
Subject: [Commit-gnuradio] r11667 - in openbts/trunk: . CLI CommonLibs Control GSM Globals HLR SIP SMS TRXManager Transceiver Transceiver52M apps smqueue
Date: Wed, 30 Dec 2009 21:21:20 -0700 (MST)

Author: dburgess00
Date: 2009-12-30 21:21:20 -0700 (Wed, 30 Dec 2009)
New Revision: 11667

Modified:
   openbts/trunk/AUTHORS
   openbts/trunk/CLI/CLI.cpp
   openbts/trunk/CLI/CLI.h
   openbts/trunk/CLI/Makefile.am
   openbts/trunk/CLI/Makefile.in
   openbts/trunk/CommonLibs/BitVector.cpp
   openbts/trunk/CommonLibs/BitVector.h
   openbts/trunk/CommonLibs/Configuration.cpp
   openbts/trunk/CommonLibs/Configuration.h
   openbts/trunk/CommonLibs/ConfigurationTest.cpp
   openbts/trunk/CommonLibs/F16.h
   openbts/trunk/CommonLibs/Interthread.h
   openbts/trunk/CommonLibs/LogTest.cpp
   openbts/trunk/CommonLibs/Logger.cpp
   openbts/trunk/CommonLibs/Logger.h
   openbts/trunk/CommonLibs/Makefile.am
   openbts/trunk/CommonLibs/Sockets.cpp
   openbts/trunk/CommonLibs/Sockets.h
   openbts/trunk/Control/CallControl.cpp
   openbts/trunk/Control/ControlCommon.cpp
   openbts/trunk/Control/ControlCommon.h
   openbts/trunk/Control/Makefile.am
   openbts/trunk/Control/MobilityManagement.cpp
   openbts/trunk/Control/RadioResource.cpp
   openbts/trunk/Control/SMSControl.cpp
   openbts/trunk/GSM/GSMCommon.cpp
   openbts/trunk/GSM/GSMCommon.h
   openbts/trunk/GSM/GSMConfig.cpp
   openbts/trunk/GSM/GSMConfig.h
   openbts/trunk/GSM/GSML1FEC.cpp
   openbts/trunk/GSM/GSML1FEC.h
   openbts/trunk/GSM/GSML2LAPDm.cpp
   openbts/trunk/GSM/GSML3CCElements.cpp
   openbts/trunk/GSM/GSML3CCElements.h
   openbts/trunk/GSM/GSML3MMElements.h
   openbts/trunk/GSM/GSML3RRElements.cpp
   openbts/trunk/GSM/GSML3RRElements.h
   openbts/trunk/GSM/GSML3RRMessages.cpp
   openbts/trunk/GSM/GSML3RRMessages.h
   openbts/trunk/GSM/GSMLogicalChannel.cpp
   openbts/trunk/GSM/GSMLogicalChannel.h
   openbts/trunk/GSM/GSMTDMA.cpp
   openbts/trunk/GSM/GSMTransfer.h
   openbts/trunk/GSM/Makefile.am
   openbts/trunk/Globals/Globals.cpp
   openbts/trunk/Globals/Makefile.am
   openbts/trunk/Globals/Makefile.in
   openbts/trunk/HLR/Makefile.am
   openbts/trunk/HLR/Makefile.in
   openbts/trunk/LEGAL
   openbts/trunk/Makefile.am
   openbts/trunk/Makefile.common
   openbts/trunk/README
   openbts/trunk/SIP/SIPEngine.cpp
   openbts/trunk/SIP/SIPEngine.h
   openbts/trunk/SIP/SIPInterface.cpp
   openbts/trunk/SIP/SIPInterface.h
   openbts/trunk/SMS/Makefile.am
   openbts/trunk/TRXManager/Makefile.am
   openbts/trunk/TRXManager/TRXManager.cpp
   openbts/trunk/TRXManager/TRXManager.h
   openbts/trunk/Transceiver/Makefile.am
   openbts/trunk/Transceiver52M/Makefile.am
   openbts/trunk/Transceiver52M/Makefile.in
   openbts/trunk/Transceiver52M/Transceiver.cpp
   openbts/trunk/Transceiver52M/USRPDevice.cpp
   openbts/trunk/Transceiver52M/USRPDevice.h
   openbts/trunk/Transceiver52M/USRPping.cpp
   openbts/trunk/Transceiver52M/radioInterface.cpp
   openbts/trunk/Transceiver52M/radioInterface.h
   openbts/trunk/Transceiver52M/sigProcLib.cpp
   openbts/trunk/apps/Makefile.am
   openbts/trunk/apps/OpenBTS.config.example
   openbts/trunk/apps/OpenBTS.cpp
   openbts/trunk/configure.ac
   openbts/trunk/smqueue/Makefile.in
   openbts/trunk/smqueue/smqueue.config.example
   openbts/trunk/smqueue/smqueue.cpp
Log:
Inter-release update.  Beyond 2.5 but not yet releasing 2.6.


Modified: openbts/trunk/AUTHORS
===================================================================
--- openbts/trunk/AUTHORS       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/AUTHORS       2009-12-31 04:21:20 UTC (rev 11667)
@@ -184,3 +184,9 @@
     SMS/TLProcessor.cpp
     SMS/TLProcessor.h
     TRXManager/TRXManager.h
+
+Alon Levy, address@hidden
+    RRLPMessages.cpp
+    RRLPMessages.h
+    RRLPTest.cpp
+

Modified: openbts/trunk/CLI/CLI.cpp
===================================================================
--- openbts/trunk/CLI/CLI.cpp   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/CLI/CLI.cpp   2009-12-31 04:21:20 UTC (rev 11667)
@@ -22,21 +22,24 @@
 
 */
 
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
 
 #include <config.h>
 #include "CLI.h"
 #include <Logger.h>
 #include <Globals.h>
-#include <string.h>
 
-#include <iostream>
-#include <fstream>
-
 #include <GSMConfig.h>
 #include <GSMLogicalChannel.h>
 #include <ControlCommon.h>
+#include <TRXManager.h>
+#include <PowerManager.h>
 
-
 using namespace std;
 using namespace CommandLine;
 
@@ -47,6 +50,8 @@
 #define TOO_MANY_ARGS 4
 #define FAILURE 5
 
+extern TransceiverManager gTRX;
+
 /** Standard responses in the CLI, much mach erorrCode enum. */
 static const char* standardResponses[] = {
        "success", // 0
@@ -180,6 +185,7 @@
        }
        if (argc!=1) return BAD_NUM_ARGS;
        ParseTable::const_iterator cp = gParser.begin();
+       os << "Type \"help\" followed by the command name for help on that 
command." << endl;
        int c=0;
        while (cp != gParser.end()) {
                os << cp->first << '\t';
@@ -220,41 +226,89 @@
                os << tp->second << " 0x" << std::hex << tp->first << std::dec 
<< endl;
                ++tp;
        }
+       os << endl << gTMSITable.size() << " TMSIs in table";
        return SUCCESS;
 }
 
+int findIMSI(int argc, char** argv, ostream& os, istream& is)
+{
+       if (argc!=2) {
+               os << "usage: findimsi <imsiprefix>\n";
+               return BAD_VALUE;
+       }
+       Control::TMSIMap::const_iterator tp = gTMSITable.begin();
+       char buf[50]; // max size in decimal digits plus 1 plus RandomPositive
+       while (tp != gTMSITable.end()) {
+               std::string target;
+               sprintf(buf, "%d", tp->first);
+               std::string imsi = buf;
+               target.assign(imsi, 0, strlen(argv[1]));
+               if (target == argv[1])
+                       os << tp->second << " 0x" << std::hex << tp->first << 
std::dec << endl;
+               ++tp;
+       }
+       return SUCCESS;
+}
 
+int dumpTMSIs(int argc, char** argv, ostream& os, istream& is)
+{
+       if (argc != 2) {
+               os << "usage: dumptmsis <filename>\n";
+               return BAD_VALUE;
+       }
+       char* subargv[] = {"tmsis", NULL};
+       int subargc = 1;
+       ofstream fileout;
+       fileout.open(argv[1], ios::out); // erases existing!
+       printTMSIs(subargc, subargv, fileout, is);
+       return SUCCESS;
+}
 
-
 /** Submit an SMS for delivery to an IMSI. */
 int sendSMS(int argc, char** argv, ostream& os, istream& is)
 {
-       // FIXME -- Replace this with initiateMTTransaction.
-
        if (argc!=3) return BAD_NUM_ARGS;
 
+       os << "enter text to send: ";
+       char txtBuf[161];
+       cin.getline(txtBuf,160,'\n');
        char *IMSI = argv[1];
        char *srcAddr = argv[2];
 
+       Control::TransactionEntry transaction(
+               GSM::L3MobileIdentity(IMSI),
+               GSM::L3CMServiceType::MobileTerminatedShortMessage,
+               GSM::L3CallingPartyBCDNumber(srcAddr),
+               txtBuf);
+       transaction.Q931State(Control::TransactionEntry::Paging);
+       Control::initiateMTTransaction(transaction,GSM::SDCCHType,30000);
+       os << "message submitted for delivery" << endl;
+       return SUCCESS;
+}
+
+/** DEBUGGING: Sends a special sms that triggers a RRLP message to an IMSI. */
+int sendRRLP(int argc, char** argv, ostream& os, istream& is)
+{
+       if (argc!=3) return BAD_NUM_ARGS;
+
+       char *IMSI = argv[1];
+
        UDPSocket sock(0,"127.0.0.1",gConfig.getNum("SIP.Port"));
        unsigned port = sock.port();
        unsigned callID = random();
-       //unsigned port = gConfig.getNum("SMSLoopback.Port");
 
        // Just fake out a SIP message.
-       const char form[] = "MESSAGE sip:address@hidden SIP/2.0\nVia: 
SIP/2.0/UDP 127.0.0.1;branch=z9hG4bK776sgdkse\nMax-Forwards: 2\nFrom: %s 
<sip:address@hidden>:%d;tag=49583\nTo: sip:address@hidden: 
address@hidden:5063\nCSeq: 1 MESSAGE\nContent-Type: text/plain\nContent-Length: 
%d\n\n%s\n";
+       const char form[] = "MESSAGE sip:address@hidden SIP/2.0\nVia: 
SIP/2.0/TCP localhost;branch=z9hG4bK776sgdkse\nMax-Forwards: 2\nFrom: 
address@hidden:%d;tag=49583\nTo: sip:address@hidden: address@hidden:5063\nCSeq: 
1 MESSAGE\nContent-Type: text/plain\nContent-Length: %lu\n\n%s\n";
 
-       os << "enter text to send: ";
        char txtBuf[161];
-       cin.getline(txtBuf,160,'\n');
+       sprintf(txtBuf,"RRLP%s",argv[2]);
        char outbuf[2048];
-       
sprintf(outbuf,form,IMSI,srcAddr,srcAddr,port,IMSI,callID,strlen(txtBuf),txtBuf);
-       //UDPSocket sock(port,"127.0.0.1",gConfig.getNum("SIP.Port"));
+       sprintf(outbuf,form,IMSI,port,IMSI,callID,strlen(txtBuf),txtBuf);
        sock.write(outbuf);
        sleep(2);
        sock.write(outbuf);
        sock.close();
-       os << "message submitted for delivery" << endl;
+       os << "RRLP Triggering message submitted for delivery" << endl;
 
        return SUCCESS;
 }
@@ -266,6 +320,12 @@
 {
        os << "SDCCH load: " << gBTS.SDCCHActive() << '/' << gBTS.SDCCHTotal() 
<< endl;
        os << "TCH/F load: " << gBTS.TCHActive() << '/' << gBTS.TCHTotal() << 
endl;
+       os << "AGCH/PCH load: " << gBTS.AGCHLoad() << '/' << gBTS.PCHLoad() << 
endl;
+       // paging table size
+       os << "Paging table size: " << gBTS.pager().pagingEntryListSize() << 
endl;
+       os << "Transactions/TMSIs: " << gTransactionTable.size() << "/" << 
gTMSITable.size() << endl;
+       // 3122 timer current value (the number of seconds an MS should hold 
off the next RACH)
+       os << "T3122: " << gBTS.T3122() << " ms" << endl;
        return SUCCESS;
 }
 
@@ -343,17 +403,40 @@
                ++trans;
                count++;
        }
-       os << count << " transactions in table" << endl;
+       os << endl << count << " transactions in table" << endl;
        return SUCCESS;
 }
 
 
 
 /** Print current configuration table. */
-int printConfig(int argc, char** argv, ostream& os, istream& is)
+int config(int argc, char** argv, ostream& os, istream& is)
 {
-       if (argc!=1) return BAD_NUM_ARGS;
-       gConfig.dump(os);
+       // no args, just print
+       if (argc==1) {
+               gConfig.dump(os);
+               return SUCCESS;
+       }
+
+       // one arg, pattern match
+       if (argc==2) {
+               StringMap::const_iterator p = gConfig.begin();
+               while (p != gConfig.end()) {
+                       if (strstr(p->first.c_str(),argv[1]))
+                               os << p->first << ": " << p->second << endl;
+                       ++p;
+               }
+               return SUCCESS;
+       }
+
+       // >1 args: set new value
+       string val;
+       for (int i=2; i<argc; i++) val.append(argv[i]);
+       if (!gConfig.set(argv[1],val)) {
+               os << argv[1] << " is static and connot be altered after 
initialization" << endl;
+               return BAD_VALUE;
+       }
+       gBTS.regenerateBeacon();
        return SUCCESS;
 }
 
@@ -427,6 +510,16 @@
        return SUCCESS;
 }
 
+/** Print the list of alarms kept by the logger, i.e. the last LOG(ALARM) << 
<text> */
+int printAlarms(int argc, char** argv, ostream& os, istream& is)
+{
+       std::ostream_iterator<std::string> output( os, "\n" );
+       std::list<std::string> alarms = gGetLoggerAlarms();
+       std::copy( alarms.begin(), alarms.end(), output );
+       return SUCCESS;
+}
+
+
 /** Version string. */
 int version(int argc, char **argv, ostream& os, istream& is)
 {
@@ -435,20 +528,25 @@
        return SUCCESS;
 }
 
-
 int page(int argc, char **argv, ostream& os, istream& is)
 {
+       if (argc==1) {
+               gBTS.pager().dump(os);
+               return SUCCESS;
+       }
        if (argc!=3) return BAD_NUM_ARGS;
        char *IMSI = argv[1];
-       if (strlen(IMSI)!=15) {
+       if (strlen(IMSI)>15) {
                os << IMSI << " is not a valid IMSI" << endl;
                return BAD_VALUE;
        }
-       
gBTS.pager().addID(GSM::L3MobileIdentity(IMSI),GSM::SDCCHType,0,1000*atoi(argv[2]));
+       Control::TransactionEntry dummy;
+       
gBTS.pager().addID(GSM::L3MobileIdentity(IMSI),GSM::SDCCHType,dummy,1000*atoi(argv[2]));
        return SUCCESS;
 }
 
 
+
 int testcall(int argc, char **argv, ostream& os, istream& is)
 {
        if (argc!=3) return BAD_NUM_ARGS;
@@ -500,16 +598,34 @@
 
 
 
+void printChanInfo(const GSM::LogicalChannel* chan, ostream& os)
+{
+               os << chan->TN() << " " << chan->typeAndOffset() << " ";
+               os << (int)round(chan->FER()*100) << " ";
+               os << (int)round(chan->RSSI()) << " ";
+               os << chan->actualMSPower() << " " << chan->actualMSTiming() << 
" ";
+               const GSM::L3MeasurementResults& meas = 
chan->SACCH()->measurementResults();
+               if (meas.MEAS_VALID()) {
+                       os << meas.RXLEV_FULL_SERVING_CELL() << " ";
+                       os << meas.RXQUAL_FULL_SERVING_CELL() << " ";
+               }
+               os << endl;
+}
 
-int fer(int argc, char **argv, ostream& os, istream& is)
+
+
+int chans(int argc, char **argv, ostream& os, istream& is)
 {
        if (argc!=1) return BAD_NUM_ARGS;
 
+       os << "TN chan FER RSSI TXPWR TXTA RXLEV RXQUAL" << endl;
+       os << "TN type \%   dB   dBm   sym " << endl;
+
        // TCHs
        GSM::TCHList::const_iterator tChanItr = gBTS.TCHPool().begin();
        while (tChanItr != gBTS.TCHPool().end()) {
                const GSM::TCHFACCHLogicalChannel* tChan = *tChanItr;
-               if (tChan->active()) os << tChan->TN() << " " << 
tChan->typeAndOffset() << " " << tChan->FER() << endl;
+               if (tChan->active()) printChanInfo(tChan,os);
                ++tChanItr;
        }
 
@@ -517,7 +633,7 @@
        GSM::SDCCHList::const_iterator sChanItr = gBTS.SDCCHPool().begin();
        while (sChanItr != gBTS.SDCCHPool().end()) {
                const GSM::SDCCHLogicalChannel* sChan = *sChanItr;
-               if (sChan->active()) os << sChan->TN() << " " << 
sChan->typeAndOffset() << " " << sChan->FER() << endl;
+               if (sChan->active()) printChanInfo(sChan,os);
                ++sChanItr;
        }
 
@@ -527,6 +643,38 @@
 
 
 
+
+int power(int argc, char **argv, ostream& os, istream& is)
+{
+       os << "current downlink power " << gBTS.powerManager().power() << " dB 
wrt full scale" << endl;
+       os << "current attenuation bounds "
+               << gConfig.getNum("GSM.PowerManager.MinAttenDB")
+               << " to "
+               << gConfig.getNum("GSM.PowerManager.MaxAttenDB")
+               << " dB" << endl;
+
+       if (argc==1) return SUCCESS;
+       if (argc!=3) return BAD_NUM_ARGS;
+
+       int min = atoi(argv[1]);
+       int max = atoi(argv[2]);
+       if (min>max) return BAD_VALUE;
+
+       gConfig.set("GSM.PowerManager.MinAttenDB",argv[1]);
+       gConfig.set("GSM.PowerManager.MaxAttenDB",argv[2]);
+
+       os << "new attenuation bounds "
+               << gConfig.getNum("GSM.PowerManager.MinAttenDB")
+               << " to "
+               << gConfig.getNum("GSM.PowerManager.MaxAttenDB")
+               << " dB" << endl;
+
+       return SUCCESS;
+}
+
+
+
+
 //@} // CLI commands
 
 
@@ -540,21 +688,26 @@
        addCommand("help", getHelp, "[command] -- list available commands or 
gets help on a specific command.");
        addCommand("exit", dummy, "-- exit the application.");
        addCommand("tmsis", printTMSIs, "[\"clear\"] -- print/clear the TMSI 
table.");
+       addCommand("findimsi", findIMSI, "-- [IMSIPrefix] - prints all imsi's 
that are prefixed by IMSIPrefix");
+       addCommand("dumptmsis", dumpTMSIs, "-- dump TMSI table to ");
        addCommand("sendsms", sendSMS, "<IMSI> <src> -- send SMS to <IMSI>, 
addressed from <src>, after prompting.");
+       addCommand("sendrrlp", sendRRLP, "<IMSI> <hexstring> -- send RRLP 
message <hexstring> to <IMSI>.");
        addCommand("load", printStats, "-- print the current activity loads.");
        addCommand("cellid", cellID, "[MCC MNC LAC CI] -- get/set location area 
identity (MCC, MNC, LAC) and cell ID (CI)");
        addCommand("assignment", assignmentType, "[type] -- get/set assignment 
type (early, veryearly)");
        addCommand("calls", printTransactions, "-- print the transaction 
table");
-       addCommand("config", printConfig, "-- print the current configuration");
+       addCommand("config", config, "[] OR [patt] OR [key val(s)] -- print the 
current configuration, print configuration values matching a pattern, or 
set/change a configuration value");
        addCommand("configsave", dumpConfig, "<path> -- write the current 
configuration to a file");
        addCommand("regperiod", configRegistration, "[GSM] [SIP] -- get/set the 
registration period (GSM T3212), in MINUTES");
        addCommand("shortname", shortName, "[name] -- get/set the network short 
name");
+       addCommand("alarms", printAlarms, "-- show latest alarms");
        addCommand("version", version,"-- print the version string");
        addCommand("page", page, "IMSI time -- page the given IMSI for the 
given period");
        addCommand("testcall", testcall, "IMSI time -- initiate a test call to 
a given IMSI with a given paging time");
        addCommand("endcall", endcall,"trans# -- terminate the given 
transaction");
        addCommand("rolllac", rolllac, "[LAC] -- increment the LAC or set a net 
value");
-       addCommand("fer", fer, "-- report FER for active channels");
+       addCommand("chans", chans, "-- report PHY status for active channels");
+       addCommand("power", power, "[minAtten maxAtten] -- report current 
attentuation or set min/max bounds");
 
        // TODO -- Commands to add: FER, CI.
 }

Modified: openbts/trunk/CLI/CLI.h
===================================================================
--- openbts/trunk/CLI/CLI.h     2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/CLI/CLI.h     2009-12-31 04:21:20 UTC (rev 11667)
@@ -70,7 +70,6 @@
        /** Parse and execute a command string. */
        int execute(char* line, std::ostream& os, std::istream& is) const;
 
-
 };
 
 

Modified: openbts/trunk/CLI/Makefile.am
===================================================================
--- openbts/trunk/CLI/Makefile.am       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/CLI/Makefile.am       2009-12-31 04:21:20 UTC (rev 11667)
@@ -23,6 +23,7 @@
 EXTRA_DIST = \
        README.CLI 
 
+AM_CXXFLAGS = -Wall
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
 
 noinst_LTLIBRARIES = libcli.la

Modified: openbts/trunk/CLI/Makefile.in
===================================================================
--- openbts/trunk/CLI/Makefile.in       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/CLI/Makefile.in       2009-12-31 04:21:20 UTC (rev 11667)
@@ -237,6 +237,7 @@
 TRX_INCLUDEDIR = $(top_srcdir)/TRXManager
 GLOBALS_INCLUDEDIR = $(top_srcdir)/Globals
 CLI_INCLUDEDIR = $(top_srcdir)/CLI
+#SQL_INCLUDEDIR = $(top_srcdir)/SQL
 HLR_INCLUDEDIR = $(top_srcdir)/HLR
 STD_DEFINES_AND_INCLUDES = \
        -I$(COMMON_INCLUDEDIR) \
@@ -249,6 +250,7 @@
        -I$(CLI_INCLUDEDIR) \
        -I$(HLR_INCLUDEDIR)
 
+#      -I$(SQL_INCLUDEDIR)
 COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
 GSM_LA = $(top_builddir)/GSM/libGSM.la
 SIP_LA = $(top_builddir)/SIP/libSIP.la
@@ -258,10 +260,12 @@
 GLOBALS_LA = $(top_builddir)/Globals/libglobals.la
 CLI_LA = $(top_builddir)/CLI/libcli.la
 HLR_LA = $(top_builddir)/HLR/libHLR.la
+#SQL_LA = $(top_builddir)/SQL/libSQL.la
 MOSTLYCLEANFILES = *~
 EXTRA_DIST = \
        README.CLI 
 
+AM_CXXFLAGS = -Wall
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
 noinst_LTLIBRARIES = libcli.la
 libcli_la_SOURCES = \

Modified: openbts/trunk/CommonLibs/BitVector.cpp
===================================================================
--- openbts/trunk/CommonLibs/BitVector.cpp      2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/CommonLibs/BitVector.cpp      2009-12-31 04:21:20 UTC (rev 
11667)
@@ -1,5 +1,5 @@
 /*
-* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2008, 2009 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.
@@ -476,7 +476,7 @@
                const float *dp = mStart;
                for (size_t i=0; i<sz; i++) {
                        // pVal is the probability that a bit is correct.
-                       // ipVal is the probability that a bit is correct.
+                       // ipVal is the probability that a bit is incorrect.
                        float pVal = dp[i];
                        if (pVal>0.5F) pVal = 1.0F-pVal;
                        float ipVal = 1.0F-pVal;

Modified: openbts/trunk/CommonLibs/BitVector.h
===================================================================
--- openbts/trunk/CommonLibs/BitVector.h        2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/CommonLibs/BitVector.h        2009-12-31 04:21:20 UTC (rev 
11667)
@@ -1,5 +1,5 @@
 /*
-* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2008, 2009 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.

Modified: openbts/trunk/CommonLibs/Configuration.cpp
===================================================================
--- openbts/trunk/CommonLibs/Configuration.cpp  2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/CommonLibs/Configuration.cpp  2009-12-31 04:21:20 UTC (rev 
11667)
@@ -35,7 +35,7 @@
 {
        ifstream configFile(filename);
        if (!configFile) {
-               LOG(WARN) << "cannot open configuration file " << filename;
+               cerr << "cannot open configuration file " << filename << endl;
                return false;
        }
        while (configFile) {
@@ -49,13 +49,19 @@
                if (thisLine[i]=='#') continue;
                // Skip blank lines
                if (thisLine[i]=='\0') continue;
+               // Catch directives
+               if (thisLine[i]=='$') {
+                       processDirective(thisLine);
+                       continue;
+               }
                // Tokenize and put in the table.
                string::size_type pos = thisLine.find_first_of(" ",i);
+               string key = thisLine.substr(i,pos);
                if (pos==string::npos) {
-                       mTable[thisLine]="";
+                       mTable[key]="";
+                       LOG(DEBUG) << "configuring " << key << " with empty 
string";
                        continue;
                }
-               string key = thisLine.substr(0,pos);
                string value = thisLine.substr(pos+1);
                mTable[key]=value;
                LOG(DEBUG) << "configuring " << key << " = " << value;
@@ -65,7 +71,21 @@
 }
 
 
+void ConfigurationTable::processDirective(const string& thisLine)
+{
+       string::size_type pos = thisLine.find_first_of(" ");
+       string directive = thisLine.substr(1,pos-1);
+       if (directive=="static") {
+               string key = thisLine.substr(pos+1);
+               mStatic[key] = true;
+               LOG(DEBUG) << "configuring " << key << " as static";
+               return;
+       }
+       cerr << "invalid configuration directive: " << thisLine << endl;
+}
 
+
+
 bool ConfigurationTable::defines(const string& key) const
 {
        StringMap::const_iterator where = mTable.find(key);
@@ -74,6 +94,15 @@
 
 
 
+bool ConfigurationTable::isStatic(const string& key) const
+{
+       StringBoolMap::const_iterator where = mStatic.find(key);
+       if (where==mStatic.end()) return false;
+       return where->second;
+}
+
+
+
 const char* ConfigurationTable::getStr(const string& key) const
 {
        StringMap::const_iterator where = mTable.find(key);
@@ -108,11 +137,18 @@
        }
 }
 
-void ConfigurationTable::set(const string& key, long value)
+bool ConfigurationTable::set(const string& key, const string& value)
 {
+       if (isStatic(key)) return false;
+       mTable[key]=value;
+       return true;
+}
+
+bool ConfigurationTable::set(const string& key, long value)
+{
        char buffer[30];
        sprintf(buffer,"%ld",value);
-       set(key,buffer);
+       return set(key,buffer);
 }
 
 

Modified: openbts/trunk/CommonLibs/Configuration.h
===================================================================
--- openbts/trunk/CommonLibs/Configuration.h    2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/CommonLibs/Configuration.h    2009-12-31 04:21:20 UTC (rev 
11667)
@@ -55,6 +55,7 @@
 
 
 typedef std::map<std::string,std::string> StringMap;
+typedef std::map<std::string,bool> StringBoolMap;
 
 
 /**
@@ -68,8 +69,11 @@
 
        private:
 
-       StringMap mTable;
+       StringMap mTable;                       ///< The configuration table
+       StringBoolMap mStatic;          ///< Flags to indicate static config 
values.
 
+       // Static config values cannot be modified after initial file read.
+
        public:
 
        bool readFile(const char* filename);
@@ -82,6 +86,9 @@
        */
        bool defines(const std::string& key) const;
 
+       /** Return true if this key is identified as static. */
+       bool isStatic(const std::string& key) const;
+
        /**
                Get a string parameter from the table.
                Throw ConfigurationTableKeyNotFound if not found.
@@ -100,14 +107,24 @@
        std::vector<unsigned> getVector(const std::string& key) const;
 
        /** Set or change a value in the table.  */
-       void set(const std::string& key, const std::string& value)
-               { mTable[key]=value; }
+       bool set(const std::string& key, const std::string& value);
 
-       void set(const std::string& key, long value);
+       bool set(const std::string& key, long value);
 
        /** Dump the table to a stream. */
        void dump(std::ostream&) const;
 
+       /** Raw iterator. */
+       StringMap::const_iterator begin() const { return mTable.begin(); }
+
+       /** End check. */
+       StringMap::const_iterator end() const { return mTable.end(); }
+
+
+       private:
+
+       void processDirective(const std::string& line);
+
 };
 
 #endif

Modified: openbts/trunk/CommonLibs/ConfigurationTest.cpp
===================================================================
--- openbts/trunk/CommonLibs/ConfigurationTest.cpp      2009-12-31 03:03:10 UTC 
(rev 11666)
+++ openbts/trunk/CommonLibs/ConfigurationTest.cpp      2009-12-31 04:21:20 UTC 
(rev 11667)
@@ -46,6 +46,6 @@
 
        std::vector<unsigned> vect = config.getVector("key5");
        cout << "vect length " << vect.size() << ": ";
-       for (int i=0; i<vect.size(); i++) cout << " " << vect[i];
+       for (unsigned i=0; i<vect.size(); i++) cout << " " << vect[i];
        cout << endl;
 }

Modified: openbts/trunk/CommonLibs/F16.h
===================================================================
--- openbts/trunk/CommonLibs/F16.h      2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/CommonLibs/F16.h      2009-12-31 04:21:20 UTC (rev 11667)
@@ -26,7 +26,7 @@
 #ifndef F16_H
 #define F16_H
 
-
+#include <stdint.h>
 #include <ostream>
 
 
@@ -75,6 +75,7 @@
        F16 operator=(int i)
        {
                mV = i<<16;
+               return *this;
        }
 
        F16 operator=(const F16& other)

Modified: openbts/trunk/CommonLibs/Interthread.h
===================================================================
--- openbts/trunk/CommonLibs/Interthread.h      2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/CommonLibs/Interthread.h      2009-12-31 04:21:20 UTC (rev 
11667)
@@ -159,7 +159,7 @@
 
 
 
-       ~InterthreadQueueWithWait()
+       virtual ~InterthreadQueueWithWait()
                { clear(); }
 
 

Modified: openbts/trunk/CommonLibs/LogTest.cpp
===================================================================
--- openbts/trunk/CommonLibs/LogTest.cpp        2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/CommonLibs/LogTest.cpp        2009-12-31 04:21:20 UTC (rev 
11667)
@@ -22,8 +22,18 @@
 
 */
 
+#include <iostream>
+#include <iterator>
+
 #include "Logger.h"
 
+void printAlarms()
+{
+    std::ostream_iterator<std::string> output( std::cout, "\n" );
+    std::list<std::string> alarms = gGetLoggerAlarms();
+    std::cout << "#alarms = " << alarms.size() << std::endl;
+    std::copy( alarms.begin(), alarms.end(), output );
+}
 
 int main(int argc, char *argv[])
 {
@@ -34,6 +44,17 @@
        LOG(INFO) << " testing the logger.";
        LOG(DEBUG) << " testing the logger.";
        LOG(DEEPDEBUG) << " testing the logger.";
+    std::cout << "\n\n\n";
+    std::cout << "testing Alarms - you should run apps/showalarms.py to check 
udp\n";
+       LOG(ALARM) << " testing the logger alarm.";
+    std::cout << "you should see one line:" << std::endl;
+    printAlarms();
+    std::cout << "----------- generating 20 alarms ----------" << std::endl;
+    for (int i = 0 ; i < 20 ; ++i) {
+        LOG(ALARM) << i;
+    }
+    std::cout << "you should see ten line with the numbers 10..19:" << 
std::endl;
+    printAlarms();
 }
 
 

Modified: openbts/trunk/CommonLibs/Logger.cpp
===================================================================
--- openbts/trunk/CommonLibs/Logger.cpp 2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/CommonLibs/Logger.cpp 2009-12-31 04:21:20 UTC (rev 11667)
@@ -22,13 +22,16 @@
 
 */
 
-#include <stdio.h>
+#include <string.h>
+#include <cstdio>
+#include <fstream>
+
+#include "Configuration.h"
+#include "Sockets.h"
 #include "Logger.h"
 #include "Timeval.h"
-#include <string.h>
 
 
-
 using namespace std;
 
 
@@ -39,6 +42,19 @@
 /** The global logging lock. */
 static Mutex gLogLock;
 
+/**@ The global alarms table. */
+//@{
+const unsigned  gMaxAlarms = 10;
+Mutex           gAlarmsLock;
+list<string>    gAlarmsList;
+void            gAddAlarm(const string&);
+const unsigned int DEFAULT_ALARM_TARGET_PORT = 10101;
+const char*     DEFAULT_ALARM_TARGET_IP = "127.0.0.1";
+unsigned int    gAlarmTargetPort = DEFAULT_ALARM_TARGET_PORT;
+std::string     gAlarmTargetIP = DEFAULT_ALARM_TARGET_IP;
+//@}
+
+
 /** The current global logging level. */
 static Log::Level gLoggingLevel = Log::LOG_WARN;
 
@@ -102,8 +118,30 @@
        return retVal;
 }
 
+void gSetAlarmTargetPort(unsigned int port)
+{
+       LOG(INFO) << "setting ALARM target port to " << port;
+    gAlarmTargetPort = port;
+}
 
+void gSetAlarmTargetIP(const char* ip)
+{
+       LOG(INFO) << "setting ALARM target IP to " << ip;
+    gAlarmTargetIP = ip;
+}
 
+// copies the alarm list and returns it. list supposed to be small.
+std::list<std::string> gGetLoggerAlarms()
+{
+    gAlarmsLock.lock();
+    std::list<std::string> ret;
+    // excuse the "complexity", but to use std::copy with a list you need
+    // an insert_iterator - copy technically overwrites, doesn't insert.
+    std::insert_iterator< std::list<std::string> > ii(ret, ret.begin());
+    std::copy(gAlarmsList.begin(), gAlarmsList.end(), ii);
+    gAlarmsLock.unlock();
+    return ret;
+}
 
 ostream& operator<<(ostream& os, Log::Level level)
 {
@@ -112,11 +150,30 @@
 }
 
 
+// Add an alarm to the alarm list, and send it out via udp
+//
+// On the first call we read the ip and port from the configuration
+// TODO - is there any global setup function where this should be done? -- Alon
+void gAddAlarm(const string& s)
+{
+    gAlarmsLock.lock();
+       // Socket open and close on every alarm - wise?
+       // Probably.  That way we are sure to pick up changes in the target 
address.
+       // Alarms should not happen often.
+       UDPSocket alarmsocket(0, gAlarmTargetIP.c_str(), gAlarmTargetPort);
+       alarmsocket.write(s.c_str());
+    // append to list and reduce list to gMaxAlarms
+    gAlarmsList.push_back(s);
+    while (gAlarmsList.size() > gMaxAlarms) gAlarmsList.pop_front();
+    gAlarmsLock.unlock();
+}
 
 
 Log::~Log()
 {
        gLogLock.lock();
+       // XXX always handle alarms, even if the logging level is too low
+       if (mReportLevel == LOG_ALARM) gAddAlarm(mStream.str().c_str());
        if (mReportLevel>gLoggingLevel) return;
        mStream << std::endl;
        fprintf(gLoggingFile, "%s", mStream.str().c_str());

Modified: openbts/trunk/CommonLibs/Logger.h
===================================================================
--- openbts/trunk/CommonLibs/Logger.h   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/CommonLibs/Logger.h   2009-12-31 04:21:20 UTC (rev 11667)
@@ -27,6 +27,8 @@
 #define LOGGER_H
 
 #include <sstream>
+#include <list>
+#include <string>
 #include "Threads.h"
 
 
@@ -69,7 +71,6 @@
 
        static FILE *sFile;
 
-
        public:
 
        Log(Level wReportLevel = LOG_WARN)
@@ -84,6 +85,10 @@
 std::ostringstream& operator<<(std::ostringstream& os, Log::Level);
 
 
+
+std::list<std::string> gGetLoggerAlarms();             ///< Get a copy of the 
recent alarm list.
+
+
 /**@ Global logging level control. */
 //@{
 void gSetLogLevel(Log::Level);
@@ -98,7 +103,13 @@
 bool gSetLogFile(const char*);
 //@}
 
+/address@hidden Global logging alarm target host control. */
+//@{
+void gSetAlarmTargetPort(unsigned int);
+void gSetAlarmTargetIP(const char*);
+//@}
 
+
 #endif
 
 // vim: ts=4 sw=4

Modified: openbts/trunk/CommonLibs/Makefile.am
===================================================================
--- openbts/trunk/CommonLibs/Makefile.am        2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/CommonLibs/Makefile.am        2009-12-31 04:21:20 UTC (rev 
11667)
@@ -21,7 +21,7 @@
 include $(top_srcdir)/Makefile.common
 
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
-AM_CXXFLAGS = -O3 -g -lpthread
+AM_CXXFLAGS = -Wall -O3 -g -lpthread
 
 EXTRA_DIST = \
        example.config \

Modified: openbts/trunk/CommonLibs/Sockets.cpp
===================================================================
--- openbts/trunk/CommonLibs/Sockets.cpp        2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/CommonLibs/Sockets.cpp        2009-12-31 04:21:20 UTC (rev 
11667)
@@ -24,6 +24,9 @@
 
 
 
+#include <unistd.h>
+#include <fcntl.h>
+#include <cstdio>
 
 #include "Threads.h"
 #include "Sockets.h"
@@ -65,6 +68,10 @@
        fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
 }
 
+void DatagramSocket::blocking()
+{
+       fcntl(mSocketFD,F_SETFL,0);
+}
 
 void DatagramSocket::close()
 {

Modified: openbts/trunk/CommonLibs/Sockets.h
===================================================================
--- openbts/trunk/CommonLibs/Sockets.h  2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/CommonLibs/Sockets.h  2009-12-31 04:21:20 UTC (rev 11667)
@@ -114,6 +114,9 @@
        /** Make the socket non-blocking. */
        void nonblocking();
 
+       /** Make the socket blocking (the default). */
+       void blocking();
+
        /** Close the socket. */
        void close();
 

Modified: openbts/trunk/Control/CallControl.cpp
===================================================================
--- openbts/trunk/Control/CallControl.cpp       2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Control/CallControl.cpp       2009-12-31 04:21:20 UTC (rev 
11667)
@@ -66,7 +66,7 @@
 */
 unsigned allocateRTPPorts()
 {
-       // FIXME -- We need a real port allocator (bug #82).
+       // FIXME -- We need a real port allocator.
        const unsigned base = gConfig.getNum("RTP.Start");
        const unsigned range = gConfig.getNum("RTP.Range");
        const unsigned top = base+range;
@@ -172,25 +172,24 @@
 bool assignTCHF(TransactionEntry& transaction, SDCCHLogicalChannel *SDCCH, 
TCHFACCHLogicalChannel *TCH)
 {
        TCH->open();
-       // Try twice to send the assignment.
-       // (The spec says just try once...)
-       for (int i=0; i<2; i++) {
-               LOG(INFO) << "sending AssignmentCommand for " << TCH << " on " 
<< SDCCH;
-               
SDCCH->send(L3AssignmentCommand(TCH->channelDescription(),L3ChannelMode(L3ChannelMode::SpeechV1)));
-       
-               // This read is SUPPOSED to time out if the assignment was 
successful.
-               // Pad the timeout just in case there's a large latency 
somewhere.
-               L3Frame *result = SDCCH->recv(T3107ms+2000);
-               if (result==NULL) {
-                       LOG(INFO) << "completing normally";
-                       SDCCH->send(HARDRELEASE);
-                       return true;
-               }
-               LOG(NOTICE) << "received " << *result;
-               delete result;
+       TCH->setPhy(*SDCCH);
+
+       // Send the assignment.
+       LOG(INFO) << "assignTCHF sending AssignmentCommand for " << TCH << " on 
" << SDCCH;
+       
SDCCH->send(L3AssignmentCommand(TCH->channelDescription(),L3ChannelMode(L3ChannelMode::SpeechV1)));
+
+       // This read is SUPPOSED to time out if the assignment was successful.
+       // Pad the timeout just in case there's a large latency somewhere.
+       L3Frame *result = SDCCH->recv(T3107ms+2000);
+       if (result==NULL) {
+               LOG(INFO) << "assignmentTCHF exiting normally";
+               SDCCH->send(RELEASE);
+               return true;
        }
 
        // If we got here, the assignment failed.
+       LOG(NOTICE) << "assignTCHF received " << *result;
+       delete result;
 
        // Turn off the TCH.
        TCH->send(RELEASE);
@@ -502,6 +501,7 @@
 {
        // See if the radio link disappeared.
        if (TCH->radioFailure()) {
+               LOG(NOTICE) << "radio link failure, dropped call";
                forceSIPClearing(transaction);
                clearTransactionHistory(transaction);
                return true;
@@ -1172,10 +1172,10 @@
 
 
 
-void Control::initiateMTTransaction(const TransactionEntry& transaction, 
GSM::ChannelType chanType, unsigned pageTime)
+void Control::initiateMTTransaction(TransactionEntry& transaction, 
GSM::ChannelType chanType, unsigned pageTime)
 {
        gTransactionTable.add(transaction);
-       
gBTS.pager().addID(transaction.subscriber(),chanType,transaction.ID(),pageTime);
+       
gBTS.pager().addID(transaction.subscriber(),chanType,transaction,pageTime);
 }
 
 

Modified: openbts/trunk/Control/ControlCommon.cpp
===================================================================
--- openbts/trunk/Control/ControlCommon.cpp     2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Control/ControlCommon.cpp     2009-12-31 04:21:20 UTC (rev 
11667)
@@ -60,16 +60,17 @@
        mT301(T301ms), mT302(T302ms), mT303(T303ms),
        mT304(T304ms), mT305(T305ms), mT308(T308ms),
        mT310(T310ms), mT313(T313ms),
-       mT3113(GSM::T3113ms),
-       mTR1M(GSM::TR1Mms)
+       mT3113(gConfig.getNum("GSM.T3113")),
+       mTR1M(TR1Mms)
 {
        mMessage[0]='\0';
 }
 
 // Form for MT transactions.
-TransactionEntry::TransactionEntry(const GSM::L3MobileIdentity& wSubscriber, 
-       const GSM::L3CMServiceType& wService,
-       const GSM::L3CallingPartyBCDNumber& wCalling)
+TransactionEntry::TransactionEntry(const L3MobileIdentity& wSubscriber, 
+       const L3CMServiceType& wService,
+       const L3CallingPartyBCDNumber& wCalling,
+       const char *wMessage)
        :mID(gTransactionTable.newID()),
        mSubscriber(wSubscriber),mService(wService),
        mTIFlag(1), mTIValue(0),
@@ -78,17 +79,18 @@
        mT301(T301ms), mT302(T302ms), mT303(T303ms),
        mT304(T304ms), mT305(T305ms), mT308(T308ms),
        mT310(T310ms), mT313(T313ms),
-       mT3113(GSM::T3113ms),
-       mTR1M(GSM::TR1Mms)
+       mT3113(gConfig.getNum("GSM.T3113")),
+       mTR1M(TR1Mms)
 {
-       mMessage[0]='\0';
+       if (wMessage) strncpy(mMessage,wMessage,160);
+       else mMessage[0]='\0';
 }
 
 // Form for MO transactions.
-TransactionEntry::TransactionEntry(const GSM::L3MobileIdentity& wSubscriber,
-       const GSM::L3CMServiceType& wService,
+TransactionEntry::TransactionEntry(const L3MobileIdentity& wSubscriber,
+       const L3CMServiceType& wService,
        unsigned wTIValue,
-       const GSM::L3CalledPartyBCDNumber& wCalled)
+       const L3CalledPartyBCDNumber& wCalled)
        :mID(gTransactionTable.newID()),
        mSubscriber(wSubscriber),mService(wService),
        mTIFlag(0), mTIValue(wTIValue),
@@ -97,17 +99,17 @@
        mT301(T301ms), mT302(T302ms), mT303(T303ms),
        mT304(T304ms), mT305(T305ms), mT308(T308ms),
        mT310(T310ms), mT313(T313ms),
-       mT3113(GSM::T3113ms),
-       mTR1M(GSM::TR1Mms)
+       mT3113(gConfig.getNum("GSM.T3113")),
+       mTR1M(TR1Mms)
 {
        mMessage[0]='\0';
 }
 
 // Form for MT transactions.
-TransactionEntry::TransactionEntry(const GSM::L3MobileIdentity& wSubscriber,
-       const GSM::L3CMServiceType& wService,
+TransactionEntry::TransactionEntry(const L3MobileIdentity& wSubscriber,
+       const L3CMServiceType& wService,
        unsigned wTIValue,
-       const GSM::L3CallingPartyBCDNumber& wCalling)
+       const L3CallingPartyBCDNumber& wCalling)
        :mID(gTransactionTable.newID()),
        mSubscriber(wSubscriber),mService(wService),
        mTIFlag(1),mTIValue(wTIValue),mCalling(wCalling),
@@ -115,8 +117,8 @@
        mT301(T301ms), mT302(T302ms), mT303(T303ms),
        mT304(T304ms), mT305(T305ms), mT308(T308ms),
        mT310(T310ms), mT313(T313ms),
-       mT3113(GSM::T3113ms),
-       mTR1M(GSM::TR1Mms)
+       mT3113(gConfig.getNum("GSM.T3113")),
+       mTR1M(TR1Mms)
 {
        mMessage[0]='\0';
 }
@@ -184,7 +186,7 @@
 bool TransactionEntry::dead() const
 {
        if (mQ931State==NullState) return true;
-       if ((mQ931State==Paging)&&mT3113.expired()) return true;
+       if ((mQ931State==Paging) && mT3113.expired()) return true;
        return false;
 }
 
@@ -193,7 +195,7 @@
 {
        switch (state) {
                case TransactionEntry::NullState: os << "null"; break;
-               case TransactionEntry::Paging: os << "MTC paging"; break;
+               case TransactionEntry::Paging: os << "paging"; break;
                case TransactionEntry::MOCInitiated: os << "MOC initiated"; 
break;
                case TransactionEntry::MOCProceeding: os << "MOC proceeding"; 
break;
                case TransactionEntry::MTCConfirmed: os << "MTC confirmed"; 
break;
@@ -220,6 +222,7 @@
        if (entry.calling().digits()[0]) os << " from=" << 
entry.calling().digits();
        os << " Q.931State=" << entry.Q931State();
        os << " SIPState=" << entry.SIP().state();
+       os << " (" << (entry.stateAge()+500)/1000 << " sec)";
        if (entry.message()[0]) os << " message=\"" << entry.message() << "\"";
        return os;
 }
@@ -338,9 +341,12 @@
        return foundIt;
 }
 
+size_t TransactionTable::size()
+{
+       return mTable.size();
+}
 
 
-
 void Control::clearTransactionHistory( TransactionEntry& transaction )
 {
        SIP::SIPEngine& engine = transaction.SIP();
@@ -354,7 +360,11 @@
 {
        if (transactionID==0) return;
        TransactionEntry transaction;
-       if (gTransactionTable.find(transactionID,transaction)) 
clearTransactionHistory(transaction);
+       if (gTransactionTable.find(transactionID,transaction)) {
+               clearTransactionHistory(transaction);
+       } else {
+               LOG(INFO) << "clearTransactionHistory didn't find " << 
transactionID << "(size = " << gTransactionTable.size() << ")";
+       }
 }
 
 

Modified: openbts/trunk/Control/ControlCommon.h
===================================================================
--- openbts/trunk/Control/ControlCommon.h       2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Control/ControlCommon.h       2009-12-31 04:21:20 UTC (rev 
11667)
@@ -156,7 +156,9 @@
 /address@hidden Functions for radio resource operations. */
 //@{
 /** Decode RACH bits and send an immediate assignment. */
-void AccessGrantResponder(unsigned requestReference, const GSM::Time& when, 
float timingError);
+void AccessGrantResponder(
+       unsigned requestReference, const GSM::Time& when,
+       float RSSI, float timingError);
 /** 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. */
@@ -206,7 +208,7 @@
 //@}
 
 /** Create a new transaction entry and start paging. */
-void initiateMTTransaction(const TransactionEntry& transaction,
+void initiateMTTransaction(TransactionEntry& transaction,
                GSM::ChannelType chanType, unsigned pageTime);
 
 //@}
@@ -270,7 +272,7 @@
        const GSM::L3MobileIdentity& ID() const { return mID; }
 
        /** Access the channel type needed. */
-       const GSM::ChannelType type() const { return mType; }
+       GSM::ChannelType type() const { return mType; }
 
        unsigned transactionID() const { return mTransactionID; }
 
@@ -315,13 +317,14 @@
                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 transaction The transaction record, which will be 
modified.
                @param wLife The paging duration in ms, default based on SIP 
INVITE retry preiod, Timer A.
        */
        void addID(
                const GSM::L3MobileIdentity& addID,
                GSM::ChannelType chanType,
-               unsigned wTransactionID,
-               unsigned wLife=gConfig.getNum("SIP.Timer.A")
+               TransactionEntry& transaction,
+               unsigned wLife=2*gConfig.getNum("SIP.Timer.A")
        );
 
        /**
@@ -344,6 +347,14 @@
 
        /** C-style adapter. */
        friend void *PagerServiceLoopAdapter(Pager*);
+
+public:
+
+       /** return size of PagingEntryList */
+       size_t pagingEntryListSize();
+
+       /** Dump the paging list to an ostream. */
+       void dump(std::ostream&) const;
 };
 
 
@@ -387,7 +398,7 @@
 
        private:
 
-       unsigned mID;                                                   ///< 
the internal transaction ID, assigned by a TransactionTable
+       unsigned mID;                                           ///< the 
internal transaction ID, assigned by a TransactionTable
 
        GSM::L3MobileIdentity mSubscriber;              ///< some kind of 
subscriber ID, preferably IMSI
        GSM::L3CMServiceType mService;                  ///< the associated 
service type
@@ -396,8 +407,9 @@
        GSM::L3CalledPartyBCDNumber mCalled;    ///< the associated called 
party number, if known
        GSM::L3CallingPartyBCDNumber mCalling;  ///< the associated calling 
party number, if known
 
-       SIP::SIPEngine mSIP;                                            ///< 
the SIP IETF RFC-3621 protocol engine
-       Q931CallState mQ931State;                                       ///< 
the GSM/ISDN/Q.931 call state
+       SIP::SIPEngine mSIP;                                    ///< the SIP 
IETF RFC-3621 protocol engine
+       Q931CallState mQ931State;                               ///< the 
GSM/ISDN/Q.931 call state
+       Timeval mStateTimer;                                    ///< timestamp 
of last state change.
 
        char mMessage[256];                                             ///< 
text messaging payload
 
@@ -421,10 +433,11 @@
 
        TransactionEntry();
 
-       /** This form is used for MTC with TI set to 0. */
+       /** This form is used for MTC or MT-SMS with TI set to 0. */
        TransactionEntry(const GSM::L3MobileIdentity& wSubscriber, 
                const GSM::L3CMServiceType& wService,
-               const GSM::L3CallingPartyBCDNumber& wCalling);
+               const GSM::L3CallingPartyBCDNumber& wCalling,
+               const char *wMessage = NULL);
 
        /** This form is used for MOC. */
        TransactionEntry(const GSM::L3MobileIdentity& wSubscriber,
@@ -466,9 +479,16 @@
        SIP::SIPEngine& SIP() { return mSIP; }
        const SIP::SIPEngine& SIP() const { return mSIP; }
 
-       void Q931State(Q931CallState wState) { mQ931State=wState; }
+       void Q931State(Q931CallState wState)
+       {
+               mStateTimer.now();
+               mQ931State=wState;
+       }
+
        Q931CallState Q931State() const { return mQ931State; }
 
+       unsigned stateAge() const { return mStateTimer.elapsed(); }
+
        /address@hidden Timer access. */
        // TODO -- If we were clever, this would be a table.
        //@{
@@ -587,9 +607,11 @@
 
        /address@hidden to raw map. */
        //@{
-       TransactionMap::const_iterator begin() const { return mTable.begin(); }
+       TransactionMap::const_iterator begin() { clearDeadEntries(); return 
mTable.begin(); }
        TransactionMap::const_iterator end() const { return mTable.end(); }
        //@}
+
+       size_t size();
 };
 
 //@} // Transaction Table
@@ -652,7 +674,14 @@
        /** Clear the table completely. */
        void clear() { mMap.clear(); }
 
+       size_t size() const {
+               mLock.lock();
+               size_t retVal = mMap.size();
+               mLock.unlock();
+               return retVal;
+       }
 
+
        TMSIMap::const_iterator begin() const { return mMap.begin(); }
        TMSIMap::const_iterator end() const { return mMap.end(); }
 
@@ -746,7 +775,6 @@
 
 
 
-
 #endif
 
 // vim: ts=4 sw=4

Modified: openbts/trunk/Control/Makefile.am
===================================================================
--- openbts/trunk/Control/Makefile.am   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/Control/Makefile.am   2009-12-31 04:21:20 UTC (rev 11667)
@@ -21,6 +21,7 @@
 include $(top_srcdir)/Makefile.common
 
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
+AM_CXXFLAGS = -Wall -O3
 
 EXTRA_DIST = README.Control
 
@@ -32,7 +33,13 @@
        ControlCommon.cpp \
        MobilityManagement.cpp \
        RadioResource.cpp \
-       DCCHDispatch.cpp
+       DCCHDispatch.cpp \
+       CollectMSInfo.cpp \
+    RRLPQueryController.cpp
 
+# TODO - move CollectMSInfo.cpp and RRLPQueryController.cpp to RRLP directory.
+
 noinst_HEADERS = \
-       ControlCommon.h
+       ControlCommon.h \
+       CollectMSInfo.h \
+       RRLPQueryController.h

Modified: openbts/trunk/Control/MobilityManagement.cpp
===================================================================
--- openbts/trunk/Control/MobilityManagement.cpp        2009-12-31 03:03:10 UTC 
(rev 11666)
+++ openbts/trunk/Control/MobilityManagement.cpp        2009-12-31 04:21:20 UTC 
(rev 11667)
@@ -24,10 +24,8 @@
 */
 
 
+#include "Timeval.h"
 
-
-
-
 #include "ControlCommon.h"
 #include "GSMLogicalChannel.h"
 #include "GSML3RRMessages.h"
@@ -35,6 +33,8 @@
 #include "GSML3CCMessages.h"
 #include "GSMConfig.h"
 
+#include "CollectMSInfo.h"
+
 using namespace std;
 
 #include "SIPInterface.h"
@@ -48,9 +48,6 @@
 using namespace Control;
 
 
-
-
-
 /** Controller for CM Service requests, dispatches out to multiple possible 
transaction controllers. */
 void Control::CMServiceResponder(const L3CMServiceRequest* cmsrq, 
LogicalChannel* DCCH)
 {
@@ -126,7 +123,6 @@
 }
 
 
-
 /**
        Controller for the Location Updating transaction, GSM 04.08 4.4.4.
        @param lur The location updating request.
@@ -163,6 +159,8 @@
                LOG(ALARM) "SIP registration timed out.  Is Asterisk running?";
                // Reject with a "network failure" cause code, 0x11.
                SDCCH->send(L3LocationUpdatingReject(0x11));
+               // HACK -- wait long enough for a response
+               sleep(4);
                // Release the channel and return.
                SDCCH->send(L3ChannelRelease());
                return;
@@ -178,8 +176,18 @@
        if (!success && !openRegistration) {
                LOG(INFO) << "registration FAILED: " << mobID;
                
SDCCH->send(L3LocationUpdatingReject(gConfig.getNum("GSM.LURejectCause")));
+               // Get position information anyhow. Slightly Evil.
+               bool withRRLP = gConfig.defines("GSM.RRLP") &&
+                       (gConfig.getNum("GSM.RRLP") == 1) &&
+                       gConfig.defines("RRLP.LocationUpdate") &&
+                       (gConfig.getNum("RRLP.LocationUpdate") == 1);
+               LOG(INFO) << "Collecting MS Info withRRLP = " << withRRLP;
+               GSM::RRLP::collectMSInfo(mobID, SDCCH, withRRLP);
                sendWelcomeMessage( "Control.FailedRegistrationWelcomeMessage",
                        "Control.FailedRegistrationWelcomeShortCode", SDCCH);
+               // Release the channel and return.
+               SDCCH->send(L3ChannelRelease());
+               return;
        }
 
        // If success is true, we had a normal registration.
@@ -194,8 +202,19 @@
        // TODO -- Set the handset clock in this message, too.
        SDCCH->send(L3MMInformation(gBTS.shortName()));
        // Accept. Make a TMSI assignment, too, if needed.
-       if (assignedTMSI) SDCCH->send(L3LocationUpdatingAccept(gBTS.LAI()));
-       else 
SDCCH->send(L3LocationUpdatingAccept(gBTS.LAI(),gTMSITable.assign(mobID.digits())));
+       if (assignedTMSI) {
+               SDCCH->send(L3LocationUpdatingAccept(gBTS.LAI()));
+       } else {
+               
SDCCH->send(L3LocationUpdatingAccept(gBTS.LAI(),gTMSITable.assign(mobID.digits())));
+               L3Frame* resp = SDCCH->recv(1000); // wait for the MM TMSI 
REALLOCATION COMPLETE message
+               if (!resp) {
+                       LOG(INFO) << "LocationUpdatingController no response to 
TMSI assignment";
+               } else {
+                       LOG(INFO) << "LocationUpdatingController got back a " 
<< *resp;
+               }
+               delete resp;
+       }
+
        // If this is an IMSI attach, send a welcome message.
        if (IMSIAttach) {
                if (success) {
@@ -207,6 +226,11 @@
                }
        }
 
+       GSM::RRLP::collectMSInfo(mobID, SDCCH, false/* no RRLP */);
+
+       // HACK -- wait long enough for a response
+       sleep(4);
+
        // Release the channel and return.
        SDCCH->send(L3ChannelRelease());
        return;
@@ -215,5 +239,4 @@
 
 
 
-
 // vim: ts=4 sw=4

Modified: openbts/trunk/Control/RadioResource.cpp
===================================================================
--- openbts/trunk/Control/RadioResource.cpp     2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Control/RadioResource.cpp     2009-12-31 04:21:20 UTC (rev 
11667)
@@ -1,7 +1,7 @@
 /address@hidden GSM Radio Resource procedures, GSM 04.18 and GSM 04.08. */
 
 /*
-* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2008, 2009 Free Software Foundation, Inc.
 *
 
     This program is free software: you can redistribute it and/or modify
@@ -46,44 +46,11 @@
 
 
 
-/address@hidden Mechanisms for exponential backoff of T3122, the access 
holdoff timer. */
-//@{
 
-unsigned curT3122ms = 5000;
-Mutex curT3122Lock;
-
 /**
-       Get latest value of T3122 and apply exponential backoff.
-       @return Current T3122 value in ms.
-*/
-unsigned curT3122()
-{
-       curT3122Lock.lock();
-       unsigned retVal = curT3122ms;
-       // Apply exponential back-off.
-       curT3122ms += (random() % curT3122ms) / 2;
-       unsigned max = gConfig.getNum("GSM.T3122Max");
-       if (curT3122ms>max) curT3122ms=max;
-       curT3122Lock.unlock();
-       return retVal;
-}
-
-/** Restore T3122 to the base value.  */
-void restoreT3122()
-{
-       curT3122Lock.lock();
-       curT3122ms = gConfig.getNum("GSM.T3122Min");
-       curT3122Lock.unlock();
-}
-
-//@}
-
-
-/**
        Determine the channel type needed.
        This is based on GSM 04.08 9.1.8, 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.
@@ -91,47 +58,67 @@
 */
 ChannelType decodeChannelNeeded(unsigned RA)
 {
-       // These values assume NECI is 0.
-       // This code is formatted in the same order as GSM 04.08 Table 9.9.
-       //
-       // Emergency
-       //
+       // This code is based on GSM 04.08 Table 9.9.
+
+       unsigned RA4 = RA>>4;
+       unsigned RA5 = RA>>5;
+
        // FIXME -- Use SDCCH to start emergency call, since some handsets 
don't support VEA.
-       if ((RA>>5) == 0x05) return TCHFType;                   // emergency 
call
-       //
-       // skip re-establishment cases
-       //
-       // "Answer to paging"
-       //
-       // We do not send the "any channel" paging indication, just SDCCH and 
TCH/F.
-       // Cases where we sent SDCCH.
-       if ((RA>>4) == 0x01) return SDCCHType;                  // answer to 
paging, SDCCH
-       // Cases where we sent TCH/F.
-       if ((RA>>5) == 0x04) return TCHFType;                   // answer to 
paging, any channel
-       if ((RA>>4) == 0x02) return TCHFType;                   // answer to 
paging, TCH/F
-       // We don't send TCH/[FH], either.
-       //
-       // MOC or SDCCH procedures.
-       //
-       if ((RA>>5) == 0x07) return SDCCHType;                  // MOC or SDCCH 
procedures
-       //
-       // Location updating.
-       //
-       if ((RA>>5) == 0x00) return SDCCHType;                  // location 
updating
-       //
-       // skip packet (GPRS) cases
-       //
-       // skip LMU case
-       //
-       // skip reserved cases
-       //
+       if (RA5 == 0x05) return TCHFType;               // emergency call
+
+       // Answer to paging, Table 9.9a.
+       // We don't support TCH/H, so it's wither SDCCH or TCH/F.
+       // The spec allows for "SDCCH-only" MS.  We won't support that here.
+       // FIXME -- So we probably should not use "any channel" in the paging 
indications.
+       if (RA5 == 0x04) return TCHFType;               // any channel or any 
TCH.
+       if (RA4 == 0x01) return SDCCHType;              // SDCCH
+       if (RA4 == 0x02) return TCHFType;               // TCH/F
+       if (RA4 == 0x03) return TCHFType;               // TCH/F
+
+       int NECI = gConfig.getNum("GSM.CS.NECI");
+       if (NECI==0) {
+               if (RA5 == 0x07) return SDCCHType;              // MOC or SDCCH 
procedures
+               if (RA5 == 0x00) return SDCCHType;              // location 
updating
+       } else {
+               assert(NECI==1);
+               bool veryEarly = gConfig.getNum("GSM.AssignmentType");
+               if (veryEarly) {
+                       if (RA5 == 0x07) return TCHFType;               // MOC 
for TCH/F
+                       if (RA4 == 0x04) return TCHFType;               // MOC, 
TCH/H sufficient
+               } else {
+                       if (RA5 == 0x07) return SDCCHType;              // MOC 
for TCH/F
+                       if (RA4 == 0x04) return SDCCHType;              // MOC, 
TCH/H sufficient
+               }
+               if (RA4 == 0x00) return SDCCHType;              // location 
updating
+               if (RA4 == 0x01) return SDCCHType;              // other 
procedures on SDCCH
+       }
+
        // Anything else falls through to here.
+       // We are still ignoring data calls, GPRS, LMU.
        return UndefinedCHType;
 }
 
 
-void Control::AccessGrantResponder(unsigned RA, const GSM::Time& when, float 
timingError)
+/** Return true is RA indicates LUR. */
+bool requestingLUR(unsigned RA)
 {
+       unsigned RA4 = RA>>4;
+       unsigned RA5 = RA>>5;
+       int NECI = gConfig.getNum("GSM.CS.NECI");
+       if (NECI==0) {
+               if (RA5 == 0x00) return true;
+       } else {
+               assert(NECI==1);
+               if (RA4 == 0x00) return true;
+       }
+       return false;
+}
+
+
+void Control::AccessGrantResponder(
+               unsigned RA, const GSM::Time& when,
+               float RSSI, float timingError)
+{
        // RR Establishment.
        // Immediate Assignment procedure, "Answer from the Network"
        // GSM 04.08 3.3.1.1.3.
@@ -140,19 +127,17 @@
        // This GSM's version of medium access control.
        // Papa Legba, open that door...
 
-       // FIXME -- Need to deal with initial timing advance, too.
-
        // Check "when" against current clock to see if we're too late.
        // Calculate maximum number of frames of delay.
        // See GSM 04.08 3.3.1.1.2 for the logic here.
        static const unsigned txInteger = gConfig.getNum("GSM.RACH.TxInteger");
-       static const unsigned maxAge = GSM::RACHSpreadSlots[txInteger] + 
GSM::RACHWaitSParam[txInteger];
+       static const int maxAge = GSM::RACHSpreadSlots[txInteger] + 
GSM::RACHWaitSParam[txInteger];
        // Check burst age.
        int age = gBTS.time() - when;
        LOG(INFO) << "RA=0x" << hex << RA << dec
                << " when=" << when << " age=" << age << " TOA=" << timingError;
        if (age>maxAge) {
-               LOG(NOTICE) << "ignoring RACH bust with age " << age;
+               LOG(WARN) << "ignoring RACH bust with age " << age;
                return;
        }
 
@@ -161,13 +146,32 @@
                if (timingError > gConfig.getNum("GSM.MaxRACHDelay")) return;
        }
 
+
+       // Get an AGCH to send on.
+       CCCHLogicalChannel *AGCH = gBTS.getAGCH();
+       // Someone had better have created a least one AGCH.
+       assert(AGCH);
+
+       // Check for location update.
+       // This gives LUR a lower priority than other services.
+       if (requestingLUR(RA)) {
+               if 
(gBTS.SDCCHAvailable()<=gConfig.getNum("GSM.PagingReservations")) {
+                       unsigned waitTime = gBTS.growT3122()/1000;
+                       LOG(NOTICE) << "AccessGrantResponder: LUR congestion, 
RA=" << RA << " T3122=" << waitTime;
+                       const L3ImmediateAssignmentReject 
reject(L3RequestReference(RA,when),waitTime);
+                       LOG(DEBUG) << "AccessGrantResponder: LUR rejection, 
sending " << reject;
+                       if (AGCH->load()<gConfig.getNum("GSM.AGCHMaxQueue")) 
AGCH->send(reject);
+                       else LOG(NOTICE) "AccessGrantResponder: AGCH 
congestion";
+                       return;
+               }
+       }
+
        // Allocate the channel according to the needed type indicated by RA.
        // The returned channel is already open and ready for the transaction.
        LogicalChannel *LCH = NULL;
        switch (decodeChannelNeeded(RA)) {
                case TCHFType: LCH = gBTS.getTCH(); break;
                case SDCCHType: LCH = gBTS.getSDCCH(); break;
-               // FIXME -- Should probably assign to an SDCCH and then send a 
reject of some kind.
                // If we don't support the service, assign to an SDCCH and we 
can reject it in L3.
                case UndefinedCHType:
                        LOG(NOTICE) << "RACH burst for unsupported service";
@@ -177,23 +181,22 @@
                default: assert(0);
        }
 
-       // Get an AGCH to send on.
-       CCCHLogicalChannel *AGCH = gBTS.getAGCH();
-       // Someone had better have created a least one AGCH.
-       assert(AGCH);
-
        // Nothing available?
        if (!LCH) {
                // Rejection, GSM 04.08 3.3.1.1.3.2.
                // BTW, emergency calls are not subject to T3122 hold-off.
-               unsigned waitTime = curT3122()/1000;
-               LOG(NOTICE) << "CONGESTION, T3122=" << waitTime;
+               unsigned waitTime = gBTS.growT3122()/1000;
+               LOG(NOTICE) << "AccessGrantResponder: congestion, RA=" << RA << 
" T3122=" << waitTime;
                const L3ImmediateAssignmentReject 
reject(L3RequestReference(RA,when),waitTime);
                LOG(DEBUG) << "rejection, sending " << reject;
-               AGCH->send(reject);
+               if (AGCH->load()<gConfig.getNum("GSM.AGCHMaxQueue")) 
AGCH->send(reject);
+               else LOG(NOTICE) "AccessGrantResponder: AGCH congestion";
                return;
        }
 
+       // Set the channel physical parameters from the RACH burst.
+       LCH->setPhy(RSSI,timingError);
+
        // Assignment, GSM 04.08 3.3.1.1.3.1.
        // Create the ImmediateAssignment message.
        int initialTA = (int)(timingError + 0.5F);
@@ -207,8 +210,8 @@
        LOG(INFO) << "sending " << assign;
        AGCH->send(assign);
 
-       // Reset exponential back-off upon successful allocation.
-       restoreT3122();
+       // On successful allocation, shrink T3122.
+       gBTS.shrinkT3122();
 }
 
 
@@ -320,15 +323,17 @@
 
 
 void Pager::addID(const L3MobileIdentity& newID, ChannelType chanType,
-               unsigned wTransactionID, unsigned wLife)
+               TransactionEntry& transaction, unsigned wLife)
 {
+       transaction.Q931State(TransactionEntry::Paging);
+       transaction.T3113().set(wLife);
+       gTransactionTable.update(transaction);
        // Add a mobile ID to the paging list for a given lifetime.
        mLock.lock();
        // If this ID is already in the list, just reset its timer.
        // Uhg, another linear time search.
        // This would be faster if the paging list were ordered by ID.
        // But the list should usually be short, so it may not be worth the 
effort.
-       bool renewed = false;
        for (PagingEntryList::iterator lp = mPageIDs.begin(); lp != 
mPageIDs.end(); ++lp) {
                if (lp->ID()==newID) {
                        LOG(DEBUG) << newID << " already in table";
@@ -339,7 +344,7 @@
                }
        }
        // If this ID is new, put it in the list.
-       mPageIDs.push_back(PagingEntry(newID,chanType,wTransactionID,wLife));
+       mPageIDs.push_back(PagingEntry(newID,chanType,transaction.ID(),wLife));
        LOG(INFO) << newID << " added to table";
        mPageSignal.signal();
        mLock.unlock();
@@ -396,16 +401,14 @@
                // HACK -- So we send every page twice.
                // That will probably mean a different Pager for each 
subchannel.
                // See 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();
                ChannelType type1 = lp->type();
                ++lp;
                if (lp==mPageIDs.end()) {
                        // Just one ID left?
                        LOG(DEBUG) << "paging " << id1;
-                       PCH->send(L3PagingRequestType1(id1,type1));
-                       PCH->send(L3PagingRequestType1(id1,type1));
+                       gBTS.getPCH(0)->send(L3PagingRequestType1(id1,type1));
+                       gBTS.getPCH(0)->send(L3PagingRequestType1(id1,type1));
                        break;
                }
                // Page by pairs when possible.
@@ -413,8 +416,8 @@
                ChannelType type2 = lp->type();
                ++lp;
                LOG(DEBUG) << "paging " << id1 << " and " << id2;
-               PCH->send(L3PagingRequestType1(id1,type1,id2,type2));
-               PCH->send(L3PagingRequestType1(id1,type1,id2,type2));
+               gBTS.getPCH(0)->send(L3PagingRequestType1(id1,type1,id2,type2));
+               gBTS.getPCH(0)->send(L3PagingRequestType1(id1,type1,id2,type2));
        }
        
        mLock.unlock();
@@ -422,8 +425,11 @@
        return mPageIDs.size();
 }
 
+size_t Pager::pagingEntryListSize()
+{
+       return mPageIDs.size();
+}
 
-
 void Pager::start()
 {
        if (mRunning) return;
@@ -443,25 +449,33 @@
 {
        while (mRunning) {
 
+               LOG(DEBUG) << "Pager blocking for signal";
+               mLock.lock();
+               while (mPageIDs.size()==0) mPageSignal.wait(mLock);
+               mLock.unlock();
+
+               // page everything
+               pageAll();
+
                // Wait for pending activity to clear the channel.
                // This wait is what causes PCH to have lower priority than 
AGCH.
                unsigned load = gBTS.getPCH()->load();
                LOG(DEBUG) << "Pager waiting for " << load << " multiframes";
                if (load) sleepFrames(51*load);
+       }
+}
 
-               // Page the list.
-               // If there is nothing to page,
-               // wait for a new entry in the list.
-               if (!pageAll()) {
-                       LOG(DEBUG) << "Pager blocking for signal";
-                       mLock.lock();
-                       while (mPageIDs.size()==0) mPageSignal.wait(mLock);
-                       mLock.unlock();
-               }
+
+
+void Pager::dump(ostream& os) const
+{
+       PagingEntryList::const_iterator lp = mPageIDs.begin();
+       while (lp != mPageIDs.end()) {
+               os << lp->ID() << " " << lp->type() << " " << lp->expired() << 
endl;
+               ++lp;
        }
 }
 
 
 
-
 // vim: ts=4 sw=4

Modified: openbts/trunk/Control/SMSControl.cpp
===================================================================
--- openbts/trunk/Control/SMSControl.cpp        2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Control/SMSControl.cpp        2009-12-31 04:21:20 UTC (rev 
11667)
@@ -61,6 +61,7 @@
 #include "SIPEngine.h"
 using namespace SIP;
 
+#include "CollectMSInfo.h"
 
 /**
        Read an L3Frame from SAP3.
@@ -404,6 +405,15 @@
        ack.parse(*CM);
        LOG(INFO) << "CPAck " << ack;
 
+       // RRLP Here if enabled
+       if (gConfig.defines("GSM.RRLP") && gConfig.getNum("GSM.RRLP") == 1 &&
+               gConfig.defines("RRLP.LocationUpdate") && 
gConfig.getNum("RRLP.LocationUpdate") == 1 /* RRLP? */)
+       {
+               Timeval start;
+               RRLP::collectMSInfo(mobileIdentity, LCH, true /* DO RRLP */);
+               LOG(INFO) << "submitSMS with RRLP took " << start.elapsed() << 
" for IMSI " << mobileIdentity;
+       }
+
        // Done.
        LOG(INFO) << "closing";
        LCH->send(L3ChannelRelease());
@@ -438,7 +448,7 @@
                RPData(reference,
                        RPAddress(gConfig.getStr("SMS.FakeSrcSMSC")),
                        TLDeliver(callingPartyDigits,message,TLPID)));
-       LOG(DEBUG) << "MTSMS: sending " << deliver;
+       LOG(INFO) << "sending " << deliver;
        LCH->send(deliver,3);
 
        // Step 2
@@ -499,12 +509,52 @@
 
 
 
+// Some utils for the RRLP hack below
+int hexchr2int(char c)
+{
+       if (c >= '0' && c <= '9')
+               return c - '0';
+       if (c >= 'a' && c <= 'z')
+               return c - 'a' + 10;
+       if (c >= 'A' && c <= 'Z')
+               return c - 'A' + 10;
+       return -10000;
+}
 
+BitVector hex2bitvector(const char* s)
+{
+       BitVector ret(strlen(s)*4);
+       size_t write_pos = 0;
+       for (;*s != 0 && *(s+1) != 0; s+= 2) {
+               ret.writeField(write_pos, hexchr2int(*s), 4);
+               ret.writeField(write_pos, hexchr2int(*(s+1)), 4);
+       }
+       return ret;
+}
+
+
 void Control::MTSMSController(TransactionEntry& transaction, 
                                                LogicalChannel *LCH)
 {
        assert(LCH);
 
+       // HACK: At this point if the message starts with "RRLP" then we don't 
do SMS at all,
+       // but instead to an RRLP transaction over the already allocated 
LogicalChannel.
+       const char* m = transaction.message(); // NOTE - not very nice, my way 
of checking.
+       if ((strlen(m) > 4) && (std::string("RRLP") == std::string(m, m+4))) {
+               BitVector rrlp_position_request = 
hex2bitvector(transaction.message() + 4);
+               LOG(INFO) << "MTSMS: Sending RRLP";
+        // TODO - how to get mobID here?
+        L3MobileIdentity mobID = L3MobileIdentity("000000000000000");
+               RRLP::PositionResult pr = GSM::RRLP::doRRLPQuery(mobID, LCH, 
rrlp_position_request);
+               if (pr.mValid) // in this case we only want to log the results 
which contain lat/lon
+                       logMSInfo(LCH, pr, mobID);
+               LOG(INFO) << "MTSMS: Closing channel after RRLP";
+               LCH->send(L3ChannelRelease());
+               clearTransactionHistory(transaction);
+               return;
+       }
+
        // See GSM 04.11 Arrow Diagram A5 for the transaction
        // Step 1       Network->MS     CP-DATA containing RP-DATA
        // Step 2       MS->Network     CP-ACK

Modified: openbts/trunk/GSM/GSMCommon.cpp
===================================================================
--- openbts/trunk/GSM/GSMCommon.cpp     2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSMCommon.cpp     2009-12-31 04:21:20 UTC (rev 11667)
@@ -333,6 +333,13 @@
        mActive=true;
 } 
 
+void Z100Timer::set(long wLimitTime)
+{
+       mLimitTime = wLimitTime;
+       set();
+} 
+
+
 long Z100Timer::remaining() const
 {
        if (!mActive) return 0;

Modified: openbts/trunk/GSM/GSMCommon.h
===================================================================
--- openbts/trunk/GSM/GSMCommon.h       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSMCommon.h       2009-12-31 04:21:20 UTC (rev 11667)
@@ -116,9 +116,8 @@
 //@{
 const unsigned T3101ms = 4000;         ///< L1 timeout for SDCCH assignment
 const unsigned T3107ms = 3000;         ///< L1 timeout for TCH/FACCH assignment
-const unsigned T3109ms = 10000;                ///< L1 timeout for an existing 
channel
+const unsigned T3109ms = 30000;                ///< L1 timeout for an existing 
channel
 const unsigned T3111ms = 2*T200ms;     ///< L1 timeout for reassignment of a 
channel
-const unsigned T3113ms = 10000;                ///< timeout for paging response
 //@}
 /address@hidden GSM timeouts for mobility management, GSM 04.08 11.2. */
 //@{
@@ -558,6 +557,9 @@
        /** Start or restart the timer. */
        void set();
 
+       /** Start or restart the timer, possibly specifying a new limit. */
+       void set(long wLimitTime);
+
        /** Stop the timer. */
        void reset() { mActive = false; }
 

Modified: openbts/trunk/GSM/GSMConfig.cpp
===================================================================
--- openbts/trunk/GSM/GSMConfig.cpp     2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSMConfig.cpp     2009-12-31 04:21:20 UTC (rev 11667)
@@ -36,16 +36,24 @@
 
 
 GSMConfig::GSMConfig()
-       :mSI5Frame(UNIT_DATA),mSI6Frame(UNIT_DATA),
+       :mBand((GSMBand)gConfig.getNum("GSM.Band")),
+       mSI5Frame(UNIT_DATA),mSI6Frame(UNIT_DATA),
+       mT3122(gConfig.getNum("GSM.T3122Min")),
        mStartTime(::time(NULL))
 {
-       mBand = (GSMBand)gConfig.getNum("GSM.Band");
        regenerateBeacon();
 }
 
+void GSMConfig::start()
+{
+       mPowerManager.start();
+       // Do not call this until the paging channels are installed.
+       mPager.start();
+}
 
 
 
+
 void GSMConfig::regenerateBeacon()
 {
        // Update everything from the configuration.
@@ -177,39 +185,45 @@
 
 
 
-template <class ChanType> bool chanAvailable(const vector<ChanType*>& chanList)
+template <class ChanType> size_t chanAvailable(const vector<ChanType*>& 
chanList)
 {
+       size_t count = 0;
        for (unsigned i=0; i<chanList.size(); i++) {
-               ChanType *chan = chanList[i];
-               if (chanList[i]->recyclable()) return true;
+               if (chanList[i]->recyclable()) count++;
        }
-       return false;
+       return count;
 }
 
 
 
-bool GSMConfig::SDCCHAvailable() const
+size_t GSMConfig::SDCCHAvailable() const
 {
        mLock.lock();
-       bool retVal = chanAvailable<SDCCHLogicalChannel>(mSDCCHPool);
+       size_t retVal = chanAvailable<SDCCHLogicalChannel>(mSDCCHPool);
        mLock.unlock();
        return retVal;
 }
 
-bool GSMConfig::TCHAvailable() const
+size_t GSMConfig::TCHAvailable() const
 {
        mLock.lock();
-       bool retVal = chanAvailable<TCHFACCHLogicalChannel>(mTCHPool);
+       size_t retVal = chanAvailable<TCHFACCHLogicalChannel>(mTCHPool);
        mLock.unlock();
        return retVal;
 }
 
 
+size_t GSMConfig::totalLoad(const CCCHList& chanList) const
+{
+       size_t total = 0;
+       for (int i=0; i<chanList.size(); i++) {
+               total += chanList[i]->load();
+       }
+       return total;
+}
 
 
 
-
-
 template <class ChanType> unsigned countActive(const vector<ChanType*>& 
chanList)
 {
        unsigned active = 0;
@@ -233,4 +247,37 @@
 }
 
 
+unsigned GSMConfig::T3122() const
+{
+       mLock.lock();
+       unsigned retVal = mT3122;
+       mLock.unlock();
+       return retVal;
+}
+
+unsigned GSMConfig::growT3122()
+{
+       unsigned max = gConfig.getNum("GSM.T3122Max");
+       mLock.lock();
+       unsigned retVal = mT3122;
+       mT3122 += (random() % mT3122) / 2;
+       if (mT3122>max) mT3122=max;
+       mLock.unlock();
+       return retVal;
+}
+
+
+unsigned GSMConfig::shrinkT3122()
+{
+       unsigned min = gConfig.getNum("GSM.T3122Min");
+       mLock.lock();
+       unsigned retVal = mT3122;
+       mT3122 -= (random() % mT3122) / 2;
+       if (mT3122<min) mT3122=min;
+       mLock.unlock();
+       return retVal;
+}
+
+
+
 // vim: ts=4 sw=4

Modified: openbts/trunk/GSM/GSMConfig.h
===================================================================
--- openbts/trunk/GSM/GSMConfig.h       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSMConfig.h       2009-12-31 04:21:20 UTC (rev 11667)
@@ -29,7 +29,8 @@
 
 #include <vector>
 
-#include "ControlCommon.h"
+#include <ControlCommon.h>
+#include <PowerManager.h>
 
 #include "GSML3RRElements.h"
 #include "GSML3CommonElements.h"
@@ -59,6 +60,8 @@
        /** The paging mechanism is built-in. */
        Control::Pager mPager;
 
+       PowerManager mPowerManager;
+
        mutable Mutex mLock;                                            ///< 
multithread access control
 
        /address@hidden Groups of CCCH subchannels -- may intersect. */
@@ -97,17 +100,23 @@
        L3Frame mSI6Frame;
        //@}
 
+       int mT3122;
+
        time_t mStartTime;
 
        L3LocationAreaIdentity mLAI;
        char mShortName[94]; // GSM 03.38 6.1.2.2.1
 
+
        public:
        
        
 
        /** All parameters come from gConfig. */
        GSMConfig();
+
+       /** Start the internal control loops. */
+       void start();
        
        /address@hidden Get references to L2 frames for BCCH SI messages. */
        //@{
@@ -139,9 +148,6 @@
        /** Return the BSIC, NCC:BCC. */
        unsigned BSIC() const { return (mNCC<<3) | mBCC; }
 
-       /** RSSI target for closed loop power control. */
-       int RSSITarget() const { return -10; }
-
        /**
                Re-encode the L2Frames for system information messages.
                Called whenever a beacon parameter is changed.
@@ -153,8 +159,14 @@
        /** Find a minimum-load CCCH from a list. */
        CCCHLogicalChannel* minimumLoad(CCCHList &chanList);
 
+       /** Return the total load of a CCCH list. */
+       size_t totalLoad(const CCCHList &chanList) const;
+
        public:
 
+       size_t AGCHLoad() { return totalLoad(mAGCHPool); }
+       size_t PCHLoad() { return totalLoad(mPCHPool); }
+
        /address@hidden Manage CCCH subchannels. */
        //@{
        /** The add method is not mutex protected and should only be used 
during initialization. */
@@ -166,6 +178,12 @@
        CCCHLogicalChannel* getAGCH() { return minimumLoad(mAGCHPool); }
        /** Return a minimum-load PCH. */
        CCCHLogicalChannel* getPCH() { return minimumLoad(mPCHPool); }
+       /** Return a specific PCH. */
+       CCCHLogicalChannel* getPCH(size_t index)
+       {
+               assert(index<mPCHPool.size());
+               return mPCHPool[index];
+       }
 
        //@}
 
@@ -177,7 +195,7 @@
        /** Return a pointer to a usable channel. */
        SDCCHLogicalChannel *getSDCCH();
        /** Return true if an SDCCH is available, but do not allocate it. */
-       bool SDCCHAvailable() const;
+       size_t SDCCHAvailable() const;
        /** Return number of total SDCCH. */
        unsigned SDCCHTotal() const { return mSDCCHPool.size(); }
        /** Return number of active SDCCH. */
@@ -193,7 +211,7 @@
        /** Return a pointer to a usable channel. */
        TCHFACCHLogicalChannel *getTCH();
        /** Return true if an TCH is available, but do not allocate it. */
-       bool TCHAvailable() const;
+       size_t TCHAvailable() const;
        /** Return number of total TCH. */
        unsigned TCHTotal() const { return mTCHPool.size(); }
        /** Return number of active TCH. */
@@ -202,9 +220,18 @@
        const TCHList& TCHPool() const { return mTCHPool; }
        //@}
 
+       /address@hidden T3122 management */
+       //@{
+       unsigned T3122() const;
+       unsigned growT3122();
+       unsigned shrinkT3122();
+       //@}
 
        /** Return number of seconds since starting. */
        time_t uptime() const { return ::time(NULL)-mStartTime; }
+
+       /** Get a handle to the power manager. */
+       PowerManager& powerManager() { return mPowerManager; }
 };
 
 

Modified: openbts/trunk/GSM/GSML1FEC.cpp
===================================================================
--- openbts/trunk/GSM/GSML1FEC.cpp      2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSML1FEC.cpp      2009-12-31 04:21:20 UTC (rev 11667)
@@ -31,9 +31,11 @@
 #include "GSMSAPMux.h"
 #include "GSMConfig.h"
 #include "GSMTDMA.h"
+#include "GSMTAPDump.h"
 #include <TRXManager.h>
 #include <Logger.h>
 #include <assert.h>
+#include <math.h>
 
 using namespace std;
 using namespace GSM;
@@ -102,7 +104,7 @@
        0, 0, 0, 0,             // 16-19
        0, 0, 0, 0,             // 20-23
        0, 0, 0, 0,             // 24-27
-       0,      36, 24, 23      // 28-31
+       0, 36, 24, 23   // 28-31
 };
 
 /** Power control codes for PCS1900 from GSM 05.05 4.1.1. */
@@ -119,6 +121,27 @@
 };
 
 
+int decodePower(unsigned code)
+{
+       const int *table = NULL;
+       switch (gBTS.band()) {
+               case GSM850:
+               case EGSM900:
+                       table = powerCommandLowBand;
+                       break;
+               case DCS1800:
+                       table = powerCommand1800;
+                       break;
+               case PCS1900:
+                       table = powerCommand1900;
+                       break;
+               default: assert(0);
+       }
+       return table[code];
+
+}
+
+
 /** Given a power level in dBm, encode the control code. */
 unsigned encodePower(int power)
 {
@@ -204,7 +227,7 @@
 
 void L1Encoder::open()
 {
-       OBJLOG(DEBUG) << "L1Encoder::open";
+       OBJLOG(DEBUG) << "L1Encoder";
        mLock.lock();
        if (!mRunning) start();
        mTotalBursts=0;
@@ -217,7 +240,7 @@
 void L1Encoder::close()
 {
        // Don't return until the channel is fully closed.
-       OBJLOG(DEBUG) << "L1Encoder::close";
+       OBJLOG(DEBUG) << "L1Encodere";
        mLock.lock();
        mActive = false;
        sendIdleFill();
@@ -236,6 +259,22 @@
 }
 
 
+void L1Decoder::setPhy(float wRSSI, float wTimingError)
+{
+       mRSSI=wRSSI;
+       mTimingError=wTimingError;
+       mPhyNew = true;
+}
+
+void SACCHL1Decoder::setPhy(const SACCHL1Decoder& other)
+{
+       mActualMSPower = other.mActualMSPower;
+       mActualMSTiming = other.mActualMSTiming;
+       L1Decoder::setPhy(other.mRSSI,other.mTimingError);
+}
+
+
+
 L1Decoder* L1Encoder::sibling()
 {
        if (!mParent) return NULL;
@@ -256,12 +295,12 @@
        // get it caught up to something reasonable.
        Time now = gBTS.time();
        int32_t delta = mNextWriteTime-now;
-       OBJLOG(DEEPDEBUG) << "L1Encoder::resync() next=" << mNextWriteTime << " 
now=" << now << " delta=" << delta;
+       OBJLOG(DEEPDEBUG) << "L1Encoder next=" << mNextWriteTime << " now=" << 
now << " delta=" << delta;
        if ((delta<0) || (delta>(51*26))) {
                mNextWriteTime = now;
                mNextWriteTime.TN(mTN);
                
mNextWriteTime.rollForward(mMapping.frameMapping(mTotalBursts),mMapping.repeatLength());
-               OBJLOG(DEEPDEBUG) <<"L1Encoder::resync() RESYNC next=" << 
mNextWriteTime << " now=" << now;
+               OBJLOG(DEEPDEBUG) <<"L1Encoder RESYNC next=" << mNextWriteTime 
<< " now=" << now;
        }
 }
 
@@ -353,7 +392,7 @@
        static const float a = 1.0F / ((float)mFERMemory);
        static const float b = 1.0F - a;
        mFER *= b;
-       OBJLOG(DEEPDEBUG) <<"L1Decoder::countGoodFrame FER=" << mFER;
+       OBJLOG(DEEPDEBUG) <<"L1Decoder FER=" << mFER;
 }
 
 
@@ -362,7 +401,7 @@
        static const float a = 1.0F / ((float)mFERMemory);
        static const float b = 1.0F - a;
        mFER = b*mFER + a;
-       OBJLOG(DEEPDEBUG) <<"L1Decoder::countBadFrame FER=" << mFER;
+       OBJLOG(DEEPDEBUG) <<"L1Decoder FER=" << mFER;
 }
 
 
@@ -469,8 +508,9 @@
        countGoodFrame();
        mD.LSB8MSB();
        unsigned RA = mD.peekField(0,8);
-       OBJLOG(DEBUG) <<"RACHL1Decoder received RA=" << RA << " at time " << 
burst.time();
-       Control::AccessGrantResponder(RA,burst.time(),burst.timingError());
+       OBJLOG(DEBUG) <<"RACHL1Decoder received RA=" << RA << " at time " << 
burst.time()
+               << " with RSSI=" << burst.RSSI() << " timingError=" << 
burst.timingError();
+       
Control::AccessGrantResponder(RA,burst.time(),burst.RSSI(),burst.timingError());
 }
 
 
@@ -509,10 +549,10 @@
 
 void XCCHL1Decoder::writeLowSide(const RxBurst& inBurst)
 {
-       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::writeLowSide " << inBurst;
+       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder " << inBurst;
        // If the channel is closed, ignore the burst.
        if (!active()) {
-               OBJLOG(DEBUG) <<"XCCHL1Decoder::writeLowSide not active, 
ignoring input";
+               OBJLOG(DEBUG) <<"XCCHL1Decoder not active, ignoring input";
                return;
        }
        // Accept the burst into the deinterleaving buffer.
@@ -521,6 +561,7 @@
        deinterleave();
        if (decode()) {
                countGoodFrame();
+               mD.LSB8MSB();
                handleGoodFrame();
        } else {
                countBadFrame();
@@ -530,7 +571,7 @@
 
 bool XCCHL1Decoder::processBurst(const RxBurst& inBurst)
 {
-       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::processBurst " << inBurst;
+       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder " << inBurst;
        // Accept the burst into the deinterleaving buffer.
        // Return true if we are ready to interleave.
 
@@ -595,9 +636,9 @@
 
        // Convolutional decoding c[] to u[].
        // GSM 05.03 4.1.3
-       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::decode c[]=" << mC;
+       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder << mC";
        mC.decode(mVCoder,mU);
-       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::decode u[]=" << mU;
+       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder << mU";
 
        // The GSM L1 u-frame has a 40-bit parity field.
        // False detections are EXTREMELY rare.
@@ -605,9 +646,9 @@
        // GSM 05.03 4.1.2.
        mP.invert();                                                    // 
parity is inverted
        // The syndrome should be zero.
-       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::decode d[]:p[]=" << mDP;
+       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder d[]:p[]=" << mDP;
        unsigned syndrome = mBlockCoder.syndrome(mDP);
-       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::decode syndrome=" << hex << 
syndrome << dec;
+       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder syndrome=" << hex << syndrome << dec;
        return (syndrome==0);
 }
 
@@ -615,7 +656,7 @@
 
 void XCCHL1Decoder::handleGoodFrame()
 {
-       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::handleGoodFrame u[]=" << mU;
+       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder u[]=" << mU;
        mLock.lock();
        // Keep T3109 from timing out.
        mT3109.set();
@@ -629,13 +670,12 @@
 
        // Get the d[] bits, the actual payload in the radio channel.
        // Undo GSM's LSB-first octet encoding.
-       mD.LSB8MSB();
-       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::handleGoodFrame d[]=" << mD;
+       OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder d[]=" << mD;
 
        if (mUpstream) {
                // Build an L2 frame and pass it up.
                const BitVector L2Part(mD.tail(headerOffset()));
-               OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder::handleGoodFrame L2=" << 
L2Part;
+               OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder L2=" << L2Part;
                mUpstream->writeLowSide(L2Frame(L2Part,DATA));
        } else {
                OBJLOG(NOTICE) << "XCCHL1Decoder with no uplink connected.";
@@ -644,8 +684,20 @@
 
 
 
+void SACCHL1Decoder::handleGoodFrame()
+{
+       // GSM 04.04 7
+       OBJLOG(DEBUG) << "SACCHL1Decoder phy header " << mU.head(16);
+       mActualMSPower = decodePower(mU.peekField(3,5));
+       int TAField = mU.peekField(9,7);
+       if (TAField<64) mActualMSTiming = TAField;
+       OBJLOG(DEBUG) << "SACCHL1Decoder actuals pow=" << mActualMSPower << " 
TA=" << mActualMSTiming;
+       XCCHL1Decoder::handleGoodFrame();
+}
 
 
+
+
 XCCHL1Encoder::XCCHL1Encoder(
                unsigned wTN,
                const TDMAMapping& wMapping,
@@ -683,7 +735,7 @@
        switch (frame.primitive()) {
                case DATA:
                        // Encode and send data.
-                       // HACK assert(active());       // We should not send 
on a non-active channel.
+                       if (!active()) { LOG(WARN) << 
"XCCHL1Encoder::writeHighSide sending on non-active channel"; }
                        resync();
                        sendFrame(frame);
                        break;
@@ -715,7 +767,7 @@
 
 void XCCHL1Encoder::sendFrame(const L2Frame& frame)
 {
-       OBJLOG(DEEPDEBUG) << "XCCH " << frame;
+       OBJLOG(DEEPDEBUG) << "XCCHL1Encoder " << frame;
        // Make sure there's something down there to take the busts.
        if (mDownstream==NULL) {
                LOG(WARN) << "XCCHL1Encoder with no downstream";
@@ -728,12 +780,14 @@
        // GSM 05.03 4.1.1.
        //assert(mD.size()==headerOffset()+frame.size());
        frame.copyToSegment(mU,headerOffset());
-       OBJLOG(DEEPDEBUG) << "d[]=" << mD;
+       OBJLOG(DEEPDEBUG) << "XCCHL1Encoder d[]=" << mD;
        mD.LSB8MSB();
-       OBJLOG(DEEPDEBUG) << "d[]=" << mD;
+       OBJLOG(DEEPDEBUG) << "XCCHL1Encoder d[]=" << mD;
        encode();                       // Encode u[] to c[], GSM 05.03 4.1.2 
and 4.1.3.
        interleave();           // Interleave c[] to i[][], GSM 05.03 4.1.4.
        transmit();                     // Send the bursts to the radio, GSM 
05.03 4.1.5.
+       // FIXME: is this FN OK, or do we need to back it up by 4?
+       gWriteGSMTAP(ARFCN(),mTN,mPrevWriteTime.FN(),frame);
 }
 
 
@@ -745,11 +799,11 @@
        // GSM 05.03 4.1.2
        // Generate the parity bits.
        mBlockCoder.writeParityWord(mD,mP);
-       OBJLOG(DEEPDEBUG) << "u[]=" << mU;
+       OBJLOG(DEEPDEBUG) << "XCCHL1Encoder u[]=" << mU;
        // GSM 05.03 4.1.3
        // Apply the convolutional encoder.
        mU.encode(mVCoder,mC);
-       OBJLOG(DEEPDEBUG) << "c[]=" << mC;
+       OBJLOG(DEEPDEBUG) << "XCCHL1Encoder c[]=" << mC;
 }
 
 
@@ -783,11 +837,11 @@
        for (int B=0; B<4; B++) {
                mBurst.time(mNextWriteTime);
                // Copy in the "encrytped" bits, GSM 05.03 4.1.5, 05.02 5.2.3.
-               OBJLOG(DEEPDEBUG) << "mI["<<B<<"]=" << mI[B];
+               OBJLOG(DEEPDEBUG) << "XCCHL1Encoder mI["<<B<<"]=" << mI[B];
                mI[B].segment(0,57).copyToSegment(mBurst,3);
                mI[B].segment(57,57).copyToSegment(mBurst,88);
                // Send it to the radio.
-               OBJLOG(DEEPDEBUG) << "mBurst=" << mBurst;
+               OBJLOG(DEEPDEBUG) << "XCCHL1Encoder mBurst=" << mBurst;
                mDownstream->writeHighSide(mBurst);
                rollForward();
        }
@@ -842,7 +896,7 @@
 
 void SCHL1Encoder::generate()
 {
-       OBJLOG(DEEPDEBUG) << "SCH " << mNextWriteTime;
+       OBJLOG(DEEPDEBUG) << "SCHL1Encoder " << mNextWriteTime;
        assert(mDownstream);
        // Data, GSM 04.08 9.1.30
        size_t wp=0;
@@ -880,7 +934,7 @@
 
 void FCCHL1Encoder::generate()
 {
-       OBJLOG(DEEPDEBUG) << "FCCH " << mNextWriteTime;
+       OBJLOG(DEEPDEBUG) << "FCCHL1Encoder " << mNextWriteTime;
        assert(mDownstream);
        resync();
        for (int i=0; i<5; i++) {
@@ -922,7 +976,7 @@
 
 void BCCHL1Encoder::generate()
 {
-       OBJLOG(DEEPDEBUG) << "BCCH " << mNextWriteTime;
+       OBJLOG(DEEPDEBUG) << "BCCHL1Encoder " << mNextWriteTime;
        // BCCH mapping, GSM 05.02 6.3.1.3
        // Since we're not doing GPRS or VGCS, it's just SI1-4 over and over.
        switch (mNextWriteTime.TC()) {
@@ -962,10 +1016,10 @@
 
 void TCHFACCHL1Decoder::writeLowSide(const RxBurst& inBurst)
 {
-       OBJLOG(DEEPDEBUG) << inBurst;
+       OBJLOG(DEEPDEBUG) << "TCHFACCHL1Decoder " << inBurst;
        // If the channel is closed, ignore the burst.
        if (!active()) {
-               OBJLOG(DEEPDEBUG) << "not active, ignoring input";
+               OBJLOG(DEEPDEBUG) << "TCHFACCHL1Decoder not active, ignoring 
input";
                return;
        }
        processBurst(inBurst);
@@ -998,7 +1052,7 @@
        int B = mMapping.reverseMapping(inBurst.time().FN()) % 8;
        // A negative value means that the demux is misconfigured.
        assert(B>=0);
-       OBJLOG(DEEPDEBUG) << "B=" << B << " " << inBurst;
+       OBJLOG(DEEPDEBUG) << "TCHFACCHL1Decoder B=" << B << " " << inBurst;
 
        // Pull the data fields (e-bits) out of the burst and put them into 
i[B][].
        // GSM 05.03 3.1.4
@@ -1017,14 +1071,15 @@
 
        // See if this was the end of a stolen frame, GSM 05.03 4.2.5.
        bool stolen = inBurst.Hl();
-       OBJLOG(DEEPDEBUG) <<"TCHFACCHL!Decoder::processBurst Hl=" << 
inBurst.Hl() << " Hu=" << inBurst.Hu();
+       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder Hl=" << inBurst.Hl() << " Hu=" 
<< inBurst.Hu();
        if (stolen) {
                if (decode()) {
-                       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder::processBurst 
good FACCH frame";
+                       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder good FACCH 
frame";
                        countGoodFrame();
+                       mD.LSB8MSB();
                        handleGoodFrame();
                } else {
-                       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder::processBurst 
bad FACCH frame";
+                       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder bad FACCH frame";
                        countBadFrame();
                }
        }
@@ -1033,7 +1088,7 @@
        // decodeTCH will handle the GSM 06.11 bad frmae processing.
        bool traffic = decodeTCH(stolen);
        if (traffic) {
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder::processBurst good TCH 
frame";
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder good TCH frame";
                countGoodFrame();
                // Don't let the channel timeout.
                mLock.lock();
@@ -1050,7 +1105,7 @@
 
 void TCHFACCHL1Decoder::deinterleave(int blockOffset )
 {
-       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder::deinterleave blockOffset=" << 
blockOffset;
+       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder blockOffset=" << blockOffset;
        for (int k=0; k<456; k++) {
                int B = ( k + blockOffset ) % 8;
                int j = 2*((49*k) % 57) + ((k%8)/4);
@@ -1100,10 +1155,10 @@
                // Check the tail bits, too.
                unsigned tail = mTCHU.peekField(185,4);
        
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder::decodeTCH c[]=" << mC;
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder::decodeTCH u[]=" << 
mTCHU;
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder::decodeTCH d[]=" << 
mTCHD;
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder::decodeTCH sentParity=" 
<< sentParity
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder c[]=" << mC;
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder u[]=" << mTCHU;
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder d[]=" << mTCHD;
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Decoder sentParity=" << 
sentParity
                        << " calcParity=" << calcParity << " tail=" << tail;
                good = (sentParity==calcParity) && (tail==0);
                if (good) {
@@ -1118,9 +1173,17 @@
        }
 
        if (!good) {
-               // FIXME -- Bad frame processing, GSM 06.11, KSP Bug #45
-               // For now, just repeat the last good frame.
-               // Need to apply attenuation and randomization of grid 
positions.
+               // Bad frame processing, GSM 06.11.
+               // Attenuate block amplitudes and andomize grid positions.
+               char rawByte = mPrevGoodFrame[27];
+               unsigned xmaxc = rawByte & 0x01f;
+               if (xmaxc>2) xmaxc -= 2;
+               else xmaxc = 0;
+               for (unsigned i=0; i<4; i++) {
+                       unsigned pos = random() % 4;
+                       mPrevGoodFrame[6+7*i] = (rawByte & 0x80) | pos | xmaxc;
+                       mPrevGoodFrame[7+7*i] &= 0x7F;
+               }
                memcpy(newFrame,mPrevGoodFrame,33);
        }
 
@@ -1171,7 +1234,7 @@
 void TCHFACCHL1Encoder::start()
 {
        L1Encoder::start();
-       OBJLOG(DEBUG) <<"TCHFACCHL1Encoder::start";
+       OBJLOG(DEBUG) <<"TCHFACCHL1Encoder";
        
mEncoderThread.start((void*(*)(void*))TCHFACCHL1EncoderRoutine,(void*)this);
 }
 
@@ -1189,7 +1252,7 @@
 void TCHFACCHL1Encoder::encodeTCH(const VocoderFrame& vFrame)
 {      
        // GSM 05.02 3.1.2
-       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder::encodeTCH";
+       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder";
 
        // Reorder bits by importance.
        // See GSM 05.03 3.1 and Table 2.
@@ -1225,7 +1288,7 @@
 
 void TCHFACCHL1Encoder::sendFrame( const L2Frame& frame )
 {
-       OBJLOG(DEEPDEBUG) << "TCHFACCH " << frame;
+       OBJLOG(DEEPDEBUG) << "TCHFACCHL1Encoder " << frame;
        mL2Q.write(new L2Frame(frame));
 }
 
@@ -1258,12 +1321,12 @@
        
        // Speech latency control.
        // Since Asterisk is local, latency should be small.
-       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder::dispatch speechQ.size=" << 
mSpeechQ.size();
+       OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder speechQ.size=" << 
mSpeechQ.size();
        while (mSpeechQ.size() > mMaxQSize) delete mSpeechQ.read();
 
        // Send, by priority: (1) FACCH, (2) TCH, (3) filler.
        if (L2Frame *fFrame = mL2Q.readNoBlock()) {
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder::dispatch FACCH " << 
*fFrame;
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder FACCH " << *fFrame;
                currentFACCH = true;
                // Copy the L2 frame into u[] for processing.
                // GSM 05.03 4.1.1.
@@ -1272,19 +1335,19 @@
                // Encode u[] to c[], GSM 05.03 4.1.2 and 4.1.3.
                encode();
                delete fFrame;
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder::dispatch FACCH c[]=" << 
mC;
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder FACCH c[]=" << mC;
        } else if (VocoderFrame *tFrame = mSpeechQ.readNoBlock()) {
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder::dispatch TCH " << 
*tFrame;
+               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::dispatch TCH c[]=" << 
mC;
+               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::dispatch filler FACCH=" 
<< currentFACCH << " c[]=" << mC;
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHL1Encoder filler FACCH=" << 
currentFACCH << " c[]=" << mC;
        }
 
        // Interleave c[] to i[].
@@ -1303,7 +1366,7 @@
                mBurst.Hu(currentFACCH);
                mBurst.Hl(mPreviousFACCH);
                // send
-               OBJLOG(DEEPDEBUG) <<"TCHFACCHEncoder::dispatch sending burst=" 
<< mBurst;
+               OBJLOG(DEEPDEBUG) <<"TCHFACCHEncoder sending burst=" << mBurst;
                mDownstream->writeHighSide(mBurst);     
                rollForward();
        }       
@@ -1329,54 +1392,103 @@
 }
 
 
+bool TCHFACCHL1Decoder::uplinkLost() const
+{
+       mLock.lock();
+       bool retVal = mT3109.expired();
+       mLock.unlock();
+       return retVal;
+}
 
 
+
+void SACCHL1FEC::setPhy(const SACCHL1FEC& other)
+{
+       mSACCHDecoder->setPhy(*other.mSACCHDecoder);
+}
+
+
+
+
+void SACCHL1Decoder::open()
+{
+       LOG(DEBUG) << "SACCHL1Decoder::open";
+       XCCHL1Decoder::open();
+       // Set initial defaults for power and timing advance.
+       // We know the handset sent the RACH burst at max power and 0 timing 
advance.
+       mActualMSPower = 40;
+       mActualMSTiming = 0;
+}
+
+
+
 SACCHL1Encoder::SACCHL1Encoder( unsigned wTN, const TDMAMapping& wMapping, 
SACCHL1FEC *wParent)
        :XCCHL1Encoder(wTN,wMapping,(L1FEC*)wParent),
        mSACCHParent(wParent),
-       mOrderedMSPower(36),mOrderedMSTiming(0)
+       mOrderedMSPower(40),mOrderedMSTiming(0)
 { }
 
 
 void SACCHL1Encoder::open()
 {
-       OBJLOG(DEBUG) <<"SACCHL1Encoder::open()";
-       // Set initial defaults for power and timing advance.
-       // FIXME -- These should be set from the RACH.
-       mOrderedMSPower = 36;
+       OBJLOG(DEBUG) <<"SACCHL1Encoder";
+       XCCHL1Encoder::open();
+       // FIXME -- Set the initial physical parameters from the RACH burst.
+       mOrderedMSPower = 40;
        mOrderedMSTiming = 0;
-       XCCHL1Encoder::open();
 }
 
 
+
+SACCHL1Encoder* SACCHL1Decoder::SACCHSibling() 
+{
+       return mSACCHParent->encoder();
+}
+
+SACCHL1Decoder* SACCHL1Encoder::SACCHSibling() 
+{
+       return mSACCHParent->decoder();
+}
+
+
+
 void SACCHL1Encoder::sendFrame(const L2Frame& frame)
 {
-       OBJLOG(DEEPDEBUG) << "SACCH " << frame;
+       OBJLOG(DEEPDEBUG) << "SACCHL1Encoder " << frame;
 
        // Physical header, GSM 04.04 6, 7.1
        // Power and timing control, GSM 05.08 4, GSM 05.10 5, 6.
 
        if (sibling()->phyNew()) {
                // Power.  GSM 05.08 4.
-               int RSSI = sibling()->RSSI();
-               int deltaP = RSSI - gBTS.RSSITarget();
-               mOrderedMSPower -= deltaP/2;
-               if (mOrderedMSPower>36) mOrderedMSPower=36;
+               // Power expressed in dBm.
+               float RSSI = SACCHSibling()->RSSI();
+               float RSSITarget = gConfig.getNum("GSM.RSSITarget");
+               float deltaP = RSSI - RSSITarget;
+               float actualPower = SACCHSibling()->actualMSPower();
+               mOrderedMSPower = actualPower - (int)round(deltaP*0.5F);
+               if (mOrderedMSPower>40) mOrderedMSPower=40;
                else if (mOrderedMSPower<0) mOrderedMSPower=0;
-               OBJLOG(DEEPDEBUG) << "SACCH RSSI=" << RSSI << " target=" << 
gBTS.RSSITarget()
-                       << " deltaP=" << deltaP << " order=" << mOrderedMSPower;
-               // FIXME -- Timing.  GSM 05.10 5, 6  Do it here...
+               OBJLOG(DEBUG) <<"SACCHL1Encoder RSSI=" << RSSI << " target=" << 
RSSITarget
+                       << " deltaP=" << deltaP << " actual=" << actualPower << 
" order=" << mOrderedMSPower;
+               // Timing.  GSM 05.10 5, 6.
+               // Time expressed in symbol periods.
+               float timingError = SACCHSibling()->timingError();
+               float actualTiming = SACCHSibling()->actualMSTiming();
+               mOrderedMSTiming = actualTiming - 0.5F*timingError;
+               if (mOrderedMSTiming>63.0F) mOrderedMSTiming=63.0F;
+               if (mOrderedMSTiming<0.0F) mOrderedMSTiming=0.0F;
+               OBJLOG(DEBUG) << "SACCHL1Encoder timingError=" << timingError  
<< " actual=" << actualTiming << " ordered=" << mOrderedMSTiming;
        }
 
        // Write physical header into mU and then call base class.
 
-       // Power encodeing, GSM 04.04 7.1.
-       OBJLOG(DEEPDEBUG) << "SACCH RSSI order=" << mOrderedMSPower;
+       // SACCH physical header, GSM 04.04 6.1, 7.1.
+       OBJLOG(DEBUG) <<"SACCHL1Encoder orders pow=" << mOrderedMSPower << " 
TA=" << mOrderedMSTiming;
        mU.fillField(0,encodePower(mOrderedMSPower),8);
+       mU.fillField(8,(int)(mOrderedMSTiming+0.5F),8); // timing (GSM 04.04 
6.1)
+       OBJLOG(DEBUG) << "SACCHL1Encoder phy header " << mU.head(16);
 
-       // FIXME -- No timing advance control for now.
-       mU.fillField(8,0x7f,8); // timing (GSM 04.04 6.1, 0x7f means "none")
-
        // Encode the rest of the frame.
        XCCHL1Encoder::sendFrame(frame);
 }

Modified: openbts/trunk/GSM/GSML1FEC.h
===================================================================
--- openbts/trunk/GSM/GSML1FEC.h        2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSML1FEC.h        2009-12-31 04:21:20 UTC (rev 11667)
@@ -296,6 +296,9 @@
        /** RSSI of most recent received burst, in dB wrt full scale. */
        float RSSI() const { mPhyNew=false; return mRSSI; }
 
+       /** Set pyshical parameters for initialization. */
+       void setPhy(float wRSSI, float wTimingError);
+
        /** Return true if the physical parameters are fresh. */
        bool phyNew() const { return mPhyNew; }
 
@@ -394,6 +397,12 @@
        float FER() const
                { assert(mDecoder); return mDecoder->FER(); }
 
+       float timingError() const
+               { assert(mDecoder); return mDecoder->timingError(); }
+
+       float RSSI() const
+               { assert(mDecoder); return mDecoder->RSSI(); }
+
        bool recyclable() const
                { assert(mDecoder); return mDecoder->recyclable(); }
 
@@ -404,6 +413,10 @@
 
        const TDMAMapping& rcvMapping() const
                { assert(mEncoder); return mDecoder->mapping(); }
+
+       void setPhy(float RSSI, float timingError)
+               { assert(mDecoder); return mDecoder->setPhy(RSSI,timingError); }
+
        //@}
 
 
@@ -583,6 +596,11 @@
        int actualMSPower() const { return mActualMSPower; }
        int actualMSTiming() const { return mActualMSTiming; }
 
+       /** Override open() to set physical parameters with reasonable 
defaults. */
+       void open();
+
+       void setPhy(const SACCHL1Decoder& other);
+
        protected:
 
        SACCHL1FEC *SACCHParent() { return mSACCHParent; }
@@ -592,7 +610,7 @@
        /**
                This is a wrapper on handleGoodFrame that processes the 
physical header.
        */
-       //void handleGoodFrame();
+       void handleGoodFrame();
 
        unsigned headerOffset() const { return 16; }
 
@@ -789,7 +807,7 @@
        unsigned queueSize() const { return mSpeechQ.size(); }
 
        /** Return true if the uplink is dead. */
-       bool uplinkLost() const { return mT3109.expired(); }
+       bool uplinkLost() const;
 };
 
 
@@ -949,7 +967,7 @@
        /address@hidden Physical header, GSM 04.04 6, 7.1, 7.2 */
        //@{
        volatile int mOrderedMSPower;           ///< ordered MS tx power level, 
dBm
-       volatile int mOrderedMSTiming;          ///< ordered MS timing advance 
in 1/256 symbols
+       volatile float mOrderedMSTiming;                ///< ordered MS timing 
advance in symbols
        //@}
 
        public:
@@ -1088,6 +1106,13 @@
 
        SACCHL1Decoder *decoder() { return mSACCHDecoder; }
        SACCHL1Encoder *encoder() { return mSACCHEncoder; }
+
+       /address@hidden Physical parameter access. */
+       //@{
+       int actualMSPower() const { assert(mSACCHDecoder); return 
mSACCHDecoder->actualMSPower(); }
+       int actualMSTiming() const { assert(mSACCHDecoder); return 
mSACCHDecoder->actualMSTiming(); }
+       void setPhy(const SACCHL1FEC&);
+       //@}
 };
 
 

Modified: openbts/trunk/GSM/GSML2LAPDm.cpp
===================================================================
--- openbts/trunk/GSM/GSML2LAPDm.cpp    2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSML2LAPDm.cpp    2009-12-31 04:21:20 UTC (rev 11667)
@@ -68,7 +68,7 @@
 
 void CCCHL2::writeHighSide(const GSM::L3Frame& l3)
 {
-       OBJLOG(DEBUG) <<"CCCHL2::writeHighSide " << l3;
+       OBJLOG(DEEPDEBUG) <<"CCCHL2::writeHighSide " << l3;
        assert(mDownstream);
        assert(l3.primitive()==UNIT_DATA);
        L2Header header(L2Length(l3.length()));
@@ -100,7 +100,7 @@
 
 void L2LAPDm::writeL1(const L2Frame& frame)
 {
-       OBJLOG(DEBUG) <<"L2LAPDm::writeL1 " << frame;
+       OBJLOG(DEEPDEBUG) <<"L2LAPDm::writeL1 " << frame;
        //assert(mDownstream);
        if (!mDownstream) return;
        mL1Lock.lock();
@@ -112,7 +112,7 @@
 void L2LAPDm::writeL1NoAck(const L2Frame& frame)
 {
        // Caller need not hold mLock.
-       OBJLOG(DEBUG) <<"L2LAPDm::writeL1NoAck " << frame;
+       OBJLOG(DEEPDEBUG) <<"L2LAPDm::writeL1NoAck " << frame;
        writeL1(frame);
 }
 
@@ -121,7 +121,7 @@
 {
        // Caller should hold mLock.
        // GSM 04.06 5.4.4.2
-       OBJLOG(DEBUG) <<"L2LAPDm::writeL1Ack " << frame;
+       OBJLOG(DEEPDEBUG) <<"L2LAPDm::writeL1Ack " << frame;
        frame.copyTo(mSentFrame);
        mSentFrame.primitive(frame.primitive());
        writeL1(frame);
@@ -918,6 +918,7 @@
        // in SACCH L3 during release.
        if (mState==LinkReleased) {
                OBJLOG(ERROR) << "attempt to send DATA on released LAPm 
channel";
+               abnormalRelease();
                sleepFrames(51);
                return;
        }

Modified: openbts/trunk/GSM/GSML3CCElements.cpp
===================================================================
--- openbts/trunk/GSM/GSML3CCElements.cpp       2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/GSM/GSML3CCElements.cpp       2009-12-31 04:21:20 UTC (rev 
11667)
@@ -83,7 +83,7 @@
                readOctets++;
                mDigits[i++]=d1+'0';
                if (d2!=0x0f) mDigits[i++]=d2+'0';
-               if (i>15) L3_READ_ERROR;
+               if (i>maxDigits) L3_READ_ERROR;
        }
        mDigits[i++]='\0';
 }

Modified: openbts/trunk/GSM/GSML3CCElements.h
===================================================================
--- openbts/trunk/GSM/GSML3CCElements.h 2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSML3CCElements.h 2009-12-31 04:21:20 UTC (rev 11667)
@@ -50,7 +50,7 @@
        size_t lengthV() const { return 2; }
        void writeV( L3Frame& dest, size_t &wp ) const;
        void parseV( const L3Frame& src, size_t &rp, size_t expectedLength );   
-       void parseV(const L3Frame&, size_t&) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -62,7 +62,8 @@
 
        private:
 
-       char mDigits[16];                                       ///< ITU-T 
E.164 limits address to 15 digits
+       static const unsigned maxDigits = 20;
+       char mDigits[maxDigits+1];                                      ///< 
ITU-T E.164 limits address to 15 digits
 
        public:
 
@@ -127,7 +128,7 @@
        size_t lengthV() const;
        void writeV( L3Frame& dest, size_t &wp  ) const;
        void parseV( const L3Frame& src, size_t &rp, size_t expectedLength);    
-       void parseV(const L3Frame&, size_t&) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
        void text(std::ostream&) const;
 };
 
@@ -165,7 +166,7 @@
        size_t lengthV() const ; 
        void writeV( L3Frame& dest, size_t &wp  ) const;
        void parseV( const L3Frame& src, size_t &rp, size_t expectedLength );   
-       void parseV(const L3Frame&, size_t&) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
        void text(std::ostream&) const;
 };
 
@@ -217,7 +218,7 @@
 
        void writeV( L3Frame& dest, size_t &wp) const;
        void parseV( const L3Frame& src, size_t &rp , size_t expectedLength );
-       void parseV(const L3Frame&, size_t&) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
        void text(std::ostream&) const;
 };
 
@@ -240,7 +241,7 @@
        size_t lengthV()const { return 1;}
        void writeV( L3Frame& dest, size_t &wp) const;
        void parseV( const L3Frame& src, size_t &rp );
-       void parseV(const L3Frame&, size_t&, size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
        void text(std::ostream&) const;
        
 };
@@ -288,8 +289,8 @@
 
        size_t lengthV() const { return 2; }
        void writeV(L3Frame& dest, size_t &wp ) const;
-       void parseV(const L3Frame&, size_t&, size_t) { abort(); }
-       void parseV(const L3Frame&, size_t&) { abort(); }
+       void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
        void text(std::ostream&) const;
 };
 
@@ -311,7 +312,7 @@
 
        size_t lengthV() const { return 1; }
        void writeV(L3Frame&, size_t&) const;
-       void parseV(const L3Frame&, size_t&, size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
        void parseV(const L3Frame& src, size_t& rp);
        void text(std::ostream&) const;
 };

Modified: openbts/trunk/GSM/GSML3MMElements.h
===================================================================
--- openbts/trunk/GSM/GSML3MMElements.h 2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSML3MMElements.h 2009-12-31 04:21:20 UTC (rev 11667)
@@ -71,9 +71,9 @@
                { return mType == other.mType; }
        
        size_t lengthV() const { return 0; }    
-       void writeV(L3Frame&, size_t&) const { abort(); }
+       void writeV(L3Frame&, size_t&) const { assert(0); }
        void parseV(const L3Frame &src, size_t &rp);
-       void parseV(const L3Frame&, size_t&, size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -97,8 +97,8 @@
 
        size_t lengthV() const { return 1; }    
        void writeV( L3Frame& dest, size_t &wp ) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 };
 
@@ -136,8 +136,8 @@
                        return 1+(strlen(mName)*7+7)/8;
        }
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 };
 
@@ -165,7 +165,7 @@
        size_t lengthV() const { return 7; }
        void writeV(L3Frame&, size_t&) const;
        void parseV(const L3Frame& src, size_t &rp);
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 };
 

Modified: openbts/trunk/GSM/GSML3RRElements.cpp
===================================================================
--- openbts/trunk/GSM/GSML3RRElements.cpp       2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/GSM/GSML3RRElements.cpp       2009-12-31 04:21:20 UTC (rev 
11667)
@@ -26,6 +26,7 @@
 
 */
 
+#include <iterator> // for L3APDUData::text
 
 #include "GSML3RRElements.h"
 
@@ -172,17 +173,13 @@
        // the variable length bitmap.
        dest.writeField(wp,0x47,7);
 
-       // For some formats, some of the first 7 bits are not spare.
-       // For those formats, the caller will need to write those
-       // bits after calling this method.
-
        // base ARFCN
        unsigned baseARFCN = base();
        dest.writeField(wp,baseARFCN,10);
        // bit map
        unsigned delta = spread();
        unsigned numBits = 8*lengthV() - 17;
-       if (numBits<delta) LOG(ALARM) << "L3FrequencyList cannot encode full 
ARFCN set";
+       if (numBits<delta) { LOG(ALARM) << "L3FrequencyList cannot encode full 
ARFCN set"; }
        for (unsigned i=0; i<numBits; i++) {
                unsigned thisARFCN = baseARFCN + 1 + i;
                if (contains(thisARFCN)) dest.writeField(wp,1,1);
@@ -205,6 +202,7 @@
 
 void L3CellChannelDescription::writeV(L3Frame& dest, size_t& wp) const
 {
+       dest.fillField(wp,0,3);
        L3FrequencyList::writeV(dest,wp);
 }
 
@@ -212,9 +210,8 @@
 
 void L3NeighborCellsDescription::writeV(L3Frame& dest, size_t& wp) const
 {
+       dest.fillField(wp,0,3);
        L3FrequencyList::writeV(dest,wp);
-       // EXT-IND and BA-IND bits.
-       dest.fillField(2,0,3);
 }
 
 
@@ -460,5 +457,164 @@
        os << mMode;
 }
 
+// Application Information IEs
 
+// APDU ID
+
+void L3APDUID::writeV( L3Frame& dest, size_t &wp) const
+{
+       // APDU ID is 1/2 octet. Protocol Identifier [3:0]
+    dest.writeField(wp,mProtocolIdentifier,4);
+}
+
+void L3APDUID::parseV( const L3Frame &src, size_t &rp)
+{
+       // Read out Protocol Identifier.
+       mProtocolIdentifier = src.readField(rp, 4);
+}
+
+void L3APDUID::text(ostream& os) const
+{
+       os << mProtocolIdentifier;
+}
+
+// APDU Flags
+
+void L3APDUFlags::writeV( L3Frame& dest, size_t &wp) const
+{
+       // APDU Flags is 1/2 octet. Protocol Identifier [3:0]
+    dest.writeField(wp,0,1); // spare
+    dest.writeField(wp,mCR,1); // C/R
+    dest.writeField(wp,mFirstSegment,1);
+    dest.writeField(wp,mLastSegment,1);
+}
+
+void L3APDUFlags::parseV( const L3Frame &src, size_t &rp)
+{
+       // Read out Protocol Identifier.
+    rp += 1; // skip spare
+       mCR = src.readField(rp, 1);
+       mFirstSegment = src.readField(rp, 1);
+       mLastSegment = src.readField(rp, 1);
+}
+
+void L3APDUFlags::text(ostream& os) const
+{
+       os << mCR << "," << mFirstSegment << "," << mLastSegment;
+}
+
+// APDU Data
+
+L3APDUData::~L3APDUData()
+{
+}
+
+L3APDUData::L3APDUData()
+    :L3ProtocolElement()
+{
+}
+
+L3APDUData::L3APDUData(BitVector data)
+    :L3ProtocolElement()
+    ,mData(data)
+{
+}
+
+
+
+void L3APDUData::writeV( L3Frame& dest, size_t &wp) const
+{
+    // we only need to write the data part
+    // TODO - single line please. copy / memcpy, anything better then a for 
loop
+    LOG(DEBUG) << "L3APDUData: writeV " << mData.size() << " bits";
+    mData.copyToSegment(dest, wp);
+    wp += mData.size() / 8;
+}
+
+void L3APDUData::parseV( const L3Frame& src, size_t &rp, size_t expectedLength 
)
+{
+    LOG(DEBUG) << "L3APDUData: parseV " << expectedLength << " bytes";
+    mData.resize(expectedLength*8);
+    src.copyToSegment(mData, rp, expectedLength*8); // expectedLength is 
bytes, not bits
+    //for ( size_t i = 0 ; i < expectedLength ; ++i)
+    //    mData[i] = src.readField(rp, 8);
+}
+
+void L3APDUData::text(ostream& os) const
+{
+    // TODO - use the following two lines (get rid of the "char / char*" error)
+    //std::ostream_iterator<std::string> output( os, "" );
+    //std::copy( mData.begin(), mData.end(), output );
+    for (size_t i = 0 ; i < mData.size() ; ++i)
+        os << mData[i];
+}
+
+
+void L3MeasurementResults::parseV(const L3Frame& frame, size_t &rp)
+{
+       mBA_USED = frame.readField(rp,1);
+       mDTX_USED = frame.readField(rp,1);
+       mRXLEV_FULL_SERVING_CELL = frame.readField(rp,6);
+       rp++;   // spare
+       mMEAS_VALID = frame.readField(rp,1);
+       mRXLEV_SUB_SERVING_CELL = frame.readField(rp,6);
+       rp++;   // spare
+       mRXQUAL_FULL_SERVING_CELL = frame.readField(rp,3);
+       mRXQUAL_SUB_SERVING_CELL = frame.readField(rp,3);
+       mNO_NCELL = frame.readField(rp,3);
+       for (unsigned i=0; i<6; i++) {
+               mRXLEV_NCELL[i] = frame.readField(rp,6);
+               mBCCH_FREQ_NCELL[i] = frame.readField(rp,5);
+               mBSIC_NCELL[i] = frame.readField(rp,6);
+       }
+}
+
+
+void L3MeasurementResults::text(ostream& os) const
+{
+       os << "BA_USED=" << mBA_USED;
+       os << " DTX_USED=" << mDTX_USED;
+       os << " MEAS_VALID=" << mMEAS_VALID;
+       if (!mMEAS_VALID) return;
+       os << " RXLEV_FULL_SERVING_CELL=" << mRXLEV_FULL_SERVING_CELL;
+       os << " RXLEV_SUB_SERVING_CELL=" << mRXLEV_SUB_SERVING_CELL;
+       os << " RXQUAL_FULL_SERVING_CELL=" << mRXQUAL_FULL_SERVING_CELL;
+       os << " RXQUAL_SUB_SERVING_CELL=" << mRXQUAL_SUB_SERVING_CELL;
+       os << " NO_NCELL=" << mNO_NCELL;
+       for (unsigned i=0; i<mNO_NCELL; i++) {
+               os << " RXLEV_NCELL" << i+1 << "=" << mRXLEV_NCELL[i];
+               os << " BCCH_FREQ_NCELL" << i+1 << "=" << mBCCH_FREQ_NCELL[i];
+               os << " BSIC_NCELL" << i+1 << "=" << mBSIC_NCELL[i];
+       }
+}
+
+
+int L3MeasurementResults::RXLEV_NCELL(int * target) const
+{
+       for (unsigned i=0; i<mNO_NCELL; i++) target[i] = mRXLEV_NCELL[i];
+       return mNO_NCELL;
+}
+
+
+int L3MeasurementResults::BCCH_FREQ_NCELL(int * target) const
+{
+       for (unsigned i=0; i<mNO_NCELL; i++) target[i] = mBCCH_FREQ_NCELL[i];
+       return mNO_NCELL;
+}
+
+
+int L3MeasurementResults::BSIC_NCELL(int * target) const
+{
+       for (unsigned i=0; i<mNO_NCELL; i++) target[i] = mBSIC_NCELL[i];
+       return mNO_NCELL;
+}
+
+
+
+
+
+
+
+
+
 // vim: ts=4 sw=4

Modified: openbts/trunk/GSM/GSML3RRElements.h
===================================================================
--- openbts/trunk/GSM/GSML3RRElements.h 2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSML3RRElements.h 2009-12-31 04:21:20 UTC (rev 11667)
@@ -61,8 +61,8 @@
 
        size_t lengthV() const { return 1; }
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 };
 
@@ -93,8 +93,8 @@
 
        size_t lengthV() const { return 1; }
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
        
 };
@@ -122,8 +122,8 @@
        {
                // Values dictated by the current implementation are hard-coded.
                mACS=0;
-               mNECI=0;
                // Configurable values.
+               mNECI=gConfig.getNum("GSM.CS.NECI");
                mMS_TXPWR_MAX_CCH=gConfig.getNum("GSM.CS.MS_TXPWR_MAX_CCH");
                mRXLEV_ACCESS_MIN=gConfig.getNum("GSM.CS.RXLEV_ACCESS_MIN");
                
mCELL_RESELECT_HYSTERESIS=gConfig.getNum("GSM.CS.CELL_RESELECT_HYSTERESIS");
@@ -131,8 +131,8 @@
 
        size_t lengthV() const { return 2; }
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -167,8 +167,8 @@
 
        size_t lengthV() const { return 3; }
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -202,8 +202,8 @@
 
        size_t lengthV() const { return 16; }
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
        private:
@@ -263,8 +263,8 @@
        {}
 
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
 
        void text(std::ostream&) const;
 
@@ -291,8 +291,8 @@
 
        size_t lengthV() const { return 1; }
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -328,8 +328,8 @@
 
        size_t lengthV() const { return 3; }
        void writeV(L3Frame& dest, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -356,7 +356,7 @@
        size_t lengthV() const { return 1; }
        void writeV( L3Frame& dest, size_t &wp ) const;
        void parseV( const L3Frame &src, size_t &rp );
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -380,8 +380,8 @@
 
        size_t lengthV() const { return 1; }
        void writeV(L3Frame &dest, size_t &wp ) const;
-       void parseV( const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV( const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -434,7 +434,7 @@
        size_t lengthV() const  { return 3; }
        void writeV( L3Frame &dest, size_t &wp ) const;
        void parseV(const L3Frame& src, size_t &rp);
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -475,8 +475,8 @@
 
        size_t lengthV() const { return 3; }
        void writeV(L3Frame &, size_t &wp ) const;
-       void parseV( const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV( const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -501,8 +501,8 @@
        
        size_t lengthV() const { return 1; }
        void writeV(L3Frame&, size_t &wp) const;
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -526,7 +526,7 @@
        size_t lengthV() const { return 1; }
        void writeV(L3Frame&, size_t&) const;
        void parseV(const L3Frame&, size_t&);
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -549,8 +549,8 @@
 
        size_t lengthV() const { return 1; }
        void writeV( L3Frame &dest, size_t &wp ) const;
-       void parseV( const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV( const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -587,7 +587,7 @@
        size_t lengthV() const { return 1; }
        void writeV(L3Frame&, size_t&) const;
        void parseV(const L3Frame&, size_t&);
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream&) const;
 
 };
@@ -614,15 +614,148 @@
        size_t lengthV() const { return 1; }
        void writeV(L3Frame& dest, size_t &wp) const
                { dest.writeField(wp,mValue,8); }
-       void parseV(const L3Frame&, size_t&) { abort(); }
-       void parseV(const L3Frame&, size_t& , size_t) { abort(); }
+       void parseV(const L3Frame&, size_t&) { assert(0); }
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
        void text(std::ostream& os) const { os << mValue; }
 
 };
 
+/**
+ Application Information Information Elements (encapsulates the RRLP message)
+ */
 
+/** GSM 04.08 10.5.2.48 */
+class L3APDUID : public L3ProtocolElement {
 
+       private:
 
+       unsigned mProtocolIdentifier;
+
+       public:
+
+       /** Default Protocol Identifier is RRLP=0, the only one defined so far 
(rest are reserved). */
+       L3APDUID(unsigned protocolIdentifier=0)
+               :L3ProtocolElement(),
+               mProtocolIdentifier(protocolIdentifier)
+       {}
+
+       size_t lengthV() const { return 1; }
+       void writeV(L3Frame& dest, size_t &wp) const;
+       void parseV(const L3Frame&, size_t&);
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
+       void text(std::ostream& os) const;
+
+};
+
+
+/** GSM 04.08 10.5.2.49 */
+class L3APDUFlags : public L3ProtocolElement {
+
+       private:
+
+    // TODO - use bool for flags?
+       unsigned mCR;
+       unsigned mFirstSegment;
+       unsigned mLastSegment;
+    // TODO - put enums for CR, FirstSegment, LastSegment
+
+       public:
+
+       /** Default is the flags for a single segment APDU - one that fits in a 
single
+        Application Information message **/
+       L3APDUFlags(unsigned cr=0, unsigned firstSegment=0, unsigned 
lastSegment=0)
+               :L3ProtocolElement(),
+               mCR(cr), mFirstSegment(firstSegment), mLastSegment(lastSegment)
+       {}
+
+       size_t lengthV() const { return 1; }
+       void writeV(L3Frame& dest, size_t &wp) const;
+       void parseV(const L3Frame&, size_t&);
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
+       void text(std::ostream& os) const;
+
+};
+
+
+/** GSM 04.08 10.5.2.50 */
+class L3APDUData : public L3ProtocolElement {
+
+       private:
+
+    BitVector mData; // will contain a RRLP message
+
+       public:
+
+    virtual ~L3APDUData();
+
+       /** Default is a zero length APDUData IE */
+       L3APDUData();
+    L3APDUData(BitVector data);
+
+       size_t lengthV() const { return mData.size(); };
+       void writeV(L3Frame& dest, size_t &wp) const;
+       void parseV( const L3Frame& src, size_t &rp, size_t expectedLength );
+       void parseV(const L3Frame&, size_t&) { abort(); }
+       void text(std::ostream& os) const;
+
+};
+
+
+
+
+/** GSM 04.08 10.5.2.20 */
+class L3MeasurementResults : public L3ProtocolElement {
+
+       private:
+
+       bool mBA_USED;
+       bool mDTX_USED;
+       bool mMEAS_VALID;
+       int mRXLEV_FULL_SERVING_CELL;
+       int mRXLEV_SUB_SERVING_CELL;
+       int mRXQUAL_FULL_SERVING_CELL;
+       int mRXQUAL_SUB_SERVING_CELL;
+
+       unsigned mNO_NCELL;
+       int mRXLEV_NCELL[6];
+       int mBCCH_FREQ_NCELL[6];
+       int mBSIC_NCELL[6];
+
+       public:
+
+       L3MeasurementResults()
+               :mMEAS_VALID(false),
+               mNO_NCELL(0)
+       { }
+
+       size_t lengthV() const { return 16; }
+       void writeV(L3Frame&, size_t&) const { assert(0); }
+       void parseV(const L3Frame&, size_t&);
+       void parseV(const L3Frame&, size_t& , size_t) { assert(0); }
+       void text(std::ostream& os) const;
+       
+       /address@hidden Accessors. */
+       //@{
+
+       bool BA_USED() const { return mBA_USED; }
+       bool DTX_USED() const { return mDTX_USED; }
+       bool MEAS_VALID() const { return mMEAS_VALID; }
+       int RXLEV_FULL_SERVING_CELL() const { return mRXLEV_FULL_SERVING_CELL; }
+       int RXLEV_SUB_SERVING_CELL() const { return mRXLEV_SUB_SERVING_CELL; }
+       int RXQUAL_FULL_SERVING_CELL() const { return 
mRXQUAL_FULL_SERVING_CELL; }
+       int RXQUAL_SUB_SERVING_CELL() const { return mRXQUAL_SUB_SERVING_CELL; }
+
+       unsigned NO_NCELL() const { return mNO_NCELL; }
+       int RXLEV_NCELL(unsigned i) const { assert(i<mNO_NCELL); return 
mRXLEV_NCELL[i]; }
+       int RXLEV_NCELL(int *) const;
+       int BCCH_FREQ_NCELL(unsigned i) const { assert(i<mNO_NCELL); return 
mBCCH_FREQ_NCELL[i]; }
+       int BCCH_FREQ_NCELL(int *) const;
+       int BSIC_NCELL(unsigned i) const { assert(i<mNO_NCELL); return 
mBSIC_NCELL[i]; }
+       int BSIC_NCELL(int *) const;
+       //@}
+
+};
+
 } // GSM
 
 

Modified: openbts/trunk/GSM/GSML3RRMessages.cpp
===================================================================
--- openbts/trunk/GSM/GSML3RRMessages.cpp       2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/GSM/GSML3RRMessages.cpp       2009-12-31 04:21:20 UTC (rev 
11667)
@@ -109,6 +109,8 @@
                        os << "Classmark Change"; break;
                case L3RRMessage::RRStatus:
                        os << "RR Status"; break;
+               case L3RRMessage::ApplicationInformation:
+                       os << "Application Information"; break;
                default: os << hex << "0x" << (int)val << dec;
        }
        return os;
@@ -130,7 +132,10 @@
                case L3RRMessage::RRStatus: return new L3RRStatus();
                case L3RRMessage::PagingResponse: return new L3PagingResponse();
                case L3RRMessage::ChannelModeModifyAcknowledge: return new 
L3ChannelModeModifyAcknowledge();
-               case L3RRMessage::GPRSSuspensionRequest: return new 
L3GPRSSuspensionRequest();
+               case L3RRMessage::MeasurementReport: return new 
L3MeasurementReport();
+               case L3RRMessage::ApplicationInformation: return new 
L3ApplicationInformation();
+        // Partial support just to get along with some phones.
+        case L3RRMessage::GPRSSuspensionRequest: return new 
L3GPRSSuspensionRequest();
                default:
                        LOG(WARN) << "no L3 RR factory support for " << MTI;
                        return NULL;
@@ -565,7 +570,77 @@
        os << " mode=(" << mMode << ")";
 }
 
+void L3MeasurementReport::parseBody(const L3Frame& frame, size_t &rp)
+{
+       mResults.parseV(frame,rp);
+}
 
+void L3MeasurementReport::text(ostream& os) const
+{
+       L3RRMessage::text(os);
+       os << mResults;
+}
+
+
+// L3ApplicationInformation
+
+L3ApplicationInformation::~L3ApplicationInformation()
+{
+}
+
+L3ApplicationInformation::L3ApplicationInformation()
+{
+}
+
+L3ApplicationInformation::
+    L3ApplicationInformation(BitVector& data, unsigned protocolIdentifier,
+                             unsigned cr, unsigned firstSegment, unsigned 
lastSegment)
+        : L3RRMessage(), mID(protocolIdentifier)
+        , mFlags(cr, firstSegment, lastSegment)
+        , mData(data)
+{
+}
+
+void L3ApplicationInformation::writeBody( L3Frame &dest, size_t &wp ) const
+{
+/*
+- APDU ID 10.5.2.48 M V 1/2
+- APDU Flags 10.5.2.49 M V 1/2
+- APDU Data 10.5.2.50 M LV N
+*/
+       // reverse order of 1/2-octet fields
+       static size_t start = wp;
+       LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " 
bits";
+       mFlags.writeV(dest, wp);
+       LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " 
bits";
+       mID.writeV(dest, wp);
+       LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " 
bits";
+       mData.writeLV(dest, wp);
+       LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " 
bits";
+}
+
+
+void L3ApplicationInformation::text(ostream& os) const
+{
+       os << "ID=("<<mID<<")";
+       os << " Flags=("<<mFlags<<")";
+       os << " Data=("<<mData<<")";
+}
+
+void L3ApplicationInformation::parseBody(const L3Frame& src, size_t &rp)
+{
+       // reverse order of 1/2-octet fields
+       mFlags.parseV(src, rp);
+       mID.parseV(src, rp);
+       mData.parseLV(src, rp);
+}
+
+size_t L3ApplicationInformation::bodyLength() const
+{
+       return 1 + mData.lengthLV();
+}
+
+
 void L3GPRSSuspensionRequest::parseBody(const L3Frame &src, size_t& rp)
 {
        // We don't really parse this yet.

Modified: openbts/trunk/GSM/GSML3RRMessages.h
===================================================================
--- openbts/trunk/GSM/GSML3RRMessages.h 2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSML3RRMessages.h 2009-12-31 04:21:20 UTC (rev 11667)
@@ -107,8 +107,12 @@
                ///@name special cases -- assigned >8-bit codes to avoid 
conflicts
                //@{
                SynchronizationChannelInformation=0x100,
-               ChannelRequest=0x101
+               ChannelRequest=0x101,
                //@}
+               ///@name application information - used for RRLP
+               //@{
+               ApplicationInformation=0x38,
+               //@}
        };
 
 
@@ -670,8 +674,6 @@
 };
 
 
-
-
 /** GSM 04.08 9.1.29 */
 class L3RRStatus : public L3RRMessage {
 
@@ -749,13 +751,68 @@
 };
 
 
-/** GSM 04.08 9.1.13b */
-class L3GPRSSuspensionRequest : public L3RRMessage {
+/** GSM 04.08 9.1.21 */
+class L3MeasurementReport : public L3RRMessage {
 
+       private:
        // This is a placeholder. We don't really parse anything yet.
+       L3MeasurementResults mResults;
 
        public:
 
+       int MTI() const { return (int) MeasurementReport; }
+       size_t bodyLength() const { return mResults.lengthV(); }
+
+       void writeBody(L3Frame&, size_t&) const { assert(0); }
+       void parseBody(const L3Frame&, size_t&);
+       void text(std::ostream&) const;
+
+       const L3MeasurementResults results() const { return mResults; }
+
+};
+
+
+/** GSM 04.08 9.1.53 */
+class L3ApplicationInformation : public L3RRMessage {
+
+       private:
+
+       L3APDUID mID;
+       L3APDUFlags mFlags;
+       L3APDUData mData;
+
+       public:
+
+       ~L3ApplicationInformation();
+
+       L3ApplicationInformation();
+       // data is the first argument to allow the rest to default, since that 
is the common case,
+       // sending a single (cr=0, first=0, last=0) RRLP (id=0) APDU wrapped in 
a ApplicationInformation L3 packet.
+       L3ApplicationInformation(BitVector& data, unsigned protocolIdentifier=0,
+                                unsigned cr=0, unsigned firstSegment=0, 
unsigned lastSegment=0);
+
+       ///@name Accessors.
+       //@{
+       const L3APDUID& id() const { return mID; }
+       const L3APDUFlags& flags() const { return mFlags; }
+       const L3APDUData& data() const { return mData; }
+       //@}
+
+       int MTI() const { return (int) ApplicationInformation; }
+
+       size_t bodyLength() const;
+       void writeBody( L3Frame&, size_t&) const;
+       void parseBody( const L3Frame &src, size_t &rp );
+       void text(std::ostream&) const;
+
+};
+
+
+/** GSM 04.08 9.1.13b */
+class L3GPRSSuspensionRequest : public L3RRMessage {
+
+       public:
+
        int MTI() const { return (int) GPRSSuspensionRequest; }
 
        size_t bodyLength() const { return 11; }

Modified: openbts/trunk/GSM/GSMLogicalChannel.cpp
===================================================================
--- openbts/trunk/GSM/GSMLogicalChannel.cpp     2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/GSM/GSMLogicalChannel.cpp     2009-12-31 04:21:20 UTC (rev 
11667)
@@ -1,7 +1,7 @@
 /address@hidden Logical Channel.  */
 
 /*
-* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2008, 2009 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.
@@ -173,7 +173,8 @@
                const MappingPair& wMapping)
                : mRunning(false)
 {
-       mL1 = new SACCHL1FEC(wTN,wMapping);
+       mSACCHL1 = new SACCHL1FEC(wTN,wMapping);
+       mL1 = mSACCHL1;
        // SAP0 is RR, SAP3 is SMS
        // SAP1 and SAP2 are not used.
        mL2[0] = new SACCHL2(1,0);
@@ -194,20 +195,49 @@
 
 
 
-void SACCHLogicalChannel::serviceLoop() 
+void SACCHLogicalChannel::serviceLoop()
 {
        // run the loop
        // For now, just send SI5 and SI6 over and over.
        // Later, we can add an incoming FIFO from L2.
+       unsigned count = 0;
        while (mRunning) {
-               if (active()) {
-                       OBJLOG(DEEPDEBUG) << 
"SACCHLogicalChannel::serviceLoop() sending SI5";
-                       LogicalChannel::send(gBTS.SI5Frame());
-                       OBJLOG(DEEPDEBUG) << 
"SACCHLogicalChannel::serviceLoop() sending SI6";
-                       LogicalChannel::send(gBTS.SI6Frame());
-               } else {
+
+               // Throttle back if not active.
+               if (!active()) {
                        sleepFrames(51);
+                       continue;
                }
+
+               // Send alternating SI5/SI6.
+               if (count%2) LogicalChannel::send(gBTS.SI5Frame());
+               else LogicalChannel::send(gBTS.SI6Frame());
+               count++;
+
+               // Receive and save measrement reports.
+               L3Frame *report = LogicalChannel::recv(100);
+               if (!report) continue;
+               if (report->PD() == 0x1) {
+                       // FIXME - getting L1 data in L3Frame.
+                       // FIXME -- Why, again, do we need to do this?
+                       L3Frame* realframe = new L3Frame(report->segment(24, 
report->size()-24));
+                       delete report;
+                       report = realframe;
+               }
+               L3Message* message = parseL3(*report);
+               delete report;
+               if (!message) {
+                       LOG(NOTICE) << "SACCH sent unanticipated unparsable L3 
frame " << *report;
+                       continue;
+               }
+               L3MeasurementReport* measurement = 
dynamic_cast<L3MeasurementReport*>(message);
+               if (!measurement) {
+                       LOG(NOTICE) << "SACCH sent unaticipated message " << 
message;
+                       continue;
+               }
+               mMeasurementResults = measurement->results();
+               LOG(DEBUG) << "SACCH measurement report " << 
this->measurementResults();
+
        }
 }
 
@@ -236,7 +266,68 @@
 
 
 
+void LogicalChannel::setPhy(const LogicalChannel& other)
+{
+       assert(other.mL1);
+       float RSSI = other.mL1->RSSI();
+       float timingError = other.mL1->timingError();
+       mL1->setPhy(RSSI,timingError);
+       if (mSACCH) mSACCH->setPhy(*other.SACCH());
+}
 
+void SACCHLogicalChannel::setPhy(const SACCHLogicalChannel& other)
+{
+       mSACCHL1->setPhy(*other.mSACCHL1);
+}
+       
 
+void LogicalChannel::setPhy(float wRSSI, float wTimingError)
+{
+       assert(mL1);
+       mL1->setPhy(wRSSI,wTimingError);
+       if (mSACCH) mSACCH->setPhy(wRSSI,wTimingError);
+}
+
+void SACCHLogicalChannel::setPhy(float wRSSI, float wTimingError)
+{
+       mL1->setPhy(wRSSI,wTimingError);
+}
+
+
+float LogicalChannel::RSSI() const
+{
+       if (mSACCH) return mSACCH->RSSI();
+       assert(mL1);
+       return mL1->RSSI();
+}
+
+
+float LogicalChannel::timingError() const
+{
+       if (mSACCH) return mSACCH->timingError();
+       assert(mL1);
+       return mL1->timingError();
+}
+
+
+int LogicalChannel::actualMSPower() const
+{
+       assert(mSACCH);
+       // The SACCHLogicalChannel overrides this to prevent a loop.
+       return mSACCH->actualMSPower();
+}
+
+
+int LogicalChannel::actualMSTiming() const
+{
+       assert(mSACCH);
+       // The SACCHLogicalChannel overrides this to prevent a loop.
+       return mSACCH->actualMSTiming();
+}
+
+
+
+
+
 // vim: ts=4 sw=4
 

Modified: openbts/trunk/GSM/GSMLogicalChannel.h
===================================================================
--- openbts/trunk/GSM/GSMLogicalChannel.h       2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/GSM/GSMLogicalChannel.h       2009-12-31 04:21:20 UTC (rev 
11667)
@@ -1,7 +1,7 @@
 /address@hidden Logical Channel.  */
 
 /*
-* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2008, 2009 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.
@@ -78,7 +78,6 @@
        /** The transaction ID associated with this channel. */
        uint32_t mTransactionID;
 
-
 public:
 
        /**
@@ -100,6 +99,7 @@
        /address@hidden Accessors. */
        //@{
        SACCHLogicalChannel* SACCH() { return mSACCH; }
+       const SACCHLogicalChannel* SACCH() const { return mSACCH; }
        L3ChannelDescription channelDescription() const;
        void transactionID(uint32_t wTransactionID) { 
mTransactionID=wTransactionID; }
        uint32_t transactionID() const { return mTransactionID; }
@@ -109,6 +109,12 @@
        /address@hidden Pass-throughs. */
        //@{
 
+       /** Set L1 physical parameters from a RACH or pre-exsting channel. */
+       virtual void setPhy(float wRSSI, float wTimingError);
+
+       /* Set L1 physical parameters from an existing logical channel. */
+       virtual void setPhy(const LogicalChannel&);
+
        /address@hidden L3 interfaces */
        //@{
 
@@ -159,28 +165,38 @@
        //@{
 
        /** Write a received radio burst into the "low" side of the channel. */
-       virtual void writeLowSide(const RxBurst& burst) { 
mL1->writeLowSide(burst); }
+       virtual void writeLowSide(const RxBurst& burst) { assert(mL1); 
mL1->writeLowSide(burst); }
 
        /** Return true if the channel is safely abandoned (closed or 
orphaned). */
-       bool recyclable() const { return mL1->recyclable(); }
+       bool recyclable() const { assert(mL1); return mL1->recyclable(); }
 
        /** Return true if the channel is active. */
-       bool active() const { return mL1->active(); }
+       bool active() const { assert(mL1); return mL1->active(); }
 
        /** The TDMA parameters for the transmit side. */
-       const TDMAMapping& txMapping() const { return mL1->txMapping(); }
+       const TDMAMapping& txMapping() const { assert(mL1); return 
mL1->txMapping(); }
 
        /** The TDMAParameters for the receive side. */
-       const TDMAMapping& rcvMapping() const { return mL1->rcvMapping(); }
+       const TDMAMapping& rcvMapping() const { assert(mL1); return 
mL1->rcvMapping(); }
 
        /** GSM 04.08 10.5.2.5 type and offset code. */
-       TypeAndOffset typeAndOffset() const { return mL1->typeAndOffset(); }
+       TypeAndOffset typeAndOffset() const { assert(mL1); return 
mL1->typeAndOffset(); }
 
+       /address@hidden Channel stats from the physical layer */
+       //@{
        /** Slot number. */
        unsigned TN() const { return mL1->TN(); }
-
        /** Receive FER. */
-       float FER() const { return mL1->FER(); }
+       float FER() const { assert(mL1); return mL1->FER(); }
+       /** RSSI wrt full scale. */
+       float RSSI() const;
+       /** Uplink timing error. */
+       float timingError() const;
+       /** Actual MS uplink power. */
+       virtual int actualMSPower() const;
+       /** Actual MS uplink timing advance. */
+       virtual int actualMSTiming() const;
+       //@}
 
        //@} // L1
 
@@ -248,7 +264,6 @@
 /**
        Logical channel for NDCCHs that use Bbis format and a pseudolength.
        This is a virtual base class this is extended for CCCH & BCCH.
-       For now, we will also use it for the SACCH.
        See GSM 04.06 4.1.1, 4.1.3.
 */
 class NDCCHLogicalChannel : public LogicalChannel {
@@ -289,9 +304,14 @@
 
        protected:
 
+       SACCHL1FEC *mSACCHL1;
        Thread mServiceThread;  ///< a thread for the service loop
        bool mRunning;                  ///< a flag to indication that the 
service loop is running
 
+       /** MeasurementResults from the MS. They are caught in serviceLoop, 
accessed
+        for recording along with GPS and other data in MobilityManagement.cpp 
*/
+       L3MeasurementResults mMeasurementResults;
+
        public:
 
        SACCHLogicalChannel(
@@ -299,13 +319,36 @@
                const MappingPair& wMapping);
 
        ChannelType type() const { return SACCHType; }
-       
-       /** This is a loop in its own thread that sends SI5 and SI6. */
-       void serviceLoop();
 
        void open();
 
+       /* Set L1 physical parameters from an existing logical channel. */
+       void setPhy(const SACCHLogicalChannel&);
+
+       void setPhy(float wRSSI, float wTimingError);
+
+
        friend void 
*SACCHLogicalChannelServiceLoopAdapter(SACCHLogicalChannel*);
+
+       /address@hidden Pass-through accoessors to L1. */
+       //@{
+       int actualMSPower() const { assert(mSACCHL1); return 
mSACCHL1->actualMSPower(); }
+       int actualMSTiming() const { assert(mSACCHL1); return 
mSACCHL1->actualMSTiming(); }
+       //@}
+
+       /address@hidden Channel and neighbour cells stats as reported from MS */
+       //@{
+       const L3MeasurementResults& measurementResults() const { return 
mMeasurementResults; }
+       //@}
+
+       protected:
+
+       /** Read and process a measurement report, called from the service 
loop. */
+       void getReport();
+
+       /** This is a loop in its own thread that sends SI5 and SI6. */
+       void serviceLoop();
+
 };
 
 /** A C interface for the SACCHLogicalChannel embedded loop. */

Modified: openbts/trunk/GSM/GSMTDMA.cpp
===================================================================
--- openbts/trunk/GSM/GSMTDMA.cpp       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSMTDMA.cpp       2009-12-31 04:21:20 UTC (rev 11667)
@@ -216,7 +216,7 @@
 const unsigned SACCH_C8_3UFrames[] = {59,60,61,62};
 MAKE_TDMA_MAPPING(SACCH_C8_3U,SDCCH_8_3,false,true,0xFF,true,102);
 
-const unsigned SACCH_C8_4DFrames[] = {82,84,85,86};
+const unsigned SACCH_C8_4DFrames[] = {83,84,85,86};
 MAKE_TDMA_MAPPING(SACCH_C8_4D,SDCCH_8_4,true,false,0xFF,true,102);
 
 const unsigned SACCH_C8_4UFrames[] = {98,99,100,101};

Modified: openbts/trunk/GSM/GSMTransfer.h
===================================================================
--- openbts/trunk/GSM/GSMTransfer.h     2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/GSMTransfer.h     2009-12-31 04:21:20 UTC (rev 11667)
@@ -60,7 +60,7 @@
                - L2-L3: DL, MDL
        We don't provide the full req-conf-ind-ack handshake because we
        don't always need it in such a tighly integrated system, so
-       out primitive set is simple.
+       our primitive set is simple.
 */
 enum Primitive {
        ESTABLISH,              ///< channel establihsment

Modified: openbts/trunk/GSM/Makefile.am
===================================================================
--- openbts/trunk/GSM/Makefile.am       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/GSM/Makefile.am       2009-12-31 04:21:20 UTC (rev 11667)
@@ -42,7 +42,9 @@
        GSMLogicalChannel.cpp \
        GSMSAPMux.cpp \
        GSMTDMA.cpp \
-       GSMTransfer.cpp
+       GSMTransfer.cpp \
+       GSMTAPDump.cpp \
+       PowerManager.cpp
 
 noinst_HEADERS = \
        GSM610Tables.h \
@@ -61,4 +63,8 @@
        GSMLogicalChannel.h \
        GSMSAPMux.h \
        GSMTDMA.h \
-       GSMTransfer.h
+       GSMTransfer.h \
+       PowerManager.h \
+       GSMTAPDump.h \
+       gsmtap.h
+

Modified: openbts/trunk/Globals/Globals.cpp
===================================================================
--- openbts/trunk/Globals/Globals.cpp   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/Globals/Globals.cpp   2009-12-31 04:21:20 UTC (rev 11667)
@@ -38,13 +38,14 @@
        "\tGNU Radio:\n"
        "\t\tJohnathan Corgan\n"
        "\tOthers:\n"
-       "\t\tAnne Kwong, Jacob Appelbaum, Alberto Escudero-Pascual\n"
+       "\t\tAnne Kwong, Jacob Appelbaum, Joshua Lackey, Alon Levy\n"
+       "\t\tAlexander Chemeris, Alberto Escudero-Pascual\n"
        "\tIncorporated GPL libraries and components:\n"
        "\t\tlibosip2, liportp2\n"
-       "This program comes with ABSOLUTELY NO WARRANTY.\n"
-       "This is free software;\n"
+       "\nThis program comes with ABSOLUTELY NO WARRANTY.\n"
+       "\nThis is free software;\n"
        "you are welcome to redistribute it under the terms of GPLv3.\n"
-       "Use of this software may be subject to other legal restrictions,\n"
+       "\nUse of this software may be subject to other legal restrictions,\n"
        "including patent licsensing and radio spectrum licensing.\n"
        "All users of this software are expected to comply with\n"
        "applicable regulations.\n"

Modified: openbts/trunk/Globals/Makefile.am
===================================================================
--- openbts/trunk/Globals/Makefile.am   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/Globals/Makefile.am   2009-12-31 04:21:20 UTC (rev 11667)
@@ -21,6 +21,7 @@
 include $(top_srcdir)/Makefile.common
 
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
+AM_CXXFLAGS = -Wall
 
 noinst_LTLIBRARIES = libglobals.la
 

Modified: openbts/trunk/Globals/Makefile.in
===================================================================
--- openbts/trunk/Globals/Makefile.in   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/Globals/Makefile.in   2009-12-31 04:21:20 UTC (rev 11667)
@@ -240,6 +240,7 @@
 TRX_INCLUDEDIR = $(top_srcdir)/TRXManager
 GLOBALS_INCLUDEDIR = $(top_srcdir)/Globals
 CLI_INCLUDEDIR = $(top_srcdir)/CLI
+#SQL_INCLUDEDIR = $(top_srcdir)/SQL
 HLR_INCLUDEDIR = $(top_srcdir)/HLR
 STD_DEFINES_AND_INCLUDES = \
        -I$(COMMON_INCLUDEDIR) \
@@ -252,6 +253,7 @@
        -I$(CLI_INCLUDEDIR) \
        -I$(HLR_INCLUDEDIR)
 
+#      -I$(SQL_INCLUDEDIR)
 COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
 GSM_LA = $(top_builddir)/GSM/libGSM.la
 SIP_LA = $(top_builddir)/SIP/libSIP.la
@@ -261,8 +263,10 @@
 GLOBALS_LA = $(top_builddir)/Globals/libglobals.la
 CLI_LA = $(top_builddir)/CLI/libcli.la
 HLR_LA = $(top_builddir)/HLR/libHLR.la
+#SQL_LA = $(top_builddir)/SQL/libSQL.la
 MOSTLYCLEANFILES = *~
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
+AM_CXXFLAGS = -Wall
 noinst_LTLIBRARIES = libglobals.la
 libglobals_la_SOURCES = Globals.cpp
 noinst_HEADERS = Globals.h

Modified: openbts/trunk/HLR/Makefile.am
===================================================================
--- openbts/trunk/HLR/Makefile.am       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/HLR/Makefile.am       2009-12-31 04:21:20 UTC (rev 11667)
@@ -29,14 +29,15 @@
 
 noinst_LTLIBRARIES = libHLR.la
 
+libHLR_la_SOURCES = \
+       HLR.cpp
+
 noinst_PROGRAMS = \
        HLRTest
 
-libHLR_la_SOURCES = \
-       HLR.cpp
-
 noinst_HEADERS = \
        HLR.h
 
+HLRTest_LDADD = $(COMMON_LA) $(HLR_LA)
 HLRTest_SOURCES = HLRTest.cpp
-HLRTest_LDADD = $(COMMON_LA) $(HLR_LA)
+

Modified: openbts/trunk/HLR/Makefile.in
===================================================================
--- openbts/trunk/HLR/Makefile.in       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/HLR/Makefile.in       2009-12-31 04:21:20 UTC (rev 11667)
@@ -245,6 +245,7 @@
 TRX_INCLUDEDIR = $(top_srcdir)/TRXManager
 GLOBALS_INCLUDEDIR = $(top_srcdir)/Globals
 CLI_INCLUDEDIR = $(top_srcdir)/CLI
+#SQL_INCLUDEDIR = $(top_srcdir)/SQL
 HLR_INCLUDEDIR = $(top_srcdir)/HLR
 STD_DEFINES_AND_INCLUDES = \
        -I$(COMMON_INCLUDEDIR) \
@@ -257,6 +258,7 @@
        -I$(CLI_INCLUDEDIR) \
        -I$(HLR_INCLUDEDIR)
 
+#      -I$(SQL_INCLUDEDIR)
 COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
 GSM_LA = $(top_builddir)/GSM/libGSM.la
 SIP_LA = $(top_builddir)/SIP/libSIP.la
@@ -266,6 +268,7 @@
 GLOBALS_LA = $(top_builddir)/Globals/libglobals.la
 CLI_LA = $(top_builddir)/CLI/libcli.la
 HLR_LA = $(top_builddir)/HLR/libHLR.la
+#SQL_LA = $(top_builddir)/SQL/libSQL.la
 MOSTLYCLEANFILES = *~
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
 AM_CXXFLAGS = -Wall -lpthread
@@ -280,8 +283,8 @@
 noinst_HEADERS = \
        HLR.h
 
+HLRTest_LDADD = $(COMMON_LA) $(HLR_LA)
 HLRTest_SOURCES = HLRTest.cpp
-HLRTest_LDADD = $(COMMON_LA) $(HLR_LA)
 all: all-am
 
 .SUFFIXES:

Modified: openbts/trunk/LEGAL
===================================================================
--- openbts/trunk/LEGAL 2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/LEGAL 2009-12-31 04:21:20 UTC (rev 11667)
@@ -1,12 +1,46 @@
 OpenBTS
-
 Copyright 2008, 2009 Free Software Foundation.
 See COPYING for details.
 
+
+Patent Laws
+
 The use of this software to provide GSM services may result in the use of
 patented technologies.  The user of this software is required to take whatever
 actions are necessary to avoid patent infringement.
 
+
+Trademark
+
+"OpenBTS" is a registered trademark of Kestrel Signal Processing, Inc. (KSP), a
+California corporation.  KSP reserves the right to control the use of this 
+trademark.  Do not use this trademark in commerce without permission.
+
+
+Telecom and Radio Spectrum Laws
+
+The primary function of OpenBTS is the provision of telecommunications service
+over a radio link.  This activity is heavily regulated nearly everywhere in
+the world.  Users of this software are expected to comply with local and 
national
+regulations in the jurisdictions where this sortware is used with radio 
equipment.
+
+
+Legal Summary
+
 The user of this software is expected to comply with all applicable laws and
-regulations, including patent laws and telecommunications regulations.
+regulations, including patent laws, copyright laws, and telecommunications
+regulations.
 
+The legal restrictions listed here are not necessarily exhaustive.
+
+
+Software Licensing
+
+OpenBTS itself is distributed publicly under GPLv3.  KSP reserves the right to
+distribute it under other licenses as well.
+
+GPLv3 releases of OpenBTS use the following GPL components that must be 
licensed,
+removed or replaced for non-GPL distributions:
+
+libosip2, liportp2
+

Modified: openbts/trunk/Makefile.am
===================================================================
--- openbts/trunk/Makefile.am   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/Makefile.am   2009-12-31 04:21:20 UTC (rev 11667)
@@ -25,12 +25,12 @@
        config \
        AsteriskConfig \
        CommonLibs \
+       HLR \
        CLI \
        Globals \
        SIP \
        GSM \
        SMS \
-       HLR \
        Transceiver \
        Transceiver52M \
        TRXManager \
@@ -38,9 +38,11 @@
        apps \
        doc \
        smqueue
+#      SQL 
 
 EXTRA_DIST = \
        INSTALLATION \
        LEGAL \
        COPYING \
        README
+

Modified: openbts/trunk/Makefile.common
===================================================================
--- openbts/trunk/Makefile.common       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/Makefile.common       2009-12-31 04:21:20 UTC (rev 11667)
@@ -26,6 +26,7 @@
 TRX_INCLUDEDIR = $(top_srcdir)/TRXManager
 GLOBALS_INCLUDEDIR = $(top_srcdir)/Globals
 CLI_INCLUDEDIR = $(top_srcdir)/CLI
+#SQL_INCLUDEDIR = $(top_srcdir)/SQL
 HLR_INCLUDEDIR = $(top_srcdir)/HLR
 
 STD_DEFINES_AND_INCLUDES = \
@@ -38,6 +39,7 @@
        -I$(GLOBALS_INCLUDEDIR) \
        -I$(CLI_INCLUDEDIR) \
        -I$(HLR_INCLUDEDIR)
+#      -I$(SQL_INCLUDEDIR)
 
 COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
 GSM_LA = $(top_builddir)/GSM/libGSM.la
@@ -48,5 +50,6 @@
 GLOBALS_LA = $(top_builddir)/Globals/libglobals.la
 CLI_LA = $(top_builddir)/CLI/libcli.la
 HLR_LA = $(top_builddir)/HLR/libHLR.la
+#SQL_LA = $(top_builddir)/SQL/libSQL.la
 
 MOSTLYCLEANFILES = *~

Modified: openbts/trunk/README
===================================================================
--- openbts/trunk/README        2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/README        2009-12-31 04:21:20 UTC (rev 11667)
@@ -20,15 +20,16 @@
 apps           OpenBTS application binaries.
 doc            Project documentation.
 tests          Test fixtures for subsets of OpenBTS components.
+smqueue                RFC-3428 store-and-forward server for SMS
 
 
 
-OpenBTS uses the following UDP port assignments:
+By default, OpenBTS assumes the following UDP port assignments:
 
-5060 -- Asterisk
-5061 -- reserved for local SIP softphone
+5060 -- Asterisk SIP interface
+5061 -- local SIP softphone
 5062 -- OpenBTS SIP interface
-5063 -- reserved for local SIMPLE server
+5063 -- smqueue SIP interface
 5700-range -- OpenBTS-transceiver interface
 
 These can be controlled in the configuration file, apps/OpenBTS.config.
@@ -36,7 +37,7 @@
 
 Releases 2.5 and later include the smqueue SMS server.  It is NOT part of the
 normal GNU build process with the rest of OpenBTS.  To build smqueue, go
-into the smqueue directory and just type "make".
+into the smqueue directory and just type "make -f Makefile.standalone".
 
 
 
@@ -94,7 +95,7 @@
                                                        command line interface
                                                        emergency call setup
 
-2.4    Kinder          KSP             rxxx (trunk)    fixed BCCH neighbor 
list bug
+2.4    Kinder          KSP             r208? (trunk)   fixed BCCH neighbor 
list bug
                                                        support for neighbor 
lists
                                                        fixed support for 
non-local Asterisk servers
                                                        cleaner configuration 
management
@@ -102,13 +103,16 @@
                                                        proper rejection of 
Hold messages
                                                        fixed L3 hanging bug in 
MTDCheckBYE
 
-
 2.4.1  Kinder          KSP                             fixed lots of valgrind 
errors
 
 2.4.2  Kinder          KSP                             zero-length calling 
party number bug
                                                        g++ 4.4 #includes
 
-2.5    Lacassine                                       SMS server support
+2.5    Lacassine       KSP             rxxx (trunk)    imported Joshua Lackey 
patches
+                                                       SIP fixes from Anne 
Kwong
+                                                       SIP fixes from testing 
with SMS server
+                                                       L3 TI handling fixes
+                                                       SMS server support
                                                        GNU Radio 3.2 
compatibility
                                                        configurable max range 
and LU-reject cause
                                                        "page" & "testcall" CLI 
features

Modified: openbts/trunk/SIP/SIPEngine.cpp
===================================================================
--- openbts/trunk/SIP/SIPEngine.cpp     2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/SIP/SIPEngine.cpp     2009-12-31 04:21:20 UTC (rev 11667)
@@ -145,7 +145,7 @@
 
 bool SIPEngine::Register( Method wMethod )
 {
-       LOG(INFO) << "SIPEngine::Register mState=" << mState << " " << wMethod 
<< " callID " << mCallID;
+       LOG(INFO) << "Register mState=" << mState << " " << wMethod << " callID 
" << mCallID;
 
        // Before start, need to add mCallID
        gSIPInterface.addCall(mCallID);
@@ -194,12 +194,18 @@
                assert(msg);
                while (msg->status_code!=200) {
                        // Looking for 200 OK.
-                       // But will keep waiting is we get 200 Trying.
-                       LOG(DEBUG) << "received status " << msg->status_code;
-                       if (msg->status_code!=100) {
-                               LOG(DEBUG) << "unexpected message";
-                               gSIPInterface.removeCall(mCallID);      
+                       // But will keep waiting if we get 1xx status mesasges, 
e.g. 100 Trying.
+                       LOG(DEBUG) << "received status " << msg->status_code << 
" " << msg->reason_phrase;
+                       if (msg->status_code>=300) {
+                               gSIPInterface.removeCall(mCallID);
                                osip_message_free(msg);
+                               if (msg->status_code==404) {
+                                       LOG(DEBUG) << "user not found";
+                               } else if (msg->status_code>=300 && 
msg->status_code<400) {
+                                       LOG(DEBUG) << "redirection is not 
implemented yet";
+                               } else {
+                                       LOG(DEBUG) << "unexpected message";
+                               }
                                return false;
                        }
                        osip_message_free(msg);
@@ -207,7 +213,7 @@
                        assert(msg);
                }
                LOG(DEBUG) << "success";
-               gSIPInterface.removeCall(mCallID);      
+               gSIPInterface.removeCall(mCallID);
                osip_message_free(msg);
                return true;
        }
@@ -427,7 +433,7 @@
        // Size of -1 means the FIFO does not exist.
        // Treat the call as cleared.
        if (fifoSize==-1) {
-               LOG(NOTICE) << "attempt to check BYE on non-existant SIP FIFO";
+               LOG(NOTICE) << "MTDCheckBYE attempt to check BYE on 
non-existant SIP FIFO";
                mState=Cleared;
                return mState;
        }
@@ -708,8 +714,13 @@
 SIPState SIPEngine::MTSMSSendOK()
 {
        LOG(DEBUG) << "mState=" << mState;
+       // If this operation was initiated from the CLI, there was no INVITE.
+       if (!mINVITE) {
+               LOG(INFO) << "clearing CLI-generated transaction";
+               mState=Cleared;
+               return mState;
+       }
        LOG(INFO) << "SIP send INVITE-OK " << mSIPUsername;
-       assert(mINVITE);
        // Form ack from invite and new parameters.
        osip_message_t * okay = sip_okay_SMS(mINVITE, mSIPUsername.c_str(),
                gConfig.getStr("SIP.IP"), mSIPPort, mToTag.c_str());

Modified: openbts/trunk/SIP/SIPEngine.h
===================================================================
--- openbts/trunk/SIP/SIPEngine.h       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/SIP/SIPEngine.h       2009-12-31 04:21:20 UTC (rev 11667)
@@ -127,7 +127,7 @@
                const char* wAsteriskIP = gConfig.getStr("Asterisk.IP");
                assert(strlen(wAsteriskIP)<256);
                strcpy(mAsteriskIP,wAsteriskIP);
-               const char* wMessengerIP = gConfig.getStr("Messenger.IP");
+               const char* wMessengerIP = gConfig.getStr("Smqueue.IP");
                assert(strlen(wMessengerIP)<256);
                strcpy(mMessengerIP,wMessengerIP);
        }

Modified: openbts/trunk/SIP/SIPInterface.cpp
===================================================================
--- openbts/trunk/SIP/SIPInterface.cpp  2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/SIP/SIPInterface.cpp  2009-12-31 04:21:20 UTC (rev 11667)
@@ -128,9 +128,9 @@
        :mSIPSocket(gConfig.getNum("SIP.Port"), gConfig.getStr("Asterisk.IP"), 
gConfig.getNum("Asterisk.Port"))
 {
        mAsteriskPort = gConfig.getNum("Asterisk.Port");
-       mMessengerPort = gConfig.getNum("Messenger.Port");
+       mMessengerPort = gConfig.getNum("Smqueue.Port");
        
assert(resolveAddress(&mAsteriskAddress,gConfig.getStr("Asterisk.IP"),mAsteriskPort));
-       
assert(resolveAddress(&mMessengerAddress,gConfig.getStr("Messenger.IP"),mMessengerPort));
+       
assert(resolveAddress(&mMessengerAddress,gConfig.getStr("Smqueue.IP"),mMessengerPort));
 }
 
 
@@ -321,8 +321,7 @@
                        return false;
                }
                LOG(INFO) << "repeated SIP INVITE/MESSAGE, repaging"; 
-               gBTS.pager().addID(mobile_id,requiredChannel,transaction.ID()); 
-               transaction.T3113().set();
+               gBTS.pager().addID(mobile_id,requiredChannel,transaction);      
                gTransactionTable.update(transaction);
                return false;
        }
@@ -352,8 +351,6 @@
        // Build the transaction table entry.
        // This constructor sets TI flag=0, TI=0 for an MT transaction.
        TransactionEntry transaction(mobile_id,serviceType,callerID);
-       transaction.T3113().set();
-       transaction.Q931State(TransactionEntry::Paging);
        LOG(DEBUG) << "call_id_num \"" << call_id_num << "\"";
        LOG(DEBUG) << "IMSI \"" << IMSI << "\"";
 
@@ -374,7 +371,7 @@
        
        // Add to paging list and tell the remote SIP end that we are trying.
        LOG(DEBUG) << "MTC MTSMS new SIP invite, initial paging for mobile ID " 
<< mobile_id;
-       gBTS.pager().addID(mobile_id,requiredChannel,transaction.ID()); 
+       gBTS.pager().addID(mobile_id,requiredChannel,transaction);      
        // FIXME -- Send TRYING?  See MTCSendTrying for example.
 
        return true;

Modified: openbts/trunk/SIP/SIPInterface.h
===================================================================
--- openbts/trunk/SIP/SIPInterface.h    2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/SIP/SIPInterface.h    2009-12-31 04:21:20 UTC (rev 11667)
@@ -62,7 +62,7 @@
                memcpy(&mReturnAddress,wReturnAddress,sizeof(mReturnAddress));
        }
 
-       ~OSIPMessageFIFO()
+       virtual ~OSIPMessageFIFO()
        {
                // We must call clear() here, because if it is called from 
InterthreadQueue
                // destructor, then clear() will call InterthreadQueue's 
freeElement() which

Modified: openbts/trunk/SMS/Makefile.am
===================================================================
--- openbts/trunk/SMS/Makefile.am       2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/SMS/Makefile.am       2009-12-31 04:21:20 UTC (rev 11667)
@@ -21,6 +21,7 @@
 include $(top_srcdir)/Makefile.common
 
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
+AM_CXXFLAGS = -Wall
 
 noinst_LTLIBRARIES = libSMS.la
 

Modified: openbts/trunk/TRXManager/Makefile.am
===================================================================
--- openbts/trunk/TRXManager/Makefile.am        2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/TRXManager/Makefile.am        2009-12-31 04:21:20 UTC (rev 
11667)
@@ -25,6 +25,7 @@
        clockdump.sh
 
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
+AM_CXXFLAGS = -Wall
 
 noinst_LTLIBRARIES = libtrxmanager.la
 

Modified: openbts/trunk/TRXManager/TRXManager.cpp
===================================================================
--- openbts/trunk/TRXManager/TRXManager.cpp     2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/TRXManager/TRXManager.cpp     2009-12-31 04:21:20 UTC (rev 
11667)
@@ -125,7 +125,7 @@
 {
        // The default demux table is full of NULL pointers.
        for (int i=0; i<8; i++) {
-               for (int j=0; j<maxModulus; j++) {
+               for (unsigned j=0; j<maxModulus; j++) {
                        mDemuxTable[i][j] = NULL;
                }
        }
@@ -156,7 +156,7 @@
 
        mTableLock.lock();
        for (unsigned i=0; i<mapping.numFrames(); i++) {
-               int FN = mapping.frameMapping(i);
+               unsigned FN = mapping.frameMapping(i);
                while (FN<maxModulus) {
                        // Don't overwrite existing entries.
                        assert(mDemuxTable[TN][FN]==NULL);
@@ -268,7 +268,7 @@
                        LOG(DEBUG) << "command retry waitTime=" << waitTime << 
" msgLen=" << msgLen;
                }
                if (msgLen<=0) {
-                       LOG(WARN) << "retrying transceiver command after 
response timeout";
+                       LOG(INFO) << "retrying transceiver command after 
response timeout";
                        continue;
                }
                else {
@@ -284,7 +284,7 @@
                return msgLen;
        }
 
-       LOG(ERROR) << "lost control link to transceiver";
+       LOG(ALARM) << "lost control link to transceiver";
        SOCKET_ERROR;
 }
 
@@ -401,6 +401,7 @@
                LOG(ALARM) << "POWEROFF failed with status " << status;
                return false;
        }
+       return true;
 }
 
 
@@ -411,6 +412,7 @@
                LOG(ALARM) << "POWERON failed with status " << status;
                return false;
        }
+       return true;
 }
 
 
@@ -454,6 +456,17 @@
        return true;
 }
 
+bool ::ARFCNManager::setMaxDelay(unsigned km)
+{
+        char paramBuf[MAX_UDP_LENGTH];
+        sprintf(paramBuf,"%d", km);
+        int status = sendCommand("SETMAXDELAY",paramBuf);
+        if (status!=0) {
+                LOG(ALARM) << "SETMAXDELAY failed with status " << status;
+                return false;
+        }
+        return true;
+}
 
 
 

Modified: openbts/trunk/TRXManager/TRXManager.h
===================================================================
--- openbts/trunk/TRXManager/TRXManager.h       2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/TRXManager/TRXManager.h       2009-12-31 04:21:20 UTC (rev 
11667)
@@ -170,7 +170,14 @@
        /** Turn on the transceiver. */
        bool powerOn();
 
+        /**     
+               Set maximum expected delay spread.
+               @param km Max network range in kilometers.
+               @return true on success.
+        */
+        bool setMaxDelay(unsigned km);
 
+
        /**
                Set power wrt full scale.
                @param dB Power level wrt full power.

Modified: openbts/trunk/Transceiver/Makefile.am
===================================================================
--- openbts/trunk/Transceiver/Makefile.am       2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Transceiver/Makefile.am       2009-12-31 04:21:20 UTC (rev 
11667)
@@ -20,8 +20,8 @@
 
 include $(top_srcdir)/Makefile.common
 
-AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) -I$(USRP_INCLUDEDIR)
-CXX_FLAGS = -O3 -g -lpthread
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) -I$(USRP_CFLAGS)
+CXXFLAGS = -Wall -O3 -g -pthread
 
 rev2dir = $(datadir)/usrp/rev2
 rev4dir = $(datadir)/usrp/rev4

Modified: openbts/trunk/Transceiver52M/Makefile.am
===================================================================
--- openbts/trunk/Transceiver52M/Makefile.am    2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Transceiver52M/Makefile.am    2009-12-31 04:21:20 UTC (rev 
11667)
@@ -43,7 +43,8 @@
 
 noinst_PROGRAMS = \
        USRPping \
-       transceiver
+       transceiver \
+       sigProcLibTest 
 
 noinst_HEADERS = \
        Complex.h \
@@ -67,7 +68,14 @@
        $(COMMON_LA) \
        $(USRP_LIBS)
 
+sigProcLibTest_SOURCES = sigProcLibTest.cpp
+sigProcLibTest_LDADD = \
+       libtransceiver.la \
+       $(GSM_LA) \
+       $(COMMON_LA) \
+       $(USRP_LIBS)
 
+
 MOSTLYCLEANFILES +=
 
 #radioInterface.cpp

Modified: openbts/trunk/Transceiver52M/Makefile.in
===================================================================
--- openbts/trunk/Transceiver52M/Makefile.in    2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Transceiver52M/Makefile.in    2009-12-31 04:21:20 UTC (rev 
11667)
@@ -57,7 +57,7 @@
 
 
 
-SOURCES = $(libtransceiver_la_SOURCES) $(USRPping_SOURCES) 
$(transceiver_SOURCES)
+SOURCES = $(libtransceiver_la_SOURCES) $(USRPping_SOURCES) 
$(sigProcLibTest_SOURCES) $(transceiver_SOURCES)
 
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
@@ -85,7 +85,8 @@
 DIST_COMMON = README $(dist_rev2_DATA) $(dist_rev4_DATA) \
        $(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
        $(top_srcdir)/Makefile.common
-noinst_PROGRAMS = USRPping$(EXEEXT) transceiver$(EXEEXT)
+noinst_PROGRAMS = USRPping$(EXEEXT) transceiver$(EXEEXT) \
+       sigProcLibTest$(EXEEXT)
 subdir = Transceiver52M
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/configure.ac
@@ -106,9 +107,13 @@
 am__DEPENDENCIES_2 =
 USRPping_DEPENDENCIES = libtransceiver.la $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_2)
+am_sigProcLibTest_OBJECTS = sigProcLibTest.$(OBJEXT)
+sigProcLibTest_OBJECTS = $(am_sigProcLibTest_OBJECTS)
+am__DEPENDENCIES_3 = $(top_builddir)/GSM/libGSM.la
+sigProcLibTest_DEPENDENCIES = libtransceiver.la $(am__DEPENDENCIES_3) \
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
 am_transceiver_OBJECTS = runTransceiver.$(OBJEXT)
 transceiver_OBJECTS = $(am_transceiver_OBJECTS)
-am__DEPENDENCIES_3 = $(top_builddir)/GSM/libGSM.la
 transceiver_DEPENDENCIES = libtransceiver.la $(am__DEPENDENCIES_3) \
        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
@@ -123,9 +128,9 @@
 CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \
        $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
 SOURCES = $(libtransceiver_la_SOURCES) $(USRPping_SOURCES) \
-       $(transceiver_SOURCES)
+       $(sigProcLibTest_SOURCES) $(transceiver_SOURCES)
 DIST_SOURCES = $(libtransceiver_la_SOURCES) $(USRPping_SOURCES) \
-       $(transceiver_SOURCES)
+       $(sigProcLibTest_SOURCES) $(transceiver_SOURCES)
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -266,6 +271,7 @@
 TRX_INCLUDEDIR = $(top_srcdir)/TRXManager
 GLOBALS_INCLUDEDIR = $(top_srcdir)/Globals
 CLI_INCLUDEDIR = $(top_srcdir)/CLI
+#SQL_INCLUDEDIR = $(top_srcdir)/SQL
 HLR_INCLUDEDIR = $(top_srcdir)/HLR
 STD_DEFINES_AND_INCLUDES = \
        -I$(COMMON_INCLUDEDIR) \
@@ -278,6 +284,7 @@
        -I$(CLI_INCLUDEDIR) \
        -I$(HLR_INCLUDEDIR)
 
+#      -I$(SQL_INCLUDEDIR)
 COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
 GSM_LA = $(top_builddir)/GSM/libGSM.la
 SIP_LA = $(top_builddir)/SIP/libSIP.la
@@ -287,6 +294,7 @@
 GLOBALS_LA = $(top_builddir)/Globals/libglobals.la
 CLI_LA = $(top_builddir)/CLI/libcli.la
 HLR_LA = $(top_builddir)/HLR/libHLR.la
+#SQL_LA = $(top_builddir)/SQL/libSQL.la
 MOSTLYCLEANFILES = *~
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) -I$(USRP_INCLUDEDIR)
 AM_CXXFLAGS = -O3 -g -lpthread
@@ -327,6 +335,13 @@
        $(COMMON_LA) \
        $(USRP_LIBS)
 
+sigProcLibTest_SOURCES = sigProcLibTest.cpp
+sigProcLibTest_LDADD = \
+       libtransceiver.la \
+       $(GSM_LA) \
+       $(COMMON_LA) \
+       $(USRP_LIBS)
+
 all: all-am
 
 .SUFFIXES:
@@ -381,6 +396,9 @@
 USRPping$(EXEEXT): $(USRPping_OBJECTS) $(USRPping_DEPENDENCIES) 
        @rm -f USRPping$(EXEEXT)
        $(CXXLINK) $(USRPping_LDFLAGS) $(USRPping_OBJECTS) $(USRPping_LDADD) 
$(LIBS)
+sigProcLibTest$(EXEEXT): $(sigProcLibTest_OBJECTS) 
$(sigProcLibTest_DEPENDENCIES) 
+       @rm -f sigProcLibTest$(EXEEXT)
+       $(CXXLINK) $(sigProcLibTest_LDFLAGS) $(sigProcLibTest_OBJECTS) 
$(sigProcLibTest_LDADD) $(LIBS)
 transceiver$(EXEEXT): $(transceiver_OBJECTS) $(transceiver_DEPENDENCIES) 
        @rm -f transceiver$(EXEEXT)
        $(CXXLINK) $(transceiver_LDFLAGS) $(transceiver_OBJECTS) 
$(transceiver_LDADD) $(LIBS)
@@ -397,6 +415,7 @@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 
 .cpp.o:
 @am__fastdepCXX_TRUE@  if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" 
-c -o $@ $<; \

Modified: openbts/trunk/Transceiver52M/Transceiver.cpp
===================================================================
--- openbts/trunk/Transceiver52M/Transceiver.cpp        2009-12-31 03:03:10 UTC 
(rev 11666)
+++ openbts/trunk/Transceiver52M/Transceiver.cpp        2009-12-31 04:21:20 UTC 
(rev 11667)
@@ -232,10 +232,7 @@
     break;
   case IV:
   case VI:
-    if ((burstFN % 51) % 10 < 2)
-      return RACH;
-    else
-      return OFF;
+    return RACH;
     break;
   case V: {
     int mod51 = burstFN % 51;
@@ -483,7 +480,7 @@
     if (!mOn)
       sprintf(response,"RSP SETMAXDELAY 1 %d",maxDelay);
     else {
-      mMaxExpectedDelay = maxDelay;
+      mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
       sprintf(response,"RSP SETMAXDELAY 0 %d",maxDelay);
     }
   }
@@ -515,34 +512,26 @@
     // tune receiver
     int freqKhz;
     sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
-    if (mOn)
-      sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
-    else {
-      mRxFreq = freqKhz*1.0e3+FREQOFFSET;
-      if (!mRadioInterface->tuneRx(mRxFreq)) {
-         LOG(ALARM) << "RX failed to tune";
-         sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
-      }
-      else
-         sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
+    mRxFreq = freqKhz*1.0e3+FREQOFFSET;
+    if (!mRadioInterface->tuneRx(mRxFreq)) {
+       LOG(ALARM) << "RX failed to tune";
+       sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
     }
+    else
+       sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
   }
   else if (strcmp(command,"TXTUNE")==0) {
     // tune txmtr
     int freqKhz;
     sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
-    if (mOn)
-      sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
-    else {
-      //freqKhz = 890e3;
-      mTxFreq = freqKhz*1.0e3+FREQOFFSET;
-      if (!mRadioInterface->tuneTx(mTxFreq)) {
-         LOG(ALARM) << "TX failed to tune";
-         sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
-      }
-      else
-         sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
+    //freqKhz = 890e3;
+    mTxFreq = freqKhz*1.0e3+FREQOFFSET;
+    if (!mRadioInterface->tuneTx(mTxFreq)) {
+       LOG(ALARM) << "TX failed to tune";
+       sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
     }
+    else
+       sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
   }
   else if (strcmp(command,"SETTSC")==0) {
     // set TSC

Modified: openbts/trunk/Transceiver52M/USRPDevice.cpp
===================================================================
--- openbts/trunk/Transceiver52M/USRPDevice.cpp 2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Transceiver52M/USRPDevice.cpp 2009-12-31 04:21:20 UTC (rev 
11667)
@@ -163,6 +163,8 @@
 {
   skipRx = wSkipRx;
 
+  writeLock.unlock();
+
   LOG(INFO) << "making USRP device..";
 #ifndef SWLOOPBACK 
   string rbf = "std_inband.rbf";
@@ -466,6 +468,8 @@
                             unsigned long long timestamp,
                             bool isControl) 
 {
+  writeLock.lock();
+
 #ifndef SWLOOPBACK 
   if (!m_uTx) return 0;
  
@@ -498,6 +502,8 @@
   m_uTx->write((const void*) outPkt,sizeof(uint32_t)*128*numPkts,NULL);
 
   samplesWritten += len/2/sizeof(short);
+  writeLock.unlock();
+
   return len/2/sizeof(short);
 #else
   int retVal = len;

Modified: openbts/trunk/Transceiver52M/USRPDevice.h
===================================================================
--- openbts/trunk/Transceiver52M/USRPDevice.h   2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Transceiver52M/USRPDevice.h   2009-12-31 04:21:20 UTC (rev 
11667)
@@ -65,7 +65,7 @@
   bool started;                        ///< flag indicates USRP has started
   bool skipRx;                 ///< set if USRP is transmit-only.
 
-  static const unsigned int currDataSize_log2 = 18;
+  static const unsigned int currDataSize_log2 = 21;
   static const unsigned long currDataSize = (1 << currDataSize_log2);
   short *data;
   unsigned long dataStart;
@@ -74,6 +74,8 @@
   TIMESTAMP timeEnd;
   bool isAligned;
 
+  Mutex writeLock;
+
   short *currData;             ///< internal data buffer when reading from USRP
   TIMESTAMP currTimestamp;     ///< timestamp of internal data buffer
   unsigned currLen;            ///< size of internal data buffer

Modified: openbts/trunk/Transceiver52M/USRPping.cpp
===================================================================
--- openbts/trunk/Transceiver52M/USRPping.cpp   2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Transceiver52M/USRPping.cpp   2009-12-31 04:21:20 UTC (rev 
11667)
@@ -24,6 +24,7 @@
 
 
 
+#include <stdio.h>
 #include "Transceiver.h"
 #include <Logger.h>
 

Modified: openbts/trunk/Transceiver52M/radioInterface.cpp
===================================================================
--- openbts/trunk/Transceiver52M/radioInterface.cpp     2009-12-31 03:03:10 UTC 
(rev 11666)
+++ openbts/trunk/Transceiver52M/radioInterface.cpp     2009-12-31 04:21:20 UTC 
(rev 11667)
@@ -98,17 +98,26 @@
   //mReceiveFIFO.clear();
 }
 
-short *RadioInterface::USRPifyVector(signalVector &wVector, short *retVector) 
+short *RadioInterface::USRPifyVector(signalVector &wVector, short *retVector, 
double scale) 
 {
 
 
   signalVector::iterator itr = wVector.begin();
   short *shortItr = retVector;
-  while (itr < wVector.end()) {
-    *shortItr++ = (short) host_to_usrp_short(itr->real());
-    *shortItr++ = (short) host_to_usrp_short(itr->imag());
-    itr++;
+  if (scale != 1.0) { 
+    while (itr < wVector.end()) {
+      *shortItr++ = (short) host_to_usrp_short(itr->real()*scale);
+      *shortItr++ = (short) host_to_usrp_short(itr->imag()*scale);
+      itr++;
+    }
   }
+  else {
+    while (itr < wVector.end()) {
+      *shortItr++ = (short) host_to_usrp_short(itr->real());
+      *shortItr++ = (short) host_to_usrp_short(itr->imag());
+      itr++;
+    }
+  }
 
   return retVector;
 
@@ -144,7 +153,7 @@
   if (sendCursor < 2*INCHUNK) return;
 
   // start the USRP when we actually have data to send to the USRP.
-  if (!started) {
+/*  if (!started) {
     started = true; 
     LOG(INFO) << "Starting USRP";
     usrp->start(); 
@@ -152,7 +161,7 @@
     usrp->updateAlignment(10000); 
     usrp->updateAlignment(10000);
   }
-
+*/
   // send resampleVector
   int samplesWritten = usrp->writeSamples(sendBuffer,
                                          INCHUNK,
@@ -196,13 +205,11 @@
 
 bool RadioInterface::tuneTx(double freq)
 {
-  if (mOn) return false;
   return usrp->setTxFreq(freq);
 }
 
 bool RadioInterface::tuneRx(double freq)
 {
-  if (mOn) return false;
   return usrp->setRxFreq(freq);
 }
 
@@ -215,6 +222,10 @@
   mOn = true;
   writeTimestamp = 20000;
   readTimestamp = 20000;
+  usrp->start(); 
+  LOG(DEBUG) << "USRP started";
+  usrp->updateAlignment(10000); 
+  usrp->updateAlignment(10000);
   LOG(DEBUG) << "radio interface started!";
 }
 
@@ -236,10 +247,8 @@
 
   if (!mOn) return;
 
-  if (powerScaling != 1.0) scaleVector(radioBurst, powerScaling);
+  USRPifyVector(radioBurst, sendBuffer+sendCursor, powerScaling);
 
-  USRPifyVector(radioBurst, sendBuffer+sendCursor);
-
   sendCursor += (radioBurst.size()*2);
 
   pushBuffer();

Modified: openbts/trunk/Transceiver52M/radioInterface.h
===================================================================
--- openbts/trunk/Transceiver52M/radioInterface.h       2009-12-31 03:03:10 UTC 
(rev 11666)
+++ openbts/trunk/Transceiver52M/radioInterface.h       2009-12-31 04:21:20 UTC 
(rev 11667)
@@ -159,7 +159,7 @@
   double powerScaling;
 
   /** format samples to USRP */ 
-  short *USRPifyVector(signalVector &wVector, short *shortVector);
+  short *USRPifyVector(signalVector &wVector, short *shortVector, double 
scale);
 
   /** format samples from USRP */
   void unUSRPifyVector(short *shortVector, signalVector &wVector);

Modified: openbts/trunk/Transceiver52M/sigProcLib.cpp
===================================================================
--- openbts/trunk/Transceiver52M/sigProcLib.cpp 2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/Transceiver52M/sigProcLib.cpp 2009-12-31 04:21:20 UTC (rev 
11667)
@@ -980,7 +980,7 @@
   assert(TOA);
   assert(gMidambles[TSC]);
 
-  if (maxTOA < 2*samplesPerSymbol) maxTOA = 2*samplesPerSymbol;
+  if (maxTOA < 3*samplesPerSymbol) maxTOA = 3*samplesPerSymbol;
   unsigned spanTOA = maxTOA;
   if (spanTOA < 5*samplesPerSymbol) spanTOA = 5*samplesPerSymbol;
 
@@ -989,7 +989,7 @@
   unsigned windowLen = endIx - startIx;
   unsigned corrLen = 2*maxTOA+1;
 
-  unsigned expectedTOAPeak = gMidambles[TSC]->TOA + 
(gMidambles[TSC]->sequenceReversedConjugated->size()-1)/2;
+  unsigned expectedTOAPeak = (unsigned) round(gMidambles[TSC]->TOA + 
(gMidambles[TSC]->sequenceReversedConjugated->size()-1)/2);
 
   signalVector burstSegment(rxBurst.begin(),startIx,windowLen);
 
@@ -1037,14 +1037,14 @@
   //       needs to be accounted for.
   
   *amplitude = (*amplitude)/gMidambles[TSC]->gain;
-  *TOA = (*TOA) - maxTOA; 
+  *TOA = (*TOA) - (maxTOA); 
 
   LOG(DEBUG) << "TCH peakAmpl=" << amplitude->abs() << " RMS=" << RMS << " 
peakToMean=" << peakToMean << " TOA=" << *TOA;
 
   LOG(DEBUG) << "autocorr: " << correlatedBurst;
   
   if (requestChannel && (peakToMean > detectThreshold)) {
-    float TOAoffset = gMidambles[TSC]->TOA+(66*samplesPerSymbol-startIx);
+    float TOAoffset = maxTOA; 
//gMidambles[TSC]->TOA+(66*samplesPerSymbol-startIx);
     delayVector(correlatedBurst,-(*TOA));
     // midamble only allows estimation of a 6-tap channel
     signalVector channelVector(6*samplesPerSymbol);
@@ -1099,8 +1099,6 @@
                         float TOA) 
 
 {
-
-
   scaleVector(rxBurst,((complex) 1.0)/channel);
   delayVector(rxBurst,-TOA);
 

Modified: openbts/trunk/apps/Makefile.am
===================================================================
--- openbts/trunk/apps/Makefile.am      2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/apps/Makefile.am      2009-12-31 04:21:20 UTC (rev 11667)
@@ -21,15 +21,16 @@
 include $(top_srcdir)/Makefile.common
 
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
+AM_CXXFLAGS = -Wall -g -pthread
 
 noinst_PROGRAMS = \
-       OpenBTS \
-       sendSimple 
+       OpenBTS 
 
 OpenBTS_SOURCES = OpenBTS.cpp
 OpenBTS_LDADD = \
        $(GLOBALS_LA) \
        $(COMMON_LA) \
+       $(HLR_LA) \
        $(SIP_LA) \
        $(GSM_LA) \
        $(TRX_LA) \
@@ -37,11 +38,9 @@
        $(SMS_LA) \
        $(CLI_LA) \
        $(OSIP_LIBS) \
-       $(ORTP_LIBS)
+       $(ORTP_LIBS) \
+       $(READLINE_LIB)
 
-sendSimple_SOURCES = sendSimple.cpp
-sendSimple_LDADD = \
-       $(COMMON_LA) 
 
 EXTRA_DIST = \
        OpenBTS.config.example

Modified: openbts/trunk/apps/OpenBTS.config.example
===================================================================
--- openbts/trunk/apps/OpenBTS.config.example   2009-12-31 03:03:10 UTC (rev 
11666)
+++ openbts/trunk/apps/OpenBTS.config.example   2009-12-31 04:21:20 UTC (rev 
11667)
@@ -4,12 +4,14 @@
 # Everything between the first space and the end of the line becomes the value.
 # Comments must start with "#" at the beginning of the line.
 # Blank lines are OK.
+# The "$static" directive indicates that a configuration value cannot
+# be changed after initialization.
 
 # As a gerenal rule, non-valid configuration values will crash OpenBTS.
 
 
 #
-# Logging parameters
+# Logging and reporting parameters
 #
 
 # The initial global logging level: ERROR, WARNING, NOTICE, INFO, DEBUG, 
DEEPDEBUG
@@ -17,12 +19,25 @@
 
 # The log file path.  If not set, logging goes to stdout.
 LogFileName test.out
+$static LogFileName
 
+# LOG(ALARM) is printed and also sent as udp to this address.
+Alarm.TargetIP 192.168.10.200
+Alarm.TargetPort 10101
+
 # Wireshark support
 # The standard IANA for GSMTAP is 4729
-# If if this is not defined, we do not generate the GSMTAP dumps.
-Wireshark.Port 4729
+# OpenBTS writes L2 GSMTAP messages to this port.
+GSMTAP.TargetIP 127.0.0.1
+GSMTAP.TargetPort 4729
 
+# Indications port
+# Some interal operations produce status reports sent to this port.
+# This can be the same as the Alarm target.
+Indications.TargetIP 127.0.0.1
+Indications.TargetPort 10202
+
+
 # Port number for test calls.
 # This is where an external program can interact with a handset via UDP.
 TestCall.Port 28670
@@ -35,50 +50,58 @@
 # Transceiver interface
 # This TRX.IP is not really adjustable.  Just leave it as 127.0.0.1.
 TRX.IP 127.0.0.1
+$static TRX.IP
 # This value is hard-coded in the transcevier.  Just leave it alone.
 TRX.Port 5700
+$static TRX.Port
 
 # Path to transceiver binary
+# If this is not defined, you will need to start the transceiver by hand.
 # YOU MUST HAVE A MATCHING libusrp AS WELL!!
 TRX.Path ../Transceiver/transceiver
+$static TRX.Path
 
 # TRX logging.
 # Logging level.
+# IF TRX.Path IS DEFINED, THIS MUST ALSO BE DEFINED.
 TRX.LogLevel NOTICE
+$static TRX.LogLevel
 # Logging file.  If not defined, logs to stdout.
 TRX.LogFileName test.TRX.out
+$static TRX.LogFileName
 
+# TRX hang-up time-out, in seconds.
+# Restart the TRX if it there is no activity within this time.
+TRX.HangupTimeout 7200
 
 
 
+
 #
 # SIP, RTP, servers
 #
 
 # Asterisk PBX
-#Asterisk.IP 192.168.0.15
 Asterisk.IP 127.0.0.1
 Asterisk.Port 5060
 
 # Messaging server
-Messenger.IP 127.0.0.1
-Messenger.Port 5063
+Smqueue.IP 127.0.0.1
+Smqueue.Port 5063
 
 # Local SIP/RTP ports
+# OpenBTS binds to these ports.
 SIP.Port 5062
 RTP.Start 16484
 RTP.Range 98
 
 # If Asterisk is 127.0.0.1, this is also 127.0.0.1.
 # Otherwise, this should be the local IP address of the interface used to 
contact asterisk.
+# In other words, this is the IP address at which Asterisk will see OpenBTS.
 SIP.IP 127.0.0.1
-# This is broken; use localhost. SIP.IP 192.168.0.16
 
 
-# Local SMS port for short code delivery.
-SMSLoopback.Port 5064
 
-
 #
 # Special extensions.
 #
@@ -93,7 +116,7 @@
 
 # SIP registration period in seconds.
 # Ideally, this should be slightly longer than GSM.T3212.
-SIP.RegistrationPeriod 3600
+SIP.RegistrationPeriod 3620
 
 #
 # SIP Internal Timers.  All timer values are given in millseconds.
@@ -101,6 +124,7 @@
 #
 
 # SIP Timer A, the INVITE retry period, RFC-3261 Section 17.1.1.2
+# in milliseconds
 SIP.Timer.A 1000
 
 
@@ -119,7 +143,7 @@
 #SMS.HTTP.Gateway api.clickatell.com
 
 # IF SMS.HTTP.Gateway IS DEFINED, SMS.HTTP.AccessString MUST ALSO BE DEFINED.
-SMS.HTTP.AccessString sendmsg?user=xxxx&password=xxxx&api_id=xxxx
+#SMS.HTTP.AccessString sendmsg?user=xxxx&password=xxxx&api_id=xxxx
 
 
 
@@ -147,8 +171,8 @@
 Control.OpenRegistrationWelcomeShortCode 23
 
 # Then message send to failed registrations.
-#Control.FailedRegistrationWelcomeMessage It's been fun.  See you next year.
-#Control.FailedRegistrationWelcomeShortCode 666
+#Control.FailedRegistrationWelcomeMessage You're doing it wrong! Go away!
+Control.FailedRegistrationWelcomeShortCode 666
 
 
 
@@ -160,11 +184,11 @@
 # Network and cell identity.
 
 # Network Color Code, 0-7
+# Also set GSM.NCCsPermitted later in this file.
 GSM.NCC 0
 # Basesation Color Code, 0-7
-GSM.BCC 0
+GSM.BCC 2
 # Mobile Country Code, 3 digits.
-# US is 310
 # MCC MUST BE 3 DIGITS.  Prefix with 0s if needed.
 # Test code is 001.
 GSM.MCC 001
@@ -188,27 +212,56 @@
 
 # Valid band values are 850, 900, 1800, 1900.
 GSM.Band 900
-#GSM.Band 850
+$static GSM.Band
 
 # Valid ARFCN range depends on the band.
-GSM.ARFCN 29
+GSM.ARFCN 39
 # ARCN 975 is inside the US ISM-900 band and also in the GSM900 band.
 #GSM.ARFCN 975
 # ARFCN 207 was what we ran at BM2008, I think, in the GSM850 band.
 #GSM.ARFCN 207
 
-# Neightbor list
-GSM.Neighbors 29
+# Neighbor list
+# Should probably include our own ARFCN
+GSM.Neighbors 39
 
-# Downlink tx power level, dB wrt full power
-GSM.PowerAttenDB 0
 
+# Maximum range of delay spread, in kilometers
+# should not be more than 5
+GSM.MaxExpectedDelaySpread 1
 
+
+# Downlink adaptive power management.
+# Manages power to prevent congestion.
+
+# Downlink tx power level bounds, dB wrt full power
+# Maximum attenuation (sets MINIMUM power level).
+GSM.PowerManager.MaxAttenDB 40
+# Minimum attenuation (sets MAXIMUM power level).
+GSM.PowerManager.MinAttenDB 10
+# Target T3122 for Power Manager.
+# Under heavy load, the power manager will adjust downlink power
+# so that T3122 meets this taret.
+# THE TARGET T3122 MUST BE BETWEEN THE MIN AND MAX VALUES.
+# THOSE ARE SET SOMEWHERE ELSE IN THIS FILE, GSM.T3122Max, GSM.T3122Min.
+GSM.PowerManager.TargetT3122 5000
+# T3122 sampling period, in milliseconds.
+# PowerMananger.SamplePeriod should be <= PowerMananger.Period.
+GSM.PowerManager.SamplePeriod 2000
+# Sample history for averaging T3122, MUST BE <100;
+GSM.PowerManager.NumSamples 10
+# Power manager adaptation step period, in milliseconds
+# Should be >= PowerMananger.SamplePeriod
+GSM.PowerManager.Period 6000
+
+
 # Channel configuration
 # Number of C-VII slots (8xSDCCH)
 GSM.NumC7s 1
+$static GSM.NumC7s
 # Number of C-I slots (1xTCH/F)
 GSM.NumC1s 5
+$static GSM.NumC1s
 
 
 
@@ -239,7 +292,7 @@
 # Maximum RACH retransmission attempts
 # This is the RAW parameter sent on the BCCH.
 # See GSM 04.08 10.5.2.29 for encoding.
-GSM.RACH.MaxRetrans 3
+GSM.RACH.MaxRetrans 1
 
 # Parameter to spread RACH busts over time.
 # This is the RAW parameter sent on the BCCH.
@@ -251,7 +304,6 @@
 # See GSM 04.08 10.5.2.29 for encoding.
 # Set to 0 to allow full access.
 GSM.RACH.AC 0
-
 GSM.RACH.CellBarAccess 0
 
 # NCCs Permitted.
@@ -261,16 +313,20 @@
 GSM.NCCsPermitted 1
 
 # Cell Selection Parameters (CS)
-
 GSM.CS.MS_TXPWR_MAX_CCH 0
 GSM.CS.RXLEV_ACCESS_MIN 0
 
 # Cell Reselection Hysteresis
 # See GSM 04.08 10.5.2.4, Table 10.5.23 for encoding.
 # Encoding is 2N dB, value values of N are 0..7 for 0..14 dB.
-GSM.CS.CELL_RESELECT_HYSTERESIS 7
+GSM.CS.CELL_RESELECT_HYSTERESIS 3
 
+# NECI, New Establishment Causes
+# This should be set to "1" to support very early assignment.
+# See GSM 04.08 10.5.2.4, Table 10.5.23 and 04.08 9.1.8, Table 9.9.
+GSM.CS.NECI 1
 
+
 # Reject cause for location updating failures
 # Reject causes come from GSM 04.08 10.5.3.6
 # Reject cause 0x04, IMSI not in VLR
@@ -279,6 +335,7 @@
 # Maximum TA for accepted bursts.
 # Can be used to control the range of the BTS.
 # The unit is GSM symbols of round trips delay, about 550 meters per symbol.
+# FIXME -- This needs to be unified with GSM.MaxRange
 GSM.MaxRACHDelay 20
 
 
@@ -295,14 +352,53 @@
 # Any value below 6 minutes disables periodic registration, which is probably 
a bad idea.
 # Valid range is 6..1530.
 # Ideally, this should be slightly less than the SIP.RegistrationPeriod.
-GSM.T3212 6
+GSM.T3212 54
 
 # T3122, RACH holdoff timer.
 # This value can vary internally between the min and max ends of the range.
 # When congestion occurs, T3122 grows exponentially.
 GSM.T3122Min 2000
-# T3211Max MUST BE NO MORE THAN 255 ms.
+# T3211Max MUST BE NO MORE THAN 255 s.
 GSM.T3122Max 255000
 
+# T3113, the paging timer
+# This is the time allowed for a handset to respond to a paging request.
+GSM.T3113 10000
 
 
+# RRLP
+
+# RRLP query conditions
+# These just have to be defined.  The actual values don't matter.
+GSM.RRLP.LUR
+GSM.RRLP.MOC
+GSM.RRLP.MTC
+GSM.RRLP.MOSMS
+GSM.RRLP.MTSMS
+
+# Accuracy requested from MS - 60 is about 400m (scale is approx. logarithmic)
+GSM.RRLP.Accuracy 60
+# Number of requests done per RRLPQueryController::doTransaction
+GSM.RRLP.Retries 1
+# RRLP query timeout, ms
+GSM.RRLP.Timeout 4000
+
+# The maximum AGCH queue length.
+GSM.AGCHMaxQueue 5
+
+# The uplink RSSI target for closed loop power control.
+GSM.RSSITarget -15
+
+# Number of channels reserved for paging responses.
+GSM.PagingReservations 8
+
+# turn on for continuous logging
+Main.Select 1
+
+# Number of seconds to do logging on (a minimum)
+# If Main.Select is off, it's ok, logging will
+# just happen on enter if more then this value
+# milliseconds have passed.
+# Make this a multiple of 1000 (current limitation, easily fixed in 
apps/OpenBTS.cpp)
+Main.SelectTimeout 2000
+

Modified: openbts/trunk/apps/OpenBTS.cpp
===================================================================
--- openbts/trunk/apps/OpenBTS.cpp      2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/apps/OpenBTS.cpp      2009-12-31 04:21:20 UTC (rev 11667)
@@ -22,8 +22,9 @@
 
 */
 
+#include <iostream>
+#include <fstream>
 
-
 #include <TRXManager.h>
 #include <GSML1FEC.h>
 #include <GSMConfig.h>
@@ -36,7 +37,10 @@
 
 #include <Logger.h>
 #include <CLI.h>
+#include <PowerManager.h>
+#include <RRLPQueryController.h>
 
+#include <assert.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
@@ -54,7 +58,6 @@
 // The global SIPInterface object.
 SIP::SIPInterface gSIPInterface;
 
-
 // Configure the BTS object based on the config file.
 // So don't create this until AFTER loading the config file.
 GSMConfig gBTS;
@@ -64,36 +67,124 @@
 
 
 
-int main(int argc, char *argv[])
+
+
+bool select_on_stdin(unsigned timeout_secs)
 {
-       srandom(time(NULL));
+       struct timeval       timeout;
+       fd_set        working_set;
+       int rc;
+       int max_sd = 0;
 
-       COUT("\n\n" << gOpenBTSWelcome << "\n");
-       COUT("\nStarting the system...");
+       FD_ZERO(&working_set);
+       max_sd = 0; // stdin
+       FD_SET(0, &working_set);
+       // wait for 10 seconds
+       timeout.tv_sec  = timeout_secs;
+       timeout.tv_usec = 0;
+       rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);
+       if (rc == 0) // timeout
+             return false;
+       return true;
+}
 
-       gSetLogLevel(gConfig.getStr("LogLevel"));
-       if (gConfig.defines("LogFileName")) {
-               gSetLogFile(gConfig.getStr("LogFileName"));
+pid_t gTransceiverPid = 0;
+
+void restartTransceiver()
+{
+       // This is harmless - if someone is running OpenBTS they WANT no 
transceiver
+       // instance at the start anyway.
+       if (gTransceiverPid > 0) {
+               LOG(INFO) << "RESTARTING TRANSCEIVER";
+               kill(gTransceiverPid,SIGKILL); // TODO - call on ctrl-c (put in 
signal?)
        }
 
        // Start the transceiver binary, if the path is defined.
        // If the path is not defined, the transceiver must be started by some 
other process.
        const char *TRXPath = NULL;
        if (gConfig.defines("TRX.Path")) TRXPath=gConfig.getStr("TRX.Path");
-       pid_t transceiverPid = 0;
        if (TRXPath) {
                const char *TRXLogLevel = gConfig.getStr("TRX.LogLevel");
                const char *TRXLogFileName = NULL;
                if (gConfig.defines("TRX.LogFileName")) 
TRXLogFileName=gConfig.getStr("TRX.LogFileName");
-               transceiverPid = vfork();
-               assert(transceiverPid>=0);
-               if (transceiverPid==0) {
+               gTransceiverPid = vfork();
+               assert(gTransceiverPid>=0);
+               if (gTransceiverPid==0) {
+                       // Pid==0 means this is the process that starts the 
transceiver.
                        
execl(TRXPath,"transceiver",TRXLogLevel,TRXLogFileName,NULL);
                        LOG(ERROR) << "cannot start transceiver";
                        _exit(0);
                }
        }
+}
 
+
+
+class TransceiverHangupDetector {
+public:
+       TransceiverHangupDetector()
+               : mLastUp()
+       {
+       }
+       Timeval mLastUp;
+       bool restartIfHung();
+};
+
+/**
+  check if SDCCHTotal is 0, if so for more the TRX.HangupTimeout then restart
+  transceiver.
+
+  Return: true if restarted, false otherwise.
+ */
+bool TransceiverHangupDetector::restartIfHung()
+{
+       unsigned totalactive = gBTS.SDCCHActive() + gBTS.TCHActive();
+       if (totalactive > 0) {
+               mLastUp = Timeval(); // reset to now
+               return false;
+       }
+       if (mLastUp.elapsed() >= 1000*gConfig.getNum("TRX.HangupTimeout")) {
+               LOG(ALARM) << "transceiver hung, restarting";
+               restartTransceiver();
+               mLastUp = Timeval();
+               return true;
+       }
+       return false;
+}
+
+TransceiverHangupDetector gHangup;
+
+void logload(ostream& os)
+{
+       os << "SDCCH load," << gBTS.SDCCHActive() << ',' << gBTS.SDCCHTotal()
+       << ",TCH/F load," << gBTS.TCHActive() << ',' << gBTS.TCHTotal()
+       << ",AGCH/PCH load," << gBTS.AGCHLoad() << ',' << gBTS.PCHLoad()
+       << ",paging size," << gBTS.pager().pagingEntryListSize()
+       << ",T3122," << gBTS.T3122()
+       << ",transactions," << gTransactionTable.size()
+       << ",tmsis," << gTMSITable.size()
+       << ",RRLP," << RRLP::RRLPQueryManager::instance()->numQueries()
+       << ",GPS," << RRLP::RRLPQueryManager::instance()->numPositions()
+       << ",Hangup," << gHangup.mLastUp.elapsed()
+       << endl;
+}
+
+int main(int argc, char *argv[])
+{
+       srandom(time(NULL));
+
+       COUT("\n\n" << gOpenBTSWelcome << "\n");
+       COUT("\nStarting the system...");
+
+       gSetLogLevel(gConfig.getStr("LogLevel"));
+       if (gConfig.defines("LogFileName")) {
+               gSetLogFile(gConfig.getStr("LogFileName"));
+       }
+       gSetAlarmTargetPort(gConfig.getNum("Alarm.TargetPort"));
+       gSetAlarmTargetIP(gConfig.getStr("Alarm.TargetIP"));
+
+       restartTransceiver();
+
        // Start the SIP interface.
        gSIPInterface.start();
 
@@ -107,19 +198,20 @@
        // Tuning.
        // Make sure its off for tuning.
        radio->powerOff();
-       // Set TSC same as BSC everywhere.
+       // Set TSC same as BCC everywhere.
        radio->setTSC(gBTS.BCC());
        // Tune.
-       radio->tune(gConfig.getNum("GSM.ARFCN"));
-       // C-V on C0T0
-       radio->setSlot(0,5);
+       radio->tune(gConfig.getNum("GSM.ARFCN"));
 
        // Turn on and power up.
        radio->powerOn();
-               radio->setPower(gConfig.getNum("GSM.PowerAttenDB"));
+       radio->setPower(gConfig.getNum("GSM.PowerManager.MinAttenDB"));
 
-       // set up a combination V beacon set
+        // Set maximum network delay
+        radio->setMaxDelay(gConfig.getNum("GSM.MaxExpectedDelaySpread"));
 
+       // C-V on C0T0
+       radio->setSlot(0,5);
        // SCH
        SCHL1FEC SCH;
        SCH.downstream(radio);
@@ -152,26 +244,25 @@
        gBTS.addAGCH(&CCCH2);
 
        // C-V C0T0 SDCCHs
-       SDCCHLogicalChannel SDCCH[4] = { 
+       SDCCHLogicalChannel C0T0SDCCH[4] = {
                SDCCHLogicalChannel(0,gSDCCH_4_0),
                SDCCHLogicalChannel(0,gSDCCH_4_1),
                SDCCHLogicalChannel(0,gSDCCH_4_2),
-               SDCCHLogicalChannel(0,gSDCCH_4_3)
+               SDCCHLogicalChannel(0,gSDCCH_4_3),
        };
-       Thread SDCCHControlThread[4];
+       Thread C0T0SDCCHControlThread[4];
        for (int i=0; i<4; i++) {
-               SDCCH[i].downstream(radio);
-               
SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&SDCCH[i]);
-               SDCCH[i].open();
-               gBTS.addSDCCH(&SDCCH[i]);
+               C0T0SDCCH[i].downstream(radio);
+               
C0T0SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&C0T0SDCCH[i]);
+               C0T0SDCCH[i].open();
+               gBTS.addSDCCH(&C0T0SDCCH[i]);
        }
 
-
        // Count configured slots.
        unsigned sCount = 1;
 
        // Create C-VII slots on C0Tn
-       for (unsigned i=0; i<gConfig.getNum("GSM.NumC7s"); i++) {
+       for (int i=0; i<gConfig.getNum("GSM.NumC7s"); i++) {
                radio->setSlot(sCount,7);
                for (unsigned sub=0; sub<8; sub++) {
                        SDCCHLogicalChannel* chan = new 
SDCCHLogicalChannel(sCount,gSDCCH8[sub]);
@@ -186,7 +277,7 @@
 
 
        // Create C-I slots on C0Tn
-       for (unsigned i=0; i<gConfig.getNum("GSM.NumC1s"); i++) {
+       for (int i=0; i<gConfig.getNum("GSM.NumC1s"); i++) {
                radio->setSlot(sCount,1);
                TCHFACCHLogicalChannel* chan = new 
TCHFACCHLogicalChannel(sCount,gTCHF_T[sCount]);
                chan->downstream(radio);
@@ -200,7 +291,6 @@
        assert(sCount<=8);
 
 
-
        /*
                Note: The number of different paging subchannels on       
                the CCCH is:                                        
@@ -213,22 +303,53 @@
 
        // Set up the pager.
        // Set up paging channels.
+       // HACK -- For now, use a single paging channel, since paging groups 
are broken.
        gBTS.addPCH(&CCCH2);
-       // Start the paging generator
-       // Don't start the pager until some PCHs exist!!
-       gBTS.pager().start();
 
+       // OK, now it is safe to start the BTS.
+       gBTS.start();
+
        LOG(INFO) << "system ready";
        COUT("\n\nWelcome to OpenBTS.  Type \"help\" to see available 
commands.");
         // FIXME: We want to catch control-d (emacs keybinding for exit())
 
+       ofstream logout;
+       logout.open("log.out", ios::app | ios::out);
+       Timeval last;
+       cout << "\nOpenBTS> ";
+       cout.flush();
+       long timeout_millisecs = 5000;
+       if (gConfig.defines("Main.SelectTimeout")) {
+               timeout_millisecs = gConfig.getNum("Main.SelectTimeout");
+       }
+       long timeout_secs = timeout_millisecs / 1000;
+       bool use_select = gConfig.defines("Main.Select") && 
gConfig.getNum("Main.Select") == 1;
+       
+
+       // 2 Purpose stuff:
+       //  command line interface (gParser, CLI)
+       //  load recording (this file)
        while (1) {
-               char inbuf[1024];
-               cout << "\nOpenBTS> ";
-               cin.getline(inbuf,1024,'\n');
-               if (strcmp(inbuf,"exit")==0) break;
-               gParser.process(inbuf,cout,cin);
+               if (!use_select || select_on_stdin(timeout_secs)) {
+                       char inbuf[1024];
+                       cin.getline(inbuf,1024,'\n');
+                       if (strcmp(inbuf,"exit")==0) break;
+                       gParser.process(inbuf,cout,cin);
+                       cout << "\nOpenBTS> ";
+                       cout.flush();
+               }
+               if (last.elapsed() >= timeout_millisecs) {
+                       last = Timeval();
+                       // log load
+                       //std::cout << "logging at " << last << "\n";
+                       logout << "Time," << last << ",Elapsed," << 
gBTS.uptime() << ",";
+                       logload(logout);
+                       //gParser.process("power", logout, cin);
+                       //gParser.process("load", logout, cin);
+               }
+               gHangup.restartIfHung();
        }
 
-       if (transceiverPid) kill(transceiverPid,SIGKILL);
+       if (gTransceiverPid) kill(gTransceiverPid,SIGKILL);
 }
+

Modified: openbts/trunk/configure.ac
===================================================================
--- openbts/trunk/configure.ac  2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/configure.ac  2009-12-31 04:21:20 UTC (rev 11667)
@@ -18,7 +18,7 @@
 dnl along with this program.  If not, see <http://www.gnu.org/licenses/>.
 dnl
 
-AC_INIT(openbts,2.5Lacassine)
+AC_INIT(openbts,2.6TRUNK)
 AC_PREREQ(2.57)
 AC_CONFIG_SRCDIR([config/Makefile.am])
 AC_CONFIG_AUX_DIR([.]) 
@@ -66,6 +66,13 @@
 # Defines ORTP_CFLAGS, ORTP_INCLUDEDIR, and ORTP_LIBS
 PKG_CHECK_MODULES(ORTP, ortp)
 
+# Removed readline due to portability problems.
+# Defines TARGET_READLINE_LIBS
+# XXX rather simply forces you to have readline()
+#AC_CHECK_LIB(readline, readline, [READLINE_LIB="-lreadline"], [echo "error: 
libreadline.so required!"; exit -1])
+#AC_SUBST([READLINE_LIB])
+
+
 dnl Output files
 AC_CONFIG_FILES([\
     Makefile \
@@ -86,5 +93,6 @@
     HLR/Makefile \
     smqueue/Makefile \
 ])
+#    SQL/Makefile \
 
 AC_OUTPUT

Modified: openbts/trunk/smqueue/Makefile.in
===================================================================
--- openbts/trunk/smqueue/Makefile.in   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/smqueue/Makefile.in   2009-12-31 04:21:20 UTC (rev 11667)
@@ -215,6 +215,7 @@
 TRX_INCLUDEDIR = $(top_srcdir)/TRXManager
 GLOBALS_INCLUDEDIR = $(top_srcdir)/Globals
 CLI_INCLUDEDIR = $(top_srcdir)/CLI
+#SQL_INCLUDEDIR = $(top_srcdir)/SQL
 HLR_INCLUDEDIR = $(top_srcdir)/HLR
 STD_DEFINES_AND_INCLUDES = \
        -I$(COMMON_INCLUDEDIR) \
@@ -227,6 +228,7 @@
        -I$(CLI_INCLUDEDIR) \
        -I$(HLR_INCLUDEDIR)
 
+#      -I$(SQL_INCLUDEDIR)
 COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
 GSM_LA = $(top_builddir)/GSM/libGSM.la
 SIP_LA = $(top_builddir)/SIP/libSIP.la
@@ -236,6 +238,7 @@
 GLOBALS_LA = $(top_builddir)/Globals/libglobals.la
 CLI_LA = $(top_builddir)/CLI/libcli.la
 HLR_LA = $(top_builddir)/HLR/libHLR.la
+#SQL_LA = $(top_builddir)/SQL/libSQL.la
 MOSTLYCLEANFILES = *~
 EXTRA_DIST = \
        Makefile.standalone \

Modified: openbts/trunk/smqueue/smqueue.config.example
===================================================================
--- openbts/trunk/smqueue/smqueue.config.example        2009-12-31 03:03:10 UTC 
(rev 11666)
+++ openbts/trunk/smqueue/smqueue.config.example        2009-12-31 04:21:20 UTC 
(rev 11667)
@@ -35,3 +35,8 @@
 #SIP.global_relay 81.201.82.50:5060
 SIP.global_relay 
 
+
+# messages
+BounceMessage.IMSILookupFailed "Cannot determine return address; bouncing 
message."
+#BounceMessage.IMSILookupFailed "You're on the BM free cellular net; text your 
phone number to 101 first"
+BounceMessage.NotRegistered "Phone not registered here."

Modified: openbts/trunk/smqueue/smqueue.cpp
===================================================================
--- openbts/trunk/smqueue/smqueue.cpp   2009-12-31 03:03:10 UTC (rev 11666)
+++ openbts/trunk/smqueue/smqueue.cpp   2009-12-31 04:21:20 UTC (rev 11667)
@@ -38,6 +38,11 @@
 using namespace std;
 using namespace SMqueue;
 
+/* The global config table. */
+// DAB
+ConfigurationTable gConfig("smqueue.config");
+
+
 /* We try to centralize most of the timeout values into this table.
    Occasionally the code might do something different where it knows
    better, but most state transitions just use this table to set the
@@ -1458,8 +1463,8 @@
                     << "> to phonenum failed." << endl;
                // cerr << qmsg->text << endl;
                return bounce_message (qmsg,
-    "You're on the BM free cellular net; text your phone number to 101 first");
-//  "First, register your phone by texting your phone number to 101");
+                       gConfig.getStr("BounceMessage.IMSILookupFailed")
+               );
                // return NO_STATE;     // Put it into limbo for debug.
        }
 
@@ -1538,7 +1543,7 @@
                        || !my_hlr.useGateway(username)) {
                        // There's no global relay -- or the HLR says not to
                        // use the global relay for it -- so send a bounce.
-                       return bounce_message (qmsg, "Phone not registered 
here");
+                       return bounce_message (qmsg, 
gConfig.getStr("BounceMessage.NotRegistered"));
                    } else {
                        // Send the message to our global relay.
                        // We leave the username as a phone number, and
@@ -2170,11 +2175,6 @@
 
 
 
-/* The global config table. */
-// DAB
-ConfigurationTable gConfig("smqueue.config");
-
-
 /* Really simple first try */
 
 int





reply via email to

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