mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
synced 2025-11-02 13:13:17 +00:00
Compare commits
75 Commits
ttsou/sigg
...
0.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71637150a1 | ||
|
|
2393964b77 | ||
|
|
9ee4df8760 | ||
|
|
c92dad32dd | ||
|
|
61837c0420 | ||
|
|
f83e11fefd | ||
|
|
01aff88ce9 | ||
|
|
11d50d950c | ||
|
|
8bd111c942 | ||
|
|
3808e479aa | ||
|
|
bd45a979f8 | ||
|
|
b7095c7bc5 | ||
|
|
77ce99ac67 | ||
|
|
f58cd8ac83 | ||
|
|
99eb07e232 | ||
|
|
89be118a3b | ||
|
|
6fafd33b13 | ||
|
|
6e55d51747 | ||
|
|
6cae1d7b4b | ||
|
|
28ce315a32 | ||
|
|
10d76b6863 | ||
|
|
708b8b44ae | ||
|
|
cb0fc9b21a | ||
|
|
8639fee504 | ||
|
|
ca46896cfe | ||
|
|
4a25d6b8f6 | ||
|
|
79baee3a8f | ||
|
|
c2ba427b52 | ||
|
|
611212676b | ||
|
|
4ebb289c90 | ||
|
|
2f376a3edf | ||
|
|
2edbe4d366 | ||
|
|
a3694bd303 | ||
|
|
2652f2bc39 | ||
|
|
93d9b114b7 | ||
|
|
2ac788b2c3 | ||
|
|
d36ef2f57b | ||
|
|
caf2abc58f | ||
|
|
de1685f6d7 | ||
|
|
f3837d26f9 | ||
|
|
ddf4743306 | ||
|
|
82f83ced73 | ||
|
|
cff4ed9b4c | ||
|
|
6ec26bb788 | ||
|
|
a1ff991402 | ||
|
|
d09843c692 | ||
|
|
e5448ff972 | ||
|
|
e48c1367dc | ||
|
|
aa60dda99a | ||
|
|
1468a5c3dc | ||
|
|
b0e1bd8c22 | ||
|
|
78e1cd20e2 | ||
|
|
db9c1b54cb | ||
|
|
099a44abfb | ||
|
|
8c80095017 | ||
|
|
d49a6aa136 | ||
|
|
81486e053c | ||
|
|
28d8081e25 | ||
|
|
87ed77b937 | ||
|
|
f9d996813d | ||
|
|
aa5acc953c | ||
|
|
934da48618 | ||
|
|
7c405a0c1f | ||
|
|
4cafb0fa15 | ||
|
|
f611569018 | ||
|
|
354741326c | ||
|
|
d2e5c5694e | ||
|
|
a3dce85ffc | ||
|
|
bb0c68ae61 | ||
|
|
87d158cc2d | ||
|
|
7278a87767 | ||
|
|
63eef9faf2 | ||
|
|
d67bd603e9 | ||
|
|
988a464d5d | ||
|
|
1b6ab7d7ee |
27
.gitignore
vendored
27
.gitignore
vendored
@@ -5,17 +5,17 @@
|
|||||||
Transceiver52M/osmo-trx
|
Transceiver52M/osmo-trx
|
||||||
|
|
||||||
# tests
|
# tests
|
||||||
CommonLibs/BitVectorTest
|
tests/CommonLibs/BitVectorTest
|
||||||
CommonLibs/ConfigurationTest
|
tests/CommonLibs/F16Test
|
||||||
CommonLibs/F16Test
|
tests/CommonLibs/InterthreadTest
|
||||||
CommonLibs/InterthreadTest
|
tests/CommonLibs/LogTest
|
||||||
CommonLibs/LogTest
|
tests/CommonLibs/RegexpTest
|
||||||
CommonLibs/RegexpTest
|
tests/CommonLibs/SocketsTest
|
||||||
CommonLibs/SocketsTest
|
tests/CommonLibs/TimevalTest
|
||||||
CommonLibs/TimevalTest
|
tests/CommonLibs/URLEncodeTest
|
||||||
CommonLibs/URLEncodeTest
|
tests/CommonLibs/VectorTest
|
||||||
CommonLibs/VectorTest
|
tests/CommonLibs/PRBSTest
|
||||||
CommonLibs/PRBSTest
|
tests/Transceiver52M/convolve_test
|
||||||
|
|
||||||
# automake/autoconf
|
# automake/autoconf
|
||||||
*.in
|
*.in
|
||||||
@@ -41,6 +41,11 @@ ltmain.sh
|
|||||||
missing
|
missing
|
||||||
stamp-h1
|
stamp-h1
|
||||||
INSTALL
|
INSTALL
|
||||||
|
tests/package.m4
|
||||||
|
tests/testsuite
|
||||||
|
tests/atconfig
|
||||||
|
tests/testsuite.dir
|
||||||
|
tests/testsuite.log
|
||||||
|
|
||||||
# vim
|
# vim
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|||||||
83
AUTHORS
83
AUTHORS
@@ -1,18 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2008, 2009 Free Software Foundation, Inc.
|
# Copyright 2008, 2009 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is part of GNU Radio
|
# This file is part of GNU Radio
|
||||||
#
|
#
|
||||||
# GNU Radio is free software; you can redistribute it and/or modify
|
# GNU Radio is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation; either version 3, or (at your option)
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
# any later version.
|
# any later version.
|
||||||
#
|
#
|
||||||
# GNU Radio is distributed in the hope that it will be useful,
|
# GNU Radio is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
@@ -23,34 +23,17 @@ David A. Burgess, dburgess@kestrelsp.com:
|
|||||||
CLI/CLI.h
|
CLI/CLI.h
|
||||||
CommonLibs/Assert.h
|
CommonLibs/Assert.h
|
||||||
CommonLibs/BitVector.cpp
|
CommonLibs/BitVector.cpp
|
||||||
CommonLibs/BitVectorTest.cpp
|
|
||||||
CommonLibs/Configuration.cpp
|
|
||||||
CommonLibs/Configuration.h
|
|
||||||
CommonLibs/ConfigurationTest.cpp
|
|
||||||
CommonLibs/Interthread.h
|
CommonLibs/Interthread.h
|
||||||
CommonLibs/InterthreadTest.cpp
|
|
||||||
CommonLibs/LinkedLists.cpp
|
CommonLibs/LinkedLists.cpp
|
||||||
CommonLibs/LinkedLists.h
|
CommonLibs/LinkedLists.h
|
||||||
CommonLibs/Regexp.h
|
CommonLibs/Regexp.h
|
||||||
CommonLibs/RegexpTest.cpp
|
|
||||||
CommonLibs/Sockets.cpp
|
CommonLibs/Sockets.cpp
|
||||||
CommonLibs/Sockets.h
|
CommonLibs/Sockets.h
|
||||||
CommonLibs/SocketsTest.cpp
|
|
||||||
CommonLibs/Threads.cpp
|
CommonLibs/Threads.cpp
|
||||||
CommonLibs/Threads.h
|
CommonLibs/Threads.h
|
||||||
CommonLibs/Timeval.cpp
|
CommonLibs/Timeval.cpp
|
||||||
CommonLibs/Timeval.h
|
CommonLibs/Timeval.h
|
||||||
CommonLibs/TimevalTest.cpp
|
|
||||||
CommonLibs/Vector.h
|
CommonLibs/Vector.h
|
||||||
CommonLibs/VectorTest.cpp
|
|
||||||
Control/CallControl.cpp
|
|
||||||
Control/ControlCommon.cpp
|
|
||||||
Control/ControlCommon.h
|
|
||||||
Control/FACCHDispatch.cpp
|
|
||||||
Control/MobilityManagement.cpp
|
|
||||||
Control/PagerTest.cpp
|
|
||||||
Control/RadioResource.cpp
|
|
||||||
Control/SDCCHDispatch.cpp
|
|
||||||
GSM/GSM610Tables.cpp
|
GSM/GSM610Tables.cpp
|
||||||
GSM/GSM610Tables.h
|
GSM/GSM610Tables.h
|
||||||
GSM/GSMCommon.cpp
|
GSM/GSMCommon.cpp
|
||||||
@@ -82,29 +65,15 @@ David A. Burgess, dburgess@kestrelsp.com:
|
|||||||
GSM/GSMTransfer.cpp
|
GSM/GSMTransfer.cpp
|
||||||
GSM/GSMTransfer.h
|
GSM/GSMTransfer.h
|
||||||
LICENSEBLOCK
|
LICENSEBLOCK
|
||||||
SIP/SIPEngine.h
|
|
||||||
SIP/SIPInterface.h
|
|
||||||
SMS/SMSMessages.cpp
|
|
||||||
SMS/SMSMessages.h
|
|
||||||
SMS/SMSTransfer.cpp
|
|
||||||
SMS/SMSTransfer.h
|
|
||||||
TRXManager/TRXManager.cpp
|
TRXManager/TRXManager.cpp
|
||||||
Transceiver/Complex.h
|
Transceiver/Complex.h
|
||||||
apps/OpenBTS900.cpp
|
tests/CommonLibs/BitVectorTest.cpp
|
||||||
apps/OpenBTS850.cpp
|
tests/CommonLibs/InterthreadTest.cpp
|
||||||
apps/OpenBTS25c3.cpp
|
tests/CommonLibs/SocketsTest.cpp
|
||||||
tests/AGCHTest.cpp
|
tests/CommonLibs/TimevalTest.cpp
|
||||||
tests/BeaconTest.cpp
|
tests/CommonLibs/VectorTest.cpp
|
||||||
tests/CallTest.cpp
|
|
||||||
tests/CallTest2.cpp
|
|
||||||
tests/LAPDmTest.cpp
|
|
||||||
tests/LoopbackTest.cpp
|
|
||||||
tests/RegistrationTest.cpp
|
|
||||||
tests/TRXSimulator.cpp
|
|
||||||
|
|
||||||
Harvind S. Samra, hssamra@kestrelsp.com:
|
Harvind S. Samra, hssamra@kestrelsp.com:
|
||||||
Control/PagerTest.cpp
|
|
||||||
Control/RadioResource.cpp
|
|
||||||
GSM/GSMConfig.h
|
GSM/GSMConfig.h
|
||||||
GSM/GSMTransfer.h
|
GSM/GSMTransfer.h
|
||||||
LICENSEBLOCK
|
LICENSEBLOCK
|
||||||
@@ -126,13 +95,6 @@ Harvind S. Samra, hssamra@kestrelsp.com:
|
|||||||
Transceiver/testRadio.cpp
|
Transceiver/testRadio.cpp
|
||||||
|
|
||||||
Raffi Sevlian, raffisev@gmail.com:
|
Raffi Sevlian, raffisev@gmail.com:
|
||||||
Control/CallControl.cpp
|
|
||||||
Control/ControlCommon.cpp
|
|
||||||
Control/ControlCommon.h
|
|
||||||
Control/FACCHDispatch.cpp
|
|
||||||
Control/MobilityManagement.cpp
|
|
||||||
Control/PagerTest.cpp
|
|
||||||
Control/RadioResource.cpp
|
|
||||||
GSM/GSMCommon.h
|
GSM/GSMCommon.h
|
||||||
GSM/GSMConfig.h
|
GSM/GSMConfig.h
|
||||||
GSM/GSML1FEC.h
|
GSM/GSML1FEC.h
|
||||||
@@ -157,36 +119,9 @@ Raffi Sevlian, raffisev@gmail.com:
|
|||||||
GSM/GSMSAPMux.h
|
GSM/GSMSAPMux.h
|
||||||
GSM/GSMTransfer.h
|
GSM/GSMTransfer.h
|
||||||
LICENSEBLOCK
|
LICENSEBLOCK
|
||||||
SIP/SIPEngine.cpp
|
|
||||||
SIP/SIPInterface.cpp
|
|
||||||
SIP/SIPInterface.h
|
|
||||||
SIP/SIPMessage.cpp
|
|
||||||
SIP/SIPMessage.h
|
|
||||||
SIP/SIPUtility.cpp
|
|
||||||
SIP/SIPUtility.h
|
|
||||||
SMS/CMMessage.cpp
|
|
||||||
SMS/CMMessage.h
|
|
||||||
SMS/CMProcessor.cpp
|
|
||||||
SMS/CMProcessor.h
|
|
||||||
SMS/CMTest.cpp
|
|
||||||
SMS/RLMessage.cpp
|
|
||||||
SMS/RLMessage.h
|
|
||||||
SMS/RLProcessor.cpp
|
|
||||||
SMS/RLProcessor.h
|
|
||||||
SMS/SMSMessages.cpp
|
|
||||||
SMS/SMSMessages.h
|
|
||||||
SMS/SMSProcessors.cpp
|
|
||||||
SMS/SMSProcessors.h
|
|
||||||
SMS/SMSTransfer.cpp
|
|
||||||
SMS/SMSTransfer.h
|
|
||||||
SMS/TLMessage.cpp
|
|
||||||
SMS/TLMessage.h
|
|
||||||
SMS/TLProcessor.cpp
|
|
||||||
SMS/TLProcessor.h
|
|
||||||
TRXManager/TRXManager.h
|
TRXManager/TRXManager.h
|
||||||
|
|
||||||
Alon Levy, alonlevy1@gmail.com
|
Alon Levy, alonlevy1@gmail.com
|
||||||
RRLPMessages.cpp
|
RRLPMessages.cpp
|
||||||
RRLPMessages.h
|
RRLPMessages.h
|
||||||
RRLPTest.cpp
|
RRLPTest.cpp
|
||||||
|
|
||||||
|
|||||||
28
COPYING
28
COPYING
@@ -673,16 +673,16 @@ on the AGPLv3 text.
|
|||||||
=========================================================================
|
=========================================================================
|
||||||
|
|
||||||
|
|
||||||
ADDITIONAL TERMS TO THE AGPLv3 LICENSE FOR OPENBTS
|
ADDITIONAL TERMS TO THE AGPLv3 LICENSE FOR OsmoTRX
|
||||||
|
|
||||||
|
|
||||||
Permissive Terms Supplementing the License
|
Permissive Terms Supplementing the License
|
||||||
|
|
||||||
1. Remote Interaction Through IP Networks.
|
1. Remote Interaction Through IP Networks.
|
||||||
|
|
||||||
OpenBTS includes an implementation of the GSM network cellular air interface,
|
OsmoTRX is an implementation of the GSM network cellular air interface,
|
||||||
as well as other interfaces to IP networks. The interaction of cellular
|
as well as other interfaces to IP networks. The interaction of cellular
|
||||||
handsets with the OpenBTS software is considered "remote network interaction"
|
handsets with the OsmoTRX software is considered "remote network interaction"
|
||||||
for the purposes of the Affero General Public License and cellular users are
|
for the purposes of the Affero General Public License and cellular users are
|
||||||
subject to the source code access requirements of Section 13 of AGPLv3 ("Remote
|
subject to the source code access requirements of Section 13 of AGPLv3 ("Remote
|
||||||
Network Interaction; Use with the GNU General Public License").
|
Network Interaction; Use with the GNU General Public License").
|
||||||
@@ -694,17 +694,6 @@ interfaces other than the GSM air interface from the requirements of Section 13
|
|||||||
is an additional permission granted to you.
|
is an additional permission granted to you.
|
||||||
|
|
||||||
|
|
||||||
Non-Permissive Terms Supplementing The License
|
|
||||||
|
|
||||||
1. Trademarks.
|
|
||||||
|
|
||||||
"OpenBTS" is a trademark of Range Networks, Inc., registered with
|
|
||||||
the US Patent and Trademark Office. Your use of OpenBTS software under a GPL
|
|
||||||
license does not include the right to use the OpenBTS trademark in commerce.
|
|
||||||
This additional non-permissive term is consistent with Section 7 of the AGPLv3
|
|
||||||
license.
|
|
||||||
|
|
||||||
|
|
||||||
END OF ADDITIONAL TERMS
|
END OF ADDITIONAL TERMS
|
||||||
|
|
||||||
|
|
||||||
@@ -712,13 +701,8 @@ END OF ADDITIONAL TERMS
|
|||||||
How to comply with Section 13 of the AGPLv3 license.
|
How to comply with Section 13 of the AGPLv3 license.
|
||||||
|
|
||||||
The recommended method for compliance with Section 13 of the AGPLv3 license is
|
The recommended method for compliance with Section 13 of the AGPLv3 license is
|
||||||
to deliver a text message to each handset that attaches to the OpenBTS cellular
|
to deliver a text message to each handset that attaches to the cellular
|
||||||
network. At a minimum, that text message should include the string "OpenBTS
|
network which uses OsmoTRX. At a minimum, that text message should include the string
|
||||||
AGPLv3" and a URL that can be used to access the OpenBTS source code. This
|
"OsmoTRX AGPLv3" and a URL that can be used to access the OsmoBTS source code. This
|
||||||
message need not be delivered to handsets that are denied registration with the
|
message need not be delivered to handsets that are denied registration with the
|
||||||
network, since those handsets have been denied service.
|
network, since those handsets have been denied service.
|
||||||
|
|
||||||
In OpenBTS 2.6, such text messages can be delivered with the "Welcome Message"
|
|
||||||
feature. See the OpenBTS.config.example file for more information on the use of
|
|
||||||
this feature for AGPLv3 compliance.
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,422 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009, 2010 Free Software Foundation, Inc.
|
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
* Copyright 2011, 2012 Range Networks, Inc.
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CONFIGURATION_H
|
|
||||||
#define CONFIGURATION_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "sqlite3util.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <regex.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <Threads.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
/** A class for configuration file errors. */
|
|
||||||
class ConfigurationTableError {};
|
|
||||||
extern char gCmdName[]; // Gotta be global, gotta be char*, gotta love it.
|
|
||||||
|
|
||||||
/** An exception thrown when a given config key isn't found. */
|
|
||||||
class ConfigurationTableKeyNotFound : public ConfigurationTableError {
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string mKey;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConfigurationTableKeyNotFound(const std::string& wKey)
|
|
||||||
:mKey(wKey)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
const std::string& key() const { return mKey; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationRecord {
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string mValue;
|
|
||||||
long mNumber;
|
|
||||||
bool mDefined;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConfigurationRecord(bool wDefined=true):
|
|
||||||
mDefined(wDefined)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
ConfigurationRecord(const std::string& wValue):
|
|
||||||
mValue(wValue),
|
|
||||||
mNumber(strtol(wValue.c_str(),NULL,0)),
|
|
||||||
mDefined(true)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
ConfigurationRecord(const char* wValue):
|
|
||||||
mValue(std::string(wValue)),
|
|
||||||
mNumber(strtol(wValue,NULL,0)),
|
|
||||||
mDefined(true)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& value() const { return mValue; }
|
|
||||||
long number() const { return mNumber; }
|
|
||||||
bool defined() const { return mDefined; }
|
|
||||||
|
|
||||||
float floatNumber() const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** A string class that uses a hash function for comparison. */
|
|
||||||
class HashString : public std::string {
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
uint64_t mHash;
|
|
||||||
|
|
||||||
void computeHash();
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
HashString(const char* src)
|
|
||||||
:std::string(src)
|
|
||||||
{
|
|
||||||
computeHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
HashString(const std::string& src)
|
|
||||||
:std::string(src)
|
|
||||||
{
|
|
||||||
computeHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
HashString()
|
|
||||||
{
|
|
||||||
mHash=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashString& operator=(std::string& src)
|
|
||||||
{
|
|
||||||
std::string::operator=(src);
|
|
||||||
computeHash();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashString& operator=(const char* src)
|
|
||||||
{
|
|
||||||
std::string::operator=(src);
|
|
||||||
computeHash();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const HashString& other)
|
|
||||||
{
|
|
||||||
return mHash==other.mHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const HashString& other)
|
|
||||||
{
|
|
||||||
return mHash<other.mHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator>(const HashString& other)
|
|
||||||
{
|
|
||||||
return mHash<other.mHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t hash() const { return mHash; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<std::string, ConfigurationRecord> ConfigurationRecordMap;
|
|
||||||
typedef std::map<HashString, ConfigurationRecord> ConfigurationMap;
|
|
||||||
class ConfigurationKey;
|
|
||||||
typedef std::map<std::string, ConfigurationKey> ConfigurationKeyMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
A class for maintaining a configuration key-value table,
|
|
||||||
based on sqlite3 and a local map-based cache.
|
|
||||||
Thread-safe, too.
|
|
||||||
*/
|
|
||||||
class ConfigurationTable {
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
sqlite3* mDB; ///< database connection
|
|
||||||
ConfigurationMap mCache; ///< cache of recently access configuration values
|
|
||||||
mutable Mutex mLock; ///< control for multithreaded access to the cache
|
|
||||||
std::vector<std::string> (*mCrossCheck)(const std::string&); ///< cross check callback pointer
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConfigurationKeyMap mSchema;///< definition of configuration default values and validation logic
|
|
||||||
|
|
||||||
ConfigurationTable(const char* filename = ":memory:", const char *wCmdName = 0, ConfigurationKeyMap wSchema = ConfigurationKeyMap());
|
|
||||||
|
|
||||||
/** Generate an up-to-date example sql file for new installs. */
|
|
||||||
std::string getDefaultSQL(const std::string& program, const std::string& version);
|
|
||||||
|
|
||||||
/** Generate an up-to-date TeX snippet. */
|
|
||||||
std::string getTeX(const std::string& program, const std::string& version);
|
|
||||||
|
|
||||||
/** Return true if the key is used in the table. */
|
|
||||||
bool defines(const std::string& key);
|
|
||||||
|
|
||||||
/** Return true if the application's schema knows about this key. */
|
|
||||||
bool keyDefinedInSchema(const std::string& name);
|
|
||||||
|
|
||||||
/** Return true if the provided value validates correctly against the defined schema. */
|
|
||||||
bool isValidValue(const std::string& name, const std::string& val);
|
|
||||||
|
|
||||||
/** Return true if the provided value validates correctly against the defined schema. */
|
|
||||||
bool isValidValue(const std::string& name, const int val) { std::stringstream ss; ss << val; return isValidValue(name, ss.str()); }
|
|
||||||
|
|
||||||
/** Return a map of all similar keys in the defined schema. */
|
|
||||||
ConfigurationKeyMap getSimilarKeys(const std::string& snippet);
|
|
||||||
|
|
||||||
/** Return true if this key is identified as static. */
|
|
||||||
bool isStatic(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a string parameter from the table.
|
|
||||||
Throw ConfigurationTableKeyNotFound if not found.
|
|
||||||
*/
|
|
||||||
std::string getStr(const std::string& key);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a boolean from the table.
|
|
||||||
Return false if NULL or 0, true otherwise.
|
|
||||||
*/
|
|
||||||
bool getBool(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a numeric parameter from the table.
|
|
||||||
Throw ConfigurationTableKeyNotFound if not found.
|
|
||||||
*/
|
|
||||||
long getNum(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a vector of strings from the table.
|
|
||||||
*/
|
|
||||||
std::vector<std::string> getVectorOfStrings(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a float from the table.
|
|
||||||
Throw ConfigurationTableKeyNotFound if not found.
|
|
||||||
*/
|
|
||||||
float getFloat(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a numeric vector from the table.
|
|
||||||
*/
|
|
||||||
std::vector<unsigned> getVector(const std::string& key);
|
|
||||||
|
|
||||||
/** Get length of a vector */
|
|
||||||
unsigned getVectorLength(const std::string &key)
|
|
||||||
{ return getVector(key).size(); }
|
|
||||||
|
|
||||||
/** Set or change a value in the table. */
|
|
||||||
bool set(const std::string& key, const std::string& value);
|
|
||||||
|
|
||||||
/** Set or change a value in the table. */
|
|
||||||
bool set(const std::string& key, long value);
|
|
||||||
|
|
||||||
/** Create an entry in the table, no value though. */
|
|
||||||
bool set(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Remove an entry from the table.
|
|
||||||
Will not alter required values.
|
|
||||||
@param key The key of the item to be removed.
|
|
||||||
@return true if anything was actually removed.
|
|
||||||
*/
|
|
||||||
bool remove(const std::string& key);
|
|
||||||
|
|
||||||
/** Search the table, dumping to a stream. */
|
|
||||||
void find(const std::string& pattern, std::ostream&) const;
|
|
||||||
|
|
||||||
/** Return all key/value pairs stored in the ConfigurationTable */
|
|
||||||
ConfigurationRecordMap getAllPairs() const;
|
|
||||||
|
|
||||||
/** Define the callback to purge the cache whenever the database changes. */
|
|
||||||
void setUpdateHook(void(*)(void *,int ,char const *,char const *,sqlite3_int64));
|
|
||||||
|
|
||||||
/** Define the callback for cross checking. */
|
|
||||||
void setCrossCheckHook(std::vector<std::string> (*wCrossCheck)(const std::string&));
|
|
||||||
|
|
||||||
/** Execute the application specific value cross checking logic. */
|
|
||||||
std::vector<std::string> crossCheck(const std::string& key);
|
|
||||||
|
|
||||||
/** purege cache if it exceeds a certain age */
|
|
||||||
void checkCacheAge();
|
|
||||||
|
|
||||||
/** Delete all records from the cache. */
|
|
||||||
void purge();
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/**
|
|
||||||
Attempt to lookup a record, cache if needed.
|
|
||||||
Throw ConfigurationTableKeyNotFound if not found.
|
|
||||||
Caller should hold mLock because the returned reference points into the cache.
|
|
||||||
*/
|
|
||||||
const ConfigurationRecord& lookup(const std::string& key);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<HashString, std::string> HashStringMap;
|
|
||||||
|
|
||||||
class SimpleKeyValue {
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
HashStringMap mMap;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** Take a C string "A=B" and set map["A"]="B". */
|
|
||||||
void addItem(const char*);
|
|
||||||
|
|
||||||
/** Take a C string "A=B C=D E=F ..." and add all of the pairs to the map. */
|
|
||||||
void addItems(const char*s);
|
|
||||||
|
|
||||||
/** Return a reference to the string at map["key"]. */
|
|
||||||
const char* get(const char*) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationKey {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum VisibilityLevel
|
|
||||||
{
|
|
||||||
CUSTOMER,
|
|
||||||
CUSTOMERSITE,
|
|
||||||
CUSTOMERTUNE,
|
|
||||||
CUSTOMERWARN,
|
|
||||||
DEVELOPER,
|
|
||||||
FACTORY
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
BOOLEAN,
|
|
||||||
CHOICE_OPT,
|
|
||||||
CHOICE,
|
|
||||||
CIDR_OPT,
|
|
||||||
CIDR,
|
|
||||||
FILEPATH_OPT,
|
|
||||||
FILEPATH,
|
|
||||||
IPADDRESS_OPT,
|
|
||||||
IPADDRESS,
|
|
||||||
IPANDPORT,
|
|
||||||
MIPADDRESS_OPT,
|
|
||||||
MIPADDRESS,
|
|
||||||
PORT_OPT,
|
|
||||||
PORT,
|
|
||||||
REGEX_OPT,
|
|
||||||
REGEX,
|
|
||||||
STRING_OPT,
|
|
||||||
STRING,
|
|
||||||
VALRANGE
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string mName;
|
|
||||||
std::string mDefaultValue;
|
|
||||||
std::string mUnits;
|
|
||||||
VisibilityLevel mVisibility;
|
|
||||||
Type mType;
|
|
||||||
std::string mValidValues;
|
|
||||||
bool mIsStatic;
|
|
||||||
std::string mDescription;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConfigurationKey(const std::string& wName, const std::string& wDefaultValue, const std::string& wUnits, const VisibilityLevel wVisibility, const Type wType, const std::string& wValidValues, bool wIsStatic, const std::string& wDescription):
|
|
||||||
mName(wName),
|
|
||||||
mDefaultValue(wDefaultValue),
|
|
||||||
mUnits(wUnits),
|
|
||||||
mVisibility(wVisibility),
|
|
||||||
mType(wType),
|
|
||||||
mValidValues(wValidValues),
|
|
||||||
mIsStatic(wIsStatic),
|
|
||||||
mDescription(wDescription)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
ConfigurationKey()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
const std::string& getName() const { return mName; }
|
|
||||||
const std::string& getDefaultValue() const { return mDefaultValue; }
|
|
||||||
void updateDefaultValue(const std::string& newValue) { mDefaultValue = newValue; }
|
|
||||||
void updateDefaultValue(const int newValue) { std::stringstream ss; ss << newValue; updateDefaultValue(ss.str()); }
|
|
||||||
const std::string& getUnits() const { return mUnits; }
|
|
||||||
const VisibilityLevel& getVisibility() const { return mVisibility; }
|
|
||||||
const Type& getType() const { return mType; }
|
|
||||||
const std::string& getValidValues() const { return mValidValues; }
|
|
||||||
bool isStatic() const { return mIsStatic; }
|
|
||||||
const std::string& getDescription() const { return mDescription; }
|
|
||||||
|
|
||||||
static bool isValidIP(const std::string& ip);
|
|
||||||
static void getMinMaxStepping(const ConfigurationKey &key, std::string &min, std::string &max, std::string &stepping);
|
|
||||||
template<class T> static bool isInValRange(const ConfigurationKey &key, const std::string& val, const bool isInteger);
|
|
||||||
static const std::string visibilityLevelToString(const VisibilityLevel& visibility);
|
|
||||||
static const std::string typeToString(const ConfigurationKey::Type& type);
|
|
||||||
static void printKey(const ConfigurationKey &key, const std::string& currentValue, std::ostream& os);
|
|
||||||
static void printDescription(const ConfigurationKey &key, std::ostream& os);
|
|
||||||
static const std::string getARFCNsString();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// vim: ts=4 sw=4
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009, 2010 Free Software Foundation, Inc.
|
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "Configuration.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
ConfigurationKeyMap getConfigurationKeys();
|
|
||||||
ConfigurationTable gConfig("exampleconfig.db","test", getConfigurationKeys());
|
|
||||||
|
|
||||||
void purgeConfig(void*,int,char const*, char const*, sqlite3_int64)
|
|
||||||
{
|
|
||||||
//cout << "update hook" << endl;
|
|
||||||
gConfig.purge();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
|
|
||||||
gConfig.setUpdateHook(purgeConfig);
|
|
||||||
|
|
||||||
const char *keys[5] = {"key1", "key2", "key3", "key4", "key5"};
|
|
||||||
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
gConfig.set(keys[i],i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
cout << "table[" << keys[i] << "]=" << gConfig.getStr(keys[i]) << endl;
|
|
||||||
cout << "table[" << keys[i] << "]=" << gConfig.getNum(keys[i]) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
cout << "defined table[" << keys[i] << "]=" << gConfig.defines(keys[i]) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
gConfig.set("key5","100 200 300 400 ");
|
|
||||||
std::vector<unsigned> vect = gConfig.getVector("key5");
|
|
||||||
cout << "vect length " << vect.size() << ": ";
|
|
||||||
for (unsigned i=0; i<vect.size(); i++) cout << " " << vect[i];
|
|
||||||
cout << endl;
|
|
||||||
std::vector<string> svect = gConfig.getVectorOfStrings("key5");
|
|
||||||
cout << "vect length " << svect.size() << ": ";
|
|
||||||
for (unsigned i=0; i<svect.size(); i++) cout << " " << svect[i] << ":";
|
|
||||||
cout << endl;
|
|
||||||
|
|
||||||
cout << "bool " << gConfig.getBool("booltest") << endl;
|
|
||||||
gConfig.set("booltest",1);
|
|
||||||
cout << "bool " << gConfig.getBool("booltest") << endl;
|
|
||||||
gConfig.set("booltest",0);
|
|
||||||
cout << "bool " << gConfig.getBool("booltest") << endl;
|
|
||||||
|
|
||||||
gConfig.getStr("newstring");
|
|
||||||
gConfig.getNum("numnumber");
|
|
||||||
|
|
||||||
|
|
||||||
SimpleKeyValue pairs;
|
|
||||||
pairs.addItems(" a=1 b=34 dd=143 ");
|
|
||||||
cout<< pairs.get("a") << endl;
|
|
||||||
cout<< pairs.get("b") << endl;
|
|
||||||
cout<< pairs.get("dd") << endl;
|
|
||||||
|
|
||||||
gConfig.set("fkey","123.456");
|
|
||||||
float fval = gConfig.getFloat("fkey");
|
|
||||||
cout << "fkey " << fval << endl;
|
|
||||||
|
|
||||||
cout << "search fkey:" << endl;
|
|
||||||
gConfig.find("fkey",cout);
|
|
||||||
cout << "search fkey:" << endl;
|
|
||||||
gConfig.find("fkey",cout);
|
|
||||||
gConfig.remove("fkey");
|
|
||||||
cout << "search fkey:" << endl;
|
|
||||||
gConfig.find("fkey",cout);
|
|
||||||
|
|
||||||
try {
|
|
||||||
gConfig.getNum("supposedtoabort");
|
|
||||||
} catch (ConfigurationTableKeyNotFound) {
|
|
||||||
cout << "ConfigurationTableKeyNotFound exception successfully caught." << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigurationKeyMap getConfigurationKeys()
|
|
||||||
{
|
|
||||||
ConfigurationKeyMap map;
|
|
||||||
ConfigurationKey *tmp;
|
|
||||||
|
|
||||||
tmp = new ConfigurationKey("booltest","0",
|
|
||||||
"",
|
|
||||||
ConfigurationKey::DEVELOPER,
|
|
||||||
ConfigurationKey::BOOLEAN,
|
|
||||||
"",
|
|
||||||
false,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
map[tmp->getName()] = *tmp;
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
tmp = new ConfigurationKey("numnumber","42",
|
|
||||||
"",
|
|
||||||
ConfigurationKey::DEVELOPER,
|
|
||||||
ConfigurationKey::VALRANGE,
|
|
||||||
"0-100",
|
|
||||||
false,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
map[tmp->getName()] = *tmp;
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
tmp = new ConfigurationKey("newstring","new string value",
|
|
||||||
"",
|
|
||||||
ConfigurationKey::DEVELOPER,
|
|
||||||
ConfigurationKey::STRING,
|
|
||||||
"",
|
|
||||||
false,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
map[tmp->getName()] = *tmp;
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 Free Software Foundation, Inc.
|
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
#include "Logger.h"
|
|
||||||
#include "Configuration.h"
|
|
||||||
|
|
||||||
ConfigurationTable gConfig;
|
|
||||||
//ConfigurationTable gConfig("example.config");
|
|
||||||
|
|
||||||
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[])
|
|
||||||
{
|
|
||||||
gLogInit("LogTest","NOTICE",LOG_LOCAL7);
|
|
||||||
|
|
||||||
LOG(EMERG) << " testing the logger.";
|
|
||||||
LOG(ALERT) << " testing the logger.";
|
|
||||||
LOG(CRIT) << " testing the logger.";
|
|
||||||
LOG(ERR) << " testing the logger.";
|
|
||||||
LOG(WARNING) << " testing the logger.";
|
|
||||||
LOG(NOTICE) << " testing the logger.";
|
|
||||||
LOG(INFO) << " testing the logger.";
|
|
||||||
LOG(DEBUG) << " testing the logger.";
|
|
||||||
std::cout << "\n\n\n";
|
|
||||||
std::cout << "testing Alarms\n";
|
|
||||||
std::cout << "you should see three lines:" << std::endl;
|
|
||||||
printAlarms();
|
|
||||||
std::cout << "----------- generating 20 alarms ----------" << std::endl;
|
|
||||||
for (int i = 0 ; i < 20 ; ++i) {
|
|
||||||
LOG(ALERT) << i;
|
|
||||||
}
|
|
||||||
std::cout << "you should see ten lines with the numbers 10..19:" << std::endl;
|
|
||||||
printAlarms();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -32,44 +32,15 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <sys/time.h> // For gettimeofday
|
#include <sys/time.h> // For gettimeofday
|
||||||
|
|
||||||
#include "Configuration.h"
|
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Threads.h" // pat added
|
#include "Threads.h" // pat added
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
// Switches to enable/disable logging targets
|
|
||||||
// MUST BE DEFINED BEFORE gConfig FOR gLogEarly() TO WORK CORRECTLY
|
|
||||||
bool gLogToConsole = true;
|
|
||||||
bool gLogToSyslog = false;
|
|
||||||
FILE *gLogToFile = NULL;
|
|
||||||
Mutex gLogToLock;
|
Mutex gLogToLock;
|
||||||
|
|
||||||
|
// Global log level threshold:
|
||||||
// Reference to a global config table, used all over the system.
|
int config_log_level;
|
||||||
extern ConfigurationTable gConfig;
|
|
||||||
|
|
||||||
|
|
||||||
/**@ The global alarms table. */
|
|
||||||
//@{
|
|
||||||
Mutex alarmsLock;
|
|
||||||
list<string> alarmsList;
|
|
||||||
void addAlarm(const string&);
|
|
||||||
//@}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// (pat) If Log messages are printed before the classes in this module are inited
|
|
||||||
// (which happens when static classes have constructors that do work)
|
|
||||||
// the OpenBTS just crashes.
|
|
||||||
// Prevent that by setting sLoggerInited to true when this module is inited.
|
|
||||||
static bool sLoggerInited = 0;
|
|
||||||
static struct CheckLoggerInitStatus {
|
|
||||||
CheckLoggerInitStatus() { sLoggerInited = 1; }
|
|
||||||
} sCheckloggerInitStatus;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Names of the logging levels. */
|
/** Names of the logging levels. */
|
||||||
const char *levelNames[] = {
|
const char *levelNames[] = {
|
||||||
@@ -96,22 +67,6 @@ int levelStringToInt(const string& name)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Given a string, return the corresponding level name. */
|
|
||||||
int lookupLevel(const string& key)
|
|
||||||
{
|
|
||||||
string val = gConfig.getStr(key);
|
|
||||||
int level = levelStringToInt(val);
|
|
||||||
|
|
||||||
if (level == -1) {
|
|
||||||
string defaultLevel = gConfig.mSchema["Log.Level"].getDefaultValue();
|
|
||||||
level = levelStringToInt(defaultLevel);
|
|
||||||
_LOG(CRIT) << "undefined logging level (" << key << " = \"" << val << "\") defaulting to \"" << defaultLevel << ".\" Valid levels are: EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO or DEBUG";
|
|
||||||
gConfig.set(key, defaultLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string format(const char *fmt, ...)
|
static std::string format(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -138,127 +93,22 @@ std::ostream& operator<<(std::ostream& os, std::ostringstream& ss)
|
|||||||
return os << ss.str();
|
return os << ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLoggingLevel(const char* filename)
|
|
||||||
{
|
|
||||||
// Default level?
|
|
||||||
if (!filename) return lookupLevel("Log.Level");
|
|
||||||
|
|
||||||
// This can afford to be inefficient since it is not called that often.
|
|
||||||
const string keyName = string("Log.Level.") + string(filename);
|
|
||||||
if (gConfig.defines(keyName)) return lookupLevel(keyName);
|
|
||||||
return lookupLevel("Log.Level");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int gGetLoggingLevel(const char* filename)
|
|
||||||
{
|
|
||||||
// This is called a lot and needs to be efficient.
|
|
||||||
|
|
||||||
static Mutex sLogCacheLock;
|
|
||||||
static map<uint64_t,int> sLogCache;
|
|
||||||
static unsigned sCacheCount;
|
|
||||||
static const unsigned sCacheRefreshCount = 1000;
|
|
||||||
|
|
||||||
if (filename==NULL) return gGetLoggingLevel("");
|
|
||||||
|
|
||||||
HashString hs(filename);
|
|
||||||
uint64_t key = hs.hash();
|
|
||||||
|
|
||||||
sLogCacheLock.lock();
|
|
||||||
// Time for a cache flush?
|
|
||||||
if (sCacheCount>sCacheRefreshCount) {
|
|
||||||
sLogCache.clear();
|
|
||||||
sCacheCount=0;
|
|
||||||
}
|
|
||||||
// Is it cached already?
|
|
||||||
map<uint64_t,int>::const_iterator where = sLogCache.find(key);
|
|
||||||
sCacheCount++;
|
|
||||||
if (where!=sLogCache.end()) {
|
|
||||||
int retVal = where->second;
|
|
||||||
sLogCacheLock.unlock();
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
// Look it up in the config table and cache it.
|
|
||||||
// FIXME: Figure out why unlock and lock below fix the config table deadlock.
|
|
||||||
// (pat) Probably because getLoggingLevel may call LOG recursively via lookupLevel().
|
|
||||||
sLogCacheLock.unlock();
|
|
||||||
int level = getLoggingLevel(filename);
|
|
||||||
sLogCacheLock.lock();
|
|
||||||
sLogCache.insert(pair<uint64_t,int>(key,level));
|
|
||||||
sLogCacheLock.unlock();
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// copies the alarm list and returns it. list supposed to be small.
|
|
||||||
list<string> gGetLoggerAlarms()
|
|
||||||
{
|
|
||||||
alarmsLock.lock();
|
|
||||||
list<string> ret;
|
|
||||||
// excuse the "complexity", but to use std::copy with a list you need
|
|
||||||
// an insert_iterator - copy technically overwrites, doesn't insert.
|
|
||||||
insert_iterator< list<string> > ii(ret, ret.begin());
|
|
||||||
copy(alarmsList.begin(), alarmsList.end(), ii);
|
|
||||||
alarmsLock.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add an alarm to the alarm list. */
|
|
||||||
void addAlarm(const string& s)
|
|
||||||
{
|
|
||||||
alarmsLock.lock();
|
|
||||||
alarmsList.push_back(s);
|
|
||||||
unsigned maxAlarms = gConfig.getNum("Log.Alarms.Max");
|
|
||||||
while (alarmsList.size() > maxAlarms) alarmsList.pop_front();
|
|
||||||
alarmsLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Log::~Log()
|
Log::~Log()
|
||||||
{
|
{
|
||||||
if (mDummyInit) return;
|
|
||||||
// Anything at or above LOG_CRIT is an "alarm".
|
// Anything at or above LOG_CRIT is an "alarm".
|
||||||
// Save alarms in the local list and echo them to stderr.
|
|
||||||
if (mPriority <= LOG_ERR) {
|
if (mPriority <= LOG_ERR) {
|
||||||
if (sLoggerInited) addAlarm(mStream.str().c_str());
|
|
||||||
cerr << mStream.str() << endl;
|
cerr << mStream.str() << endl;
|
||||||
}
|
}
|
||||||
// Current logging level was already checked by the macro. So just log.
|
|
||||||
// Log to syslog
|
int mlen = mStream.str().size();
|
||||||
if (gLogToSyslog) {
|
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
|
||||||
syslog(mPriority, "%s", mStream.str().c_str());
|
ScopedLock lock(gLogToLock);
|
||||||
}
|
// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
|
||||||
// Log to file and console
|
// so just use std::cout.
|
||||||
if (gLogToConsole||gLogToFile) {
|
std::cout << mStream.str();
|
||||||
int mlen = mStream.str().size();
|
if (neednl) std::cout<<"\n";
|
||||||
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
|
|
||||||
ScopedLock lock(gLogToLock);
|
|
||||||
if (gLogToConsole) {
|
|
||||||
// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
|
|
||||||
// so just use std::cout.
|
|
||||||
std::cout << mStream.str();
|
|
||||||
if (neednl) std::cout<<"\n";
|
|
||||||
}
|
|
||||||
if (gLogToFile) {
|
|
||||||
fputs(mStream.str().c_str(),gLogToFile);
|
|
||||||
if (neednl) {fputc('\n',gLogToFile);}
|
|
||||||
fflush(gLogToFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Log::Log(const char* name, const char* level, int facility)
|
|
||||||
{
|
|
||||||
mDummyInit = true;
|
|
||||||
gLogInit(name, level, facility);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ostringstream& Log::get()
|
ostringstream& Log::get()
|
||||||
{
|
{
|
||||||
assert(mPriority<numLevels);
|
assert(mPriority<numLevels);
|
||||||
@@ -268,64 +118,11 @@ ostringstream& Log::get()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void gLogInit(const char* name, const char* level, int facility)
|
void gLogInit(const char* level, char *fn)
|
||||||
{
|
{
|
||||||
// Set the level if one has been specified.
|
// Set the level if one has been specified.
|
||||||
if (level) {
|
if (level)
|
||||||
gConfig.set("Log.Level",level);
|
config_log_level = levelStringToInt(level);
|
||||||
}
|
|
||||||
|
|
||||||
// Both the transceiver and OpenBTS use this same facility, but only OpenBTS/OpenNodeB may use this log file:
|
|
||||||
string str = gConfig.getStr("Log.File");
|
|
||||||
if (gLogToFile==NULL && str.length() && 0==strncmp(gCmdName,"Open",4)) {
|
|
||||||
const char *fn = str.c_str();
|
|
||||||
if (fn && *fn && strlen(fn)>3) { // strlen because a garbage char is getting in sometimes.
|
|
||||||
gLogToFile = fopen(fn,"w"); // New log file each time we start.
|
|
||||||
if (gLogToFile) {
|
|
||||||
time_t now;
|
|
||||||
time(&now);
|
|
||||||
fprintf(gLogToFile,"Starting at %s",ctime(&now));
|
|
||||||
fflush(gLogToFile);
|
|
||||||
std::cout << "Logging to file: " << fn << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the log connection.
|
|
||||||
openlog(name,0,facility);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void gLogEarly(int level, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
|
|
||||||
if (gLogToSyslog) {
|
|
||||||
va_list args_copy;
|
|
||||||
va_copy(args_copy, args);
|
|
||||||
vsyslog(level | LOG_USER, fmt, args_copy);
|
|
||||||
va_end(args_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gLogToConsole) {
|
|
||||||
va_list args_copy;
|
|
||||||
va_copy(args_copy, args);
|
|
||||||
vprintf(fmt, args_copy);
|
|
||||||
printf("\n");
|
|
||||||
va_end(args_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gLogToFile) {
|
|
||||||
va_list args_copy;
|
|
||||||
va_copy(args_copy, args);
|
|
||||||
vfprintf(gLogToFile, fmt, args_copy);
|
|
||||||
fprintf(gLogToFile, "\n");
|
|
||||||
va_end(args_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: ts=4 sw=4
|
// vim: ts=4 sw=4
|
||||||
|
|||||||
@@ -32,19 +32,27 @@
|
|||||||
#ifndef LOGGER_H
|
#ifndef LOGGER_H
|
||||||
#define LOGGER_H
|
#define LOGGER_H
|
||||||
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
extern int config_log_level;
|
||||||
|
|
||||||
|
#define LOG_EMERG 0 /* system is unusable */
|
||||||
|
#define LOG_ALERT 1 /* action must be taken immediately */
|
||||||
|
#define LOG_CRIT 2 /* critical conditions */
|
||||||
|
#define LOG_ERR 3 /* error conditions */
|
||||||
|
#define LOG_WARNING 4 /* warning conditions */
|
||||||
|
#define LOG_NOTICE 5 /* normal but significant condition */
|
||||||
|
#define LOG_INFO 6 /* informational */
|
||||||
|
#define LOG_DEBUG 7 /* debug-level messages */
|
||||||
|
|
||||||
#define _LOG(level) \
|
#define _LOG(level) \
|
||||||
Log(LOG_##level).get() << pthread_self() \
|
Log(LOG_##level).get() << pthread_self() \
|
||||||
<< timestr() << " " __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ": "
|
<< timestr() << " " __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ": "
|
||||||
|
|
||||||
#define IS_LOG_LEVEL(wLevel) (gGetLoggingLevel(__FILE__)>=LOG_##wLevel)
|
#define IS_LOG_LEVEL(wLevel) (config_log_level>=LOG_##wLevel)
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
#define LOG(wLevel) \
|
#define LOG(wLevel) \
|
||||||
@@ -54,40 +62,8 @@
|
|||||||
if (IS_LOG_LEVEL(wLevel)) _LOG(wLevel)
|
if (IS_LOG_LEVEL(wLevel)) _LOG(wLevel)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// pat: And for your edification here are the 'levels' as defined in syslog.h:
|
|
||||||
// LOG_EMERG 0 system is unusable
|
|
||||||
// LOG_ALERT 1 action must be taken immediately
|
|
||||||
// LOG_CRIT 2 critical conditions
|
|
||||||
// LOG_ERR 3 error conditions
|
|
||||||
// LOG_WARNING 4 warning conditions
|
|
||||||
// LOG_NOTICE 5 normal, but significant, condition
|
|
||||||
// LOG_INFO 6 informational message
|
|
||||||
// LOG_DEBUG 7 debug-level message
|
|
||||||
|
|
||||||
// (pat) added - print out a var and its name.
|
|
||||||
// Use like this: int descriptive_name; LOG(INFO)<<LOGVAR(descriptive_name);
|
|
||||||
#define LOGVAR2(name,val) " " << name << "=" << (val)
|
|
||||||
#define LOGVAR(var) (" " #var "=") << var
|
|
||||||
#define LOGHEX(var) (" " #var "=0x") << hex << ((unsigned)var) << dec
|
|
||||||
#define LOGHEX2(name,val) " " << name << "=0x" << hex << ((unsigned)(val)) << dec
|
|
||||||
// These are kind of cheesy, but you can use for bitvector
|
|
||||||
#define LOGBV2(name,val) " " << name << "=(" << val<<" size:"<<val.size()<<")"
|
|
||||||
#define LOGBV(bv) LOGBV2(#bv,bv)
|
|
||||||
#define LOGVARRANGE(name,cur,lo,hi) " "<<name <<"=("<<(cur) << " range:"<<(lo) << " to "<<(hi) <<")"
|
|
||||||
|
|
||||||
|
|
||||||
#define OBJLOG(wLevel) \
|
|
||||||
LOG(wLevel) << "obj: " << this << ' '
|
|
||||||
|
|
||||||
#define LOG_ASSERT(x) { if (!(x)) LOG(EMERG) << "assertion " #x " failed"; } assert(x);
|
|
||||||
|
|
||||||
|
|
||||||
#include "Threads.h" // must be after defines above, if these files are to be allowed to use LOG()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A C++ stream-based thread-safe logger.
|
A C++ stream-based thread-safe logger.
|
||||||
Derived from Dr. Dobb's Sept. 2007 issue.
|
|
||||||
Updated to use syslog.
|
|
||||||
This object is NOT the global logger;
|
This object is NOT the global logger;
|
||||||
every log record is an object of this class.
|
every log record is an object of this class.
|
||||||
*/
|
*/
|
||||||
@@ -99,28 +75,19 @@ class Log {
|
|||||||
|
|
||||||
std::ostringstream mStream; ///< This is where we buffer up the log entry.
|
std::ostringstream mStream; ///< This is where we buffer up the log entry.
|
||||||
int mPriority; ///< Priority of current report.
|
int mPriority; ///< Priority of current report.
|
||||||
bool mDummyInit;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Log(int wPriority)
|
Log(int wPriority)
|
||||||
:mPriority(wPriority), mDummyInit(false)
|
:mPriority(wPriority)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Log(const char* name, const char* level=NULL, int facility=LOG_USER);
|
|
||||||
|
|
||||||
// Most of the work is in the destructor.
|
// Most of the work is in the destructor.
|
||||||
/** The destructor actually generates the log entry. */
|
/** The destructor actually generates the log entry. */
|
||||||
~Log();
|
~Log();
|
||||||
|
|
||||||
std::ostringstream& get();
|
std::ostringstream& get();
|
||||||
};
|
};
|
||||||
extern bool gLogToConsole; // Output log messages to stdout
|
|
||||||
extern bool gLogToSyslog; // Output log messages to syslog
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::list<std::string> gGetLoggerAlarms(); ///< Get a copy of the recent alarm list.
|
|
||||||
|
|
||||||
const std::string timestr(); // A timestamp to print in messages.
|
const std::string timestr(); // A timestamp to print in messages.
|
||||||
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss);
|
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss);
|
||||||
@@ -128,11 +95,7 @@ std::ostream& operator<<(std::ostream& os, std::ostringstream& ss);
|
|||||||
/**@ Global control and initialization of the logging system. */
|
/**@ Global control and initialization of the logging system. */
|
||||||
//@{
|
//@{
|
||||||
/** Initialize the global logging system. */
|
/** Initialize the global logging system. */
|
||||||
void gLogInit(const char* name, const char* level=NULL, int facility=LOG_USER);
|
void gLogInit(const char* level=NULL, char* fn=NULL);
|
||||||
/** Get the logging level associated with a given file. */
|
|
||||||
int gGetLoggingLevel(const char *filename=NULL);
|
|
||||||
/** Allow early logging when still in constructors */
|
|
||||||
void gLogEarly(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
include $(top_srcdir)/Makefile.common
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
|
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
|
||||||
AM_CXXFLAGS = -Wall -O3 -g -ldl -lpthread
|
AM_CXXFLAGS = -Wall -O3 -g -lpthread
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
example.config \
|
example.config \
|
||||||
@@ -36,21 +36,7 @@ libcommon_la_SOURCES = \
|
|||||||
Sockets.cpp \
|
Sockets.cpp \
|
||||||
Threads.cpp \
|
Threads.cpp \
|
||||||
Timeval.cpp \
|
Timeval.cpp \
|
||||||
Logger.cpp \
|
Logger.cpp
|
||||||
Configuration.cpp \
|
|
||||||
sqlite3util.cpp
|
|
||||||
|
|
||||||
noinst_PROGRAMS = \
|
|
||||||
BitVectorTest \
|
|
||||||
PRBSTest \
|
|
||||||
InterthreadTest \
|
|
||||||
SocketsTest \
|
|
||||||
TimevalTest \
|
|
||||||
VectorTest \
|
|
||||||
ConfigurationTest \
|
|
||||||
LogTest
|
|
||||||
|
|
||||||
# ReportingTest
|
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
BitVector.h \
|
BitVector.h \
|
||||||
@@ -61,38 +47,4 @@ noinst_HEADERS = \
|
|||||||
Threads.h \
|
Threads.h \
|
||||||
Timeval.h \
|
Timeval.h \
|
||||||
Vector.h \
|
Vector.h \
|
||||||
Configuration.h \
|
Logger.h
|
||||||
Logger.h \
|
|
||||||
sqlite3util.h
|
|
||||||
|
|
||||||
BitVectorTest_SOURCES = BitVectorTest.cpp
|
|
||||||
BitVectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
|
|
||||||
|
|
||||||
PRBSTest_SOURCES = PRBSTest.cpp
|
|
||||||
|
|
||||||
InterthreadTest_SOURCES = InterthreadTest.cpp
|
|
||||||
InterthreadTest_LDADD = libcommon.la
|
|
||||||
InterthreadTest_LDFLAGS = -lpthread
|
|
||||||
|
|
||||||
SocketsTest_SOURCES = SocketsTest.cpp
|
|
||||||
SocketsTest_LDADD = libcommon.la
|
|
||||||
SocketsTest_LDFLAGS = -lpthread
|
|
||||||
|
|
||||||
TimevalTest_SOURCES = TimevalTest.cpp
|
|
||||||
TimevalTest_LDADD = libcommon.la
|
|
||||||
|
|
||||||
VectorTest_SOURCES = VectorTest.cpp
|
|
||||||
VectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
|
|
||||||
|
|
||||||
ConfigurationTest_SOURCES = ConfigurationTest.cpp
|
|
||||||
ConfigurationTest_LDADD = libcommon.la $(SQLITE3_LIBS)
|
|
||||||
|
|
||||||
# ReportingTest_SOURCES = ReportingTest.cpp
|
|
||||||
# ReportingTest_LDADD = libcommon.la $(SQLITE_LA)
|
|
||||||
|
|
||||||
LogTest_SOURCES = LogTest.cpp
|
|
||||||
LogTest_LDADD = libcommon.la $(SQLITE3_LIBS)
|
|
||||||
|
|
||||||
MOSTLYCLEANFILES += testSource testDestination
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -223,18 +223,18 @@ int DatagramSocket::read(char* buffer, size_t length, unsigned timeout)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
UDPSocket::UDPSocket(unsigned short wSrcPort)
|
UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort)
|
||||||
:DatagramSocket()
|
:DatagramSocket()
|
||||||
{
|
{
|
||||||
open(wSrcPort);
|
open(wSrcPort, wSrcIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UDPSocket::UDPSocket(unsigned short wSrcPort,
|
UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort,
|
||||||
const char * wDestIP, unsigned short wDestPort )
|
const char *wDestIP, unsigned short wDestPort)
|
||||||
:DatagramSocket()
|
:DatagramSocket()
|
||||||
{
|
{
|
||||||
open(wSrcPort);
|
open(wSrcPort, wSrcIP);
|
||||||
destination(wDestPort, wDestIP);
|
destination(wDestPort, wDestIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +246,7 @@ void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UDPSocket::open(unsigned short localPort)
|
void UDPSocket::open(unsigned short localPort, const char *wlocalIP)
|
||||||
{
|
{
|
||||||
// create
|
// create
|
||||||
mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
|
mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
|
||||||
@@ -265,7 +265,7 @@ void UDPSocket::open(unsigned short localPort)
|
|||||||
size_t length = sizeof(address);
|
size_t length = sizeof(address);
|
||||||
bzero(&address,length);
|
bzero(&address,length);
|
||||||
address.sin_family = AF_INET;
|
address.sin_family = AF_INET;
|
||||||
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
address.sin_addr.s_addr = inet_addr(wlocalIP);
|
||||||
address.sin_port = htons(localPort);
|
address.sin_port = htons(localPort);
|
||||||
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
|
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
|
||||||
perror("bind() failed");
|
perror("bind() failed");
|
||||||
@@ -284,50 +284,4 @@ unsigned short UDPSocket::port() const
|
|||||||
return ntohs(name.sin_port);
|
return ntohs(name.sin_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
|
|
||||||
:DatagramSocket()
|
|
||||||
{
|
|
||||||
if (localPath!=NULL) open(localPath);
|
|
||||||
if (remotePath!=NULL) destination(remotePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void UDDSocket::open(const char* localPath)
|
|
||||||
{
|
|
||||||
// create
|
|
||||||
mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
|
|
||||||
if (mSocketFD<0) {
|
|
||||||
perror("socket() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind
|
|
||||||
struct sockaddr_un address;
|
|
||||||
size_t length = sizeof(address);
|
|
||||||
bzero(&address,length);
|
|
||||||
address.sun_family = AF_UNIX;
|
|
||||||
strcpy(address.sun_path,localPath);
|
|
||||||
unlink(localPath);
|
|
||||||
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
|
|
||||||
perror("bind() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void UDDSocket::destination(const char* remotePath)
|
|
||||||
{
|
|
||||||
struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
|
|
||||||
strcpy(unAddr->sun_path,remotePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// vim:ts=4:sw=4
|
// vim:ts=4:sw=4
|
||||||
|
|||||||
@@ -144,11 +144,11 @@ class UDPSocket : public DatagramSocket {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/** Open a USP socket with an OS-assigned port and no default destination. */
|
/** Open a USP socket with an OS-assigned port and no default destination. */
|
||||||
UDPSocket( unsigned short localPort=0);
|
UDPSocket(const char *localIP, unsigned short localPort);
|
||||||
|
|
||||||
/** Given a full specification, open the socket and set the dest address. */
|
/** Given a full specification, open the socket and set the dest address. */
|
||||||
UDPSocket( unsigned short localPort,
|
UDPSocket(const char *localIP, unsigned short localPort,
|
||||||
const char * remoteIP, unsigned short remotePort);
|
const char *remoteIP, unsigned short remotePort);
|
||||||
|
|
||||||
/** Set the destination port. */
|
/** Set the destination port. */
|
||||||
void destination( unsigned short wDestPort, const char * wDestIP );
|
void destination( unsigned short wDestPort, const char * wDestIP );
|
||||||
@@ -157,7 +157,7 @@ public:
|
|||||||
unsigned short port() const;
|
unsigned short port() const;
|
||||||
|
|
||||||
/** Open and bind the UDP socket to a local port. */
|
/** Open and bind the UDP socket to a local port. */
|
||||||
void open(unsigned short localPort=0);
|
void open(unsigned short localPort=0, const char *wlocalIP="127.0.0.1");
|
||||||
|
|
||||||
/** Give the return address of the most recently received packet. */
|
/** Give the return address of the most recently received packet. */
|
||||||
const struct sockaddr_in* source() const { return (const struct sockaddr_in*)mSource; }
|
const struct sockaddr_in* source() const { return (const struct sockaddr_in*)mSource; }
|
||||||
@@ -166,26 +166,6 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Unix Domain Datagram Socket */
|
|
||||||
class UDDSocket : public DatagramSocket {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UDDSocket(const char* localPath=NULL, const char* remotePath=NULL);
|
|
||||||
|
|
||||||
void destination(const char* remotePath);
|
|
||||||
|
|
||||||
void open(const char* localPath);
|
|
||||||
|
|
||||||
/** Give the return address of the most recently received packet. */
|
|
||||||
const struct sockaddr_un* source() const { return (const struct sockaddr_un*)mSource; }
|
|
||||||
|
|
||||||
size_t addressSize() const { return sizeof(struct sockaddr_un); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ template <class T> class Vector {
|
|||||||
/** Build an empty Vector of a given size. */
|
/** Build an empty Vector of a given size. */
|
||||||
Vector(size_t wSize=0):mData(NULL) { resize(wSize); }
|
Vector(size_t wSize=0):mData(NULL) { resize(wSize); }
|
||||||
|
|
||||||
/** Build a Vector by shifting the data block. */
|
/** Build a Vector by moving another. */
|
||||||
Vector(Vector<T>& other)
|
Vector(Vector<T>&& other)
|
||||||
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd)
|
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd)
|
||||||
{ other.mData=NULL; }
|
{ other.mData=NULL; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,154 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
#include "sqlite3util.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
// Wrappers to sqlite operations.
|
|
||||||
// These will eventually get moved to commonlibs.
|
|
||||||
|
|
||||||
int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query)
|
|
||||||
{
|
|
||||||
int src = SQLITE_BUSY;
|
|
||||||
while (src==SQLITE_BUSY) {
|
|
||||||
src = sqlite3_prepare_v2(DB,query,strlen(query),stmt,NULL);
|
|
||||||
if (src==SQLITE_BUSY) {
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (src) {
|
|
||||||
fprintf(stderr,"sqlite3_prepare_v2 failed for \"%s\": %s\n",query,sqlite3_errmsg(DB));
|
|
||||||
sqlite3_finalize(*stmt);
|
|
||||||
}
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt)
|
|
||||||
{
|
|
||||||
int src = SQLITE_BUSY;
|
|
||||||
while (src==SQLITE_BUSY) {
|
|
||||||
src = sqlite3_step(stmt);
|
|
||||||
if (src==SQLITE_BUSY) {
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((src!=SQLITE_DONE) && (src!=SQLITE_ROW)) {
|
|
||||||
fprintf(stderr,"sqlite3_run_query failed: %s: %s\n", sqlite3_sql(stmt), sqlite3_errmsg(DB));
|
|
||||||
}
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool sqlite3_exists(sqlite3* DB, const char *tableName,
|
|
||||||
const char* keyName, const char* keyData)
|
|
||||||
{
|
|
||||||
size_t stringSize = 100 + strlen(tableName) + strlen(keyName) + strlen(keyData);
|
|
||||||
char query[stringSize];
|
|
||||||
sprintf(query,"SELECT * FROM %s WHERE %s == \"%s\"",tableName,keyName,keyData);
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Read the result.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
// Anything there?
|
|
||||||
return (src == SQLITE_ROW);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char *tableName,
|
|
||||||
const char* keyName, const char* keyData,
|
|
||||||
const char* valueName, unsigned &valueData)
|
|
||||||
{
|
|
||||||
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
|
|
||||||
char query[stringSize];
|
|
||||||
sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Read the result.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
bool retVal = false;
|
|
||||||
if (src == SQLITE_ROW) {
|
|
||||||
valueData = (unsigned)sqlite3_column_int64(stmt,0);
|
|
||||||
retVal = true;
|
|
||||||
}
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// This function returns an allocated string that must be free'd by the caller.
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, const char* keyData,
|
|
||||||
const char* valueName, char* &valueData)
|
|
||||||
{
|
|
||||||
valueData=NULL;
|
|
||||||
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
|
|
||||||
char query[stringSize];
|
|
||||||
sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Read the result.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
bool retVal = false;
|
|
||||||
if (src == SQLITE_ROW) {
|
|
||||||
const char* ptr = (const char*)sqlite3_column_text(stmt,0);
|
|
||||||
if (ptr) valueData = strdup(ptr);
|
|
||||||
retVal = true;
|
|
||||||
}
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// This function returns an allocated string that must be free'd by tha caller.
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, unsigned keyData,
|
|
||||||
const char* valueName, char* &valueData)
|
|
||||||
{
|
|
||||||
valueData=NULL;
|
|
||||||
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + 20;
|
|
||||||
char query[stringSize];
|
|
||||||
sprintf(query,"SELECT %s FROM %s WHERE %s == %u",valueName,tableName,keyName,keyData);
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Read the result.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
bool retVal = false;
|
|
||||||
if (src == SQLITE_ROW) {
|
|
||||||
const char* ptr = (const char*)sqlite3_column_text(stmt,0);
|
|
||||||
if (ptr) valueData = strdup(ptr);
|
|
||||||
retVal = true;
|
|
||||||
}
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool sqlite3_command(sqlite3* DB, const char* query)
|
|
||||||
{
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Run the query.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return src==SQLITE_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#ifndef SQLITE3UTIL_H
|
|
||||||
#define SQLITE3UTIL_H
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query);
|
|
||||||
|
|
||||||
int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt);
|
|
||||||
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char *tableName,
|
|
||||||
const char* keyName, const char* keyData,
|
|
||||||
const char* valueName, unsigned &valueData);
|
|
||||||
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, const char* keyData,
|
|
||||||
const char* valueName, char* &valueData);
|
|
||||||
|
|
||||||
// This function returns an allocated string that must be free'd by the caller.
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, unsigned keyData,
|
|
||||||
const char* valueName, char* &valueData);
|
|
||||||
|
|
||||||
bool sqlite3_exists(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, const char* keyData);
|
|
||||||
|
|
||||||
/** Run a query, ignoring the result; return true on success. */
|
|
||||||
bool sqlite3_command(sqlite3* DB, const char* query);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
22
INSTALLATION
22
INSTALLATION
@@ -2,32 +2,18 @@ Installation Requirements
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
OpenBTS compiles to a simple Unix binary and does not require special
|
osmo-trx compiles to a simple Unix binary and does not require special
|
||||||
installation.
|
installation.
|
||||||
|
|
||||||
One some systems (Ubuntu), you will need to define LIBS = -lpthread prior to
|
One some systems (Ubuntu), you will need to define LIBS = -lpthread prior to
|
||||||
running configure.
|
running configure.
|
||||||
|
|
||||||
To run OpenBTS, the following should be installed:
|
To run osmo-trx, the following should be installed:
|
||||||
|
libuhd (https://gnuradio.org).
|
||||||
Asterisk (http://www.asterisk.org), running SIP on port 5060.
|
|
||||||
|
|
||||||
libosip2 (http://www.gnu.org/software/osip/)
|
|
||||||
|
|
||||||
libortp (http://freshmeat.net/projects/ortp/)
|
|
||||||
|
|
||||||
libusrp (http://gnuradio.org).
|
|
||||||
This is part of the GNURadio installation.
|
This is part of the GNURadio installation.
|
||||||
It is the only part used by OpenBTS.
|
|
||||||
|
|
||||||
|
|
||||||
OpenBTS logs to syslogd as facility LOG_LOCAL7. Please set your /etc/syslog.conf
|
|
||||||
accordingly.
|
|
||||||
|
|
||||||
|
|
||||||
For information on specific executables, see tests/README.tests and
|
For information on specific executables, see tests/README.tests and
|
||||||
apps/README.apps.
|
apps/README.apps.
|
||||||
|
|
||||||
See http://gnuradio.org/redmine/wiki/gnuradio/OpenBTS/BuildingAndRunning for more
|
See https://osmocom.org/projects/osmotrx/wiki/OsmoTRX for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
|||||||
20
LEGAL
20
LEGAL
@@ -1,5 +1,8 @@
|
|||||||
OpenBTS
|
OpenBTS
|
||||||
|
|
||||||
|
The OsmoTRX project is direved from OpenBTS transceiver code. See http://openbts.org/ for details.
|
||||||
|
|
||||||
|
The related copyrights:
|
||||||
Most parts copyright 2008-2011 Free Software Foundation.
|
Most parts copyright 2008-2011 Free Software Foundation.
|
||||||
Some parts copyright 2010 Kestrel Signal Processing, Inc.
|
Some parts copyright 2010 Kestrel Signal Processing, Inc.
|
||||||
Some parts copyright 2011 Range Networks, Inc.
|
Some parts copyright 2011 Range Networks, Inc.
|
||||||
@@ -12,17 +15,9 @@ patented technologies. The user of this software is required to take whatever
|
|||||||
actions are necessary to avoid patent infringement.
|
actions are necessary to avoid patent infringement.
|
||||||
|
|
||||||
|
|
||||||
Trademark
|
|
||||||
|
|
||||||
"OpenBTS" is a registered trademark of Range Networks, Inc. (Range), a
|
|
||||||
California corporation. Range reserves the right to control the use of this
|
|
||||||
trademark. Do not use this trademark in commerce without permission and do not
|
|
||||||
rebrand OpenBTS under a different trademark.
|
|
||||||
|
|
||||||
|
|
||||||
Telecom and Radio Spectrum Laws
|
Telecom and Radio Spectrum Laws
|
||||||
|
|
||||||
The primary function of OpenBTS is the provision of telecommunications service
|
The primary function of OsmoTRX is the provision of telecommunications service
|
||||||
over a radio link. This activity is heavily regulated nearly everywhere in
|
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
|
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.
|
regulations in the jurisdictions where this sortware is used with radio equipment.
|
||||||
@@ -39,7 +34,7 @@ The legal restrictions listed here are not necessarily exhaustive.
|
|||||||
|
|
||||||
Note to US Government Users
|
Note to US Government Users
|
||||||
|
|
||||||
The OpenBTS software applications and associated documentation are "Commercial
|
The OsmoTRX software applications and associated documentation are "Commercial
|
||||||
Item(s)," as that term is defined at 48 C.F.R. Section 2.101, consisting of
|
Item(s)," as that term is defined at 48 C.F.R. Section 2.101, consisting of
|
||||||
"Commercial Computer Software" and "Commercial Computer Software Documentation,"
|
"Commercial Computer Software" and "Commercial Computer Software Documentation,"
|
||||||
as such terms are used in 48 C.F.R. 12.212 or 48 C.F.R. 227.7202, as
|
as such terms are used in 48 C.F.R. 12.212 or 48 C.F.R. 227.7202, as
|
||||||
@@ -54,13 +49,12 @@ and AGPLv3.
|
|||||||
Note to US Government Contractors
|
Note to US Government Contractors
|
||||||
|
|
||||||
GPL is not compatible with "government purpose rights" (GPR). If you receive
|
GPL is not compatible with "government purpose rights" (GPR). If you receive
|
||||||
OpenBTS software under a GPL and deliver it under GPR, you will be in violation
|
OsmoTRX software under a GPL and deliver it under GPR, you will be in violation
|
||||||
of GPL and possibly subject to enforcement actions by the original authors and
|
of GPL and possibly subject to enforcement actions by the original authors and
|
||||||
copyright holders, including the Free Software Foundation, Inc.
|
copyright holders, including the Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
|
||||||
Software Licensing and Distribution
|
Software Licensing and Distribution
|
||||||
|
|
||||||
A subset of OpenBTS is distributed publicly under AGPLv3. Range reserves the right to
|
The OsmoTRX is distributed publicly under AGPLv3. See the COPYING file
|
||||||
distribute most of this source code other licenses as well. See the COPYING file
|
|
||||||
for more information on the license for this distribution.
|
for more information on the license for this distribution.
|
||||||
|
|||||||
14
Makefile.am
14
Makefile.am
@@ -21,16 +21,17 @@
|
|||||||
include $(top_srcdir)/Makefile.common
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I config
|
ACLOCAL_AMFLAGS = -I config
|
||||||
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES) $(SQLITE3_CFLAGS)
|
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES)
|
||||||
AM_CXXFLAGS = -Wall -pthread -ldl
|
AM_CXXFLAGS = -Wall -pthread
|
||||||
#AM_CXXFLAGS = -Wall -O2 -NDEBUG -pthread -ldl
|
#AM_CXXFLAGS = -Wall -O2 -NDEBUG -pthread
|
||||||
#AM_CFLAGS = -Wall -O2 -NDEBUG -pthread -ldl
|
#AM_CFLAGS = -Wall -O2 -NDEBUG -pthread
|
||||||
|
|
||||||
# Order must be preserved
|
# Order must be preserved
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
CommonLibs \
|
CommonLibs \
|
||||||
GSM \
|
GSM \
|
||||||
Transceiver52M
|
Transceiver52M \
|
||||||
|
tests
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
autogen.sh \
|
autogen.sh \
|
||||||
@@ -39,6 +40,9 @@ EXTRA_DIST = \
|
|||||||
COPYING \
|
COPYING \
|
||||||
README
|
README
|
||||||
|
|
||||||
|
.PHONY: release
|
||||||
|
|
||||||
|
@RELMAKE@
|
||||||
|
|
||||||
dox: FORCE
|
dox: FORCE
|
||||||
doxygen doxconfig
|
doxygen doxconfig
|
||||||
|
|||||||
@@ -32,4 +32,10 @@ STD_DEFINES_AND_INCLUDES = \
|
|||||||
COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
|
COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
|
||||||
GSM_LA = $(top_builddir)/GSM/libGSM.la
|
GSM_LA = $(top_builddir)/GSM/libGSM.la
|
||||||
|
|
||||||
|
if ARCH_ARM
|
||||||
|
ARCH_LA = $(top_builddir)/Transceiver52M/arm/libarch.la
|
||||||
|
else
|
||||||
|
ARCH_LA = $(top_builddir)/Transceiver52M/x86/libarch.la
|
||||||
|
endif
|
||||||
|
|
||||||
MOSTLYCLEANFILES = *~
|
MOSTLYCLEANFILES = *~
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "Logger.h"
|
|
||||||
#include "Channelizer.h"
|
#include "Channelizer.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -22,17 +22,11 @@
|
|||||||
include $(top_srcdir)/Makefile.common
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/common
|
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/common
|
||||||
AM_CXXFLAGS = -ldl -lpthread
|
AM_CXXFLAGS = -lpthread
|
||||||
|
|
||||||
SUBDIRS = arm x86
|
SUBDIRS = arm x86
|
||||||
|
|
||||||
if ARCH_ARM
|
if USRP1
|
||||||
ARCH_LA = arm/libarch.la
|
|
||||||
else
|
|
||||||
ARCH_LA = x86/libarch.la
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USRP1
|
|
||||||
AM_CPPFLAGS += $(USRP_CFLAGS)
|
AM_CPPFLAGS += $(USRP_CFLAGS)
|
||||||
else
|
else
|
||||||
AM_CPPFLAGS += $(UHD_CFLAGS)
|
AM_CPPFLAGS += $(UHD_CFLAGS)
|
||||||
@@ -97,12 +91,13 @@ osmo_trx_LDADD = \
|
|||||||
libtransceiver.la \
|
libtransceiver.la \
|
||||||
$(ARCH_LA) \
|
$(ARCH_LA) \
|
||||||
$(GSM_LA) \
|
$(GSM_LA) \
|
||||||
$(COMMON_LA) $(SQLITE3_LIBS)
|
$(COMMON_LA) \
|
||||||
|
$(FFTWF_LIBS)
|
||||||
|
|
||||||
if USRP1
|
if USRP1
|
||||||
libtransceiver_la_SOURCES += USRPDevice.cpp
|
libtransceiver_la_SOURCES += USRPDevice.cpp
|
||||||
osmo_trx_LDADD += $(USRP_LIBS)
|
osmo_trx_LDADD += $(USRP_LIBS)
|
||||||
else
|
else
|
||||||
libtransceiver_la_SOURCES += UHDDevice.cpp
|
libtransceiver_la_SOURCES += UHDDevice.cpp
|
||||||
osmo_trx_LDADD += $(UHD_LIBS) $(FFTWF_LIBS)
|
osmo_trx_LDADD += $(UHD_LIBS)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Resampler.h"
|
#include "Resampler.h"
|
||||||
|
|
||||||
@@ -35,6 +36,8 @@ extern "C" {
|
|||||||
|
|
||||||
#define MAX_OUTPUT_LEN 4096
|
#define MAX_OUTPUT_LEN 4096
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
static float sinc(float x)
|
static float sinc(float x)
|
||||||
{
|
{
|
||||||
if (x == 0.0)
|
if (x == 0.0)
|
||||||
@@ -43,32 +46,19 @@ static float sinc(float x)
|
|||||||
return sin(M_PI * x) / (M_PI * x);
|
return sin(M_PI * x) / (M_PI * x);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resampler::initFilters(float bw)
|
void Resampler::initFilters(float bw)
|
||||||
{
|
{
|
||||||
size_t proto_len = p * filt_len;
|
float cutoff;
|
||||||
float *proto, val, cutoff;
|
|
||||||
float sum = 0.0f, scale = 0.0f;
|
float sum = 0.0f, scale = 0.0f;
|
||||||
float midpt = (float) (proto_len - 1.0) / 2.0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate partition filters and the temporary prototype filter
|
* Allocate partition filters and the temporary prototype filter
|
||||||
* according to numerator of the rational rate. Coefficients are
|
* according to numerator of the rational rate. Coefficients are
|
||||||
* real only and must be 16-byte memory aligned for SSE usage.
|
* real only and must be 16-byte memory aligned for SSE usage.
|
||||||
*/
|
*/
|
||||||
proto = new float[proto_len];
|
auto proto = vector<float>(p * filt_len);
|
||||||
if (!proto)
|
for (auto &part : partitions)
|
||||||
return false;
|
part = (complex<float> *) memalign(16, filt_len * sizeof(complex<float>));
|
||||||
|
|
||||||
partitions = (float **) malloc(sizeof(float *) * p);
|
|
||||||
if (!partitions) {
|
|
||||||
delete[] proto;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < p; i++) {
|
|
||||||
partitions[i] = (float *)
|
|
||||||
memalign(16, filt_len * 2 * sizeof(float));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate the prototype filter with a Blackman-harris window.
|
* Generate the prototype filter with a Blackman-harris window.
|
||||||
@@ -85,47 +75,26 @@ bool Resampler::initFilters(float bw)
|
|||||||
else
|
else
|
||||||
cutoff = (float) q;
|
cutoff = (float) q;
|
||||||
|
|
||||||
for (size_t i = 0; i < proto_len; i++) {
|
float midpt = (proto.size() - 1) / 2.0;
|
||||||
|
for (size_t i = 0; i < proto.size(); i++) {
|
||||||
proto[i] = sinc(((float) i - midpt) / cutoff * bw);
|
proto[i] = sinc(((float) i - midpt) / cutoff * bw);
|
||||||
proto[i] *= a0 -
|
proto[i] *= a0 -
|
||||||
a1 * cos(2 * M_PI * i / (proto_len - 1)) +
|
a1 * cos(2 * M_PI * i / (proto.size() - 1)) +
|
||||||
a2 * cos(4 * M_PI * i / (proto_len - 1)) -
|
a2 * cos(4 * M_PI * i / (proto.size() - 1)) -
|
||||||
a3 * cos(6 * M_PI * i / (proto_len - 1));
|
a3 * cos(6 * M_PI * i / (proto.size() - 1));
|
||||||
sum += proto[i];
|
sum += proto[i];
|
||||||
}
|
}
|
||||||
scale = p / sum;
|
scale = p / sum;
|
||||||
|
|
||||||
/* Populate filter partitions from the prototype filter */
|
/* Populate filter partitions from the prototype filter */
|
||||||
for (size_t i = 0; i < filt_len; i++) {
|
for (size_t i = 0; i < filt_len; i++) {
|
||||||
for (size_t n = 0; n < p; n++) {
|
for (size_t n = 0; n < p; n++)
|
||||||
partitions[n][2 * i + 0] = proto[i * p + n] * scale;
|
partitions[n][i] = complex<float>(proto[i * p + n] * scale);
|
||||||
partitions[n][2 * i + 1] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For convolution, we store the filter taps in reverse */
|
/* Store filter taps in reverse */
|
||||||
for (size_t n = 0; n < p; n++) {
|
for (auto &part : partitions)
|
||||||
for (size_t i = 0; i < filt_len / 2; i++) {
|
reverse(&part[0], &part[filt_len]);
|
||||||
val = partitions[n][2 * i];
|
|
||||||
partitions[n][2 * i] = partitions[n][2 * (filt_len - 1 - i)];
|
|
||||||
partitions[n][2 * (filt_len - 1 - i)] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] proto;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resampler::releaseFilters()
|
|
||||||
{
|
|
||||||
if (partitions) {
|
|
||||||
for (size_t i = 0; i < p; i++)
|
|
||||||
free(partitions[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(partitions);
|
|
||||||
partitions = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_vec_len(int in_len, int out_len, int p, int q)
|
static bool check_vec_len(int in_len, int out_len, int p, int q)
|
||||||
@@ -159,14 +128,6 @@ static bool check_vec_len(int in_len, int out_len, int p, int q)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resampler::computePath()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MAX_OUTPUT_LEN; i++) {
|
|
||||||
in_index[i] = (q * i) / p;
|
|
||||||
out_path[i] = (q * i) % p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len)
|
int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len)
|
||||||
{
|
{
|
||||||
int n, path;
|
int n, path;
|
||||||
@@ -180,8 +141,8 @@ int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len
|
|||||||
path = out_path[i];
|
path = out_path[i];
|
||||||
|
|
||||||
convolve_real(in, in_len,
|
convolve_real(in, in_len,
|
||||||
partitions[path], filt_len,
|
reinterpret_cast<float *>(partitions[path]),
|
||||||
&out[2 * i], out_len - i,
|
filt_len, &out[2 * i], out_len - i,
|
||||||
n, 1, 1, 0);
|
n, 1, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,14 +151,18 @@ int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len
|
|||||||
|
|
||||||
bool Resampler::init(float bw)
|
bool Resampler::init(float bw)
|
||||||
{
|
{
|
||||||
|
if (p == 0 || q == 0 || filt_len == 0) return false;
|
||||||
|
|
||||||
/* Filterbank filter internals */
|
/* Filterbank filter internals */
|
||||||
if (!initFilters(bw))
|
initFilters(bw);
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Precompute filterbank paths */
|
/* Precompute filterbank paths */
|
||||||
in_index = new size_t[MAX_OUTPUT_LEN];
|
int i = 0;
|
||||||
out_path = new size_t[MAX_OUTPUT_LEN];
|
for (auto &index : in_index)
|
||||||
computePath();
|
index = (q * i++) / p;
|
||||||
|
i = 0;
|
||||||
|
for (auto &path : out_path)
|
||||||
|
path = (q * i++) % p;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -208,7 +173,7 @@ size_t Resampler::len()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Resampler::Resampler(size_t p, size_t q, size_t filt_len)
|
Resampler::Resampler(size_t p, size_t q, size_t filt_len)
|
||||||
: in_index(NULL), out_path(NULL), partitions(NULL)
|
: in_index(MAX_OUTPUT_LEN), out_path(MAX_OUTPUT_LEN), partitions(p)
|
||||||
{
|
{
|
||||||
this->p = p;
|
this->p = p;
|
||||||
this->q = q;
|
this->q = q;
|
||||||
@@ -217,8 +182,6 @@ Resampler::Resampler(size_t p, size_t q, size_t filt_len)
|
|||||||
|
|
||||||
Resampler::~Resampler()
|
Resampler::~Resampler()
|
||||||
{
|
{
|
||||||
releaseFilters();
|
for (auto &part : partitions)
|
||||||
|
free(part);
|
||||||
delete in_index;
|
|
||||||
delete out_path;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
#ifndef _RESAMPLER_H_
|
#ifndef _RESAMPLER_H_
|
||||||
#define _RESAMPLER_H_
|
#define _RESAMPLER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
class Resampler {
|
class Resampler {
|
||||||
public:
|
public:
|
||||||
/* Constructor for rational sample rate conversion
|
/* Constructor for rational sample rate conversion
|
||||||
@@ -63,14 +66,11 @@ private:
|
|||||||
size_t p;
|
size_t p;
|
||||||
size_t q;
|
size_t q;
|
||||||
size_t filt_len;
|
size_t filt_len;
|
||||||
size_t *in_index;
|
std::vector<size_t> in_index;
|
||||||
size_t *out_path;
|
std::vector<size_t> out_path;
|
||||||
|
std::vector<std::complex<float> *> partitions;
|
||||||
|
|
||||||
float **partitions;
|
void initFilters(float bw);
|
||||||
|
|
||||||
bool initFilters(float bw);
|
|
||||||
void releaseFilters();
|
|
||||||
void computePath();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _RESAMPLER_H_ */
|
#endif /* _RESAMPLER_H_ */
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "Logger.h"
|
|
||||||
#include "Synthesis.h"
|
#include "Synthesis.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -112,16 +112,17 @@ bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc, un
|
|||||||
}
|
}
|
||||||
|
|
||||||
Transceiver::Transceiver(int wBasePort,
|
Transceiver::Transceiver(int wBasePort,
|
||||||
const char *wTRXAddress,
|
const char *TRXAddress,
|
||||||
|
const char *GSMcoreAddress,
|
||||||
size_t tx_sps, size_t rx_sps, size_t chans,
|
size_t tx_sps, size_t rx_sps, size_t chans,
|
||||||
GSM::Time wTransmitLatency,
|
GSM::Time wTransmitLatency,
|
||||||
RadioInterface *wRadioInterface,
|
RadioInterface *wRadioInterface,
|
||||||
double wRssiOffset)
|
double wRssiOffset)
|
||||||
: mBasePort(wBasePort), mAddr(wTRXAddress),
|
: mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
|
||||||
mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
|
mClockSocket(TRXAddress, wBasePort, GSMcoreAddress, wBasePort + 100),
|
||||||
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
|
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
|
||||||
rssiOffset(wRssiOffset),
|
rssiOffset(wRssiOffset),
|
||||||
mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false),
|
mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false), mForceClockInterface(false),
|
||||||
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
|
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
|
||||||
mWriteBurstToDiskMask(0)
|
mWriteBurstToDiskMask(0)
|
||||||
{
|
{
|
||||||
@@ -197,8 +198,8 @@ bool Transceiver::init(int filler, size_t rtsc, unsigned rach_delay, bool edge)
|
|||||||
d_srcport = mBasePort + 2 * i + 2;
|
d_srcport = mBasePort + 2 * i + 2;
|
||||||
d_dstport = mBasePort + 2 * i + 102;
|
d_dstport = mBasePort + 2 * i + 102;
|
||||||
|
|
||||||
mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
|
mCtrlSockets[i] = new UDPSocket(mLocalAddr.c_str(), c_srcport, mRemoteAddr.c_str(), c_dstport);
|
||||||
mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
|
mDataSockets[i] = new UDPSocket(mLocalAddr.c_str(), d_srcport, mRemoteAddr.c_str(), d_dstport);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Randomize the central clock */
|
/* Randomize the central clock */
|
||||||
@@ -273,7 +274,7 @@ bool Transceiver::start()
|
|||||||
TxUpperLoopAdapter, (void*) chan);
|
TxUpperLoopAdapter, (void*) chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeClockInterface();
|
mForceClockInterface = true;
|
||||||
mOn = true;
|
mOn = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -297,6 +298,10 @@ void Transceiver::stop()
|
|||||||
LOG(NOTICE) << "Stopping the transceiver";
|
LOG(NOTICE) << "Stopping the transceiver";
|
||||||
mTxLowerLoopThread->cancel();
|
mTxLowerLoopThread->cancel();
|
||||||
mRxLowerLoopThread->cancel();
|
mRxLowerLoopThread->cancel();
|
||||||
|
mTxLowerLoopThread->join();
|
||||||
|
mRxLowerLoopThread->join();
|
||||||
|
delete mTxLowerLoopThread;
|
||||||
|
delete mRxLowerLoopThread;
|
||||||
|
|
||||||
for (size_t i = 0; i < mChans; i++) {
|
for (size_t i = 0; i < mChans; i++) {
|
||||||
mRxServiceLoopThreads[i]->cancel();
|
mRxServiceLoopThreads[i]->cancel();
|
||||||
@@ -315,11 +320,6 @@ void Transceiver::stop()
|
|||||||
mTxPriorityQueues[i].clear();
|
mTxPriorityQueues[i].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
mTxLowerLoopThread->join();
|
|
||||||
mRxLowerLoopThread->join();
|
|
||||||
delete mTxLowerLoopThread;
|
|
||||||
delete mRxLowerLoopThread;
|
|
||||||
|
|
||||||
mOn = false;
|
mOn = false;
|
||||||
LOG(NOTICE) << "Transceiver stopped";
|
LOG(NOTICE) << "Transceiver stopped";
|
||||||
}
|
}
|
||||||
@@ -430,7 +430,7 @@ void Transceiver::setModulus(size_t timeslot, size_t chan)
|
|||||||
case V:
|
case V:
|
||||||
state->fillerModulus[timeslot] = 51;
|
state->fillerModulus[timeslot] = 51;
|
||||||
break;
|
break;
|
||||||
//case V:
|
//case V:
|
||||||
case VII:
|
case VII:
|
||||||
state->fillerModulus[timeslot] = 102;
|
state->fillerModulus[timeslot] = 102;
|
||||||
break;
|
break;
|
||||||
@@ -545,7 +545,7 @@ void writeToFile(radioVector *radio_burst, size_t chan)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Pull bursts from the FIFO and handle according to the slot
|
* Pull bursts from the FIFO and handle according to the slot
|
||||||
* and burst correlation type. Equalzation is currently disabled.
|
* and burst correlation type. Equalzation is currently disabled.
|
||||||
*/
|
*/
|
||||||
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
|
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
|
||||||
double &timingOffset, double &noise,
|
double &timingOffset, double &noise,
|
||||||
@@ -656,7 +656,7 @@ void Transceiver::reset()
|
|||||||
mTxPriorityQueues[i].clear();
|
mTxPriorityQueues[i].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Transceiver::driveControl(size_t chan)
|
void Transceiver::driveControl(size_t chan)
|
||||||
{
|
{
|
||||||
int MAX_PACKET_LENGTH = 100;
|
int MAX_PACKET_LENGTH = 100;
|
||||||
@@ -678,9 +678,6 @@ void Transceiver::driveControl(size_t chan)
|
|||||||
|
|
||||||
sscanf(buffer,"%3s %s",cmdcheck,command);
|
sscanf(buffer,"%3s %s",cmdcheck,command);
|
||||||
|
|
||||||
if (!chan)
|
|
||||||
writeClockInterface();
|
|
||||||
|
|
||||||
if (strcmp(cmdcheck,"CMD")!=0) {
|
if (strcmp(cmdcheck,"CMD")!=0) {
|
||||||
LOG(WARNING) << "bogus message on control interface";
|
LOG(WARNING) << "bogus message on control interface";
|
||||||
return;
|
return;
|
||||||
@@ -805,7 +802,7 @@ void Transceiver::driveControl(size_t chan)
|
|||||||
LOG(WARNING) << "bogus message on control interface";
|
LOG(WARNING) << "bogus message on control interface";
|
||||||
sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
|
sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
|
mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
|
||||||
setModulus(timeslot, chan);
|
setModulus(timeslot, chan);
|
||||||
sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
|
sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
|
||||||
@@ -853,14 +850,14 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
|
|||||||
frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
|
frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
|
||||||
|
|
||||||
LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
|
LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
|
||||||
|
|
||||||
int RSSI = (int) buffer[5];
|
int RSSI = (int) buffer[5];
|
||||||
BitVector newBurst(burstLen);
|
BitVector newBurst(burstLen);
|
||||||
BitVector::iterator itr = newBurst.begin();
|
BitVector::iterator itr = newBurst.begin();
|
||||||
char *bufferItr = buffer+6;
|
char *bufferItr = buffer+6;
|
||||||
while (itr < newBurst.end())
|
while (itr < newBurst.end())
|
||||||
*itr++ = *bufferItr++;
|
*itr++ = *bufferItr++;
|
||||||
|
|
||||||
GSM::Time currTime = GSM::Time(frameNum,timeSlot);
|
GSM::Time currTime = GSM::Time(frameNum,timeSlot);
|
||||||
|
|
||||||
addRadioVector(chan, newBurst, RSSI, currTime);
|
addRadioVector(chan, newBurst, RSSI, currTime);
|
||||||
@@ -874,9 +871,9 @@ void Transceiver::driveReceiveRadio()
|
|||||||
{
|
{
|
||||||
if (!mRadioInterface->driveReceiveRadio()) {
|
if (!mRadioInterface->driveReceiveRadio()) {
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
} else {
|
} else if (mForceClockInterface || mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) {
|
||||||
if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
|
mForceClockInterface = false;
|
||||||
writeClockInterface();
|
writeClockInterface();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -946,7 +943,7 @@ void Transceiver::driveTxFIFO()
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Features a carefully controlled latency mechanism, to
|
Features a carefully controlled latency mechanism, to
|
||||||
assure that transmit packets arrive at the radio/USRP
|
assure that transmit packets arrive at the radio/USRP
|
||||||
before they need to be transmitted.
|
before they need to be transmitted.
|
||||||
|
|
||||||
@@ -957,7 +954,7 @@ void Transceiver::driveTxFIFO()
|
|||||||
|
|
||||||
|
|
||||||
RadioClock *radioClock = (mRadioInterface->getClock());
|
RadioClock *radioClock = (mRadioInterface->getClock());
|
||||||
|
|
||||||
if (mOn) {
|
if (mOn) {
|
||||||
//radioClock->wait(); // wait until clock updates
|
//radioClock->wait(); // wait until clock updates
|
||||||
LOG(DEBUG) << "radio clock " << radioClock->get();
|
LOG(DEBUG) << "radio clock " << radioClock->get();
|
||||||
|
|||||||
@@ -89,15 +89,17 @@ struct TransceiverState {
|
|||||||
/** The Transceiver class, responsible for physical layer of basestation */
|
/** The Transceiver class, responsible for physical layer of basestation */
|
||||||
class Transceiver {
|
class Transceiver {
|
||||||
public:
|
public:
|
||||||
/** Transceiver constructor
|
/** Transceiver constructor
|
||||||
@param wBasePort base port number of UDP sockets
|
@param wBasePort base port number of UDP sockets
|
||||||
@param TRXAddress IP address of the TRX manager, as a string
|
@param TRXAddress IP address of the TRX, as a string
|
||||||
|
@param GSMcoreAddress IP address of the GSM core, as a string
|
||||||
@param wSPS number of samples per GSM symbol
|
@param wSPS number of samples per GSM symbol
|
||||||
@param wTransmitLatency initial setting of transmit latency
|
@param wTransmitLatency initial setting of transmit latency
|
||||||
@param radioInterface associated radioInterface object
|
@param radioInterface associated radioInterface object
|
||||||
*/
|
*/
|
||||||
Transceiver(int wBasePort,
|
Transceiver(int wBasePort,
|
||||||
const char *TRXAddress,
|
const char *TRXAddress,
|
||||||
|
const char *GSMcoreAddress,
|
||||||
size_t tx_sps, size_t rx_sps, size_t chans,
|
size_t tx_sps, size_t rx_sps, size_t chans,
|
||||||
GSM::Time wTransmitLatency,
|
GSM::Time wTransmitLatency,
|
||||||
RadioInterface *wRadioInterface,
|
RadioInterface *wRadioInterface,
|
||||||
@@ -152,7 +154,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
int mBasePort;
|
int mBasePort;
|
||||||
std::string mAddr;
|
std::string mLocalAddr;
|
||||||
|
std::string mRemoteAddr;
|
||||||
|
|
||||||
std::vector<UDPSocket *> mDataSockets; ///< socket for writing to/reading from GSM core
|
std::vector<UDPSocket *> mDataSockets; ///< socket for writing to/reading from GSM core
|
||||||
std::vector<UDPSocket *> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
|
std::vector<UDPSocket *> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
|
||||||
@@ -169,7 +172,7 @@ private:
|
|||||||
|
|
||||||
GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
|
GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
|
||||||
GSM::Time mLatencyUpdateTime; ///< last time latency was updated
|
GSM::Time mLatencyUpdateTime; ///< last time latency was updated
|
||||||
GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
|
GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
|
||||||
GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
|
GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
|
||||||
|
|
||||||
RadioInterface *mRadioInterface; ///< associated radioInterface object
|
RadioInterface *mRadioInterface; ///< associated radioInterface object
|
||||||
@@ -208,6 +211,7 @@ private:
|
|||||||
|
|
||||||
bool mEdge;
|
bool mEdge;
|
||||||
bool mOn; ///< flag to indicate that transceiver is powered on
|
bool mOn; ///< flag to indicate that transceiver is powered on
|
||||||
|
bool mForceClockInterface; ///< flag to indicate whether IND CLOCK shall be sent unconditionally after transceiver is started
|
||||||
bool mHandover[8][8]; ///< expect handover to the timeslot/subslot
|
bool mHandover[8][8]; ///< expect handover to the timeslot/subslot
|
||||||
double mTxFreq; ///< the transmit frequency
|
double mTxFreq; ///< the transmit frequency
|
||||||
double mRxFreq; ///< the receive frequency
|
double mRxFreq; ///< the receive frequency
|
||||||
@@ -275,4 +279,3 @@ void *ControlServiceLoopAdapter(TransceiverChannel *);
|
|||||||
|
|
||||||
/** transmit queueing thread loop */
|
/** transmit queueing thread loop */
|
||||||
void *TxUpperLoopAdapter(TransceiverChannel *);
|
void *TxUpperLoopAdapter(TransceiverChannel *);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Device support for Ettus Research UHD driver
|
* Device support for Ettus Research UHD driver
|
||||||
*
|
*
|
||||||
* Copyright 2010,2011 Free Software Foundation, Inc.
|
* Copyright 2010,2011 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 2015 Ettus Research LLC
|
* Copyright (C) 2015 Ettus Research LLC
|
||||||
@@ -130,7 +130,7 @@ static const std::map<dev_key, dev_desc> dev_param_map {
|
|||||||
{ std::make_tuple(UMTRX, 1, 1), { 2, 0.0, GSMRATE, 9.9692e-5, "UmTRX 1 SPS" } },
|
{ std::make_tuple(UMTRX, 1, 1), { 2, 0.0, GSMRATE, 9.9692e-5, "UmTRX 1 SPS" } },
|
||||||
{ std::make_tuple(UMTRX, 4, 1), { 2, 0.0, GSMRATE, 7.3846e-5, "UmTRX 4/1 Tx/Rx SPS"} },
|
{ std::make_tuple(UMTRX, 4, 1), { 2, 0.0, GSMRATE, 7.3846e-5, "UmTRX 4/1 Tx/Rx SPS"} },
|
||||||
{ std::make_tuple(UMTRX, 4, 4), { 2, 0.0, GSMRATE, 5.1503e-5, "UmTRX 4 SPS" } },
|
{ std::make_tuple(UMTRX, 4, 4), { 2, 0.0, GSMRATE, 5.1503e-5, "UmTRX 4 SPS" } },
|
||||||
{ std::make_tuple(LIMESDR, 4, 4), { 1, GSMRATE*32, GSMRATE, 16.5/GSMRATE, "STREAM/LimeSDR (4 SPS TX/RX)" } },
|
{ std::make_tuple(LIMESDR, 4, 4), { 1, GSMRATE*32, GSMRATE, 8.9e-5, "LimeSDR 4 SPS" } },
|
||||||
{ std::make_tuple(B2XX_MCBTS, 4, 4), { 1, 51.2e6, MCBTS_SPACING*4, B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" } },
|
{ std::make_tuple(B2XX_MCBTS, 4, 4), { 1, 51.2e6, MCBTS_SPACING*4, B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -143,8 +143,8 @@ class smpl_buf {
|
|||||||
public:
|
public:
|
||||||
/** Sample buffer constructor
|
/** Sample buffer constructor
|
||||||
@param len number of 32-bit samples the buffer should hold
|
@param len number of 32-bit samples the buffer should hold
|
||||||
@param rate sample clockrate
|
@param rate sample clockrate
|
||||||
@param timestamp
|
@param timestamp
|
||||||
*/
|
*/
|
||||||
smpl_buf(size_t len, double rate);
|
smpl_buf(size_t len, double rate);
|
||||||
~smpl_buf();
|
~smpl_buf();
|
||||||
@@ -172,7 +172,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::string str_status(size_t ts) const;
|
std::string str_status(size_t ts) const;
|
||||||
|
|
||||||
/** Formatted error string
|
/** Formatted error string
|
||||||
@param code an error code
|
@param code an error code
|
||||||
@return a formatted error string
|
@return a formatted error string
|
||||||
*/
|
*/
|
||||||
@@ -208,7 +208,9 @@ private:
|
|||||||
class uhd_device : public RadioDevice {
|
class uhd_device : public RadioDevice {
|
||||||
public:
|
public:
|
||||||
uhd_device(size_t tx_sps, size_t rx_sps, InterfaceType type,
|
uhd_device(size_t tx_sps, size_t rx_sps, InterfaceType type,
|
||||||
size_t chans, double offset);
|
size_t chans, double offset,
|
||||||
|
const std::vector<std::string>& tx_paths,
|
||||||
|
const std::vector<std::string>& rx_paths);
|
||||||
~uhd_device();
|
~uhd_device();
|
||||||
|
|
||||||
int open(const std::string &args, int ref, bool swap_channels);
|
int open(const std::string &args, int ref, bool swap_channels);
|
||||||
@@ -248,6 +250,11 @@ public:
|
|||||||
double getRxFreq(size_t chan);
|
double getRxFreq(size_t chan);
|
||||||
double getRxFreq();
|
double getRxFreq();
|
||||||
|
|
||||||
|
bool setRxAntenna(const std::string &ant, size_t chan);
|
||||||
|
std::string getRxAntenna(size_t chan);
|
||||||
|
bool setTxAntenna(const std::string &ant, size_t chan);
|
||||||
|
std::string getTxAntenna(size_t chan);
|
||||||
|
|
||||||
inline double getSampleRate() { return tx_rate; }
|
inline double getSampleRate() { return tx_rate; }
|
||||||
inline double numberRead() { return rx_pkt_cnt; }
|
inline double numberRead() { return rx_pkt_cnt; }
|
||||||
inline double numberWritten() { return 0; }
|
inline double numberWritten() { return 0; }
|
||||||
@@ -280,6 +287,7 @@ private:
|
|||||||
|
|
||||||
std::vector<double> tx_gains, rx_gains;
|
std::vector<double> tx_gains, rx_gains;
|
||||||
std::vector<double> tx_freqs, rx_freqs;
|
std::vector<double> tx_freqs, rx_freqs;
|
||||||
|
std::vector<std::string> tx_paths, rx_paths;
|
||||||
size_t tx_spp, rx_spp;
|
size_t tx_spp, rx_spp;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
@@ -295,6 +303,7 @@ private:
|
|||||||
void init_gains();
|
void init_gains();
|
||||||
void set_channels(bool swap);
|
void set_channels(bool swap);
|
||||||
void set_rates();
|
void set_rates();
|
||||||
|
bool set_antennas();
|
||||||
bool parse_dev_type();
|
bool parse_dev_type();
|
||||||
bool flush_recv(size_t num_pkts);
|
bool flush_recv(size_t num_pkts);
|
||||||
int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls);
|
int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls);
|
||||||
@@ -353,18 +362,22 @@ static void thread_enable_cancel(bool cancel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uhd_device::uhd_device(size_t tx_sps, size_t rx_sps,
|
uhd_device::uhd_device(size_t tx_sps, size_t rx_sps,
|
||||||
InterfaceType iface, size_t chans, double offset)
|
InterfaceType iface, size_t chans, double offset,
|
||||||
|
const std::vector<std::string>& tx_paths,
|
||||||
|
const std::vector<std::string>& rx_paths)
|
||||||
: tx_gain_min(0.0), tx_gain_max(0.0),
|
: tx_gain_min(0.0), tx_gain_max(0.0),
|
||||||
rx_gain_min(0.0), rx_gain_max(0.0),
|
rx_gain_min(0.0), rx_gain_max(0.0),
|
||||||
tx_spp(0), rx_spp(0),
|
tx_spp(0), rx_spp(0),
|
||||||
started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
|
started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
|
||||||
prev_ts(0,0), ts_initial(0), ts_offset(0)
|
prev_ts(0,0), ts_initial(0), ts_offset(0), async_event_thrd(NULL)
|
||||||
{
|
{
|
||||||
this->tx_sps = tx_sps;
|
this->tx_sps = tx_sps;
|
||||||
this->rx_sps = rx_sps;
|
this->rx_sps = rx_sps;
|
||||||
this->chans = chans;
|
this->chans = chans;
|
||||||
this->offset = offset;
|
this->offset = offset;
|
||||||
this->iface = iface;
|
this->iface = iface;
|
||||||
|
this->tx_paths = tx_paths;
|
||||||
|
this->rx_paths = rx_paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
uhd_device::~uhd_device()
|
uhd_device::~uhd_device()
|
||||||
@@ -437,10 +450,37 @@ void uhd_device::set_rates()
|
|||||||
tx_rate = usrp_dev->get_tx_rate();
|
tx_rate = usrp_dev->get_tx_rate();
|
||||||
rx_rate = usrp_dev->get_rx_rate();
|
rx_rate = usrp_dev->get_rx_rate();
|
||||||
|
|
||||||
ts_offset = (TIMESTAMP) desc.offset * rx_rate;
|
ts_offset = static_cast<TIMESTAMP>(desc.offset * rx_rate);
|
||||||
LOG(INFO) << "Rates configured for " << desc.str;
|
LOG(INFO) << "Rates configured for " << desc.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool uhd_device::set_antennas()
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < tx_paths.size(); i++) {
|
||||||
|
if (tx_paths[i] == "")
|
||||||
|
continue;
|
||||||
|
LOG(DEBUG) << "Configuring channel " << i << " with antenna " << tx_paths[i];
|
||||||
|
if (!setTxAntenna(tx_paths[i], i)) {
|
||||||
|
LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << tx_paths[i];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < rx_paths.size(); i++) {
|
||||||
|
if (rx_paths[i] == "")
|
||||||
|
continue;
|
||||||
|
LOG(DEBUG) << "Configuring channel " << i << " with antenna " << rx_paths[i];
|
||||||
|
if (!setRxAntenna(rx_paths[i], i)) {
|
||||||
|
LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << rx_paths[i];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Antennas configured successfully";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
double uhd_device::setTxGain(double db, size_t chan)
|
double uhd_device::setTxGain(double db, size_t chan)
|
||||||
{
|
{
|
||||||
if (iface == MULTI_ARFCN)
|
if (iface == MULTI_ARFCN)
|
||||||
@@ -519,6 +559,7 @@ bool uhd_device::parse_dev_type()
|
|||||||
{ "B100", { B100, TX_WINDOW_USRP1 } },
|
{ "B100", { B100, TX_WINDOW_USRP1 } },
|
||||||
{ "B200", { B200, TX_WINDOW_USRP1 } },
|
{ "B200", { B200, TX_WINDOW_USRP1 } },
|
||||||
{ "B200mini", { B200, TX_WINDOW_USRP1 } },
|
{ "B200mini", { B200, TX_WINDOW_USRP1 } },
|
||||||
|
{ "B205mini", { B200, TX_WINDOW_USRP1 } },
|
||||||
{ "B210", { B210, TX_WINDOW_USRP1 } },
|
{ "B210", { B210, TX_WINDOW_USRP1 } },
|
||||||
{ "E100", { E1XX, TX_WINDOW_FIXED } },
|
{ "E100", { E1XX, TX_WINDOW_FIXED } },
|
||||||
{ "E110", { E1XX, TX_WINDOW_FIXED } },
|
{ "E110", { E1XX, TX_WINDOW_FIXED } },
|
||||||
@@ -526,25 +567,25 @@ bool uhd_device::parse_dev_type()
|
|||||||
{ "E3XX", { E3XX, TX_WINDOW_FIXED } },
|
{ "E3XX", { E3XX, TX_WINDOW_FIXED } },
|
||||||
{ "X300", { X3XX, TX_WINDOW_FIXED } },
|
{ "X300", { X3XX, TX_WINDOW_FIXED } },
|
||||||
{ "X310", { X3XX, TX_WINDOW_FIXED } },
|
{ "X310", { X3XX, TX_WINDOW_FIXED } },
|
||||||
|
{ "USRP2", { USRP2, TX_WINDOW_FIXED } },
|
||||||
{ "UmTRX", { UMTRX, TX_WINDOW_FIXED } },
|
{ "UmTRX", { UMTRX, TX_WINDOW_FIXED } },
|
||||||
{ "STREAM", { LIMESDR, TX_WINDOW_USRP1 } },
|
{ "LimeSDR", { LIMESDR, TX_WINDOW_FIXED } },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compare UHD motherboard and device strings */
|
// Compare UHD motherboard and device strings */
|
||||||
std::string found;
|
auto mapIter = devStringMap.begin();
|
||||||
if (devStringMap.find(devString) != devStringMap.end())
|
while (mapIter != devStringMap.end()) {
|
||||||
found = devString;
|
if (devString.find(mapIter->first) != std::string::npos ||
|
||||||
else if (devStringMap.find(mboardString) != devStringMap.end())
|
mboardString.find(mapIter->first) != std::string::npos) {
|
||||||
found = mboardString;
|
dev_type = std::get<0>(mapIter->second);
|
||||||
|
tx_window = std::get<1>(mapIter->second);
|
||||||
if (found.empty()) {
|
return true;
|
||||||
LOG(ALERT) << "Unsupported device " << devString;
|
}
|
||||||
return false;
|
mapIter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_type = devStringMap.at(found).first;
|
LOG(ALERT) << "Unsupported device " << devString;
|
||||||
tx_window = devStringMap.at(found).second;
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -576,7 +617,7 @@ void uhd_device::set_channels(bool swap)
|
|||||||
chans = 1;
|
chans = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chans > dev_param_map.at(dev_key(dev_type, 1, 1)).channels)
|
if (chans > dev_param_map.at(dev_key(dev_type, tx_sps, rx_sps)).channels)
|
||||||
throw std::invalid_argument("Device does not support number of requested channels");
|
throw std::invalid_argument("Device does not support number of requested channels");
|
||||||
|
|
||||||
std::string subdev_string;
|
std::string subdev_string;
|
||||||
@@ -643,6 +684,11 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!set_antennas()) {
|
||||||
|
LOG(ALERT) << "UHD antenna setting failed";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
tx_freqs.resize(chans);
|
tx_freqs.resize(chans);
|
||||||
rx_freqs.resize(chans);
|
rx_freqs.resize(chans);
|
||||||
tx_gains.resize(chans);
|
tx_gains.resize(chans);
|
||||||
@@ -704,7 +750,7 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
|
|||||||
for (size_t i = 0; i < rx_buffers.size(); i++)
|
for (size_t i = 0; i < rx_buffers.size(); i++)
|
||||||
rx_buffers[i] = new smpl_buf(buf_len, rx_rate);
|
rx_buffers[i] = new smpl_buf(buf_len, rx_rate);
|
||||||
|
|
||||||
// Initialize and shadow gain values
|
// Initialize and shadow gain values
|
||||||
init_gains();
|
init_gains();
|
||||||
|
|
||||||
// Print configuration
|
// Print configuration
|
||||||
@@ -925,7 +971,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
|||||||
|
|
||||||
rx_pkt_cnt++;
|
rx_pkt_cnt++;
|
||||||
|
|
||||||
// Check for errors
|
// Check for errors
|
||||||
rc = check_rx_md_err(metadata, num_smpls);
|
rc = check_rx_md_err(metadata, num_smpls);
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case ERROR_UNRECOVERABLE:
|
case ERROR_UNRECOVERABLE:
|
||||||
@@ -1069,7 +1115,7 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
|
|||||||
|
|
||||||
/* Find center frequency between channels */
|
/* Find center frequency between channels */
|
||||||
rf_spread = fabs(freqs[!chan] - freq);
|
rf_spread = fabs(freqs[!chan] - freq);
|
||||||
if (rf_spread > dev_param_map.at(dev_key(B210, 1, 1)).mcr) {
|
if (rf_spread > dev_param_map.at(dev_key(B210, tx_sps, rx_sps)).mcr) {
|
||||||
LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n";
|
LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n";
|
||||||
return treq;
|
return treq;
|
||||||
}
|
}
|
||||||
@@ -1164,6 +1210,78 @@ double uhd_device::getRxFreq(size_t chan)
|
|||||||
return rx_freqs[chan];
|
return rx_freqs[chan];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool uhd_device::setRxAntenna(const std::string &ant, size_t chan)
|
||||||
|
{
|
||||||
|
std::vector<std::string> avail;
|
||||||
|
if (chan >= rx_paths.size()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
avail = usrp_dev->get_rx_antennas(chan);
|
||||||
|
if (std::find(avail.begin(), avail.end(), ant) == avail.end()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent Rx antenna " << ant << " on channel " << chan;
|
||||||
|
LOG(INFO) << "Available Rx antennas: ";
|
||||||
|
for (std::vector<std::string>::const_iterator i = avail.begin(); i != avail.end(); ++i)
|
||||||
|
LOG(INFO) << "- '" << *i << "'";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
usrp_dev->set_rx_antenna(ant, chan);
|
||||||
|
rx_paths[chan] = usrp_dev->get_rx_antenna(chan);
|
||||||
|
|
||||||
|
if (ant != rx_paths[chan]) {
|
||||||
|
LOG(ALERT) << "Failed setting antenna " << ant << " on channel " << chan << ", got instead " << rx_paths[chan];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string uhd_device::getRxAntenna(size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= rx_paths.size()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return usrp_dev->get_rx_antenna(chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhd_device::setTxAntenna(const std::string &ant, size_t chan)
|
||||||
|
{
|
||||||
|
std::vector<std::string> avail;
|
||||||
|
if (chan >= tx_paths.size()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
avail = usrp_dev->get_tx_antennas(chan);
|
||||||
|
if (std::find(avail.begin(), avail.end(), ant) == avail.end()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent Tx antenna " << ant << " on channel " << chan;
|
||||||
|
LOG(INFO) << "Available Tx antennas: ";
|
||||||
|
for (std::vector<std::string>::const_iterator i = avail.begin(); i != avail.end(); ++i)
|
||||||
|
LOG(INFO) << "- '" << *i << "'";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
usrp_dev->set_tx_antenna(ant, chan);
|
||||||
|
tx_paths[chan] = usrp_dev->get_tx_antenna(chan);
|
||||||
|
|
||||||
|
if (ant != tx_paths[chan]) {
|
||||||
|
LOG(ALERT) << "Failed setting antenna " << ant << " on channel " << chan << ", got instead " << tx_paths[chan];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string uhd_device::getTxAntenna(size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= tx_paths.size()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return usrp_dev->get_tx_antenna(chan);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only allow sampling the Rx path lower than Tx and not vice-versa.
|
* Only allow sampling the Rx path lower than Tx and not vice-versa.
|
||||||
* Using Tx with 4 SPS and Rx at 1 SPS is the only allowed mixed
|
* Using Tx with 4 SPS and Rx at 1 SPS is the only allowed mixed
|
||||||
@@ -1185,7 +1303,7 @@ TIMESTAMP uhd_device::initialReadTimestamp()
|
|||||||
double uhd_device::fullScaleInputValue()
|
double uhd_device::fullScaleInputValue()
|
||||||
{
|
{
|
||||||
if (dev_type == LIMESDR)
|
if (dev_type == LIMESDR)
|
||||||
return (double) 2047 * LIMESDR_TX_AMPL;
|
return (double) SHRT_MAX * LIMESDR_TX_AMPL;
|
||||||
if (dev_type == UMTRX)
|
if (dev_type == UMTRX)
|
||||||
return (double) SHRT_MAX * UMTRX_TX_AMPL;
|
return (double) SHRT_MAX * UMTRX_TX_AMPL;
|
||||||
else
|
else
|
||||||
@@ -1194,7 +1312,6 @@ double uhd_device::fullScaleInputValue()
|
|||||||
|
|
||||||
double uhd_device::fullScaleOutputValue()
|
double uhd_device::fullScaleOutputValue()
|
||||||
{
|
{
|
||||||
if (dev_type == LIMESDR) return (double) 2047;
|
|
||||||
return (double) SHRT_MAX;
|
return (double) SHRT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1451,7 +1568,9 @@ std::string smpl_buf::str_code(ssize_t code)
|
|||||||
}
|
}
|
||||||
|
|
||||||
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
|
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
|
||||||
InterfaceType iface, size_t chans, double offset)
|
InterfaceType iface, size_t chans, double offset,
|
||||||
|
const std::vector<std::string>& tx_paths,
|
||||||
|
const std::vector<std::string>& rx_paths)
|
||||||
{
|
{
|
||||||
return new uhd_device(tx_sps, rx_sps, iface, chans, offset);
|
return new uhd_device(tx_sps, rx_sps, iface, chans, offset, tx_paths, rx_paths);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,17 +27,16 @@
|
|||||||
Compilation Flags
|
Compilation Flags
|
||||||
|
|
||||||
SWLOOPBACK compile for software loopback testing
|
SWLOOPBACK compile for software loopback testing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "Logger.h"
|
||||||
#include "Threads.h"
|
#include "Threads.h"
|
||||||
#include "USRPDevice.h"
|
#include "USRPDevice.h"
|
||||||
|
|
||||||
#include <Logger.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -81,7 +80,7 @@ USRPDevice::USRPDevice(size_t sps)
|
|||||||
else
|
else
|
||||||
pingOffset = 0;
|
pingOffset = 0;
|
||||||
|
|
||||||
#ifdef SWLOOPBACK
|
#ifdef SWLOOPBACK
|
||||||
samplePeriod = 1.0e6/actualSampleRate;
|
samplePeriod = 1.0e6/actualSampleRate;
|
||||||
loopbackBufferSize = 0;
|
loopbackBufferSize = 0;
|
||||||
gettimeofday(&lastReadTime,NULL);
|
gettimeofday(&lastReadTime,NULL);
|
||||||
@@ -94,9 +93,9 @@ int USRPDevice::open(const std::string &, int, bool)
|
|||||||
writeLock.unlock();
|
writeLock.unlock();
|
||||||
|
|
||||||
LOG(INFO) << "opening USRP device..";
|
LOG(INFO) << "opening USRP device..";
|
||||||
#ifndef SWLOOPBACK
|
#ifndef SWLOOPBACK
|
||||||
string rbf = "std_inband.rbf";
|
string rbf = "std_inband.rbf";
|
||||||
//string rbf = "inband_1rxhb_1tx.rbf";
|
//string rbf = "inband_1rxhb_1tx.rbf";
|
||||||
m_uRx.reset();
|
m_uRx.reset();
|
||||||
if (!skipRx) {
|
if (!skipRx) {
|
||||||
try {
|
try {
|
||||||
@@ -145,7 +144,7 @@ int USRPDevice::open(const std::string &, int, bool)
|
|||||||
|
|
||||||
if (!skipRx) m_uRx->stop();
|
if (!skipRx) m_uRx->stop();
|
||||||
m_uTx->stop();
|
m_uTx->stop();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (dboardConfig) {
|
switch (dboardConfig) {
|
||||||
@@ -176,19 +175,19 @@ int USRPDevice::open(const std::string &, int, bool)
|
|||||||
samplesRead = 0;
|
samplesRead = 0;
|
||||||
samplesWritten = 0;
|
samplesWritten = 0;
|
||||||
started = false;
|
started = false;
|
||||||
|
|
||||||
return NORMAL;
|
return NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool USRPDevice::start()
|
bool USRPDevice::start()
|
||||||
{
|
{
|
||||||
LOG(INFO) << "starting USRP...";
|
LOG(INFO) << "starting USRP...";
|
||||||
#ifndef SWLOOPBACK
|
#ifndef SWLOOPBACK
|
||||||
if (!m_uRx && !skipRx) return false;
|
if (!m_uRx && !skipRx) return false;
|
||||||
if (!m_uTx) return false;
|
if (!m_uTx) return false;
|
||||||
|
|
||||||
if (!skipRx) m_uRx->stop();
|
if (!skipRx) m_uRx->stop();
|
||||||
m_uTx->stop();
|
m_uTx->stop();
|
||||||
|
|
||||||
@@ -218,8 +217,8 @@ bool USRPDevice::start()
|
|||||||
hi32Timestamp = 0;
|
hi32Timestamp = 0;
|
||||||
isAligned = false;
|
isAligned = false;
|
||||||
|
|
||||||
|
|
||||||
if (!skipRx)
|
if (!skipRx)
|
||||||
started = (m_uRx->start() && m_uTx->start());
|
started = (m_uRx->start() && m_uTx->start());
|
||||||
else
|
else
|
||||||
started = m_uTx->start();
|
started = m_uTx->start();
|
||||||
@@ -230,14 +229,14 @@ bool USRPDevice::start()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USRPDevice::stop()
|
bool USRPDevice::stop()
|
||||||
{
|
{
|
||||||
#ifndef SWLOOPBACK
|
#ifndef SWLOOPBACK
|
||||||
if (!m_uRx) return false;
|
if (!m_uRx) return false;
|
||||||
if (!m_uTx) return false;
|
if (!m_uTx) return false;
|
||||||
|
|
||||||
delete[] currData;
|
delete[] currData;
|
||||||
|
|
||||||
started = !(m_uRx->stop() && m_uTx->stop());
|
started = !(m_uRx->stop() && m_uTx->stop());
|
||||||
return !started;
|
return !started;
|
||||||
#else
|
#else
|
||||||
@@ -258,7 +257,7 @@ double USRPDevice::minTxGain()
|
|||||||
double USRPDevice::maxRxGain()
|
double USRPDevice::maxRxGain()
|
||||||
{
|
{
|
||||||
return m_dbRx->gain_max();
|
return m_dbRx->gain_max();
|
||||||
}
|
}
|
||||||
|
|
||||||
double USRPDevice::minRxGain()
|
double USRPDevice::minRxGain()
|
||||||
{
|
{
|
||||||
@@ -314,28 +313,68 @@ double USRPDevice::setRxGain(double dB, size_t chan)
|
|||||||
return dB;
|
return dB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool USRPDevice::setRxAntenna(const std::string &ant, size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= rx_paths.size()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG(ALERT) << "Not implemented";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string USRPDevice::getRxAntenna(size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= rx_paths.size()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
LOG(ALERT) << "Not implemented";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USRPDevice::setTxAntenna(const std::string &ant, size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= tx_paths.size()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG(ALERT) << "Not implemented";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string USRPDevice::getTxAntenna(size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= tx_paths.size()) {
|
||||||
|
LOG(ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
LOG(ALERT) << "Not implemented";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOTE: Assumes sequential reads
|
// NOTE: Assumes sequential reads
|
||||||
int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
||||||
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
|
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
|
||||||
{
|
{
|
||||||
#ifndef SWLOOPBACK
|
#ifndef SWLOOPBACK
|
||||||
if (!m_uRx)
|
if (!m_uRx)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
short *buf = bufs[0];
|
short *buf = bufs[0];
|
||||||
|
|
||||||
timestamp += timestampOffset;
|
timestamp += timestampOffset;
|
||||||
|
|
||||||
if (timestamp + len < timeStart) {
|
if (timestamp + len < timeStart) {
|
||||||
memset(buf,0,len*2*sizeof(short));
|
memset(buf,0,len*2*sizeof(short));
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (underrun) *underrun = false;
|
if (underrun) *underrun = false;
|
||||||
|
|
||||||
uint32_t readBuf[2000];
|
uint32_t readBuf[2000];
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
//guestimate USB read size
|
//guestimate USB read size
|
||||||
int readLen=0;
|
int readLen=0;
|
||||||
@@ -345,7 +384,7 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
|||||||
readLen = 512 * ((int) ceil((float) numSamplesNeeded/126.0));
|
readLen = 512 * ((int) ceil((float) numSamplesNeeded/126.0));
|
||||||
if (readLen > 8000) readLen= (8000/512)*512;
|
if (readLen > 8000) readLen= (8000/512)*512;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read USRP packets, parse and save A/D data as needed
|
// read USRP packets, parse and save A/D data as needed
|
||||||
readLen = m_uRx->read((void *)readBuf,readLen,overrun);
|
readLen = m_uRx->read((void *)readBuf,readLen,overrun);
|
||||||
for(int pktNum = 0; pktNum < (readLen/512); pktNum++) {
|
for(int pktNum = 0; pktNum < (readLen/512); pktNum++) {
|
||||||
@@ -382,13 +421,13 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((word0 >> 28) & 0x04) {
|
if ((word0 >> 28) & 0x04) {
|
||||||
if (underrun) *underrun = true;
|
if (underrun) *underrun = true;
|
||||||
LOG(DEBUG) << "UNDERRUN in TRX->USRP interface";
|
LOG(DEBUG) << "UNDERRUN in TRX->USRP interface";
|
||||||
}
|
}
|
||||||
if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
|
if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
|
||||||
|
|
||||||
if (!isAligned) continue;
|
if (!isAligned) continue;
|
||||||
|
|
||||||
unsigned cursorStart = pktTimestamp - timeStart + dataStart;
|
unsigned cursorStart = pktTimestamp - timeStart + dataStart;
|
||||||
while (cursorStart*2 > currDataSize) {
|
while (cursorStart*2 > currDataSize) {
|
||||||
cursorStart -= currDataSize/2;
|
cursorStart -= currDataSize/2;
|
||||||
@@ -401,17 +440,17 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
|||||||
else {
|
else {
|
||||||
memcpy(data+cursorStart*2,tmpBuf+2,payloadSz);
|
memcpy(data+cursorStart*2,tmpBuf+2,payloadSz);
|
||||||
}
|
}
|
||||||
if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd)
|
if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd)
|
||||||
timeEnd = pktTimestamp+payloadSz/2/sizeof(short);
|
timeEnd = pktTimestamp+payloadSz/2/sizeof(short);
|
||||||
|
|
||||||
LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp;
|
LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy desired data to buf
|
// copy desired data to buf
|
||||||
unsigned bufStart = dataStart+(timestamp-timeStart);
|
unsigned bufStart = dataStart+(timestamp-timeStart);
|
||||||
if (bufStart + len < currDataSize/2) {
|
if (bufStart + len < currDataSize/2) {
|
||||||
LOG(DEBUG) << "bufStart: " << bufStart;
|
LOG(DEBUG) << "bufStart: " << bufStart;
|
||||||
memcpy(buf,data+bufStart*2,len*2*sizeof(short));
|
memcpy(buf,data+bufStart*2,len*2*sizeof(short));
|
||||||
memset(data+bufStart*2,0,len*2*sizeof(short));
|
memset(data+bufStart*2,0,len*2*sizeof(short));
|
||||||
@@ -429,21 +468,21 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
|||||||
timeStart = timestamp + len;
|
timeStart = timestamp + len;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
if (loopbackBufferSize < 2) return 0;
|
if (loopbackBufferSize < 2) return 0;
|
||||||
int numSamples = 0;
|
int numSamples = 0;
|
||||||
struct timeval currTime;
|
struct timeval currTime;
|
||||||
gettimeofday(&currTime,NULL);
|
gettimeofday(&currTime,NULL);
|
||||||
double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 +
|
double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 +
|
||||||
(currTime.tv_usec - lastReadTime.tv_usec);
|
(currTime.tv_usec - lastReadTime.tv_usec);
|
||||||
if (timeElapsed < samplePeriod) {return 0;}
|
if (timeElapsed < samplePeriod) {return 0;}
|
||||||
int numSamplesToRead = (int) floor(timeElapsed/samplePeriod);
|
int numSamplesToRead = (int) floor(timeElapsed/samplePeriod);
|
||||||
if (numSamplesToRead < len) return 0;
|
if (numSamplesToRead < len) return 0;
|
||||||
|
|
||||||
if (numSamplesToRead > len) numSamplesToRead = len;
|
if (numSamplesToRead > len) numSamplesToRead = len;
|
||||||
if (numSamplesToRead > loopbackBufferSize/2) {
|
if (numSamplesToRead > loopbackBufferSize/2) {
|
||||||
firstRead =false;
|
firstRead =false;
|
||||||
numSamplesToRead = loopbackBufferSize/2;
|
numSamplesToRead = loopbackBufferSize/2;
|
||||||
}
|
}
|
||||||
memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead);
|
memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead);
|
||||||
@@ -461,7 +500,7 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
|||||||
firstRead = true;
|
firstRead = true;
|
||||||
}
|
}
|
||||||
samplesRead += numSamples;
|
samplesRead += numSamples;
|
||||||
|
|
||||||
return numSamples;
|
return numSamples;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -472,7 +511,7 @@ int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
|
|||||||
{
|
{
|
||||||
writeLock.lock();
|
writeLock.lock();
|
||||||
|
|
||||||
#ifndef SWLOOPBACK
|
#ifndef SWLOOPBACK
|
||||||
if (!m_uTx)
|
if (!m_uTx)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -519,14 +558,14 @@ int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
|
|||||||
memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len);
|
memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len);
|
||||||
samplesWritten += retVal;
|
samplesWritten += retVal;
|
||||||
loopbackBufferSize += retVal*2;
|
loopbackBufferSize += retVal*2;
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
|
bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
|
||||||
{
|
{
|
||||||
#ifndef SWLOOPBACK
|
#ifndef SWLOOPBACK
|
||||||
short data[] = {0x00,0x02,0x00,0x00};
|
short data[] = {0x00,0x02,0x00,0x00};
|
||||||
uint32_t *wordPtr = (uint32_t *) data;
|
uint32_t *wordPtr = (uint32_t *) data;
|
||||||
*wordPtr = host_to_usrp_u32(*wordPtr);
|
*wordPtr = host_to_usrp_u32(*wordPtr);
|
||||||
@@ -543,7 +582,7 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SWLOOPBACK
|
#ifndef SWLOOPBACK
|
||||||
bool USRPDevice::setTxFreq(double wFreq, size_t chan)
|
bool USRPDevice::setTxFreq(double wFreq, size_t chan)
|
||||||
{
|
{
|
||||||
usrp_tune_result result;
|
usrp_tune_result result;
|
||||||
@@ -601,7 +640,9 @@ bool USRPDevice::setRxFreq(double wFreq) { return true;};
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
|
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
|
||||||
size_t chans, double)
|
InterfaceType iface, size_t chans, double offset,
|
||||||
|
const std::vector<std::string>& tx_paths,
|
||||||
|
const std::vector<std::string>& rx_paths)
|
||||||
{
|
{
|
||||||
return new USRPDevice(tx_sps);
|
return new USRPDevice(tx_sps);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ private:
|
|||||||
|
|
||||||
double rxGain;
|
double rxGain;
|
||||||
|
|
||||||
#ifdef SWLOOPBACK
|
#ifdef SWLOOPBACK
|
||||||
short loopbackBuffer[1000000];
|
short loopbackBuffer[1000000];
|
||||||
int loopbackBufferSize;
|
int loopbackBufferSize;
|
||||||
double samplePeriod;
|
double samplePeriod;
|
||||||
|
|
||||||
struct timeval startTime;
|
struct timeval startTime;
|
||||||
struct timeval lastReadTime;
|
struct timeval lastReadTime;
|
||||||
@@ -179,6 +179,18 @@ private:
|
|||||||
/** return minimum Rx Gain **/
|
/** return minimum Rx Gain **/
|
||||||
double minTxGain(void);
|
double minTxGain(void);
|
||||||
|
|
||||||
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
||||||
|
bool setRxAntenna(const std::string &ant, size_t chan = 0);
|
||||||
|
|
||||||
|
/* return the used RX path */
|
||||||
|
std::string getRxAntenna(size_t chan = 0);
|
||||||
|
|
||||||
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
||||||
|
bool setTxAntenna(const std::string &ant, size_t chan = 0);
|
||||||
|
|
||||||
|
/* return the used RX path */
|
||||||
|
std::string getTxAntenna(size_t chan = 0);
|
||||||
|
|
||||||
/** Return internal status values */
|
/** Return internal status values */
|
||||||
inline double getTxFreq(size_t chan = 0) { return 0; }
|
inline double getTxFreq(size_t chan = 0) { return 0; }
|
||||||
inline double getRxFreq(size_t chan = 0) { return 0; }
|
inline double getRxFreq(size_t chan = 0) { return 0; }
|
||||||
@@ -186,7 +198,7 @@ private:
|
|||||||
inline double numberRead() { return samplesRead; }
|
inline double numberRead() { return samplesRead; }
|
||||||
inline double numberWritten() { return samplesWritten; }
|
inline double numberWritten() { return samplesWritten; }
|
||||||
|
|
||||||
|
std::vector<std::string> tx_paths, rx_paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _USRP_DEVICE_H_
|
#endif // _USRP_DEVICE_H_
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,9 @@
|
|||||||
void neon_convert_ps_si16_4n(short *, const float *, const float *, int);
|
void neon_convert_ps_si16_4n(short *, const float *, const float *, int);
|
||||||
void neon_convert_si16_ps_4n(float *, const short *, int);
|
void neon_convert_si16_ps_4n(float *, const short *, int);
|
||||||
|
|
||||||
|
void convert_init(void) {
|
||||||
|
}
|
||||||
|
|
||||||
/* 4*N 16-bit signed integer conversion with remainder */
|
/* 4*N 16-bit signed integer conversion with remainder */
|
||||||
static void neon_convert_si16_ps(float *out,
|
static void neon_convert_si16_ps(float *out,
|
||||||
const short *in,
|
const short *in,
|
||||||
@@ -54,7 +57,6 @@ static void neon_convert_ps_si16(short *out,
|
|||||||
for (int i = 0; i < len % 4; i++)
|
for (int i = 0; i < len % 4; i++)
|
||||||
out[start + i] = (short) (in[start + i] * (*scale));
|
out[start + i] = (short) (in[start + i] * (*scale));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void convert_float_short(short *out, const float *in, float scale, int len)
|
void convert_float_short(short *out, const float *in, float scale, int len)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,10 +27,14 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <GSMCommon.h>
|
#include <GSMCommon.h>
|
||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
#include <Configuration.h>
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "convolve.h"
|
#include "convolve.h"
|
||||||
@@ -61,7 +65,8 @@ extern "C" {
|
|||||||
|
|
||||||
struct trx_config {
|
struct trx_config {
|
||||||
std::string log_level;
|
std::string log_level;
|
||||||
std::string addr;
|
std::string local_addr;
|
||||||
|
std::string remote_addr;
|
||||||
std::string dev_args;
|
std::string dev_args;
|
||||||
unsigned port;
|
unsigned port;
|
||||||
unsigned tx_sps;
|
unsigned tx_sps;
|
||||||
@@ -77,10 +82,11 @@ struct trx_config {
|
|||||||
double rssi_offset;
|
double rssi_offset;
|
||||||
bool swap_channels;
|
bool swap_channels;
|
||||||
bool edge;
|
bool edge;
|
||||||
|
int sched_rr;
|
||||||
|
std::vector<std::string> rx_paths;
|
||||||
|
std::vector<std::string> tx_paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigurationTable gConfig;
|
|
||||||
|
|
||||||
volatile bool gshutdown = false;
|
volatile bool gshutdown = false;
|
||||||
|
|
||||||
/* Setup configuration values
|
/* Setup configuration values
|
||||||
@@ -93,6 +99,7 @@ volatile bool gshutdown = false;
|
|||||||
bool trx_setup_config(struct trx_config *config)
|
bool trx_setup_config(struct trx_config *config)
|
||||||
{
|
{
|
||||||
std::string refstr, fillstr, divstr, mcstr, edgestr;
|
std::string refstr, fillstr, divstr, mcstr, edgestr;
|
||||||
|
std::vector<std::string>::const_iterator si;
|
||||||
|
|
||||||
if (config->mcbts && config->chans > 5) {
|
if (config->mcbts && config->chans > 5) {
|
||||||
std::cout << "Unsupported number of channels" << std::endl;
|
std::cout << "Unsupported number of channels" << std::endl;
|
||||||
@@ -132,7 +139,8 @@ bool trx_setup_config(struct trx_config *config)
|
|||||||
ost << " Log Level............... " << config->log_level << std::endl;
|
ost << " Log Level............... " << config->log_level << std::endl;
|
||||||
ost << " Device args............. " << config->dev_args << std::endl;
|
ost << " Device args............. " << config->dev_args << std::endl;
|
||||||
ost << " TRX Base Port........... " << config->port << std::endl;
|
ost << " TRX Base Port........... " << config->port << std::endl;
|
||||||
ost << " TRX Address............. " << config->addr << std::endl;
|
ost << " TRX Address............. " << config->local_addr << std::endl;
|
||||||
|
ost << " GSM Core Address........." << config->remote_addr << std::endl;
|
||||||
ost << " Channels................ " << config->chans << std::endl;
|
ost << " Channels................ " << config->chans << std::endl;
|
||||||
ost << " Tx Samples-per-Symbol... " << config->tx_sps << std::endl;
|
ost << " Tx Samples-per-Symbol... " << config->tx_sps << std::endl;
|
||||||
ost << " Rx Samples-per-Symbol... " << config->rx_sps << std::endl;
|
ost << " Rx Samples-per-Symbol... " << config->rx_sps << std::endl;
|
||||||
@@ -143,8 +151,16 @@ bool trx_setup_config(struct trx_config *config)
|
|||||||
ost << " Tuning offset........... " << config->offset << std::endl;
|
ost << " Tuning offset........... " << config->offset << std::endl;
|
||||||
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
|
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
|
||||||
ost << " Swap channels........... " << config->swap_channels << std::endl;
|
ost << " Swap channels........... " << config->swap_channels << std::endl;
|
||||||
std::cout << ost << std::endl;
|
ost << " Tx Antennas.............";
|
||||||
|
for (si = config->tx_paths.begin(); si != config->tx_paths.end(); ++si)
|
||||||
|
ost << " '" << ((*si != "") ? *si : "<default>") << "'";
|
||||||
|
ost << std::endl;
|
||||||
|
ost << " Rx Antennas.............";
|
||||||
|
for (si = config->rx_paths.begin(); si != config->rx_paths.end(); ++si)
|
||||||
|
ost << " '" << ((*si != "") ? *si : "<default>") << "'";
|
||||||
|
ost << std::endl;
|
||||||
|
|
||||||
|
std::cout << ost << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,9 +214,10 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio)
|
|||||||
Transceiver *trx;
|
Transceiver *trx;
|
||||||
VectorFIFO *fifo;
|
VectorFIFO *fifo;
|
||||||
|
|
||||||
trx = new Transceiver(config->port, config->addr.c_str(),
|
trx = new Transceiver(config->port, config->local_addr.c_str(),
|
||||||
config->tx_sps, config->rx_sps, config->chans,
|
config->remote_addr.c_str(), config->tx_sps,
|
||||||
GSM::Time(3,0), radio, config->rssi_offset);
|
config->rx_sps, config->chans, GSM::Time(3,0),
|
||||||
|
radio, config->rssi_offset);
|
||||||
if (!trx->init(config->filler, config->rtsc,
|
if (!trx->init(config->filler, config->rtsc,
|
||||||
config->rach_delay, config->edge)) {
|
config->rach_delay, config->edge)) {
|
||||||
LOG(ALERT) << "Failed to initialize transceiver";
|
LOG(ALERT) << "Failed to initialize transceiver";
|
||||||
@@ -239,6 +256,21 @@ static void setup_signal_handlers()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static std::vector<std::string> comma_delimited_to_vector(char* opt) {
|
||||||
|
std::string str = std::string(opt);
|
||||||
|
std::vector<std::string> result;
|
||||||
|
std::stringstream ss(str);
|
||||||
|
|
||||||
|
while( ss.good() )
|
||||||
|
{
|
||||||
|
std::string substr;
|
||||||
|
getline(ss, substr, ',');
|
||||||
|
result.push_back(substr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static void print_help()
|
static void print_help()
|
||||||
{
|
{
|
||||||
fprintf(stdout, "Options:\n"
|
fprintf(stdout, "Options:\n"
|
||||||
@@ -246,6 +278,7 @@ static void print_help()
|
|||||||
" -a UHD device args\n"
|
" -a UHD device args\n"
|
||||||
" -l Logging level (%s)\n"
|
" -l Logging level (%s)\n"
|
||||||
" -i IP address of GSM core\n"
|
" -i IP address of GSM core\n"
|
||||||
|
" -j IP address of osmo-trx\n"
|
||||||
" -p Base port number\n"
|
" -p Base port number\n"
|
||||||
" -e Enable EDGE receiver\n"
|
" -e Enable EDGE receiver\n"
|
||||||
" -m Enable multi-ARFCN transceiver (default=disabled)\n"
|
" -m Enable multi-ARFCN transceiver (default=disabled)\n"
|
||||||
@@ -259,16 +292,21 @@ static void print_help()
|
|||||||
" -r Random Normal Burst test mode with TSC\n"
|
" -r Random Normal Burst test mode with TSC\n"
|
||||||
" -A Random Access Burst test mode with delay\n"
|
" -A Random Access Burst test mode with delay\n"
|
||||||
" -R RSSI to dBm offset in dB (default=0)\n"
|
" -R RSSI to dBm offset in dB (default=0)\n"
|
||||||
" -S Swap channels (UmTRX only)\n",
|
" -S Swap channels (UmTRX only)\n"
|
||||||
|
" -t SCHED_RR real-time priority (1..32)\n"
|
||||||
|
" -y comma-delimited list of Tx paths (num elements matches -c)\n"
|
||||||
|
" -z comma-delimited list of Rx paths (num elements matches -c)\n",
|
||||||
"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
|
"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_options(int argc, char **argv, struct trx_config *config)
|
static void handle_options(int argc, char **argv, struct trx_config *config)
|
||||||
{
|
{
|
||||||
int option;
|
int option;
|
||||||
|
bool tx_path_set = false, rx_path_set = false;
|
||||||
|
|
||||||
config->log_level = "NOTICE";
|
config->log_level = "NOTICE";
|
||||||
config->addr = DEFAULT_TRX_IP;
|
config->local_addr = DEFAULT_TRX_IP;
|
||||||
|
config->remote_addr = DEFAULT_TRX_IP;
|
||||||
config->port = DEFAULT_TRX_PORT;
|
config->port = DEFAULT_TRX_PORT;
|
||||||
config->tx_sps = DEFAULT_TX_SPS;
|
config->tx_sps = DEFAULT_TX_SPS;
|
||||||
config->rx_sps = DEFAULT_RX_SPS;
|
config->rx_sps = DEFAULT_RX_SPS;
|
||||||
@@ -283,8 +321,11 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
|
|||||||
config->rssi_offset = 0.0;
|
config->rssi_offset = 0.0;
|
||||||
config->swap_channels = false;
|
config->swap_channels = false;
|
||||||
config->edge = false;
|
config->edge = false;
|
||||||
|
config->sched_rr = -1;
|
||||||
|
config->tx_paths = std::vector<std::string>(DEFAULT_CHANS, "");
|
||||||
|
config->rx_paths = std::vector<std::string>(DEFAULT_CHANS, "");
|
||||||
|
|
||||||
while ((option = getopt(argc, argv, "ha:l:i:p:c:dmxgfo:s:b:r:A:R:Se")) != -1) {
|
while ((option = getopt(argc, argv, "ha:l:i:j:p:c:dmxgfo:s:b:r:A:R:Set:y:z:")) != -1) {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case 'h':
|
case 'h':
|
||||||
print_help();
|
print_help();
|
||||||
@@ -297,7 +338,10 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
|
|||||||
config->log_level = optarg;
|
config->log_level = optarg;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
config->addr = optarg;
|
config->remote_addr = optarg;
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
config->local_addr = optarg;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
config->port = atoi(optarg);
|
config->port = atoi(optarg);
|
||||||
@@ -343,6 +387,17 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
|
|||||||
case 'e':
|
case 'e':
|
||||||
config->edge = true;
|
config->edge = true;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
config->sched_rr = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
config->tx_paths = comma_delimited_to_vector(optarg);
|
||||||
|
tx_path_set = true;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
config->rx_paths = comma_delimited_to_vector(optarg);
|
||||||
|
rx_path_set = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
print_help();
|
print_help();
|
||||||
exit(0);
|
exit(0);
|
||||||
@@ -379,6 +434,19 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
|
|||||||
goto bad_config;
|
goto bad_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!tx_path_set) {
|
||||||
|
config->tx_paths = std::vector<std::string>(config->chans, "");
|
||||||
|
} else if (config->tx_paths.size() != config->chans) {
|
||||||
|
printf("Num of channels and num of Tx Antennas doesn't match\n\n");
|
||||||
|
goto bad_config;
|
||||||
|
}
|
||||||
|
if (!rx_path_set) {
|
||||||
|
config->rx_paths = std::vector<std::string>(config->chans, "");
|
||||||
|
} else if (config->rx_paths.size() != config->chans) {
|
||||||
|
printf("Num of channels and num of Rx Antennas doesn't match\n\n");
|
||||||
|
goto bad_config;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bad_config:
|
bad_config:
|
||||||
@@ -386,6 +454,21 @@ bad_config:
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_sched_rr(int prio)
|
||||||
|
{
|
||||||
|
struct sched_param param;
|
||||||
|
int rc;
|
||||||
|
memset(¶m, 0, sizeof(param));
|
||||||
|
param.sched_priority = prio;
|
||||||
|
printf("Setting SCHED_RR priority(%d)\n", param.sched_priority);
|
||||||
|
rc = sched_setscheduler(getpid(), SCHED_RR, ¶m);
|
||||||
|
if (rc != 0) {
|
||||||
|
std::cerr << "Config: Setting SCHED_RR failed" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int type, chans, ref;
|
int type, chans, ref;
|
||||||
@@ -424,6 +507,11 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
handle_options(argc, argv, &config);
|
handle_options(argc, argv, &config);
|
||||||
|
|
||||||
|
if (config.sched_rr != -1) {
|
||||||
|
if (set_sched_rr(config.sched_rr) < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
setup_signal_handlers();
|
setup_signal_handlers();
|
||||||
|
|
||||||
/* Check database sanity */
|
/* Check database sanity */
|
||||||
@@ -432,7 +520,7 @@ int main(int argc, char *argv[])
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gLogInit("transceiver", config.log_level.c_str(), LOG_LOCAL7);
|
gLogInit(config.log_level.c_str());
|
||||||
|
|
||||||
srandom(time(NULL));
|
srandom(time(NULL));
|
||||||
|
|
||||||
@@ -448,7 +536,7 @@ int main(int argc, char *argv[])
|
|||||||
ref = RadioDevice::REF_INTERNAL;
|
ref = RadioDevice::REF_INTERNAL;
|
||||||
|
|
||||||
usrp = RadioDevice::make(config.tx_sps, config.rx_sps, iface,
|
usrp = RadioDevice::make(config.tx_sps, config.rx_sps, iface,
|
||||||
config.chans, config.offset);
|
config.chans, config.offset, config.tx_paths, config.rx_paths);
|
||||||
type = usrp->open(config.dev_args, ref, config.swap_channels);
|
type = usrp->open(config.dev_args, ref, config.swap_channels);
|
||||||
if (type < 0) {
|
if (type < 0) {
|
||||||
LOG(ALERT) << "Failed to create radio device" << std::endl;
|
LOG(ALERT) << "Failed to create radio device" << std::endl;
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ class RadioDevice {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static RadioDevice *make(size_t tx_sps, size_t rx_sps, InterfaceType type,
|
static RadioDevice *make(size_t tx_sps, size_t rx_sps, InterfaceType type,
|
||||||
size_t chans = 1, double offset = 0.0);
|
size_t chans = 1, double offset = 0.0,
|
||||||
|
const std::vector<std::string>& tx_paths = std::vector<std::string>(1, ""),
|
||||||
|
const std::vector<std::string>& rx_paths = std::vector<std::string>(1, ""));
|
||||||
|
|
||||||
/** Initialize the USRP */
|
/** Initialize the USRP */
|
||||||
virtual int open(const std::string &args, int ref, bool swap_channels)=0;
|
virtual int open(const std::string &args, int ref, bool swap_channels)=0;
|
||||||
@@ -136,6 +138,18 @@ class RadioDevice {
|
|||||||
/** return minimum Tx Gain **/
|
/** return minimum Tx Gain **/
|
||||||
virtual double minTxGain(void) = 0;
|
virtual double minTxGain(void) = 0;
|
||||||
|
|
||||||
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
||||||
|
virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) = 0;
|
||||||
|
|
||||||
|
/** return the used RX path */
|
||||||
|
virtual std::string getRxAntenna(size_t chan = 0) = 0;
|
||||||
|
|
||||||
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
||||||
|
virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) = 0;
|
||||||
|
|
||||||
|
/** return the used RX path */
|
||||||
|
virtual std::string getTxAntenna(size_t chan = 0) = 0;
|
||||||
|
|
||||||
/** Return internal status values */
|
/** Return internal status values */
|
||||||
virtual double getTxFreq(size_t chan = 0) = 0;
|
virtual double getTxFreq(size_t chan = 0) = 0;
|
||||||
virtual double getRxFreq(size_t chan = 0) = 0;
|
virtual double getRxFreq(size_t chan = 0) = 0;
|
||||||
|
|||||||
@@ -46,14 +46,10 @@ using namespace GSM;
|
|||||||
#define CLIP_THRESH 30000.0f
|
#define CLIP_THRESH 30000.0f
|
||||||
|
|
||||||
/** Lookup tables for trigonometric approximation */
|
/** Lookup tables for trigonometric approximation */
|
||||||
static float cosTable[TABLESIZE+1]; // add 1 element for wrap around
|
static float sincTable[TABLESIZE+1]; // add 1 element for wrap around
|
||||||
static float sinTable[TABLESIZE+1];
|
|
||||||
static float sincTable[TABLESIZE+1];
|
|
||||||
|
|
||||||
/** Constants */
|
/** Constants */
|
||||||
static const float M_PI_F = (float)M_PI;
|
static const float M_PI_F = (float)M_PI;
|
||||||
static const float M_2PI_F = (float)(2.0*M_PI);
|
|
||||||
static const float M_1_2PI_F = 1/M_2PI_F;
|
|
||||||
|
|
||||||
/* Precomputed rotation vectors */
|
/* Precomputed rotation vectors */
|
||||||
static signalVector *GMSKRotation4 = NULL;
|
static signalVector *GMSKRotation4 = NULL;
|
||||||
@@ -182,29 +178,6 @@ static float vectorNorm2(const signalVector &x)
|
|||||||
return Energy;
|
return Energy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** compute e^(-jx) via lookup table. */
|
|
||||||
static complex expjLookup(float x)
|
|
||||||
{
|
|
||||||
float arg = x*M_1_2PI_F;
|
|
||||||
while (arg > 1.0F) arg -= 1.0F;
|
|
||||||
while (arg < 0.0F) arg += 1.0F;
|
|
||||||
|
|
||||||
const float argT = arg*((float)TABLESIZE);
|
|
||||||
const int argI = (int)argT;
|
|
||||||
const float delta = argT-argI;
|
|
||||||
const float iDelta = 1.0F-delta;
|
|
||||||
return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
|
|
||||||
iDelta*sinTable[argI] + delta*sinTable[argI+1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Library setup functions */
|
|
||||||
static void initTrigTables() {
|
|
||||||
for (int i = 0; i < TABLESIZE+1; i++) {
|
|
||||||
cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
|
|
||||||
sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize 4 sps and 1 sps rotation tables
|
* Initialize 4 sps and 1 sps rotation tables
|
||||||
*/
|
*/
|
||||||
@@ -216,11 +189,11 @@ static void initGMSKRotationTables()
|
|||||||
GMSKReverseRotation4 = new signalVector(len4);
|
GMSKReverseRotation4 = new signalVector(len4);
|
||||||
signalVector::iterator rotPtr = GMSKRotation4->begin();
|
signalVector::iterator rotPtr = GMSKRotation4->begin();
|
||||||
signalVector::iterator revPtr = GMSKReverseRotation4->begin();
|
signalVector::iterator revPtr = GMSKReverseRotation4->begin();
|
||||||
float phase = 0.0;
|
auto phase = 0.0;
|
||||||
while (rotPtr != GMSKRotation4->end()) {
|
while (rotPtr != GMSKRotation4->end()) {
|
||||||
*rotPtr++ = expjLookup(phase);
|
*rotPtr++ = complex(cos(phase), sin(phase));
|
||||||
*revPtr++ = expjLookup(-phase);
|
*revPtr++ = complex(cos(-phase), sin(-phase));
|
||||||
phase += M_PI_F / 2.0F / 4.0;
|
phase += M_PI / 2.0 / 4.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GMSKRotation1 = new signalVector(len1);
|
GMSKRotation1 = new signalVector(len1);
|
||||||
@@ -229,9 +202,9 @@ static void initGMSKRotationTables()
|
|||||||
revPtr = GMSKReverseRotation1->begin();
|
revPtr = GMSKReverseRotation1->begin();
|
||||||
phase = 0.0;
|
phase = 0.0;
|
||||||
while (rotPtr != GMSKRotation1->end()) {
|
while (rotPtr != GMSKRotation1->end()) {
|
||||||
*rotPtr++ = expjLookup(phase);
|
*rotPtr++ = complex(cos(phase), sin(phase));
|
||||||
*revPtr++ = expjLookup(-phase);
|
*revPtr++ = complex(cos(-phase), sin(-phase));
|
||||||
phase += M_PI_F / 2.0F;
|
phase += M_PI / 2.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,7 +558,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
|
|||||||
int guardPeriodLength, int sps)
|
int guardPeriodLength, int sps)
|
||||||
{
|
{
|
||||||
int burst_len;
|
int burst_len;
|
||||||
signalVector *pulse, rotated, *shaped;
|
signalVector *pulse, rotated;
|
||||||
signalVector::iterator itr;
|
signalVector::iterator itr;
|
||||||
|
|
||||||
pulse = GSMPulse1->empty;
|
pulse = GSMPulse1->empty;
|
||||||
@@ -602,11 +575,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
|
|||||||
rotated.isReal(false);
|
rotated.isReal(false);
|
||||||
|
|
||||||
/* Dummy filter operation */
|
/* Dummy filter operation */
|
||||||
shaped = convolve(&rotated, pulse, NULL, START_ONLY);
|
return convolve(&rotated, pulse, NULL, START_ONLY);
|
||||||
if (!shaped)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return shaped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rotateBurst2(signalVector &burst, double phase)
|
static void rotateBurst2(signalVector &burst, double phase)
|
||||||
@@ -626,8 +595,7 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
|
|||||||
{
|
{
|
||||||
int burst_len, sps = 4;
|
int burst_len, sps = 4;
|
||||||
float phase;
|
float phase;
|
||||||
signalVector *c0_pulse, *c1_pulse, *c0_burst;
|
signalVector *c0_pulse, *c1_pulse, *c0_shaped, *c1_shaped;
|
||||||
signalVector *c1_burst, *c0_shaped, *c1_shaped;
|
|
||||||
signalVector::iterator c0_itr, c1_itr;
|
signalVector::iterator c0_itr, c1_itr;
|
||||||
|
|
||||||
c0_pulse = GSMPulse4->c0;
|
c0_pulse = GSMPulse4->c0;
|
||||||
@@ -638,13 +606,12 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
|
|||||||
|
|
||||||
burst_len = 625;
|
burst_len = 625;
|
||||||
|
|
||||||
c0_burst = new signalVector(burst_len, c0_pulse->size());
|
signalVector c0_burst(burst_len, c0_pulse->size());
|
||||||
c0_burst->isReal(true);
|
c0_burst.isReal(true);
|
||||||
c0_itr = c0_burst->begin();
|
c0_itr = c0_burst.begin();
|
||||||
|
|
||||||
c1_burst = new signalVector(burst_len, c1_pulse->size());
|
signalVector c1_burst(burst_len, c1_pulse->size());
|
||||||
c1_burst->isReal(true);
|
c1_itr = c1_burst.begin();
|
||||||
c1_itr = c1_burst->begin();
|
|
||||||
|
|
||||||
/* Padded differential tail bits */
|
/* Padded differential tail bits */
|
||||||
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
|
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
|
||||||
@@ -660,10 +627,10 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
|
|||||||
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
|
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
|
||||||
|
|
||||||
/* Generate C0 phase coefficients */
|
/* Generate C0 phase coefficients */
|
||||||
GMSKRotate(*c0_burst, sps);
|
GMSKRotate(c0_burst, sps);
|
||||||
c0_burst->isReal(false);
|
c0_burst.isReal(false);
|
||||||
|
|
||||||
c0_itr = c0_burst->begin();
|
c0_itr = c0_burst.begin();
|
||||||
c0_itr += sps * 2;
|
c0_itr += sps * 2;
|
||||||
c1_itr += sps * 2;
|
c1_itr += sps * 2;
|
||||||
|
|
||||||
@@ -688,8 +655,8 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
|
|||||||
*c1_itr = *c0_itr * Complex<float>(0, phase);
|
*c1_itr = *c0_itr * Complex<float>(0, phase);
|
||||||
|
|
||||||
/* Primary (C0) and secondary (C1) pulse shaping */
|
/* Primary (C0) and secondary (C1) pulse shaping */
|
||||||
c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
|
c0_shaped = convolve(&c0_burst, c0_pulse, NULL, START_ONLY);
|
||||||
c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
|
c1_shaped = convolve(&c1_burst, c1_pulse, NULL, START_ONLY);
|
||||||
|
|
||||||
/* Sum shaped outputs into C0 */
|
/* Sum shaped outputs into C0 */
|
||||||
c0_itr = c0_shaped->begin();
|
c0_itr = c0_shaped->begin();
|
||||||
@@ -697,10 +664,7 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
|
|||||||
for (unsigned i = 0; i < c0_shaped->size(); i++ )
|
for (unsigned i = 0; i < c0_shaped->size(); i++ )
|
||||||
*c0_itr++ += *c1_itr++;
|
*c0_itr++ += *c1_itr++;
|
||||||
|
|
||||||
delete c0_burst;
|
|
||||||
delete c1_burst;
|
|
||||||
delete c1_shaped;
|
delete c1_shaped;
|
||||||
|
|
||||||
return c0_shaped;
|
return c0_shaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -774,7 +738,6 @@ static signalVector *mapEdgeSymbols(const BitVector &bits)
|
|||||||
static signalVector *shapeEdgeBurst(const signalVector &symbols)
|
static signalVector *shapeEdgeBurst(const signalVector &symbols)
|
||||||
{
|
{
|
||||||
size_t nsyms, nsamps = 625, sps = 4;
|
size_t nsyms, nsamps = 625, sps = 4;
|
||||||
signalVector *burst, *shape;
|
|
||||||
signalVector::iterator burst_itr;
|
signalVector::iterator burst_itr;
|
||||||
|
|
||||||
nsyms = symbols.size();
|
nsyms = symbols.size();
|
||||||
@@ -782,10 +745,10 @@ static signalVector *shapeEdgeBurst(const signalVector &symbols)
|
|||||||
if (nsyms * sps > nsamps)
|
if (nsyms * sps > nsamps)
|
||||||
nsyms = 156;
|
nsyms = 156;
|
||||||
|
|
||||||
burst = new signalVector(nsamps, GSMPulse4->c0->size());
|
signalVector burst(nsamps, GSMPulse4->c0->size());
|
||||||
|
|
||||||
/* Delay burst by 1 symbol */
|
/* Delay burst by 1 symbol */
|
||||||
burst_itr = burst->begin() + sps;
|
burst_itr = burst.begin() + sps;
|
||||||
for (size_t i = 0; i < nsyms; i++) {
|
for (size_t i = 0; i < nsyms; i++) {
|
||||||
float phase = i * 3.0f * M_PI / 8.0f;
|
float phase = i * 3.0f * M_PI / 8.0f;
|
||||||
Complex<float> rot = Complex<float>(cos(phase), sin(phase));
|
Complex<float> rot = Complex<float>(cos(phase), sin(phase));
|
||||||
@@ -795,10 +758,7 @@ static signalVector *shapeEdgeBurst(const signalVector &symbols)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Single Gaussian pulse approximation shaping */
|
/* Single Gaussian pulse approximation shaping */
|
||||||
shape = convolve(burst, GSMPulse4->c0, NULL, START_ONLY);
|
return convolve(&burst, GSMPulse4->c0, NULL, START_ONLY);
|
||||||
delete burst;
|
|
||||||
|
|
||||||
return shape;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -812,40 +772,36 @@ signalVector *genRandNormalBurst(int tsc, int sps, int tn)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
BitVector *bits = new BitVector(148);
|
BitVector bits(148);
|
||||||
signalVector *burst;
|
|
||||||
|
|
||||||
/* Tail bits */
|
/* Tail bits */
|
||||||
for (; i < 3; i++)
|
for (; i < 3; i++)
|
||||||
(*bits)[i] = 0;
|
bits[i] = 0;
|
||||||
|
|
||||||
/* Random bits */
|
/* Random bits */
|
||||||
for (; i < 60; i++)
|
for (; i < 60; i++)
|
||||||
(*bits)[i] = rand() % 2;
|
bits[i] = rand() % 2;
|
||||||
|
|
||||||
/* Stealing bit */
|
/* Stealing bit */
|
||||||
(*bits)[i++] = 0;
|
bits[i++] = 0;
|
||||||
|
|
||||||
/* Training sequence */
|
/* Training sequence */
|
||||||
for (int n = 0; i < 87; i++, n++)
|
for (int n = 0; i < 87; i++, n++)
|
||||||
(*bits)[i] = gTrainingSequence[tsc][n];
|
bits[i] = gTrainingSequence[tsc][n];
|
||||||
|
|
||||||
/* Stealing bit */
|
/* Stealing bit */
|
||||||
(*bits)[i++] = 0;
|
bits[i++] = 0;
|
||||||
|
|
||||||
/* Random bits */
|
/* Random bits */
|
||||||
for (; i < 145; i++)
|
for (; i < 145; i++)
|
||||||
(*bits)[i] = rand() % 2;
|
bits[i] = rand() % 2;
|
||||||
|
|
||||||
/* Tail bits */
|
/* Tail bits */
|
||||||
for (; i < 148; i++)
|
for (; i < 148; i++)
|
||||||
(*bits)[i] = 0;
|
bits[i] = 0;
|
||||||
|
|
||||||
int guard = 8 + !(tn % 4);
|
int guard = 8 + !(tn % 4);
|
||||||
burst = modulateBurst(*bits, guard, sps);
|
return modulateBurst(bits, guard, sps);
|
||||||
delete bits;
|
|
||||||
|
|
||||||
return burst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -861,30 +817,26 @@ signalVector *genRandAccessBurst(int delay, int sps, int tn)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
BitVector *bits = new BitVector(88+delay);
|
BitVector bits(88 + delay);
|
||||||
signalVector *burst;
|
|
||||||
|
|
||||||
/* delay */
|
/* delay */
|
||||||
for (; i < delay; i++)
|
for (; i < delay; i++)
|
||||||
(*bits)[i] = 0;
|
bits[i] = 0;
|
||||||
|
|
||||||
/* head and synch bits */
|
/* head and synch bits */
|
||||||
for (int n = 0; i < 49+delay; i++, n++)
|
for (int n = 0; i < 49+delay; i++, n++)
|
||||||
(*bits)[i] = gRACHBurst[n];
|
bits[i] = gRACHBurst[n];
|
||||||
|
|
||||||
/* Random bits */
|
/* Random bits */
|
||||||
for (; i < 85+delay; i++)
|
for (; i < 85+delay; i++)
|
||||||
(*bits)[i] = rand() % 2;
|
bits[i] = rand() % 2;
|
||||||
|
|
||||||
/* Tail bits */
|
/* Tail bits */
|
||||||
for (; i < 88+delay; i++)
|
for (; i < 88+delay; i++)
|
||||||
(*bits)[i] = 0;
|
bits[i] = 0;
|
||||||
|
|
||||||
int guard = 68-delay + !(tn % 4);
|
int guard = 68-delay + !(tn % 4);
|
||||||
burst = modulateBurst(*bits, guard, sps);
|
return modulateBurst(bits, guard, sps);
|
||||||
delete bits;
|
|
||||||
|
|
||||||
return burst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signalVector *generateEmptyBurst(int sps, int tn)
|
signalVector *generateEmptyBurst(int sps, int tn)
|
||||||
@@ -921,17 +873,17 @@ signalVector *generateEdgeBurst(int tsc)
|
|||||||
if ((tsc < 0) || (tsc > 7))
|
if ((tsc < 0) || (tsc > 7))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
signalVector *shape, *burst = new signalVector(148);
|
signalVector burst(148);
|
||||||
const BitVector *midamble = &gEdgeTrainingSequence[tsc];
|
const BitVector *midamble = &gEdgeTrainingSequence[tsc];
|
||||||
|
|
||||||
/* Tail */
|
/* Tail */
|
||||||
int n, i = 0;
|
int n, i = 0;
|
||||||
for (; i < tail; i++)
|
for (; i < tail; i++)
|
||||||
(*burst)[i] = psk8_table[7];
|
burst[i] = psk8_table[7];
|
||||||
|
|
||||||
/* Body */
|
/* Body */
|
||||||
for (; i < tail + data; i++)
|
for (; i < tail + data; i++)
|
||||||
(*burst)[i] = psk8_table[rand() % 8];
|
burst[i] = psk8_table[rand() % 8];
|
||||||
|
|
||||||
/* TSC */
|
/* TSC */
|
||||||
for (n = 0; i < tail + data + train; i++, n++) {
|
for (n = 0; i < tail + data + train; i++, n++) {
|
||||||
@@ -939,21 +891,18 @@ signalVector *generateEdgeBurst(int tsc)
|
|||||||
(((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
|
(((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
|
||||||
(((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
|
(((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
|
||||||
|
|
||||||
(*burst)[i] = psk8_table[index];
|
burst[i] = psk8_table[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Body */
|
/* Body */
|
||||||
for (; i < tail + data + train + data; i++)
|
for (; i < tail + data + train + data; i++)
|
||||||
(*burst)[i] = psk8_table[rand() % 8];
|
burst[i] = psk8_table[rand() % 8];
|
||||||
|
|
||||||
/* Tail */
|
/* Tail */
|
||||||
for (; i < tail + data + train + data + tail; i++)
|
for (; i < tail + data + train + data + tail; i++)
|
||||||
(*burst)[i] = psk8_table[7];
|
burst[i] = psk8_table[7];
|
||||||
|
|
||||||
shape = shapeEdgeBurst(*burst);
|
return shapeEdgeBurst(burst);
|
||||||
delete burst;
|
|
||||||
|
|
||||||
return shape;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -989,7 +938,7 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
|
|||||||
int guard_len, int sps)
|
int guard_len, int sps)
|
||||||
{
|
{
|
||||||
int burst_len;
|
int burst_len;
|
||||||
signalVector *pulse, *burst, *shaped;
|
signalVector *pulse;
|
||||||
signalVector::iterator burst_itr;
|
signalVector::iterator burst_itr;
|
||||||
|
|
||||||
if (sps == 1)
|
if (sps == 1)
|
||||||
@@ -999,9 +948,9 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
|
|||||||
|
|
||||||
burst_len = sps * (bits.size() + guard_len);
|
burst_len = sps * (bits.size() + guard_len);
|
||||||
|
|
||||||
burst = new signalVector(burst_len, pulse->size());
|
signalVector burst(burst_len, pulse->size());
|
||||||
burst->isReal(true);
|
burst.isReal(true);
|
||||||
burst_itr = burst->begin();
|
burst_itr = burst.begin();
|
||||||
|
|
||||||
/* Raw bits are not differentially encoded */
|
/* Raw bits are not differentially encoded */
|
||||||
for (unsigned i = 0; i < bits.size(); i++) {
|
for (unsigned i = 0; i < bits.size(); i++) {
|
||||||
@@ -1009,15 +958,11 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
|
|||||||
burst_itr += sps;
|
burst_itr += sps;
|
||||||
}
|
}
|
||||||
|
|
||||||
GMSKRotate(*burst, sps);
|
GMSKRotate(burst, sps);
|
||||||
burst->isReal(false);
|
burst.isReal(false);
|
||||||
|
|
||||||
/* Single Gaussian pulse approximation shaping */
|
/* Single Gaussian pulse approximation shaping */
|
||||||
shaped = convolve(burst, pulse, NULL, START_ONLY);
|
return convolve(&burst, pulse, NULL, START_ONLY);
|
||||||
|
|
||||||
delete burst;
|
|
||||||
|
|
||||||
return shaped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assume input bits are not differentially encoded */
|
/* Assume input bits are not differentially encoded */
|
||||||
@@ -1034,16 +979,10 @@ signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
|
|||||||
|
|
||||||
static void generateSincTable()
|
static void generateSincTable()
|
||||||
{
|
{
|
||||||
float x;
|
|
||||||
|
|
||||||
for (int i = 0; i < TABLESIZE; i++) {
|
for (int i = 0; i < TABLESIZE; i++) {
|
||||||
x = (float) i / TABLESIZE * 8 * M_PI;
|
auto x = (double) i / TABLESIZE * 8 * M_PI;
|
||||||
if (fabs(x) < 0.01) {
|
auto y = sin(x) / x;
|
||||||
sincTable[i] = 1.0f;
|
sincTable[i] = std::isnan(y) ? 1.0 : y;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
sincTable[i] = sinf(x) / x;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1516,19 +1455,16 @@ float energyDetect(const signalVector &rxBurst, unsigned windowLength)
|
|||||||
|
|
||||||
static signalVector *downsampleBurst(const signalVector &burst)
|
static signalVector *downsampleBurst(const signalVector &burst)
|
||||||
{
|
{
|
||||||
signalVector *in, *out;
|
signalVector in(DOWNSAMPLE_IN_LEN, dnsampler->len());
|
||||||
|
signalVector *out = new signalVector(DOWNSAMPLE_OUT_LEN);
|
||||||
|
memcpy(in.begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
|
||||||
|
|
||||||
in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len());
|
if (dnsampler->rotate((float *) in.begin(), DOWNSAMPLE_IN_LEN,
|
||||||
out = new signalVector(DOWNSAMPLE_OUT_LEN);
|
|
||||||
memcpy(in->begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
|
|
||||||
|
|
||||||
if (dnsampler->rotate((float *) in->begin(), DOWNSAMPLE_IN_LEN,
|
|
||||||
(float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
|
(float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
|
||||||
delete out;
|
delete out;
|
||||||
out = NULL;
|
out = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete in;
|
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1621,7 +1557,6 @@ static int detectGeneralBurst(const signalVector &rxBurst,
|
|||||||
{
|
{
|
||||||
int rc, start, len;
|
int rc, start, len;
|
||||||
bool clipping = false;
|
bool clipping = false;
|
||||||
signalVector *corr;
|
|
||||||
|
|
||||||
if ((sps != 1) && (sps != 4))
|
if ((sps != 1) && (sps != 4))
|
||||||
return -SIGERR_UNSUPPORTED;
|
return -SIGERR_UNSUPPORTED;
|
||||||
@@ -1637,12 +1572,10 @@ static int detectGeneralBurst(const signalVector &rxBurst,
|
|||||||
|
|
||||||
start = target - head - 1;
|
start = target - head - 1;
|
||||||
len = head + tail;
|
len = head + tail;
|
||||||
corr = new signalVector(len);
|
signalVector corr(len);
|
||||||
|
|
||||||
rc = detectBurst(rxBurst, *corr, sync,
|
rc = detectBurst(rxBurst, corr, sync,
|
||||||
thresh, sps, &, &toa, start, len);
|
thresh, sps, &, &toa, start, len);
|
||||||
delete corr;
|
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
return -SIGERR_INTERNAL;
|
return -SIGERR_INTERNAL;
|
||||||
} else if (!rc) {
|
} else if (!rc) {
|
||||||
@@ -1921,7 +1854,6 @@ SoftVector *demodAnyBurst(const signalVector &burst, int sps, complex amp,
|
|||||||
|
|
||||||
bool sigProcLibSetup()
|
bool sigProcLibSetup()
|
||||||
{
|
{
|
||||||
initTrigTables();
|
|
||||||
generateSincTable();
|
generateSincTable();
|
||||||
initGMSKRotationTables();
|
initGMSKRotationTables();
|
||||||
|
|
||||||
|
|||||||
26
configure.ac
26
configure.ac
@@ -18,12 +18,15 @@ dnl You should have received a copy of the GNU General Public License
|
|||||||
dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
|
dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
dnl
|
dnl
|
||||||
|
|
||||||
AC_INIT(openbts,P2.8TRUNK)
|
AC_INIT([osmo-trx],
|
||||||
|
m4_esyscmd([./git-version-gen .tarball-veresion]),
|
||||||
|
[openbsc@lists.osmocom.org])
|
||||||
AC_PREREQ(2.57)
|
AC_PREREQ(2.57)
|
||||||
AC_CONFIG_SRCDIR([Transceiver52M/Makefile.am])
|
AC_CONFIG_SRCDIR([Transceiver52M/Makefile.am])
|
||||||
AC_CONFIG_AUX_DIR([.])
|
AC_CONFIG_AUX_DIR([.])
|
||||||
AC_CONFIG_MACRO_DIR([config])
|
AC_CONFIG_MACRO_DIR([config])
|
||||||
AM_CONFIG_HEADER(config.h)
|
AM_CONFIG_HEADER(config.h)
|
||||||
|
AC_CONFIG_TESTDIR(tests)
|
||||||
|
|
||||||
AC_CANONICAL_BUILD
|
AC_CANONICAL_BUILD
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_HOST
|
||||||
@@ -34,6 +37,10 @@ AM_INIT_AUTOMAKE([subdir-objects])
|
|||||||
dnl Linux kernel KBuild style compile messages
|
dnl Linux kernel KBuild style compile messages
|
||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
|
|
||||||
|
dnl include release helper
|
||||||
|
RELMAKE='-include osmo-release.mk'
|
||||||
|
AC_SUBST([RELMAKE])
|
||||||
|
|
||||||
AM_PROG_AS
|
AM_PROG_AS
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
AX_CXX_COMPILE_STDCXX_11
|
AX_CXX_COMPILE_STDCXX_11
|
||||||
@@ -42,6 +49,13 @@ AC_PROG_MAKE_SET
|
|||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
AC_PATH_PROG([RM_PROG], [rm])
|
AC_PATH_PROG([RM_PROG], [rm])
|
||||||
|
|
||||||
|
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
|
||||||
|
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
|
||||||
|
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
||||||
|
AC_MSG_WARN([You need to install pkg-config])
|
||||||
|
fi
|
||||||
|
PKG_PROG_PKG_CONFIG([0.20])
|
||||||
|
|
||||||
AC_LIBTOOL_WIN32_DLL
|
AC_LIBTOOL_WIN32_DLL
|
||||||
AC_ENABLE_SHARED dnl do build shared libraries
|
AC_ENABLE_SHARED dnl do build shared libraries
|
||||||
AC_DISABLE_STATIC dnl don't build static libraries
|
AC_DISABLE_STATIC dnl don't build static libraries
|
||||||
@@ -106,7 +120,6 @@ AS_IF([test "x$with_usrp1" != "xyes"],[
|
|||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
AC_DEFINE(USE_UHD, 1, All UHD versions)
|
AC_DEFINE(USE_UHD, 1, All UHD versions)
|
||||||
PKG_CHECK_MODULES(FFTWF, fftw3f)
|
|
||||||
])
|
])
|
||||||
|
|
||||||
AS_IF([test "x$with_singledb" = "xyes"], [
|
AS_IF([test "x$with_singledb" = "xyes"], [
|
||||||
@@ -152,10 +165,8 @@ AM_CONDITIONAL(USRP1, [test "x$with_usrp1" = "xyes"])
|
|||||||
AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])
|
AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])
|
||||||
AM_CONDITIONAL(ARCH_ARM_A15, [test "x$with_neon_vfpv4" = "xyes"])
|
AM_CONDITIONAL(ARCH_ARM_A15, [test "x$with_neon_vfpv4" = "xyes"])
|
||||||
|
|
||||||
AC_CHECK_LIB(sqlite3, sqlite3_open, , AC_MSG_ERROR(sqlite3 is not available))
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBUSB, libusb-1.0)
|
PKG_CHECK_MODULES(LIBUSB, libusb-1.0)
|
||||||
PKG_CHECK_MODULES(SQLITE3, sqlite3)
|
PKG_CHECK_MODULES(FFTWF, fftw3f)
|
||||||
|
|
||||||
AC_CHECK_HEADER([boost/config.hpp],[],
|
AC_CHECK_HEADER([boost/config.hpp],[],
|
||||||
[AC_MSG_ERROR([boost/config.hpp not found, install e.g. libboost-dev])])
|
[AC_MSG_ERROR([boost/config.hpp not found, install e.g. libboost-dev])])
|
||||||
@@ -168,6 +179,9 @@ AC_CONFIG_FILES([\
|
|||||||
Transceiver52M/Makefile \
|
Transceiver52M/Makefile \
|
||||||
Transceiver52M/arm/Makefile \
|
Transceiver52M/arm/Makefile \
|
||||||
Transceiver52M/x86/Makefile \
|
Transceiver52M/x86/Makefile \
|
||||||
|
tests/Makefile \
|
||||||
|
tests/CommonLibs/Makefile \
|
||||||
|
tests/Transceiver52M/Makefile \
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
@@ -1,7 +1,63 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
substr() { [ -z "${2##*$1*}" ]; }
|
||||||
|
|
||||||
|
#apt-get install qemu qemu-user-static qemu-system-arm debootstrap fakeroot proot
|
||||||
|
mychroot_nocwd() {
|
||||||
|
# LC_ALL + LANGUAGE set to avoid lots of print errors due to locale not being set inside container
|
||||||
|
# PATH is needed to be able to reach binaries like ldconfig without logging in to root, which adds the paths to PATH.
|
||||||
|
# PROOT_NO_SECCOMP is requried due to proot bug #106
|
||||||
|
LC_ALL=C LANGUAGE=C PATH="$PATH:/usr/sbin:/sbin" PROOT_NO_SECCOMP=1 proot -r "$ROOTFS" -w / -b /proc --root-id -q qemu-arm-static "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
mychroot() {
|
||||||
|
mychroot_nocwd -w / "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z "${INSIDE_CHROOT}" ]; then
|
||||||
|
|
||||||
|
osmo-clean-workspace.sh
|
||||||
|
|
||||||
|
# Only use ARM chroot if host is not ARM and the target is ARM:
|
||||||
|
if ! $(substr "arm" "$(uname -m)") && [ "x${INSTR}" = "x--with-neon" -o "x${INSTR}" = "x--with-neon-vfpv4" ]; then
|
||||||
|
|
||||||
|
OSMOTRX_DIR="$PWD" # we assume we are called as contrib/jenkins.sh
|
||||||
|
ROOTFS_PREFIX="${ROOTFS_PREFIX:-/opt}"
|
||||||
|
ROOTFS="${ROOTFS_PREFIX}/qemu-img"
|
||||||
|
mkdir -p "${ROOTFS_PREFIX}"
|
||||||
|
|
||||||
|
# Prepare chroot:
|
||||||
|
if [ ! -d "$ROOTFS" ]; then
|
||||||
|
mkdir -p "$ROOTFS"
|
||||||
|
if [ "x${USE_DEBOOTSTRAP}" = "x1" ]; then
|
||||||
|
fakeroot qemu-debootstrap --foreign --include="linux-image-armmp-lpae" --arch=armhf stretch "$ROOTFS" http://ftp.de.debian.org/debian/
|
||||||
|
# Hack to avoid debootstrap trying to mount /proc, as it will fail with "no permissions" and anyway proot takes care of it:
|
||||||
|
sed -i "s/setup_proc//g" "$ROOTFS/debootstrap/suite-script"
|
||||||
|
mychroot /debootstrap/debootstrap --second-stage --verbose http://ftp.de.debian.org/debian/
|
||||||
|
else
|
||||||
|
YESTERDAY=$(python -c 'import datetime ; print((datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y%m%d"))')
|
||||||
|
wget -nc -q "https://uk.images.linuxcontainers.org/images/debian/stretch/armhf/default/${YESTERDAY}_22:42/rootfs.tar.xz"
|
||||||
|
tar -xf rootfs.tar.xz -C "$ROOTFS/" || true
|
||||||
|
echo "nameserver 8.8.8.8" > "$ROOTFS/etc/resolv.conf"
|
||||||
|
fi
|
||||||
|
mychroot -b /dev apt-get update
|
||||||
|
mychroot apt-get -y install build-essential dh-autoreconf pkg-config libuhd-dev libusb-1.0-0-dev libusb-dev git
|
||||||
|
fi
|
||||||
|
# Run jenkins.sh inside the chroot:
|
||||||
|
INSIDE_CHROOT=1 mychroot_nocwd -w /osmo-trx -b "$OSMOTRX_DIR:/osmo-trx" -b "$(which osmo-clean-workspace.sh):/usr/bin/osmo-clean-workspace.sh" ./contrib/jenkins.sh
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
### BUILD osmo-trx
|
||||||
|
|
||||||
autoreconf --install --force
|
autoreconf --install --force
|
||||||
./configure
|
./configure $INSTR
|
||||||
$MAKE $PARALLEL_MAKE
|
$MAKE $PARALLEL_MAKE
|
||||||
$MAKE check \
|
$MAKE check \
|
||||||
|| cat-testlogs.sh
|
|| cat-testlogs.sh
|
||||||
|
|
||||||
|
if [ -z "x${INSIDE_CHROOT}" ]; then
|
||||||
|
osmo-clean-workspace.sh
|
||||||
|
fi
|
||||||
|
|||||||
235
debian/changelog
vendored
235
debian/changelog
vendored
@@ -1,3 +1,238 @@
|
|||||||
|
osmo-trx (0.3.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
[ Neels Hofmeyr ]
|
||||||
|
* jenkins: use osmo-clean-workspace.sh before and after build
|
||||||
|
|
||||||
|
[ Harald Welte ]
|
||||||
|
* SocketsTest: Fix printing of non-nul-terminated string
|
||||||
|
|
||||||
|
[ Piotr Krysik ]
|
||||||
|
* UHDDevice.cpp: add USRP B205mini support
|
||||||
|
|
||||||
|
[ Max ]
|
||||||
|
* Mark release target as virtual
|
||||||
|
* Remove outdated references to OpenBTS
|
||||||
|
* Remove unused headers
|
||||||
|
* Update installation instructions
|
||||||
|
* Update legal disclaimer
|
||||||
|
* Update license notes
|
||||||
|
* tests: null-terminate buffer
|
||||||
|
|
||||||
|
[ Pau Espin Pedrol ]
|
||||||
|
* cosmetic: Remove trailing whitespace
|
||||||
|
* Logger: Stop using Log.Alarms.Max from config
|
||||||
|
* Logger: Stop using Log.File and Log.Level from config
|
||||||
|
* Drop use of ConfigurationTable gConfig
|
||||||
|
* Remove Configuration module and libsqlite dependency
|
||||||
|
* cosmetic: AUTHORS: fix trailing whitespace
|
||||||
|
* Set up GNU Autotest infrastructure
|
||||||
|
* tests: InterThread: adapt to have reproducible output and enable autotest
|
||||||
|
* tests: Timeval: adapt to have reproducible output and enable autotest
|
||||||
|
* tests: Log: adapt to have reproducible output and enable autotest
|
||||||
|
* Sockets.cpp: Fix initialization of UDD socket
|
||||||
|
* tests: Sockets: adapt to have reproducible output and enable autotest
|
||||||
|
* utils/convolvtest: Remove uneeded libosmocore dependency
|
||||||
|
* Move ARCH_LA to Makefile.common
|
||||||
|
* tests: Migrate convtest util to autotest infrastructure
|
||||||
|
* arm/convert.c: Fix compilation error
|
||||||
|
* arm/convert.c: Add missing convert_init implementation
|
||||||
|
* .gitignore: Add missing test related files
|
||||||
|
* Remove UDDSocket class
|
||||||
|
* tests: SocketTests: Pick OS-assigned instead of setting one manually
|
||||||
|
* tests: SocketsTest: Avoid hang forever if test fails
|
||||||
|
* tests: SocketsTest: Fail test on write fail
|
||||||
|
* tests: TimevalTest: refactor and avoid double comparison
|
||||||
|
* contrib/jenkins.sh: Use qemu+proot+debootstrap to run tests with ARM instruction set
|
||||||
|
* tests: convolve: Disable due to difference in output in different archs
|
||||||
|
* Remove unneeded libdl dependency
|
||||||
|
* Fix whitespace
|
||||||
|
* Add support to set Rx/TxAntenna
|
||||||
|
* UHDDevice: Initialize async_event_thrd in constructor
|
||||||
|
* Logger: Drop unused gLogEarly
|
||||||
|
* Logger: Remove unused logging macros
|
||||||
|
* Logger: get rid of alarm APIs
|
||||||
|
* Logger: Drop syslog support
|
||||||
|
* Logger: Drop support to log into file
|
||||||
|
* Logger: Remove unused includes
|
||||||
|
* Logger: Remove gLogToConsole flag
|
||||||
|
* configure.ac: Check for pkg-config
|
||||||
|
|
||||||
|
[ Alexander Huemer ]
|
||||||
|
* Unbreak `./configure --with-usrp1` build
|
||||||
|
* Fix USRP1 build with support for setting Rx/TxAntenna
|
||||||
|
|
||||||
|
[ Alexander Couzens ]
|
||||||
|
* jenkins.sh: fix the download url if the qemu image wasn't setup
|
||||||
|
|
||||||
|
-- Pau Espin Pedrol <pespin@sysmocom.de> Mon, 05 Mar 2018 16:49:42 +0100
|
||||||
|
|
||||||
|
osmo-trx (0.2.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
[ Alexander Chemeris ]
|
||||||
|
* EDGE: Add support for UmTRX.
|
||||||
|
* Common: Get rid of a compilation warning.
|
||||||
|
* Common: Make sure gLogEarly() log to the same facilities as the normal log.
|
||||||
|
* transceiver: Properly handle MAXDLY.
|
||||||
|
* transceiver: Add an option to generate random Access Bursts.
|
||||||
|
* osmo-trx: Output Rx SPS as a part of configuration output.
|
||||||
|
* transceiver: Do not pass transceiver state struct to function where it's not used.
|
||||||
|
* makefile: Fix build from an external path.
|
||||||
|
* radioDevice: GSMRATE macro must have parentheses around its definition.
|
||||||
|
* uhd: Fix comment.
|
||||||
|
* radioInterface: Initialize power scale with a meaningful default.
|
||||||
|
* transceiver: Log channel number in DEBUG output of demoded bursts.
|
||||||
|
* transceiver: Add an option to emulate a RACH delay in random filler mode.
|
||||||
|
* UHD: Initial LimeSDR support.
|
||||||
|
* CommonLibs: Remove unused files.
|
||||||
|
* sigProcLib: Typo sybols -> symbols
|
||||||
|
* radioBuffer: Remove extra ; at the end of inline function definitions.
|
||||||
|
* sigProcLib: Fix documentation, sync argument names in .cpp and .h files.
|
||||||
|
* sigProcLib: make energyDetect() simpler by returning actual energy.
|
||||||
|
* sigProcLib: Rename demodulateBurst() to demodGmskBurst() for clarity.
|
||||||
|
* sigProcLib: Slice SoftVector instead of signalVector for GMSK demod.
|
||||||
|
* Call vectorSlicer() right before packing bits for transmission to osmo-bts.
|
||||||
|
* CommonLibs: Print soft bits with less confidence to console when printing a soft vector.
|
||||||
|
* BitVector: Remove convolutional codec - we don't use it in osmo-trx.
|
||||||
|
* BitVector: Convert SoftVector from 0..1 to -1..+1 soft bits.
|
||||||
|
* signalVector: Implement segment().
|
||||||
|
* vector: Introduce segmentMove() method to move data inside of a vector.
|
||||||
|
* vector: Introduce shrink() function to shrink vector size without loosing data.
|
||||||
|
* Move CorrType type from Transceiver to sigProcLib.
|
||||||
|
* sigProcLib: rename signalError type to SignalError.
|
||||||
|
* Move Transceiver::detectBurst() to sigProcLib to make it reusable.
|
||||||
|
* Move BURST_THRESH from Transceiver.cpp to sigProcLib.h to make it reusable.
|
||||||
|
* sigProcLib: Add operator<< to print CorrType to a string.
|
||||||
|
* sigProcLib.h: Fix whitespaces. No non-whitespace changes.
|
||||||
|
* Move Transceiver::demodulate() to sigProcLib to make it reusable.
|
||||||
|
* sigProcLib: constify signalVector arguments for detectBurst() functions.
|
||||||
|
* sigProcLib: Constify demodulation functions burst argument.
|
||||||
|
* sigProcLib: Fix number of tail bits in random Normal Bursts and zero Stealing Bits.
|
||||||
|
* Configuration: Variables allocated with 'new' must be freed with 'delete'.
|
||||||
|
* BitVector: Remove Generator class.
|
||||||
|
* PRBS: a Pseudo-random binary sequence (PRBS) generator class.
|
||||||
|
|
||||||
|
[ Tom Tsou ]
|
||||||
|
* EDGE: Fix USRP B210 device support
|
||||||
|
* uhd: Correct timing alignment in 8-PSK and GMSK downlink bursts
|
||||||
|
* EDGE: Fix demodulation slicer input
|
||||||
|
* common: Restrict UDP binding to localhost only
|
||||||
|
* common: Add mandatory length field to UDP receive calls
|
||||||
|
* uhd: Update default E3XX settings
|
||||||
|
* uhd: Set default Tx sampling to 4 sps
|
||||||
|
* uhd: Make device offset check a private method
|
||||||
|
* uhd: Set minimum UHD version requirement for E3XX
|
||||||
|
* sigproc: Expand RACH, TSC, and EDGE correlation windows
|
||||||
|
* transceiver: Do not report error on SETTSC when radio is on
|
||||||
|
* transceiver: Add Rx samples-per-symbol option
|
||||||
|
* radioInterface: Convert diversity argument to general type
|
||||||
|
* iface: Add inner ring-buffer implementation
|
||||||
|
* mcbts: Add multi-ARFCN channelizing filters
|
||||||
|
* mcbts: Add multi-ARFCN radio support
|
||||||
|
* sigproc: Adjust burst detection threshold criteria
|
||||||
|
* egprs: Enable 8-PSK length vectors on the Tx interface
|
||||||
|
* egprs: Enable 8-PSK burst detection when EDGE is enabled
|
||||||
|
* transceiver: Remove HANDOVER warnings
|
||||||
|
* mcbts: Allow out of order channel setup
|
||||||
|
* radioInterface: Fix multi-channel buffer index bug
|
||||||
|
* uhd: Add command line option for GPS reference
|
||||||
|
* transceiver: Fix mixed GSMK / 8-PSK transmission
|
||||||
|
* transceiver: Fix 4 SPS receive TOA value
|
||||||
|
* sigproc: Fix missing 8-PSK tail symbols
|
||||||
|
* uhd: Update USRP2/N200/N210 for 4 SPS Rx
|
||||||
|
* sigproc: Match differential GMSK start/end bits to tail bits
|
||||||
|
* uhd: Add missing B200 sample timing for 4 SPS receive
|
||||||
|
* transceiver: Fix command build warning
|
||||||
|
* uhd: Set minimum supported version to 3.9.0
|
||||||
|
* uhd: Add X300 sample timing for 4 SPS
|
||||||
|
* Revert "uhd: Set minimum supported version to 3.9.0"
|
||||||
|
* uhd: Add support for UHD-3.11 logging control
|
||||||
|
* uhd: Increase MC-BTS FPGA clock rate to 51.2 MHz
|
||||||
|
* Resampler: Fix initialization return checking
|
||||||
|
* sigProcLib: Remove unreachable code and no-effect checks
|
||||||
|
* sigProcLib: Check return status on downsampling
|
||||||
|
* sigProcLib: Fix negative value check on unsigned value
|
||||||
|
* Resampler: Fix non-array delete for filter taps
|
||||||
|
* Transceiver: Remove unsigned negative compares
|
||||||
|
* Configuration: Fix const and signedness compile warnings
|
||||||
|
* config: Remove OpenBTS style sqlite configuration
|
||||||
|
* radioInterface: Remove UmTRX 'diversity' option
|
||||||
|
* build: Require and check for gcc C++11 support
|
||||||
|
* uhd: Use map container for for device parameter access
|
||||||
|
* sigProcLib: Remove unused functions from public interface
|
||||||
|
* uhd: Add non-UmTRX channel swap support
|
||||||
|
* uhd: Fix Tx-RX timing offset setting
|
||||||
|
* uhd: Fix USRP2/N200/N210 device detection
|
||||||
|
* transceiver: Fix POWEROFF crash on USRP2/N200/X300 devices
|
||||||
|
* sigProcLib: Fix complex/real vector flag in Laurent modulator
|
||||||
|
* sigProcLib: Remove heap based signal vector allocations
|
||||||
|
* common: Declare explicit Vector move constructor
|
||||||
|
* sigProcLib: Remove trigonometric tables
|
||||||
|
* sigProcLib: Use explicit NaN check in sinc table generation
|
||||||
|
* sigProcLib: Replace dynamically allocated resampling buffers
|
||||||
|
* sigProcLib: Specify standard namespace for isnan()
|
||||||
|
* uhd: Always specify samples-per-symbol for device lookup
|
||||||
|
* LimeSDR: set approximate tx offset value to make GSM work
|
||||||
|
|
||||||
|
[ Neels Hofmeyr ]
|
||||||
|
* add basic .gitignore
|
||||||
|
* configure.ac: check for boost/config.hpp header
|
||||||
|
* The INSTALL file is being overwritten by autoreconf, but it is committed as empty file. As a result, the INSTALL file always shows as modified. Instead, remove INSTALL from git and ignore it.
|
||||||
|
* add contrib/jenkins.sh, for gerrit build bot
|
||||||
|
|
||||||
|
[ pierre.baudry ]
|
||||||
|
* transceiver: Fix mismatched allocations and deallocations
|
||||||
|
|
||||||
|
[ Holger Hans Peter Freyther ]
|
||||||
|
* debian: Require fftw3 header files for osmo-trx
|
||||||
|
|
||||||
|
[ Max ]
|
||||||
|
* Add gerrit settings
|
||||||
|
* Integrate Debian packaging changes
|
||||||
|
* Remove embedded sqlite3
|
||||||
|
* Fix building against sqlite3
|
||||||
|
* Add autoconf-archive to dependencies
|
||||||
|
* debian: remove obsolete dependency
|
||||||
|
* deb: remove unused dependency
|
||||||
|
* Remove redundant explicit dependency
|
||||||
|
* Use release helper from libosmocore
|
||||||
|
|
||||||
|
[ Ruben Undheim ]
|
||||||
|
* Do not embed sqlite3 when building
|
||||||
|
|
||||||
|
[ Philipp Maier ]
|
||||||
|
* buildenv: Turn off native architecture builds
|
||||||
|
* cosmetic: Make parameter lists uniform
|
||||||
|
* Add test program to verify convolution implementation
|
||||||
|
* ssedetect: Add runtime CPU detection
|
||||||
|
* cosmetic: remove code duplication
|
||||||
|
* buildenv: Make build CPU invariant
|
||||||
|
* buildenv: Split up SSE3 and SSE4.1 code
|
||||||
|
* cosmetic: Add info about SSE support
|
||||||
|
|
||||||
|
[ Vadim Yanitskiy ]
|
||||||
|
* buildenv: correct the ax_sse macro description
|
||||||
|
* buildenv: actually strip unused cpuid functionality
|
||||||
|
* buildenv: fix build on systems without SIMD support
|
||||||
|
* buildenv: cosmetic changes
|
||||||
|
* buildenv: check for __builtin_cpu_supports call support
|
||||||
|
* ssedetect: call __builtin_cpu_supports() only if supported
|
||||||
|
|
||||||
|
[ Pau Espin Pedrol ]
|
||||||
|
* cosmetic: transciever: Remove trailing whitespaces
|
||||||
|
* transceiver: Avoid sending clock indications when trx is not powered on
|
||||||
|
* Add -j option to bind to specific address
|
||||||
|
|
||||||
|
[ ignasj ]
|
||||||
|
* LimeSDR: Change device detection to work with USB and PCIe versions
|
||||||
|
* LimeSDR: change tx window type to TX_WINDOW_FIXED
|
||||||
|
* LimeSDR: Fix sample value range
|
||||||
|
|
||||||
|
[ Harald Welte ]
|
||||||
|
* Add '-t' command line option to enable SCHED_RR
|
||||||
|
* Import git-version-gen and update AC_INIT()
|
||||||
|
|
||||||
|
-- Harald Welte <laforge@gnumonks.org> Sat, 28 Oct 2017 17:52:32 +0200
|
||||||
|
|
||||||
osmo-trx (0.1.9) trusty; urgency=medium
|
osmo-trx (0.1.9) trusty; urgency=medium
|
||||||
|
|
||||||
* Ask Ivan, really
|
* Ask Ivan, really
|
||||||
|
|||||||
4
debian/control
vendored
4
debian/control
vendored
@@ -5,8 +5,6 @@ Maintainer: Ivan Klyuchnikov <ivan.kluchnikov@fairwaves.ru>
|
|||||||
Build-Depends: debhelper (>= 9),
|
Build-Depends: debhelper (>= 9),
|
||||||
autotools-dev,
|
autotools-dev,
|
||||||
autoconf-archive,
|
autoconf-archive,
|
||||||
libdbd-sqlite3,
|
|
||||||
libsqlite3-dev,
|
|
||||||
pkg-config,
|
pkg-config,
|
||||||
dh-autoreconf,
|
dh-autoreconf,
|
||||||
libuhd-dev,
|
libuhd-dev,
|
||||||
@@ -20,7 +18,7 @@ Homepage: https://projects.osmocom.org/projects/osmotrx
|
|||||||
|
|
||||||
Package: osmo-trx
|
Package: osmo-trx
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
Description: SDR transceiver that implements Layer 1 of a GSM BTS
|
Description: SDR transceiver that implements Layer 1 of a GSM BTS
|
||||||
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
|
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
|
||||||
physical layer of a BTS comprising the following 3GPP specifications:
|
physical layer of a BTS comprising the following 3GPP specifications:
|
||||||
|
|||||||
14
debian/copyright
vendored
14
debian/copyright
vendored
@@ -52,20 +52,6 @@ Copyright: 2005-2009 United States Government as represented by
|
|||||||
the U.S. Army Research Laboratory.
|
the U.S. Army Research Laboratory.
|
||||||
License: BSD-3-clause
|
License: BSD-3-clause
|
||||||
|
|
||||||
Files: CommonLibs/sqlite3util.cpp
|
|
||||||
Copyright: 2010 Kestrel Signal Processing Inc.
|
|
||||||
License: none
|
|
||||||
No license described for file.
|
|
||||||
Comment: In the previous version of the file in the git repository
|
|
||||||
at upstream it is written:
|
|
||||||
Written by David A. Burgess, Kestrel Signal Processing, Inc., 2010
|
|
||||||
The author disclaims copyright to this source code.
|
|
||||||
In the git log, this is written:
|
|
||||||
I do not claim any copyright over this change, as it's very basic.
|
|
||||||
Looking forward to see it merged into mainline.
|
|
||||||
See revision e766abbf82f02473038a83fd2f78befd08544cab at
|
|
||||||
https://github.com/osmocom/osmo-trx
|
|
||||||
|
|
||||||
Files: debian/*
|
Files: debian/*
|
||||||
Copyright: 2015 Ruben Undheim <ruben.undheim@gmail.com>
|
Copyright: 2015 Ruben Undheim <ruben.undheim@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|||||||
151
git-version-gen
Executable file
151
git-version-gen
Executable file
@@ -0,0 +1,151 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Print a version string.
|
||||||
|
scriptversion=2010-01-28.01
|
||||||
|
|
||||||
|
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
|
||||||
|
# It may be run two ways:
|
||||||
|
# - from a git repository in which the "git describe" command below
|
||||||
|
# produces useful output (thus requiring at least one signed tag)
|
||||||
|
# - from a non-git-repo directory containing a .tarball-version file, which
|
||||||
|
# presumes this script is invoked like "./git-version-gen .tarball-version".
|
||||||
|
|
||||||
|
# In order to use intra-version strings in your project, you will need two
|
||||||
|
# separate generated version string files:
|
||||||
|
#
|
||||||
|
# .tarball-version - present only in a distribution tarball, and not in
|
||||||
|
# a checked-out repository. Created with contents that were learned at
|
||||||
|
# the last time autoconf was run, and used by git-version-gen. Must not
|
||||||
|
# be present in either $(srcdir) or $(builddir) for git-version-gen to
|
||||||
|
# give accurate answers during normal development with a checked out tree,
|
||||||
|
# but must be present in a tarball when there is no version control system.
|
||||||
|
# Therefore, it cannot be used in any dependencies. GNUmakefile has
|
||||||
|
# hooks to force a reconfigure at distribution time to get the value
|
||||||
|
# correct, without penalizing normal development with extra reconfigures.
|
||||||
|
#
|
||||||
|
# .version - present in a checked-out repository and in a distribution
|
||||||
|
# tarball. Usable in dependencies, particularly for files that don't
|
||||||
|
# want to depend on config.h but do want to track version changes.
|
||||||
|
# Delete this file prior to any autoconf run where you want to rebuild
|
||||||
|
# files to pick up a version string change; and leave it stale to
|
||||||
|
# minimize rebuild time after unrelated changes to configure sources.
|
||||||
|
#
|
||||||
|
# It is probably wise to add these two files to .gitignore, so that you
|
||||||
|
# don't accidentally commit either generated file.
|
||||||
|
#
|
||||||
|
# Use the following line in your configure.ac, so that $(VERSION) will
|
||||||
|
# automatically be up-to-date each time configure is run (and note that
|
||||||
|
# since configure.ac no longer includes a version string, Makefile rules
|
||||||
|
# should not depend on configure.ac for version updates).
|
||||||
|
#
|
||||||
|
# AC_INIT([GNU project],
|
||||||
|
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
|
||||||
|
# [bug-project@example])
|
||||||
|
#
|
||||||
|
# Then use the following lines in your Makefile.am, so that .version
|
||||||
|
# will be present for dependencies, and so that .tarball-version will
|
||||||
|
# exist in distribution tarballs.
|
||||||
|
#
|
||||||
|
# BUILT_SOURCES = $(top_srcdir)/.version
|
||||||
|
# $(top_srcdir)/.version:
|
||||||
|
# echo $(VERSION) > $@-t && mv $@-t $@
|
||||||
|
# dist-hook:
|
||||||
|
# echo $(VERSION) > $(distdir)/.tarball-version
|
||||||
|
|
||||||
|
case $# in
|
||||||
|
1) ;;
|
||||||
|
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
tarball_version_file=$1
|
||||||
|
nl='
|
||||||
|
'
|
||||||
|
|
||||||
|
# First see if there is a tarball-only version file.
|
||||||
|
# then try "git describe", then default.
|
||||||
|
if test -f $tarball_version_file
|
||||||
|
then
|
||||||
|
v=`cat $tarball_version_file` || exit 1
|
||||||
|
case $v in
|
||||||
|
*$nl*) v= ;; # reject multi-line output
|
||||||
|
[0-9]*) ;;
|
||||||
|
*) v= ;;
|
||||||
|
esac
|
||||||
|
test -z "$v" \
|
||||||
|
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -n "$v"
|
||||||
|
then
|
||||||
|
: # use $v
|
||||||
|
elif
|
||||||
|
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|
||||||
|
|| git describe --abbrev=4 HEAD 2>/dev/null` \
|
||||||
|
&& case $v in
|
||||||
|
[0-9]*) ;;
|
||||||
|
v[0-9]*) ;;
|
||||||
|
*) (exit 1) ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
# Is this a new git that lists number of commits since the last
|
||||||
|
# tag or the previous older version that did not?
|
||||||
|
# Newer: v6.10-77-g0f8faeb
|
||||||
|
# Older: v6.10-g0f8faeb
|
||||||
|
case $v in
|
||||||
|
*-*-*) : git describe is okay three part flavor ;;
|
||||||
|
*-*)
|
||||||
|
: git describe is older two part flavor
|
||||||
|
# Recreate the number of commits and rewrite such that the
|
||||||
|
# result is the same as if we were using the newer version
|
||||||
|
# of git describe.
|
||||||
|
vtag=`echo "$v" | sed 's/-.*//'`
|
||||||
|
numcommits=`git rev-list "$vtag"..HEAD | wc -l`
|
||||||
|
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Change the first '-' to a '.', so version-comparing tools work properly.
|
||||||
|
# Remove the "g" in git describe's output string, to save a byte.
|
||||||
|
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
|
||||||
|
else
|
||||||
|
v=UNKNOWN
|
||||||
|
fi
|
||||||
|
|
||||||
|
v=`echo "$v" |sed 's/^v//'`
|
||||||
|
|
||||||
|
# Don't declare a version "dirty" merely because a time stamp has changed.
|
||||||
|
git status > /dev/null 2>&1
|
||||||
|
|
||||||
|
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
|
||||||
|
case "$dirty" in
|
||||||
|
'') ;;
|
||||||
|
*) # Append the suffix only if there isn't one already.
|
||||||
|
case $v in
|
||||||
|
*-dirty) ;;
|
||||||
|
*) v="$v-dirty" ;;
|
||||||
|
esac ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
|
||||||
|
echo "$v" | tr -d '\012'
|
||||||
|
|
||||||
|
# Local variables:
|
||||||
|
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||||
|
# time-stamp-start: "scriptversion="
|
||||||
|
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||||
|
# time-stamp-end: "$"
|
||||||
|
# End:
|
||||||
8
tests/CommonLibs/BitVectorTest.ok
Normal file
8
tests/CommonLibs/BitVectorTest.ok
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
15 15 240
|
||||||
|
000011110000
|
||||||
|
101011110000
|
||||||
|
175
|
||||||
|
111101010000
|
||||||
|
ts=abcdefgh
|
||||||
|
tp=0110000101100010011000110110010001100101011001100110011101101000000000
|
||||||
|
ts=abcdefgh
|
||||||
@@ -35,14 +35,20 @@ using namespace std;
|
|||||||
InterthreadQueue<int> gQ;
|
InterthreadQueue<int> gQ;
|
||||||
InterthreadMap<int,int> gMap;
|
InterthreadMap<int,int> gMap;
|
||||||
|
|
||||||
|
int q_last_read_val = -1;
|
||||||
|
int q_last_write_val;
|
||||||
|
int m_last_read_val;
|
||||||
|
int m_last_write_val;
|
||||||
|
|
||||||
void* qWriter(void*)
|
void* qWriter(void*)
|
||||||
{
|
{
|
||||||
int *p;
|
int *p;
|
||||||
for (int i=0; i<20; i++) {
|
for (int i=0; i<20; i++) {
|
||||||
p = new int;
|
p = new int;
|
||||||
*p = i;
|
*p = i;
|
||||||
COUT("queue write " << *p);
|
CERR("queue write " << *p);
|
||||||
gQ.write(p);
|
gQ.write(p);
|
||||||
|
q_last_write_val = i;
|
||||||
if (random()%2) sleep(1);
|
if (random()%2) sleep(1);
|
||||||
}
|
}
|
||||||
p = new int;
|
p = new int;
|
||||||
@@ -56,8 +62,14 @@ void* qReader(void*)
|
|||||||
bool done = false;
|
bool done = false;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
int *p = gQ.read();
|
int *p = gQ.read();
|
||||||
COUT("queue read " << *p);
|
CERR("queue read " << *p);
|
||||||
if (*p<0) done=true;
|
if (*p<0) {
|
||||||
|
assert(q_last_read_val == 19 && *p == -1);
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
assert(q_last_read_val == *p - 1);
|
||||||
|
q_last_read_val = *p;
|
||||||
|
}
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -70,8 +82,9 @@ void* mapWriter(void*)
|
|||||||
for (int i=0; i<20; i++) {
|
for (int i=0; i<20; i++) {
|
||||||
p = new int;
|
p = new int;
|
||||||
*p = i;
|
*p = i;
|
||||||
COUT("map write " << *p);
|
CERR("map write " << *p);
|
||||||
gMap.write(i,p);
|
gMap.write(i,p);
|
||||||
|
m_last_write_val = i;
|
||||||
if (random()%2) sleep(1);
|
if (random()%2) sleep(1);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -81,7 +94,9 @@ void* mapReader(void*)
|
|||||||
{
|
{
|
||||||
for (int i=0; i<20; i++) {
|
for (int i=0; i<20; i++) {
|
||||||
int *p = gMap.read(i);
|
int *p = gMap.read(i);
|
||||||
COUT("map read " << *p);
|
CERR("map read " << *p);
|
||||||
|
assert(*p == i);
|
||||||
|
m_last_read_val = *p;
|
||||||
// InterthreadMap will delete the pointers
|
// InterthreadMap will delete the pointers
|
||||||
// delete p;
|
// delete p;
|
||||||
}
|
}
|
||||||
@@ -109,6 +124,13 @@ int main(int argc, char *argv[])
|
|||||||
qWriterThread.join();
|
qWriterThread.join();
|
||||||
mapReaderThread.join();
|
mapReaderThread.join();
|
||||||
mapWriterThread.join();
|
mapWriterThread.join();
|
||||||
|
|
||||||
|
assert(q_last_write_val == 19);
|
||||||
|
assert(q_last_read_val == 19);
|
||||||
|
assert(m_last_write_val == 19);
|
||||||
|
assert(m_last_read_val == 19);
|
||||||
|
|
||||||
|
printf("Done\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
1
tests/CommonLibs/InterthreadTest.ok
Normal file
1
tests/CommonLibs/InterthreadTest.ok
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Done
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2009 Free Software Foundation, Inc.
|
||||||
|
* Copyright 2010 Kestrel Signal Processing, Inc.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
@@ -23,23 +24,25 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "Timeval.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
using namespace std;
|
#include "Logger.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
gLogInit("NOTICE");
|
||||||
|
|
||||||
Timeval then(10000);
|
Log(LOG_EMERG).get() << " testing the logger.";
|
||||||
cout << then.elapsed() << endl;
|
Log(LOG_ALERT).get() << " testing the logger.";
|
||||||
|
Log(LOG_CRIT).get() << " testing the logger.";
|
||||||
while (!then.passed()) {
|
Log(LOG_ERR).get() << " testing the logger.";
|
||||||
cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl;
|
Log(LOG_WARNING).get() << " testing the logger.";
|
||||||
usleep(500000);
|
Log(LOG_NOTICE).get() << " testing the logger.";
|
||||||
}
|
Log(LOG_INFO).get() << " testing the logger.";
|
||||||
cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl;
|
Log(LOG_DEBUG).get() << " testing the logger.";
|
||||||
|
std::cout << "----------- generating 20 alarms ----------" << std::endl;
|
||||||
|
for (int i = 0 ; i < 20 ; ++i) {
|
||||||
|
Log(LOG_ALERT).get() << i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
24
tests/CommonLibs/LogTest.err
Normal file
24
tests/CommonLibs/LogTest.err
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
EMERG testing the logger.
|
||||||
|
ALERT testing the logger.
|
||||||
|
CRIT testing the logger.
|
||||||
|
ERR testing the logger.
|
||||||
|
ALERT 0
|
||||||
|
ALERT 1
|
||||||
|
ALERT 2
|
||||||
|
ALERT 3
|
||||||
|
ALERT 4
|
||||||
|
ALERT 5
|
||||||
|
ALERT 6
|
||||||
|
ALERT 7
|
||||||
|
ALERT 8
|
||||||
|
ALERT 9
|
||||||
|
ALERT 10
|
||||||
|
ALERT 11
|
||||||
|
ALERT 12
|
||||||
|
ALERT 13
|
||||||
|
ALERT 14
|
||||||
|
ALERT 15
|
||||||
|
ALERT 16
|
||||||
|
ALERT 17
|
||||||
|
ALERT 18
|
||||||
|
ALERT 19
|
||||||
29
tests/CommonLibs/LogTest.ok
Normal file
29
tests/CommonLibs/LogTest.ok
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
EMERG testing the logger.
|
||||||
|
ALERT testing the logger.
|
||||||
|
CRIT testing the logger.
|
||||||
|
ERR testing the logger.
|
||||||
|
WARNING testing the logger.
|
||||||
|
NOTICE testing the logger.
|
||||||
|
INFO testing the logger.
|
||||||
|
DEBUG testing the logger.
|
||||||
|
----------- generating 20 alarms ----------
|
||||||
|
ALERT 0
|
||||||
|
ALERT 1
|
||||||
|
ALERT 2
|
||||||
|
ALERT 3
|
||||||
|
ALERT 4
|
||||||
|
ALERT 5
|
||||||
|
ALERT 6
|
||||||
|
ALERT 7
|
||||||
|
ALERT 8
|
||||||
|
ALERT 9
|
||||||
|
ALERT 10
|
||||||
|
ALERT 11
|
||||||
|
ALERT 12
|
||||||
|
ALERT 13
|
||||||
|
ALERT 14
|
||||||
|
ALERT 15
|
||||||
|
ALERT 16
|
||||||
|
ALERT 17
|
||||||
|
ALERT 18
|
||||||
|
ALERT 19
|
||||||
44
tests/CommonLibs/Makefile.am
Normal file
44
tests/CommonLibs/Makefile.am
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
|
AM_CPPFLAGS = -Wall -I$(top_srcdir)/CommonLibs $(STD_DEFINES_AND_INCLUDES) -g
|
||||||
|
|
||||||
|
EXTRA_DIST = BitVectorTest.ok \
|
||||||
|
PRBSTest.ok \
|
||||||
|
InterthreadTest.ok \
|
||||||
|
SocketsTest.ok \
|
||||||
|
TimevalTest.ok \
|
||||||
|
VectorTest.ok \
|
||||||
|
LogTest.ok
|
||||||
|
|
||||||
|
noinst_PROGRAMS = \
|
||||||
|
BitVectorTest \
|
||||||
|
PRBSTest \
|
||||||
|
InterthreadTest \
|
||||||
|
SocketsTest \
|
||||||
|
TimevalTest \
|
||||||
|
VectorTest \
|
||||||
|
LogTest
|
||||||
|
|
||||||
|
BitVectorTest_SOURCES = BitVectorTest.cpp
|
||||||
|
BitVectorTest_LDADD = $(COMMON_LA)
|
||||||
|
|
||||||
|
PRBSTest_SOURCES = PRBSTest.cpp
|
||||||
|
|
||||||
|
InterthreadTest_SOURCES = InterthreadTest.cpp
|
||||||
|
InterthreadTest_LDADD = $(COMMON_LA)
|
||||||
|
InterthreadTest_LDFLAGS = -lpthread
|
||||||
|
|
||||||
|
SocketsTest_SOURCES = SocketsTest.cpp
|
||||||
|
SocketsTest_LDADD = $(COMMON_LA)
|
||||||
|
SocketsTest_LDFLAGS = -lpthread
|
||||||
|
|
||||||
|
TimevalTest_SOURCES = TimevalTest.cpp
|
||||||
|
TimevalTest_LDADD = $(COMMON_LA)
|
||||||
|
|
||||||
|
VectorTest_SOURCES = VectorTest.cpp
|
||||||
|
VectorTest_LDADD = $(COMMON_LA)
|
||||||
|
|
||||||
|
LogTest_SOURCES = LogTest.cpp
|
||||||
|
LogTest_LDADD = $(COMMON_LA)
|
||||||
|
|
||||||
|
MOSTLYCLEANFILES += testSource testDestination
|
||||||
4
tests/CommonLibs/PRBSTest.ok
Normal file
4
tests/CommonLibs/PRBSTest.ok
Normal file
File diff suppressed because one or more lines are too long
@@ -30,21 +30,27 @@
|
|||||||
#include "Threads.h"
|
#include "Threads.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
static const int gNumToSend = 10;
|
static const int gNumToSend = 10;
|
||||||
|
|
||||||
|
static void sigalarm_handler(int foo)
|
||||||
void *testReaderIP(void *)
|
|
||||||
{
|
{
|
||||||
UDPSocket readSocket(5934, "localhost", 5061);
|
printf("FAIL: test did not run successfully\n");
|
||||||
readSocket.nonblocking();
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *testReaderIP(void *param)
|
||||||
|
{
|
||||||
|
UDPSocket *readSocket = (UDPSocket *)param;
|
||||||
|
readSocket->nonblocking();
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
while (rc<gNumToSend) {
|
while (rc<gNumToSend) {
|
||||||
char buf[MAX_UDP_LENGTH];
|
char buf[MAX_UDP_LENGTH] = { 0 };
|
||||||
int count = readSocket.read(buf, MAX_UDP_LENGTH);
|
int count = readSocket->read(buf, MAX_UDP_LENGTH);
|
||||||
if (count>0) {
|
if (count>0) {
|
||||||
COUT("read: " << buf);
|
CERR("read: " << buf);
|
||||||
rc++;
|
rc++;
|
||||||
} else {
|
} else {
|
||||||
sleep(2);
|
sleep(2);
|
||||||
@@ -53,51 +59,42 @@ void *testReaderIP(void *)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void *testReaderUnix(void *)
|
|
||||||
{
|
|
||||||
UDDSocket readSocket("testDestination");
|
|
||||||
readSocket.nonblocking();
|
|
||||||
int rc = 0;
|
|
||||||
while (rc<gNumToSend) {
|
|
||||||
char buf[MAX_UDP_LENGTH];
|
|
||||||
int count = readSocket.read(buf, MAX_UDP_LENGTH);
|
|
||||||
if (count>0) {
|
|
||||||
COUT("read: " << buf);
|
|
||||||
rc++;
|
|
||||||
} else {
|
|
||||||
sleep(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[] )
|
int main(int argc, char * argv[] )
|
||||||
{
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if (signal(SIGALRM, sigalarm_handler) == SIG_ERR) {
|
||||||
|
perror("signal");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the test takes longer than 2*gNumToSend seconds, abort it */
|
||||||
|
alarm(2* gNumToSend);
|
||||||
|
|
||||||
|
UDPSocket readSocket("127.0.0.1", 0);
|
||||||
|
UDPSocket socket1("127.0.0.1", 0, "localhost", readSocket.port());
|
||||||
|
|
||||||
|
CERR("socket1: " << socket1.port() << ", readSocket: " << readSocket.port());
|
||||||
|
|
||||||
Thread readerThreadIP;
|
Thread readerThreadIP;
|
||||||
readerThreadIP.start(testReaderIP,NULL);
|
readerThreadIP.start(testReaderIP, &readSocket);
|
||||||
Thread readerThreadUnix;
|
|
||||||
readerThreadUnix.start(testReaderUnix,NULL);
|
|
||||||
|
|
||||||
UDPSocket socket1(5061, "127.0.0.1",5934);
|
|
||||||
UDDSocket socket1U("testSource","testDestination");
|
|
||||||
|
|
||||||
COUT("socket1: " << socket1.port());
|
|
||||||
|
|
||||||
// give the readers time to open
|
// give the readers time to open
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
for (int i=0; i<gNumToSend; i++) {
|
for (int i=0; i<gNumToSend; i++) {
|
||||||
socket1.write("Hello IP land");
|
CERR("write");
|
||||||
socket1U.write("Hello Unix domain");
|
count = socket1.write("Hello IP land");
|
||||||
sleep(1);
|
if (count < 0) {
|
||||||
|
COUT("FAIL: write");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
readerThreadIP.join();
|
readerThreadIP.join();
|
||||||
readerThreadUnix.join();
|
|
||||||
|
printf("Done\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: ts=4 sw=4
|
// vim: ts=4 sw=4
|
||||||
1
tests/CommonLibs/SocketsTest.ok
Normal file
1
tests/CommonLibs/SocketsTest.ok
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Done
|
||||||
64
tests/CommonLibs/TimevalTest.cpp
Normal file
64
tests/CommonLibs/TimevalTest.cpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*
|
||||||
|
* This use of this software may be subject to additional restrictions.
|
||||||
|
* See the LEGAL file in the main directory for details.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "Timeval.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
long last_remaining = 10000;
|
||||||
|
Timeval then(last_remaining);
|
||||||
|
assert(then.elapsed() == -last_remaining);
|
||||||
|
cerr << then << " elapsed: " << then.elapsed() << endl;
|
||||||
|
|
||||||
|
/* Check that last_remaining parameter affects setting time in the future */
|
||||||
|
usleep(10000);
|
||||||
|
double increased_time_secs = Timeval().seconds();
|
||||||
|
assert(increased_time_secs <= then.seconds());
|
||||||
|
|
||||||
|
struct timespec invariant_time = then.timespec();
|
||||||
|
int loops = 0;
|
||||||
|
|
||||||
|
while (!then.passed()) {
|
||||||
|
struct timespec tspecnow = then.timespec();
|
||||||
|
cerr << "now: " << Timeval().seconds() << " then: " << then << " remaining: " << then.remaining() << endl;
|
||||||
|
assert(last_remaining >= then.remaining());
|
||||||
|
assert(tspecnow.tv_sec == invariant_time.tv_sec && tspecnow.tv_nsec == invariant_time.tv_nsec);
|
||||||
|
usleep(500000);
|
||||||
|
loops++;
|
||||||
|
}
|
||||||
|
cerr << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl;
|
||||||
|
assert(then.remaining() <= 0);
|
||||||
|
assert(loops >= 18);
|
||||||
|
|
||||||
|
printf("Done\n");
|
||||||
|
}
|
||||||
1
tests/CommonLibs/TimevalTest.ok
Normal file
1
tests/CommonLibs/TimevalTest.ok
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Done
|
||||||
@@ -28,10 +28,6 @@
|
|||||||
#include "Vector.h"
|
#include "Vector.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// We must have a gConfig now to include Vector.
|
|
||||||
#include "Configuration.h"
|
|
||||||
ConfigurationTable gConfig;
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
typedef Vector<int> TestVector;
|
typedef Vector<int> TestVector;
|
||||||
10
tests/CommonLibs/VectorTest.ok
Normal file
10
tests/CommonLibs/VectorTest.ok
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
0 1 2 3 4
|
||||||
|
10 11 12 13 14
|
||||||
|
0 1 2 3 4 10 11 12 13 14
|
||||||
|
0 1 2
|
||||||
|
3 4 10 11 12 13 14
|
||||||
|
8 8 8 8 8 8 8 8 8 8
|
||||||
|
8 8 8 0 1 2 3 4 8 8
|
||||||
|
1 2 3
|
||||||
|
8 8 8 0 9 9 9 4 8 8
|
||||||
|
9 9 9
|
||||||
41
tests/Makefile.am
Normal file
41
tests/Makefile.am
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
SUBDIRS = \
|
||||||
|
CommonLibs \
|
||||||
|
Transceiver52M \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
|
||||||
|
$(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||||
|
:;{ \
|
||||||
|
echo '# Signature of the current package.' && \
|
||||||
|
echo 'm4_define([AT_PACKAGE_NAME],' && \
|
||||||
|
echo ' [$(PACKAGE_NAME)])' && \
|
||||||
|
echo 'm4_define([AT_PACKAGE_TARNAME],' && \
|
||||||
|
echo ' [$(PACKAGE_TARNAME)])' && \
|
||||||
|
echo 'm4_define([AT_PACKAGE_VERSION],' && \
|
||||||
|
echo ' [$(PACKAGE_VERSION)])' && \
|
||||||
|
echo 'm4_define([AT_PACKAGE_STRING],' && \
|
||||||
|
echo ' [$(PACKAGE_STRING)])' && \
|
||||||
|
echo 'm4_define([AT_PACKAGE_BUGREPORT],' && \
|
||||||
|
echo ' [$(PACKAGE_BUGREPORT)])'; \
|
||||||
|
echo 'm4_define([AT_PACKAGE_URL],' && \
|
||||||
|
echo ' [$(PACKAGE_URL)])'; \
|
||||||
|
} >'$(srcdir)/package.m4'
|
||||||
|
|
||||||
|
EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE)
|
||||||
|
TESTSUITE = $(srcdir)/testsuite
|
||||||
|
DISTCLEANFILES = atconfig $(NULL)
|
||||||
|
|
||||||
|
check-local: atconfig $(TESTSUITE)
|
||||||
|
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
|
||||||
|
|
||||||
|
installcheck-local: atconfig $(TESTSUITE)
|
||||||
|
$(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' $(TESTSUITEFLAGS)
|
||||||
|
|
||||||
|
clean-local:
|
||||||
|
test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean
|
||||||
|
|
||||||
|
AUTOM4TE = $(SHELL) $(top_srcdir)/missing --run autom4te
|
||||||
|
AUTOTEST = $(AUTOM4TE) --language=autotest
|
||||||
|
$(TESTSUITE): $(srcdir)/testsuite.at $(srcdir)/package.m4
|
||||||
|
$(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
|
||||||
|
mv $@.tmp $@
|
||||||
17
tests/Transceiver52M/Makefile.am
Normal file
17
tests/Transceiver52M/Makefile.am
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
|
AM_CFLAGS = -Wall -I$(top_srcdir)/Transciever52 $(STD_DEFINES_AND_INCLUDES) -g
|
||||||
|
|
||||||
|
EXTRA_DIST = convolve_test.ok
|
||||||
|
|
||||||
|
noinst_PROGRAMS = \
|
||||||
|
convolve_test
|
||||||
|
|
||||||
|
convolve_test_SOURCES = convolve_test.c
|
||||||
|
convolve_test_LDADD = $(COMMON_LA) $(ARCH_LA)
|
||||||
|
if HAVE_SSE3
|
||||||
|
convolve_test_CFLAGS = $(AM_CFLAGS) $(SIMD_FLAGS)
|
||||||
|
endif
|
||||||
|
if HAVE_SSE4_1
|
||||||
|
convolve_test_CFLAGS = $(AM_CFLAGS) $(SIMD_FLAGS)
|
||||||
|
endif
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <osmocom/core/utils.h>
|
#include <stdlib.h>
|
||||||
#include "../../Transceiver52M/common/convolve.h"
|
#include "../../Transceiver52M/common/convolve.h"
|
||||||
|
|
||||||
#define TESTVEC_LEN 1000
|
#define TESTVEC_LEN 1000
|
||||||
53
tests/testsuite.at
Normal file
53
tests/testsuite.at
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
AT_INIT
|
||||||
|
AT_BANNER([Regression tests.])
|
||||||
|
|
||||||
|
AT_SETUP([BitVectorTest])
|
||||||
|
AT_KEYWORDS([BitVectorTest])
|
||||||
|
cat $abs_srcdir/CommonLibs/BitVectorTest.ok > expout
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/CommonLibs/BitVectorTest], [], [expout], [])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([InterthreadTest])
|
||||||
|
AT_KEYWORDS([InterthreadTest])
|
||||||
|
cat $abs_srcdir/CommonLibs/InterthreadTest.ok > expout
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/CommonLibs/InterthreadTest], [], [expout], [ignore])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([LogTest])
|
||||||
|
AT_KEYWORDS([LogTest])
|
||||||
|
cat $abs_srcdir/CommonLibs/LogTest.ok > expout
|
||||||
|
cat $abs_srcdir/CommonLibs/LogTest.err > experr
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/CommonLibs/LogTest], [], [expout], [experr])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([PRBSTest])
|
||||||
|
AT_KEYWORDS([PRBSTest])
|
||||||
|
cat $abs_srcdir/CommonLibs/PRBSTest.ok > expout
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/CommonLibs/PRBSTest], [], [expout], [])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([SocketsTest])
|
||||||
|
AT_KEYWORDS([SocketsTest])
|
||||||
|
cat $abs_srcdir/CommonLibs/SocketsTest.ok > expout
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/CommonLibs/SocketsTest], [], [expout], [ignore])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([TimevalTest])
|
||||||
|
AT_KEYWORDS([TimevalTest])
|
||||||
|
cat $abs_srcdir/CommonLibs/TimevalTest.ok > expout
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/CommonLibs/TimevalTest], [], [expout], [ignore])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([VectorTest])
|
||||||
|
AT_KEYWORDS([VectorTest])
|
||||||
|
cat $abs_srcdir/CommonLibs/VectorTest.ok > expout
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/CommonLibs/VectorTest], [], [expout], [])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([convolve_test])
|
||||||
|
AT_KEYWORDS([convolve_test])
|
||||||
|
# Different results for i686, x86_64 and ARM. see OS#2826, OS#2828, and https://lists.osmocom.org/pipermail/openbsc/2018-January/011655.html
|
||||||
|
AT_SKIP_IF(true)
|
||||||
|
cat $abs_srcdir/Transceiver52M/convolve_test.ok > expout
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/Transceiver52M/convolve_test], [], [expout], [])
|
||||||
|
AT_CLEANUP
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
all: main.o convolve_base.o convolve.o convolve_sse_3.o
|
|
||||||
gcc -g -Wall ./*.o -o convtest -losmocore
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f ./*.o
|
|
||||||
rm -f ./convtest
|
|
||||||
|
|
||||||
main.o: main.c
|
|
||||||
gcc -g -Wall -c main.c
|
|
||||||
|
|
||||||
convolve_base.o: ../../Transceiver52M/common/convolve_base.c
|
|
||||||
gcc -std=c99 -c ../../Transceiver52M/common/convolve_base.c
|
|
||||||
|
|
||||||
convolve.o: ../../Transceiver52M/x86/convolve.c
|
|
||||||
gcc -std=c99 -c ../../Transceiver52M/x86/convolve.c -I ../../Transceiver52M/common/ -msse3 -DHAVE_SSE3
|
|
||||||
|
|
||||||
convolve_sse_3.o: ../../Transceiver52M/x86/convolve_sse_3.c
|
|
||||||
gcc -std=c99 -c ../../Transceiver52M/x86/convolve_sse_3.c -I ../../Transceiver52M/common/ -msse3 -DHAVE_SSE3
|
|
||||||
Reference in New Issue
Block a user