kalibrate-rtl/src/kal.cc
Hoernchen 482dd05ecd add win32 support
Signed-off-by: Steve Markgraf <steve@steve-m.de>
2012-10-11 02:10:36 +02:00

301 lines
7.5 KiB
C++

/*
* Copyright (c) 2010, Joshua Lackey
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* kal
*
* Two functions:
*
* 1. Calculates the frequency offset between a local GSM tower and the
* USRP clock.
*
* 2. Identifies the frequency of all GSM base stations in a given band.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#else
#define PACKAGE_VERSION "custom build"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#endif
#ifdef D_HOST_OSX
#include <libgen.h>
#endif /* D_HOST_OSX */
#include <string.h>
#include <errno.h>
#include "usrp_source.h"
#include "fcch_detector.h"
#include "arfcn_freq.h"
#include "offset.h"
#include "c0_detect.h"
#include "version.h"
#ifdef _WIN32
#include <getopt.h>
#define basename(x) "meh"
#define strtof strtod
#endif
#define GSM_RATE (1625000.0 / 6.0)
int g_verbosity = 0;
int g_debug = 0;
void usage(char *prog) {
printf("kalibrate v%s-rtl, Copyright (c) 2010, Joshua Lackey\n", kal_version_string);
printf("modified for use with rtl-sdr devices, Copyright (c) 2012, Steve Markgraf");
printf("\nUsage:\n");
printf("\tGSM Base Station Scan:\n");
printf("\t\t%s <-s band indicator> [options]\n", basename(prog));
printf("\n");
printf("\tClock Offset Calculation:\n");
printf("\t\t%s <-f frequency | -c channel> [options]\n", basename(prog));
printf("\n");
printf("Where options are:\n");
printf("\t-s\tband to scan (GSM850, GSM-R, GSM900, EGSM, DCS, PCS)\n");
printf("\t-f\tfrequency of nearby GSM base station\n");
printf("\t-c\tchannel of nearby GSM base station\n");
printf("\t-b\tband indicator (GSM850, GSM-R, GSM900, EGSM, DCS, PCS)\n");
printf("\t-g\tgain in dB\n");
printf("\t-d\trtl-sdr device index\n");
printf("\t-e\tinitial frequency error in ppm\n");
printf("\t-v\tverbose\n");
printf("\t-D\tenable debug messages\n");
printf("\t-h\thelp\n");
exit(-1);
}
int main(int argc, char **argv) {
char *endptr;
int c, antenna = 1, bi = BI_NOT_DEFINED, chan = -1, bts_scan = 0;
int ppm_error = 0;
unsigned int subdev = 0, decimation = 192;
long int fpga_master_clock_freq = 52000000;
float gain = 0;
double freq = -1.0, fd;
usrp_source *u;
while((c = getopt(argc, argv, "f:c:s:b:R:A:g:e:d:vDh?")) != EOF) {
switch(c) {
case 'f':
freq = strtod(optarg, 0);
break;
case 'c':
chan = strtoul(optarg, 0, 0);
break;
case 's':
if((bi = str_to_bi(optarg)) == -1) {
fprintf(stderr, "error: bad band "
"indicator: ``%s''\n", optarg);
usage(argv[0]);
}
bts_scan = 1;
break;
case 'b':
if((bi = str_to_bi(optarg)) == -1) {
fprintf(stderr, "error: bad band "
"indicator: ``%s''\n", optarg);
usage(argv[0]);
}
break;
case 'R':
errno = 0;
subdev = strtoul(optarg, &endptr, 0);
if((!errno) && (endptr != optarg))
break;
if(tolower(*optarg) == 'a') {
subdev = 0;
} else if(tolower(*optarg) == 'b') {
subdev = 1;
} else {
fprintf(stderr, "error: bad side: "
"``%s''\n",
optarg);
usage(argv[0]);
}
break;
case 'A':
if(!strcmp(optarg, "RX2")) {
antenna = 1;
} else if(!strcmp(optarg, "TX/RX")) {
antenna = 0;
} else {
errno = 0;
antenna = strtoul(optarg, &endptr, 0);
if(errno || (endptr == optarg)) {
fprintf(stderr, "error: bad "
"antenna: ``%s''\n",
optarg);
usage(argv[0]);
}
}
break;
case 'g':
gain = strtof(optarg, 0) * 10;
break;
case 'F':
fpga_master_clock_freq = strtol(optarg, 0, 0);
if(!fpga_master_clock_freq)
fpga_master_clock_freq = (long int)strtod(optarg, 0);
// was answer in MHz?
if(fpga_master_clock_freq < 1000) {
fpga_master_clock_freq *= 1000000;
}
break;
case 'e':
ppm_error = strtol(optarg, 0, 0);
break;
case 'd':
subdev = strtol(optarg, 0, 0);
break;
case 'v':
g_verbosity++;
break;
case 'D':
g_debug = 1;
break;
case 'h':
case '?':
default:
usage(argv[0]);
break;
}
}
// sanity check frequency / channel
if(bts_scan) {
if(bi == BI_NOT_DEFINED) {
fprintf(stderr, "error: scaning requires band\n");
usage(argv[0]);
}
} else {
if(freq < 0.0) {
if(chan < 0) {
fprintf(stderr, "error: must enter channel or "
"frequency\n");
usage(argv[0]);
}
if((freq = arfcn_to_freq(chan, &bi)) < 869e6)
usage(argv[0]);
}
if((freq < 869e6) || (2e9 < freq)) {
fprintf(stderr, "error: bad frequency: %lf\n", freq);
usage(argv[0]);
}
chan = freq_to_arfcn(freq, &bi);
}
#if 0
// sanity check clock
if(fpga_master_clock_freq < 48000000) {
fprintf(stderr, "error: FPGA master clock too slow: %li\n", fpga_master_clock_freq);
usage(argv[0]);
}
// calculate decimation -- get as close to GSM rate as we can
fd = (double)fpga_master_clock_freq / GSM_RATE;
decimation = (unsigned int)fd;
#endif
if(g_debug) {
#ifdef D_HOST_OSX
printf("debug: Mac OS X version\n");
#endif
printf("debug: FPGA Master Clock Freq:\t%li\n", fpga_master_clock_freq);
printf("debug: decimation :\t%u\n", decimation);
printf("debug: RX Subdev Spec :\t%s\n", subdev? "B" : "A");
printf("debug: Antenna :\t%s\n", antenna? "RX2" : "TX/RX");
printf("debug: Gain :\t%f\n", gain);
}
u = new usrp_source(decimation, fpga_master_clock_freq);
if(!u) {
fprintf(stderr, "error: usrp_source\n");
return -1;
}
if(u->open(subdev) == -1) {
fprintf(stderr, "error: usrp_source::open\n");
return -1;
}
// u->set_antenna(antenna);
if (gain != 0) {
if(!u->set_gain(gain)) {
fprintf(stderr, "error: usrp_source::set_gain\n");
return -1;
}
}
if (ppm_error != 0) {
if(u->set_freq_correction(ppm_error) < 0) {
fprintf(stderr, "error: usrp_source::set_freq_correction\n");
return -1;
}
}
if(!bts_scan) {
if(!u->tune(freq)) {
fprintf(stderr, "error: usrp_source::tune\n");
return -1;
}
fprintf(stderr, "%s: Calculating clock frequency offset.\n",
basename(argv[0]));
fprintf(stderr, "Using %s channel %d (%.1fMHz)\n",
bi_to_str(bi), chan, freq / 1e6);
return offset_detect(u);
}
fprintf(stderr, "%s: Scanning for %s base stations.\n",
basename(argv[0]), bi_to_str(bi));
return c0_detect(u, bi);
}