diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c250ca..1e76e35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,9 +19,14 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=gnu++11") # Add the local Find*.cmake scripts LIST (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) -FIND_PACKAGE( RTLSDR REQUIRED ) -INCLUDE_DIRECTORIES("${RTLSDR_INCLUDE_DIR}") - +FIND_PACKAGE(SoapySDR NO_MODULE) +if (SOAPYSDR_FOUND) + INCLUDE_DIRECTORIES("${LIBSOAPYSDR_INCLUDE_DIR}") +endif () +FIND_PACKAGE(avro NO_MODULE) +if (AVRO_FOUND) + INCLUDE_DIRECTORIES("${AVRO_INCLUDE_DIR}") +endif () # liquid, avro, ssl, crypto @@ -29,8 +34,7 @@ configure_file( version_config.h.in generated/version_config.h ) #ADD_SUBDIRECTORY(drivers/rtlsdr/converter/) -set(SOURCE_FILES main.cpp drivers/Driver.h drivers/rtlsdr/rtlsdrDriver.cpp drivers/rtlsdr/rtlsdrDriver.h - drivers/rtlsdr/converter/converter.c drivers/rtlsdr/converter/converter.h +set(SOURCE_FILES main.cpp drivers/Driver.h drivers/soapysdr/soapyDriver.cpp drivers/soapysdr/soapyDriver.h context/ElectrosenseContext.cpp context/ElectrosenseContext.h drivers/common/SequentialHopping.cpp drivers/common/SequentialHopping.h types/SpectrumSegment.cpp types/SpectrumSegment.h ProcessingBlocks/RemoveDC.cpp ProcessingBlocks/RemoveDC.h @@ -40,9 +44,12 @@ set(SOURCE_FILES main.cpp drivers/Driver.h drivers/rtlsdr/rtlsdrDriver.cpp drive misc/TLS.cpp misc/TLS.h misc/TCP.cpp misc/TCP.h MiscBlocks/IQSink.cpp MiscBlocks/IQSink.h) add_executable(es_sensor ${SOURCE_FILES}) +list(APPEND SoapySDR_LIBRARIES -pthread) +list(APPEND AVRO_LIBRARIES -pthread) + target_link_libraries(es_sensor - ${RTLSDR_LIBRARY} + SoapySDR pthread dl liquid @@ -52,7 +59,7 @@ target_link_libraries(es_sensor ) -INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/es_sensor DESTINATION /usr/share/electrosense/bin/) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/build/es_sensor DESTINATION /usr/share/electrosense/bin/) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/schemas/rtl-spec.avsc DESTINATION /usr/share/electrosense/schemas/) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/schemas/iq-spec.avsc DESTINATION /usr/share/electrosense/schemas/) diff --git a/drivers/soapysdr/soapyDriver.cpp b/drivers/soapysdr/soapyDriver.cpp new file mode 100644 index 0000000..9403369 --- /dev/null +++ b/drivers/soapysdr/soapyDriver.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2018 by IMDEA Networks Institute + * + * This file is part of Electrosense. + * + * Electrosense 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. + * + * Electrosense 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 RTL-Spec. If not, see . + * + * Authors: + * Roberto Calvo-Palomino + * + */ + + +#include "soapyDriver.h" +#include +#include +#include +#include + +namespace electrosense { + + +soapyDriver::soapyDriver() { + + mQueueOut = new ReaderWriterQueue(100); +} + + +int soapyDriver::open(std::string device) { + // rtlsdr lib expects to have integer id for identifying the device + + int device_index = -1; + SoapySDR::KwargsList list = SoapySDR::Device::enumerate(device); + int n_rtlsdr = list.size(); + + if (n_rtlsdr==0) { + std::cerr << "* Error: no RTL-SDR USB devices found" << std::endl; + throw std::logic_error("Fatal Error"); + } + + // Choose which device to use + if ((n_rtlsdr==1)) { + device_index=0; + std::cout << "Device index " << device_index << ": [Device: " << list[device_index]["device"] << "] [Product: " << list[device_index]["driver"] << "] [URI: " << list[device_index]["uri"] << "]" << std::endl; + } + if ((device_index<0)||(device_index>=n_rtlsdr)) { + std::cerr << "Error: must specify which USB device to use with --device-index" << std::endl; + std::cerr << "Found the following USB devices:" << std::endl; + for (int t=0;tgetSamplingRate(); + + // Sampling frequency + mDevice->setSampleRate(SOAPY_SDR_RX,0,samplingRate); + mDevice->setBandwidth(SOAPY_SDR_RX,0,samplingRate); + + int frequency = 24e6; // default value + mDevice->setFrequency(SOAPY_SDR_RX,0,frequency); + + double gain = ElectrosenseContext::getInstance()->getGain(); + mDevice->setGainMode(SOAPY_SDR_RX,0,false); + + mDevice->setGain(SOAPY_SDR_RX,0,gain); + gain = mDevice->getGain(SOAPY_SDR_RX,0); + + + std::cout << "[*] Initializing dongle with following configuration: " << std::endl; + std::cout << "\t Center Frequency: " << frequency << " Hz" << std::endl; + std::cout << "\t Sampling Rate: " << samplingRate << " samples/sec" << std::endl; + std::cout << "\t Gain: " << gain << " dB" << std::endl; + + return 1; + +} + + +int soapyDriver::close () { + return 1; +} + + +void timespec_diff(struct timespec *start, struct timespec *stop, + struct timespec *result) +{ + if ((stop->tv_nsec - start->tv_nsec) < 0) { + result->tv_sec = stop->tv_sec - start->tv_sec - 1; + result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000; + } else { + result->tv_sec = stop->tv_sec - start->tv_sec; + result->tv_nsec = stop->tv_nsec - start->tv_nsec; + } + + return; +} + +bool soapyDriver::isRunning () { + return mRunning; +} + +static void *aux_thread (void *arg) { + soapyDriver *sd_t = (soapyDriver *) arg; + sd_t->SyncSampling(); + pthread_exit(NULL); +} + + +void soapyDriver::run () { + mRunning = true; + pthread_t myth; + pthread_create ( &myth, NULL, aux_thread, (void *)this ); + pthread_join(myth,NULL); + mRunning = false; +} + +void soapyDriver::SyncSampling() { + + const int BULK_TRANSFER_MULTIPLE = 512; + struct timespec start_time; + clock_gettime(CLOCK_REALTIME, &start_time); + + std::cout << "soapyDriver::run" << std::endl; + + mSeqHopping = new SequentialHopping(); + uint64_t center_freq=0, previous_freq=0, fft_size=0, slen=0; + + std::complex *iq_buf = NULL; + + while (mRunning) + { + + // Introduce here the concept of segment per band (before jumping). + + center_freq = mSeqHopping->nextHop(); + + if (previous_freq != center_freq) + { + previous_freq = center_freq; + + mDevice->setFrequency(SOAPY_SDR_RX,0,center_freq); + +// // Reset the buffer + if (mStream != 0) + { + mDevice->deactivateStream(mStream,0,0); + mDevice->closeStream(mStream); + } + mStream=mDevice->setupStream(SOAPY_SDR_RX,"CF32"); + mDevice->activateStream(mStream); + + + + } + + unsigned int current_fft_size = 1<getLog2FftSize(); + + if (fft_size != current_fft_size) + { + + fft_size = current_fft_size; + + slen = ((current_fft_size-ElectrosenseContext::getInstance()->getSoverlap()) * + ElectrosenseContext::getInstance()->getAvgFactor()+ElectrosenseContext::getInstance()->getSoverlap())*2; + + + if(slen % BULK_TRANSFER_MULTIPLE != 0) + slen = slen + (BULK_TRANSFER_MULTIPLE - (slen % BULK_TRANSFER_MULTIPLE)); + + iq_buf = (std::complex *) realloc(iq_buf,slen*sizeof(std::complex)); + + } + std::vector iqbufs(1); + iqbufs[0] = iq_buf; + + struct timespec current_time; + clock_gettime(CLOCK_REALTIME, ¤t_time); + + int flags; + long long timeNs; + int r = mDevice->readStream(mStream,iqbufs.data(),slen,flags,timeNs,100000); + if(r <= 0 ){ + fprintf(stderr, "WARNING: Synchronous read failed.\n"); + std::cout << r << " " << slen << std::endl; + mRunning = false; + } + + std::vector> iq_vector; + + for (unsigned int i=0; igetAvgFactor(); i++) { + + iq_vector.clear(); + + for (unsigned int j = 0; j < current_fft_size*2; j ++) { + + // Every segment overlaps getSoverlap() samples in time domain. + + iq_vector.push_back( + iq_buf[j+i*(current_fft_size-ElectrosenseContext::getInstance()->getSoverlap())*2]); + + } + + //TODO: Id should be the ethernet MAC + + SpectrumSegment *segment = new SpectrumSegment(-1000, current_time, center_freq, + ElectrosenseContext::getInstance()->getSamplingRate(), + iq_vector); + mQueueOut->enqueue(segment); + + } + struct timespec diff; + timespec_diff(&start_time, ¤t_time, &diff); + if (diff.tv_sec > ElectrosenseContext::getInstance()->getMonitorTime() && + ElectrosenseContext::getInstance()->getMonitorTime()!= 0) + { + std::cout << "sampling done" << std::endl; + mRunning = false; + } + } + + delete(mSeqHopping); + +} + + + + +int soapyDriver::stop() +{ + mRunning = false; + waitForThread(); + + // Workaround: RPi does not work properly the cancellation of the async task + if (ElectrosenseContext::getInstance()->getPipeline().compare("PSD") ==0 ) { + SoapySDR::Device::unmake(mDevice); + mDevice = NULL; + } + + return 1; +} +} diff --git a/drivers/soapysdr/soapyDriver.h b/drivers/soapysdr/soapyDriver.h new file mode 100644 index 0000000..524cdde --- /dev/null +++ b/drivers/soapysdr/soapyDriver.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 by IMDEA Networks Institute + * + * This file is part of Electrosense. + * + * Electrosense 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. + * + * Electrosense 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 RTL-Spec. If not, see . + * + * Authors: + * Roberto Calvo-Palomino + * + */ +#ifndef ES_SENSOR_RTLSDR_H +#define ES_SENSOR_RTLSDR_H + +#include +#include +#include +#include +#include + +#include "../Driver.h" +#include "../Component.h" +#include "../Communication.h" +#include "soapyDriver.h" +#include "../../context/ElectrosenseContext.h" +#include "../common/SequentialHopping.h" + +// Workaround issue #4 , complex.h breaks openssl's RSA library +// include RSA before any mention to complex.h +#include "../../types/SpectrumSegment.h" +#include + +namespace electrosense { + + + + class soapyDriver: public Driver, public Component, public Communication { + + public: + + soapyDriver(); + + ~soapyDriver(); + + // Open the device + int open(std::string deviceId); + + // Close the device + int close(); + + // Stop + int stop(); + + // Running + bool isRunning (); + + void SyncSampling(); + + ReaderWriterQueue* getQueueIn() { return NULL; } + void setQueueIn (ReaderWriterQueue* QueueIn ) {}; + + ReaderWriterQueue* getQueueOut() { return mQueueOut; }; + void setQueueOut (ReaderWriterQueue* QueueOut) {}; + + std::string getNameId () { return std::string("soapyDriver"); }; + + + private: + + + // Run the driver in the thread + void run(); + + bool mRunning; + + int mDeviceId; + + SoapySDR::Device * mDevice; + SoapySDR::Stream * mStream; + + SequentialHopping* mSeqHopping; + + ReaderWriterQueue* mQueueOut; + + + + std::vector> m_capbuf_raw; + + }; + +} + +#endif //ES_SENSOR_RTLSDR_H diff --git a/main.cpp b/main.cpp index 9e001c6..6c83e74 100644 --- a/main.cpp +++ b/main.cpp @@ -35,10 +35,10 @@ #include "MiscBlocks/FileSink.h" #include "MiscBlocks/IQSink.h" -#include "generated/version_config.h" +#include "build/generated/version_config.h" #include "context/ElectrosenseContext.h" -#include "drivers/rtlsdr/rtlsdrDriver.h" +#include "drivers/soapysdr/soapyDriver.h" #include "drivers/Component.h" #include "ProcessingBlocks/RemoveDC.h" @@ -304,7 +304,7 @@ int main( int argc, char* argv[] ) { electrosense::Averaging *avgBlock; // RTL-SDR Driver - auto *rtlDriver = new electrosense::rtlsdrDriver(); + auto *rtlDriver = new electrosense::soapyDriver(); vComponents.push_back(rtlDriver); rtlDriver->open("0");