示例#1
0
文件: xb300.c 项目: 2ephyr/bladeRF
static int enable_xb300(struct cli_state *state)
{
    int status;

    printf("  Enabling XB-300 Amplifier board\n");
    status = bladerf_expansion_attach(state->dev, BLADERF_XB_300);
    if (status != 0) {
        state->last_lib_error = status;
        return CLI_RET_LIBBLADERF;
    }

    printf("  XB-300 Amplifier board successfully enabled\n\n");

    return status;
}
示例#2
0
文件: xb100.c 项目: 2ephyr/bladeRF
int cmd_xb100(struct cli_state *state, int argc, char **argv)
{
    int modelnum = MODEL_INVALID;
    int status = 0;
    const char *subcommand = NULL;

    if (NULL == state) {
        assert(0);  // developer error
        return CLI_RET_INVPARAM;
    }

    if (argc < 3) {
        // incorrect number of arguments
        return CLI_RET_NARGS;
    }

    // xb 100 <subcommand> <args>
    modelnum = atoi(argv[1]);
    subcommand = argv[2];

    if (modelnum != MODEL_XB100) {
        assert(0);  // developer error
        return CLI_RET_INVPARAM;
    }

    putchar('\n');

    // xb 100 enable
    if (!strcmp(subcommand, "enable")) {
        printf("  Enabling XB-100 GPIO expansion board\n");
        status = bladerf_expansion_attach(state->dev, BLADERF_XB_100);
        if (status != 0) {
            state->last_lib_error = status;
            return CLI_RET_LIBBLADERF;
        }

        printf("  XB-100 GPIO expansion board successfully enabled\n\n");
    } else {
        // unknown subcommand
        cli_err(state, subcommand, "Invalid subcommand for xb %d\n", modelnum);
        return CLI_RET_INVPARAM;
    }

    return status;
}
示例#3
0
bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool force)
{
	bool forwardChange    = false;
    bool suspendOwnThread = false;
    bool threadWasRunning = false;
    QList<QString> reverseAPIKeys;
//	QMutexLocker mutexLocker(&m_mutex);

	qDebug() << "BladerfOutput::applySettings: m_dev: " << m_dev;

    if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) {
        reverseAPIKeys.append("centerFrequency");
    }
    if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) {
        reverseAPIKeys.append("devSampleRate");
    }
    if ((m_settings.m_log2Interp != settings.m_log2Interp) || force) {
        reverseAPIKeys.append("log2Interp");
    }

    if ((m_settings.m_devSampleRate != settings.m_devSampleRate) ||
        (m_settings.m_log2Interp != settings.m_log2Interp) || force)
    {
        suspendOwnThread = true;
    }

    if (suspendOwnThread)
    {
        if (m_bladerfThread)
        {
            if (m_bladerfThread->isRunning())
            {
                m_bladerfThread->stopWork();
                threadWasRunning = true;
            }
        }
    }

	if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || (m_settings.m_log2Interp != settings.m_log2Interp) || force)
	{
	    int fifoSize;

	    if (settings.m_log2Interp >= 5)
	    {
	        fifoSize = DeviceBladeRF1Shared::m_sampleFifoMinSize32;
	    }
	    else
	    {
            fifoSize = (std::max)(
	            (int) ((settings.m_devSampleRate/(1<<settings.m_log2Interp)) * DeviceBladeRF1Shared::m_sampleFifoLengthInSeconds),
	            DeviceBladeRF1Shared::m_sampleFifoMinSize);
	    }

        m_sampleSourceFifo.resize(fifoSize);
	}

    if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
    {
        forwardChange = true;

        if (m_dev != 0)
        {
            unsigned int actualSamplerate;

            if (bladerf_set_sample_rate(m_dev, BLADERF_MODULE_TX, settings.m_devSampleRate, &actualSamplerate) < 0) {
                qCritical("BladerfOutput::applySettings: could not set sample rate: %d", settings.m_devSampleRate);
            } else {
                qDebug() << "BladerfOutput::applySettings: bladerf_set_sample_rate(BLADERF_MODULE_TX) actual sample rate is " << actualSamplerate;
            }
        }
    }

    if ((m_settings.m_log2Interp != settings.m_log2Interp) || force)
    {
        forwardChange = true;

        if (m_bladerfThread != 0)
        {
            m_bladerfThread->setLog2Interpolation(settings.m_log2Interp);
            qDebug() << "BladerfOutput::applySettings: set interpolation to " << (1<<settings.m_log2Interp);
        }
    }

	if ((m_settings.m_vga1 != settings.m_vga1) || force)
	{
        reverseAPIKeys.append("vga1");

		if (m_dev != 0)
		{
			if (bladerf_set_txvga1(m_dev, settings.m_vga1) != 0) {
				qDebug("BladerfOutput::applySettings: bladerf_set_txvga1() failed");
			} else {
				qDebug() << "BladerfOutput::applySettings: VGA1 gain set to " << settings.m_vga1;
			}
		}
	}

	if ((m_settings.m_vga2 != settings.m_vga2) || force)
	{
        reverseAPIKeys.append("vga2");

		if(m_dev != 0)
		{
			if (bladerf_set_txvga2(m_dev, settings.m_vga2) != 0) {
				qDebug("BladerfOutput::applySettings:bladerf_set_rxvga2() failed");
			} else {
				qDebug() << "BladerfOutput::applySettings: VGA2 gain set to " << settings.m_vga2;
			}
		}
	}

	if ((m_settings.m_xb200 != settings.m_xb200) || force)
	{
        reverseAPIKeys.append("xb200");

		if (m_dev != 0)
		{
            bool changeSettings;

            if (m_deviceAPI->getSourceBuddies().size() > 0)
            {
                DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[0];

                if (buddy->getDeviceSourceEngine()->state() == DSPDeviceSourceEngine::StRunning) { // Tx side running
                    changeSettings = false;
                } else {
                    changeSettings = true;
                }
            }
            else // No Rx open
            {
                changeSettings = true;
            }

            if (changeSettings)
            {
                if (settings.m_xb200)
                {
                    if (bladerf_expansion_attach(m_dev, BLADERF_XB_200) != 0) {
                        qDebug("BladerfOutput::applySettings: bladerf_expansion_attach(xb200) failed");
                    } else {
                        qDebug() << "BladerfOutput::applySettings: Attach XB200";
                    }
                }
                else
                {
                    if (bladerf_expansion_attach(m_dev, BLADERF_XB_NONE) != 0) {
                        qDebug("BladerfOutput::applySettings: bladerf_expansion_attach(none) failed");
                    } else {
                        qDebug() << "BladerfOutput::applySettings: Detach XB200";
                    }
                }

                m_sharedParams.m_xb200Attached = settings.m_xb200;
            }
        }
	}

	if ((m_settings.m_xb200Path != settings.m_xb200Path) || force)
	{
        reverseAPIKeys.append("xb200Path");

		if (m_dev != 0)
		{
			if (bladerf_xb200_set_path(m_dev, BLADERF_MODULE_TX, settings.m_xb200Path) != 0) {
				qDebug("BladerfOutput::applySettings: bladerf_xb200_set_path(BLADERF_MODULE_TX) failed");
			} else {
				qDebug() << "BladerfOutput::applySettings: set xb200 path to " << settings.m_xb200Path;
			}
		}
	}

	if ((m_settings.m_xb200Filter != settings.m_xb200Filter) || force)
	{
        reverseAPIKeys.append("xb200Filter");

		if (m_dev != 0)
		{
			if (bladerf_xb200_set_filterbank(m_dev, BLADERF_MODULE_TX, settings.m_xb200Filter) != 0) {
				qDebug("BladerfOutput::applySettings: bladerf_xb200_set_filterbank(BLADERF_MODULE_TX) failed");
			} else {
				qDebug() << "BladerfOutput::applySettings: set xb200 filter to " << settings.m_xb200Filter;
			}
		}
	}

	if ((m_settings.m_bandwidth != settings.m_bandwidth) || force)
	{
        reverseAPIKeys.append("bandwidth");

		if (m_dev != 0)
		{
			unsigned int actualBandwidth;

			if (bladerf_set_bandwidth(m_dev, BLADERF_MODULE_TX, settings.m_bandwidth, &actualBandwidth) < 0) {
				qCritical("BladerfOutput::applySettings: could not set bandwidth: %d", settings.m_bandwidth);
			} else {
				qDebug() << "BladerfOutput::applySettings: bladerf_set_bandwidth(BLADERF_MODULE_TX) actual bandwidth is " << actualBandwidth;
			}
		}
	}

	if (m_settings.m_centerFrequency != settings.m_centerFrequency)
	{
		forwardChange = true;
	}

	if (m_dev != 0)
	{
		if (bladerf_set_frequency( m_dev, BLADERF_MODULE_TX, settings.m_centerFrequency ) != 0)
		{
			qDebug("BladerfOutput::applySettings: bladerf_set_frequency(%lld) failed", settings.m_centerFrequency);
		}
	}

    if (threadWasRunning)
    {
        m_bladerfThread->startWork();
    }

    if (settings.m_useReverseAPI)
    {
        bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
                (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
                (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
                (m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex);
        webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
    }

    m_settings = settings;

	if (forwardChange)
	{
		int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2Interp);
		DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency);
		m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
	}

	qDebug() << "BladerfOutput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz"
			<< " device sample rate: " << m_settings.m_devSampleRate << "S/s"
			<< " baseband sample rate: " << m_settings.m_devSampleRate/(1<<m_settings.m_log2Interp) << "S/s"
			<< " BW: " << m_settings.m_bandwidth << "Hz";

	return true;
}
示例#4
0
文件: main.c 项目: DINKIN/bladeRF
int main(int argc, char *argv[])
{
    int status;
    struct app_params p;
    size_t i;
    struct bladerf *dev = NULL;
    bladerf_xb expected, attached;
    struct stats *stats = NULL;
    bool pass = true;

    status = get_params(argc, argv, &p);
    if (status != 0) {
        if (status == 1) {
            status = 0;
        }
        goto out;
    }

    for (i = 0; i < ARRAY_SIZE(tests); i++) {
        if (p.test_name == NULL || !strcasecmp(p.test_name, tests[i]->name)) {
            break;
        }
    }

    if (i >= ARRAY_SIZE(tests)) {
        fprintf(stderr, "Invalid test: %s\n", p.test_name);
        status = -1;
        goto out;
    }

    stats = calloc(ARRAY_SIZE(tests), sizeof(stats[0]));
    if (stats == NULL) {
        perror("calloc");
        status = -1;
        goto out;
    }

    status = bladerf_open(&dev, p.device_str);
    if (status != 0) {
        fprintf(stderr, "Failed to open device: %s\n",
                bladerf_strerror(status));
        goto out;
    }

    if (p.use_xb200) {
        expected = BLADERF_XB_200;

        status = bladerf_expansion_attach(dev, BLADERF_XB_200);
        if (status != 0) {
            fprintf(stderr, "Failed to attach XB-200: %s\n",
                    bladerf_strerror(status));
            goto out;
        }
    } else {
        expected = BLADERF_XB_NONE;
    }

    status = bladerf_expansion_get_attached(dev, &attached);
    if (status != 0) {
        fprintf(stderr, "Failed to query attached expansion board: %s\n",
                bladerf_strerror(status));
        goto out;
    }

    if (expected != attached) {
        fprintf(stderr, "Unexpected expansion board readback: %d\n", attached);
        status = -1;
        goto out;
    }

    for (i = 0; i < ARRAY_SIZE(tests); i++) {
        if (p.test_name == NULL || !strcasecmp(p.test_name, tests[i]->name)) {
            p.randval_state = p.randval_seed;
            stats[i].ran = true;
            stats[i].failures = tests[i]->fn(dev, &p, false);
        }
    }

    puts("\nFailure counts");
    puts("--------------------------------------------");
    for (i = 0; i < ARRAY_SIZE(tests); i++) {
        if (stats[i].ran) {
            printf("%16s %u\n", tests[i]->name, stats[i].failures);
        }

        if (stats[i].failures != 0) {
            pass = false;
        }
    }
    puts("");

    status = pass ? 0 : -1;

out:
    if (dev) {
        bladerf_close(dev);
    }

    free(p.device_str);
    free(p.test_name);
    free(stats);
    return status;
}
示例#5
0
// Open BladeRF device.
BladeRFSource::BladeRFSource(const char *serial) :
    m_dev(0),
    m_sampleRate(1000000),
    m_actualSampleRate(1000000),
    m_frequency(300000000),
    m_minFrequency(300000000),
    m_bandwidth(1500000),
    m_actualBandwidth(1500000),
    m_lnaGain(3),
    m_vga1Gain(6),
    m_vga2Gain(5),
    m_thread(0)
{
    int status;
    struct bladerf_devinfo info;

    bladerf_init_devinfo(&info);

    if (serial != 0)
    {
        strncpy(info.serial, serial, BLADERF_SERIAL_LENGTH - 1);
        info.serial[BLADERF_SERIAL_LENGTH - 1] = '\0';
    }

    status = bladerf_open_with_devinfo(&m_dev, &info);

    if (status == BLADERF_ERR_NODEV)
    {
        std::ostringstream err_ostr;
        err_ostr << "No devices available with serial=" << serial;
        m_error = err_ostr.str();
        m_dev = 0;
    }
    else if (status != 0)
    {
        std::ostringstream err_ostr;
        err_ostr << "Failed to open device with serial=" << serial;
        m_error = err_ostr.str();
        m_dev = 0;
    }
    else
    {
        int fpga_loaded = bladerf_is_fpga_configured(m_dev);

        if (fpga_loaded < 0)
        {
            std::ostringstream err_ostr;
            err_ostr << "Failed to check FPGA state: " << bladerf_strerror(fpga_loaded);
            m_error = err_ostr.str();
            m_dev = 0;
        }
        else if (fpga_loaded == 0)
        {
            m_error = "The device's FPGA is not loaded.";
            m_dev = 0;
        }
        else
        {
            if ((status = bladerf_sync_config(m_dev, BLADERF_MODULE_RX, BLADERF_FORMAT_SC16_Q11, 64, 8192, 32, 10000)) < 0)
            {
                std::ostringstream err_ostr;
                err_ostr << "bladerf_sync_config failed with return code " << status;
                m_error = err_ostr.str();
                m_dev = 0;
            }
            else
            {
                if ((status = bladerf_enable_module(m_dev, BLADERF_MODULE_RX, true)) < 0)
                {
                    std::ostringstream err_ostr;
                    err_ostr << "bladerf_enable_module failed with return code " << status;
                    m_error = err_ostr.str();
                    m_dev = 0;
                }
                else
                {
                    if (bladerf_expansion_attach(m_dev, BLADERF_XB_200) == 0)
                    {
                        std::cerr << "BladeRFSource::BladeRFSource: Attached XB200 extension" << std::endl;

                        if ((status = bladerf_xb200_set_path(m_dev, BLADERF_MODULE_RX, BLADERF_XB200_MIX)) != 0)
                        {
                            std::cerr << "BladeRFSource::BladeRFSource: bladerf_xb200_set_path failed with return code " << status << std::endl;
                        }
                        else
                        {
                            if ((status = bladerf_xb200_set_filterbank(m_dev, BLADERF_MODULE_RX, BLADERF_XB200_AUTO_1DB)) != 0)
                            {
                                std::cerr << "BladeRFSource::BladeRFSource: bladerf_xb200_set_filterbank failed with return code " << status << std::endl;
                            }
                            else
                            {
                                std::cerr << "BladeRFSource::BladeRFSource: XB200 configured. Min freq set to 100kHz" << std::endl;
                                m_minFrequency = 100000;
                            }
                        }
                    }
                }
            }
        }
    }

    std::ostringstream lgains_ostr;

    for (int g: m_lnaGains) {
        lgains_ostr << g << " ";
    }

    m_lnaGainsStr = lgains_ostr.str();

    std::ostringstream v1gains_ostr;

    for (int g: m_vga1Gains) {
        v1gains_ostr << g << " ";
    }

    m_vga1GainsStr = v1gains_ostr.str();

    std::ostringstream v2gains_ostr;

    for (int g: m_vga2Gains) {
        v2gains_ostr << g << " ";
    }

    m_vga2GainsStr = v2gains_ostr.str();

    std::ostringstream bw_ostr;

    for (int b: m_halfbw) {
        bw_ostr << 2*b << " ";
    }

    m_bwfiltStr = bw_ostr.str();

    m_this = this;
}
示例#6
0
int main(int argc, char *argv[])
{
	sim_t s;
	char *devstr = NULL;
	int xb_board=0;

	int result;
	double duration;
	datetime_t t0;

	if (argc<3)
	{
		usage();
		exit(1);
	}
	s.finished = false;

	s.opt.navfile[0] = 0;
	s.opt.umfile[0] = 0;
	s.opt.g0.week = -1;
	s.opt.g0.sec = 0.0;
	s.opt.iduration = USER_MOTION_SIZE;
	s.opt.verb = TRUE;
	s.opt.nmeaGGA = FALSE;
	s.opt.staticLocationMode = TRUE; // default user motion
	s.opt.llh[0] = 35.274016 / R2D;
	s.opt.llh[1] = 137.013765 / R2D;
	s.opt.llh[2] = 100.0;
	s.opt.interactive = FALSE;

	while ((result=getopt(argc,argv,"e:u:g:l:t:d:x:i"))!=-1)
	{
		switch (result)
		{
		case 'e':
			strcpy(s.opt.navfile, optarg);
			break;
		case 'u':
			strcpy(s.opt.umfile, optarg);
			s.opt.nmeaGGA = FALSE;
			s.opt.staticLocationMode = FALSE;
			break;
		case 'g':
			strcpy(s.opt.umfile, optarg);
			s.opt.nmeaGGA = TRUE;
			s.opt.staticLocationMode = FALSE;
			break;
		case 'l':
			// Static geodetic coordinates input mode
			// Added by [email protected]
			s.opt.nmeaGGA = FALSE;
			s.opt.staticLocationMode = TRUE;
			sscanf(optarg,"%lf,%lf,%lf",&s.opt.llh[0],&s.opt.llh[1],&s.opt.llh[2]);
			s.opt.llh[0] /= R2D; // convert to RAD
			s.opt.llh[1] /= R2D; // convert to RAD
			break;
		case 't':
			sscanf(optarg, "%d/%d/%d,%d:%d:%lf", &t0.y, &t0.m, &t0.d, &t0.hh, &t0.mm, &t0.sec);
			if (t0.y<=1980 || t0.m<1 || t0.m>12 || t0.d<1 || t0.d>31 ||
				t0.hh<0 || t0.hh>23 || t0.mm<0 || t0.mm>59 || t0.sec<0.0 || t0.sec>=60.0)
			{
				printf("ERROR: Invalid date and time.\n");
				exit(1);
			}
			t0.sec = floor(t0.sec);
			date2gps(&t0, &s.opt.g0);
			break;
		case 'd':
			duration = atof(optarg);
			if (duration<0.0 || duration>((double)USER_MOTION_SIZE)/10.0)
			{
				printf("ERROR: Invalid duration.\n");
				exit(1);
			}
			s.opt.iduration = (int)(duration*10.0+0.5);
			break;
		case 'x':
			xb_board=atoi(optarg);
			break;
		case 'i':
			s.opt.interactive = TRUE;
			break;
		case ':':
		case '?':
			usage();
			exit(1);
		default:
			break;
		}
	}

	if (s.opt.navfile[0]==0)
	{
		printf("ERROR: GPS ephemeris file is not specified.\n");
		exit(1);
	}

	if (s.opt.umfile[0]==0 && !s.opt.staticLocationMode)
	{
		printf("ERROR: User motion file / NMEA GGA stream is not specified.\n");
		printf("You may use -l to specify the static location directly.\n");
		exit(1);
	}

	// Initialize simulator
	init_sim(&s);

	// Allocate TX buffer to hold each block of samples to transmit.
	s.tx.buffer = (int16_t *)malloc(SAMPLES_PER_BUFFER * sizeof(int16_t) * 2); // for 16-bit I and Q samples
	
	if (s.tx.buffer == NULL) {
		fprintf(stderr, "Failed to allocate TX buffer.\n");
		goto out;
	}

	// Allocate FIFOs to hold 0.1 seconds of I/Q samples each.
	s.fifo = (int16_t *)malloc(FIFO_LENGTH * sizeof(int16_t) * 2); // for 16-bit I and Q samples

	if (s.fifo == NULL) {
		fprintf(stderr, "Failed to allocate I/Q sample buffer.\n");
		goto out;
	}

	// Initializing device.
	printf("Opening and initializing device...\n");

	s.status = bladerf_open(&s.tx.dev, devstr);
	if (s.status != 0) {
		fprintf(stderr, "Failed to open device: %s\n", bladerf_strerror(s.status));
		goto out;
	}

	if(xb_board == 200) {
		printf("Initializing XB200 expansion board...\n");

		s.status = bladerf_expansion_attach(s.tx.dev, BLADERF_XB_200);
		if (s.status != 0) {
			fprintf(stderr, "Failed to enable XB200: %s\n", bladerf_strerror(s.status));
			goto out;
		}

		s.status = bladerf_xb200_set_filterbank(s.tx.dev, BLADERF_MODULE_TX, BLADERF_XB200_CUSTOM);
		if (s.status != 0) {
			fprintf(stderr, "Failed to set XB200 TX filterbank: %s\n", bladerf_strerror(s.status));
			goto out;
		}

		s.status = bladerf_xb200_set_path(s.tx.dev, BLADERF_MODULE_TX, BLADERF_XB200_BYPASS);
		if (s.status != 0) {
			fprintf(stderr, "Failed to enable TX bypass path on XB200: %s\n", bladerf_strerror(s.status));
			goto out;
		}

		//For sake of completeness set also RX path to a known good state.
		s.status = bladerf_xb200_set_filterbank(s.tx.dev, BLADERF_MODULE_RX, BLADERF_XB200_CUSTOM);
		if (s.status != 0) {
			fprintf(stderr, "Failed to set XB200 RX filterbank: %s\n", bladerf_strerror(s.status));
			goto out;
		}

		s.status = bladerf_xb200_set_path(s.tx.dev, BLADERF_MODULE_RX, BLADERF_XB200_BYPASS);
		if (s.status != 0) {
			fprintf(stderr, "Failed to enable RX bypass path on XB200: %s\n", bladerf_strerror(s.status));
			goto out;
		}
	}

	if(xb_board == 300) {
		fprintf(stderr, "XB300 does not support transmitting on GPS frequency\n");
		goto out;
	}

	s.status = bladerf_set_frequency(s.tx.dev, BLADERF_MODULE_TX, TX_FREQUENCY);
	if (s.status != 0) {
		fprintf(stderr, "Faield to set TX frequency: %s\n", bladerf_strerror(s.status));
		goto out;
	} 
	else {
		printf("TX frequency: %u Hz\n", TX_FREQUENCY);
	}

	s.status = bladerf_set_sample_rate(s.tx.dev, BLADERF_MODULE_TX, TX_SAMPLERATE, NULL);
	if (s.status != 0) {
		fprintf(stderr, "Failed to set TX sample rate: %s\n", bladerf_strerror(s.status));
		goto out;
	}
	else {
		printf("TX sample rate: %u sps\n", TX_SAMPLERATE);
	}

	s.status = bladerf_set_bandwidth(s.tx.dev, BLADERF_MODULE_TX, TX_BANDWIDTH, NULL);
	if (s.status != 0) {
		fprintf(stderr, "Failed to set TX bandwidth: %s\n", bladerf_strerror(s.status));
		goto out;
	}
	else {
		printf("TX bandwidth: %u Hz\n", TX_BANDWIDTH);
	}

	s.status = bladerf_set_txvga1(s.tx.dev, TX_VGA1);
	if (s.status != 0) {
		fprintf(stderr, "Failed to set TX VGA1 gain: %s\n", bladerf_strerror(s.status));
		goto out;
	}
	else {
		printf("TX VGA1 gain: %d dB\n", TX_VGA1);
	}

	s.status = bladerf_set_txvga2(s.tx.dev, TX_VGA2);
	if (s.status != 0) {
		fprintf(stderr, "Failed to set TX VGA2 gain: %s\n", bladerf_strerror(s.status));
		goto out;
	}
	else {
		printf("TX VGA2 gain: %d dB\n", TX_VGA2);
	}

	// Start GPS task.
	s.status = start_gps_task(&s);
	if (s.status < 0) {
		fprintf(stderr, "Failed to start GPS task.\n");
		goto out;
	}
	else
		printf("Creating GPS task...\n");

	// Wait until GPS task is initialized
	pthread_mutex_lock(&(s.tx.lock));
	while (!s.gps.ready)
		pthread_cond_wait(&(s.gps.initialization_done), &(s.tx.lock));
	pthread_mutex_unlock(&(s.tx.lock));

	// Fillfull the FIFO.
	if (is_fifo_write_ready(&s))
		pthread_cond_signal(&(s.fifo_write_ready));

	// Configure the TX module for use with the synchronous interface.
	s.status = bladerf_sync_config(s.tx.dev,
			BLADERF_MODULE_TX,
			BLADERF_FORMAT_SC16_Q11,
			NUM_BUFFERS,
			SAMPLES_PER_BUFFER,
			NUM_TRANSFERS,
			TIMEOUT_MS);

	if (s.status != 0) {
		fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(s.status));
		goto out;
	}

	// We must always enable the modules *after* calling bladerf_sync_config().
	s.status = bladerf_enable_module(s.tx.dev, BLADERF_MODULE_TX, true);
	if (s.status != 0) {
		fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(s.status));
		goto out;
	}

	// Start TX task
	s.status = start_tx_task(&s);
	if (s.status < 0) {
		fprintf(stderr, "Failed to start TX task.\n");
		goto out;
	}
	else
		printf("Creating TX task...\n");

	// Running...
	printf("Running...\n");
	printf("Press 'Ctrl+C' to abort.\n");

	// Wainting for TX task to complete.
	pthread_join(s.tx.thread, NULL);
	printf("\nDone!\n");

	// Disable TX module and shut down underlying TX stream.
	s.status = bladerf_enable_module(s.tx.dev, BLADERF_MODULE_TX, false);
	if (s.status != 0)
		fprintf(stderr, "Failed to disable TX module: %s\n", bladerf_strerror(s.status));

out:
	// Free up resources
	if (s.tx.buffer != NULL)
		free(s.tx.buffer);

	if (s.fifo != NULL)
		free(s.fifo);

	printf("Closing device...\n");
	bladerf_close(s.tx.dev);

	return(0);
}