From df0dd82843382184cb6e0af4b996d7c79936f8e6 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Wed, 16 May 2018 10:49:27 +0200 Subject: [PATCH] Optimizing custom UDP packet source and applying code style --- conf/gnss-sdr_GPS_L1_2ch_udp.conf | 34 +- .../adapters/udp_signal_source.cc | 171 +++---- .../adapters/udp_signal_source.h | 23 +- .../gnuradio_blocks/CMakeLists.txt | 2 + .../gr_complex_ip_packet_source.cc | 439 ++++++++++++++++++ .../gr_complex_ip_packet_source.h | 117 +++++ .../unpack_byte_4bit_samples.cc | 86 ++++ .../unpack_byte_4bit_samples.h | 61 +++ 8 files changed, 789 insertions(+), 144 deletions(-) create mode 100644 src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc create mode 100644 src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h create mode 100644 src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc create mode 100644 src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h diff --git a/conf/gnss-sdr_GPS_L1_2ch_udp.conf b/conf/gnss-sdr_GPS_L1_2ch_udp.conf index d80ffda68..d63eac95d 100644 --- a/conf/gnss-sdr_GPS_L1_2ch_udp.conf +++ b/conf/gnss-sdr_GPS_L1_2ch_udp.conf @@ -6,23 +6,25 @@ ;######### GLOBAL OPTIONS ################## ;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [Sps]. -;GNSS-SDR.internal_fs_sps=3312500 -GNSS-SDR.internal_fs_sps=2650000 +GNSS-SDR.internal_fs_sps=13250000 ;//66.25/5 +;GNSS-SDR.internal_fs_sps=6625000 ;//66.25/10 +;GNSS-SDR.internal_fs_sps=3312500 ;//66.25/20 +;GNSS-SDR.internal_fs_sps=2650000 ;//66.25/25 ;######### SIGNAL_SOURCE CONFIG ############ SignalSource.implementation=UDP_Signal_Source ;SignalSource.implementation=File_Signal_Source -SignalSource.filename=/home/javier/gnss/gnss-simulator/build/signal_out.bin ; <- PUT YOUR FILE HERE +;SignalSource.filename=/home/javier/gnss/gnss-simulator/build/signal_out.bin ; <- PUT YOUR FILE HERE SignalSource.item_type=gr_complex SignalSource.origin_address=0.0.0.0 SignalSource.capture_device=eth0 SignalSource.port=1234 SignalSource.payload_bytes=1472 -SignalSource.sample_type=cbyte +;SignalSource.sample_type=cbyte +SignalSource.sample_type=c4bits +SignalSource.IQ_swap=false SignalSource.RF_channels=1 -SignalSource.select_single_channel=0 SignalSource.channels_in_udp=2 -SignalSource.IQ_swap=true SignalSource.dump=false SignalSource.dump_filename=./signal_source.dat @@ -33,12 +35,22 @@ SignalConditioner.implementation=Pass_Through ;SignalConditioner1.implementation=Pass_Through ;######### CHANNELS GLOBAL CONFIG ############ -Channels_1C.count=1 +Channels_1C.count=8 Channels.in_acquisition=1 ;# CHANNEL CONNECTION Channel.signal=1C -;Channel0.RF_channel_ID=0 +Channel0.RF_channel_ID=0 +Channel1.RF_channel_ID=0 +Channel2.RF_channel_ID=0 +Channel3.RF_channel_ID=0 +Channel4.RF_channel_ID=0 +Channel5.RF_channel_ID=0 +Channel6.RF_channel_ID=0 +Channel7.RF_channel_ID=0 +Channel8.RF_channel_ID=1 +Channel9.RF_channel_ID=1 + ;Channel0.signal=1C ;Channel1.RF_channel_ID=1 ;Channel1.signal=1C @@ -46,11 +58,11 @@ Channel.signal=1C ;######### ACQUISITION GLOBAL CONFIG ############ Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition Acquisition_1C.item_type=gr_complex -Acquisition_1C.threshold=60 +Acquisition_1C.threshold=17 Acquisition_1C.use_CFAR_algorithm=false Acquisition_1C.blocking=false Acquisition_1C.doppler_max=5000 -Acquisition_1C.doppler_step=500 +Acquisition_1C.doppler_step=250 Acquisition_1C.dump=false Acquisition_1C.dump_filename=./acq_dump.dat @@ -78,7 +90,7 @@ Observables.dump_filename=./observables.dat ;######### PVT CONFIG ############ PVT.implementation=RTKLIB_PVT -PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.positioning_mode=PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad PVT.output_rate_ms=100 diff --git a/src/algorithms/signal_source/adapters/udp_signal_source.cc b/src/algorithms/signal_source/adapters/udp_signal_source.cc index ed79ff97f..93af9dd4a 100644 --- a/src/algorithms/signal_source/adapters/udp_signal_source.cc +++ b/src/algorithms/signal_source/adapters/udp_signal_source.cc @@ -1,13 +1,12 @@ /*! - * \file rtl_tcp_signal_source.cc - * \brief Signal source for the Realtek RTL2832U USB dongle DVB-T receiver - * over TCP. - * (see http://sdr.osmocom.org/trac/wiki/rtl-sdr for more information) - * \author Anthony Arnold, 2015. anthony.arnold(at)uqconnect.edu.au + * \file udp_signal_source.cc * + * \brief Receives ip frames containing samples in UDP frame encapsulation + * using a high performance packet capture library (libpcap) + * \author Javier Arribas jarribas (at) cttc.es * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -30,6 +29,7 @@ * ------------------------------------------------------------------------- */ + #include "udp_signal_source.h" #include "configuration_interface.h" #include "GPS_L1_CA.h" @@ -64,58 +64,46 @@ UDPSignalSource::UDPSignalSource(ConfigurationInterface* configuration, RF_channels_ = configuration->property(role + ".RF_channels", 1); - select_single_channel_ = configuration->property(role + ".select_single_channel", 0); - channels_in_udp_= configuration->property(role + ".channels_in_udp", 1); - IQ_swap_= configuration->property(role + ".IQ_swap", false); + channels_in_udp_ = configuration->property(role + ".channels_in_udp", 1); + IQ_swap_ = configuration->property(role + ".IQ_swap", false); std::string default_sample_type = "cbyte"; std::string sample_type = configuration->property(role + ".sample_type", default_sample_type); item_type_ = configuration->property(role + ".item_type", default_item_type); - - if (sample_type.compare("cbyte")==0) - { - udp_gnss_rx_source_ = raw_ip_packet_source::make(capture_device, address, port, payload_bytes); - demux_=gr::blocks::deinterleave::make(sizeof(char),1); - }else{ - std::cout<<"WARNING: Requested UDP sample type unsuported, setting sample type to cbyte\n"; - udp_gnss_rx_source_ = raw_ip_packet_source::make(capture_device, address, port, payload_bytes); - demux_=gr::blocks::deinterleave::make(sizeof(char),1); - } - - //create I, Q -> gr_complex type conversion blocks - for (int n = 0; n < (channels_in_udp_ * 2); n++) - { - char_to_float_.push_back(gr::blocks::char_to_float::make()); - } - - for (int n = 0; n < channels_in_udp_; n++) - { - float_to_complex_.push_back(gr::blocks::float_to_complex::make()); - } - - if (channels_in_udp_>RF_channels_) - { - for (int n = 0; n < channels_in_udp_; n++) - { - null_sinks_.push_back(gr::blocks::null_sink::make(sizeof(gr_complex))); - } - }else - { - std::cout<<"Configuration error: RF_channels= RF_channels_) + { + for (int n = 0; n < channels_in_udp_; n++) + { + null_sinks_.push_back(gr::blocks::null_sink::make(sizeof(gr_complex))); + } + } + else + { + std::cout << "Configuration error: RF_channelsconnect(udp_gnss_rx_source_,0, demux_,0); - DLOG(INFO)<<"connected udp_source to demux"<connect(demux_, n, char_to_float_.at(n), 0); - DLOG(INFO) << "connected demux to char_to_float CH" << n; - } + //connect null sinks to unused streams for (int n = 0; n < channels_in_udp_; n++) { - if (!IQ_swap_) - { - top_block->connect(char_to_float_.at(n * 2), 0, float_to_complex_.at(n), 0); - top_block->connect(char_to_float_.at(n * 2 + 1), 0, float_to_complex_.at(n), 1); - } - else - { - top_block->connect(char_to_float_.at(n * 2), 0, float_to_complex_.at(n), 1); - top_block->connect(char_to_float_.at(n * 2 + 1), 0, float_to_complex_.at(n), 0); - } - DLOG(INFO) << "connected char_to_float to float_to_complex_ CH" << n; + top_block->connect(udp_gnss_rx_source_, n, null_sinks_.at(n), 0); } - - //connect null sinks to unused streams - if (channels_in_udp_>RF_channels_) - { - for (int n = 0; n < channels_in_udp_; n++) - { - top_block->connect(float_to_complex_.at(n),0,null_sinks_.at(n),0); - } - } + DLOG(INFO) << "connected udp_source to null_sinks to enable the use of spare channels" << std::endl; if (dump_) { for (int n = 0; n < channels_in_udp_; n++) - { - top_block->connect(float_to_complex_.at(n), 0, file_sink_.at(n), 0); - DLOG(INFO) << "connected source to file sink"; - } + { + top_block->connect(udp_gnss_rx_source_, n, file_sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } } } void UDPSignalSource::disconnect(gr::top_block_sptr top_block) { - - for (int n = 0; n < (channels_in_udp_ * 2); n++) - { - top_block->disconnect(demux_, n, char_to_float_.at(n), 0); - DLOG(INFO) << "disconnect demux to char_to_float CH" << n; - } + //disconnect null sinks to unused streams for (int n = 0; n < channels_in_udp_; n++) { - if (!IQ_swap_) - { - top_block->disconnect(char_to_float_.at(n * 2), 0, float_to_complex_.at(n), 0); - top_block->disconnect(char_to_float_.at(n * 2 + 1), 0, float_to_complex_.at(n), 1); - } - else - { - top_block->disconnect(char_to_float_.at(n * 2), 0, float_to_complex_.at(n), 1); - top_block->disconnect(char_to_float_.at(n * 2 + 1), 0, float_to_complex_.at(n), 0); - } - DLOG(INFO) << "disconnect char_to_float to float_to_complex_ CH" << n; + top_block->disconnect(udp_gnss_rx_source_, n, null_sinks_.at(n), 0); } - - //disconnect null sinks to unused streams - if (channels_in_udp_>RF_channels_) - { - for (int n = 0; n < channels_in_udp_; n++) - { - top_block->disconnect(float_to_complex_.at(n),0,null_sinks_.at(n),0); - } - } - - if (dump_) { - for (int n = 0; n < channels_in_udp_; n++) - { - top_block->disconnect(float_to_complex_.at(n), 0, file_sink_.at(n), 0); - DLOG(INFO) << "disconnected source to file sink"; + for (int n = 0; n < channels_in_udp_; n++) + { + top_block->disconnect(udp_gnss_rx_source_, n, file_sink_.at(n), 0); + DLOG(INFO) << "disconnected source to file sink"; + } } - } - top_block->disconnect(udp_gnss_rx_source_,0, demux_,0); - DLOG(INFO)<<"disconnected udp_source to demux"< #include -#include #include #include -#include -#include #include #include #include @@ -90,7 +88,6 @@ private: bool IQ_swap_; int RF_channels_; - int select_single_channel_; int channels_in_udp_; unsigned int in_stream_; unsigned int out_stream_; @@ -99,12 +96,8 @@ private: size_t item_size_; bool dump_; std::string dump_filename_; - std::vector> char_to_float_; - std::vector> float_to_complex_; std::vector> null_sinks_; - - raw_ip_packet_source::sptr udp_gnss_rx_source_; - gr::blocks::deinterleave::sptr demux_; + gr_complex_ip_packet_source::sptr udp_gnss_rx_source_; std::vector> file_sink_; boost::shared_ptr queue_; }; diff --git a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt index 83a7ee7b2..55c8db1c9 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt @@ -20,12 +20,14 @@ set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES unpack_byte_2bit_samples.cc unpack_byte_2bit_cpx_samples.cc + unpack_byte_4bit_samples.cc unpack_intspir_1bit_samples.cc rtl_tcp_signal_source_c.cc unpack_2bit_samples.cc unpack_spir_gss6450_samples.cc labsat23_source.cc raw_ip_packet_source.cc + gr_complex_ip_packet_source.cc ) include_directories( diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc new file mode 100644 index 000000000..038ea6fbe --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.cc @@ -0,0 +1,439 @@ +/*! + * \file gr_complex_ip_packet_source.cc + * + * \brief Receives ip frames containing samples in UDP frame encapsulation + * using a high performance packet capture library (libpcap) + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include +#include "gr_complex_ip_packet_source.h" + +#include +#include + + +#define FIFO_SIZE 1472000 + + +/* 4 bytes IP address */ +typedef struct gr_ip_address +{ + u_char byte1; + u_char byte2; + u_char byte3; + u_char byte4; +} gr_ip_address; + +/* IPv4 header */ +typedef struct gr_ip_header +{ + u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits) + u_char tos; // Type of service + u_short tlen; // Total length + u_short identification; // Identification + u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits) + u_char ttl; // Time to live + u_char proto; // Protocol + u_short crc; // Header checksum + gr_ip_address saddr; // Source address + gr_ip_address daddr; // Destination address + u_int op_pad; // Option + Padding +} gr_ip_header; + +/* UDP header*/ +typedef struct gr_udp_header +{ + u_short sport; // Source port + u_short dport; // Destination port + u_short len; // Datagram length + u_short crc; // Checksum +} gr_udp_header; + +gr_complex_ip_packet_source::sptr +gr_complex_ip_packet_source::make(std::string src_device, + std::string origin_address, + int udp_port, + int udp_packet_size, + int n_baseband_channels, + std::string wire_sample_type, + size_t item_size, + bool IQ_swap_) +{ + return gnuradio::get_initial_sptr(new gr_complex_ip_packet_source(src_device, + origin_address, + udp_port, + udp_packet_size, + n_baseband_channels, + wire_sample_type, + item_size, + IQ_swap_)); +} + +/* + * The private constructor + */ +gr_complex_ip_packet_source::gr_complex_ip_packet_source(std::string src_device, + __attribute__((unused)) std::string origin_address, + int udp_port, + int udp_packet_size, + int n_baseband_channels, + std::string wire_sample_type, + size_t item_size, + bool IQ_swap_) + : gr::sync_block("gr_complex_ip_packet_source", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 4, item_size)) //1 to 4 baseband complex channels +{ + // constructor code here + std::cout << "Start Ethernet packet capture\n"; + + d_n_baseband_channels = n_baseband_channels; + if (wire_sample_type.compare("cbyte") == 0) + { + d_wire_sample_type = 1; + d_bytes_per_sample = d_n_baseband_channels * 2; + } + else if (wire_sample_type.compare("c4bits") == 0) + { + d_wire_sample_type = 2; + d_bytes_per_sample = d_n_baseband_channels; + } + else + { + std::cout << "Unknown wire sample type\n"; + exit(0); + } + std::cout << "d_wire_sample_type:" << d_wire_sample_type << std::endl; + d_src_device = src_device; + d_udp_port = udp_port; + d_udp_payload_size = udp_packet_size; + d_fifo_full = false; + + //allocate signal samples buffer + fifo_buff = new char[FIFO_SIZE]; + fifo_read_ptr = 0; + fifo_write_ptr = 0; + fifo_items = 0; + d_item_size = item_size; + d_IQ_swap = IQ_swap_; + d_sock_raw = 0; + d_pcap_thread = NULL; + descr = NULL; +} + + +//Called by gnuradio to enable drivers, etc for i/o devices. +bool gr_complex_ip_packet_source::start() +{ + std::cout << "gr_complex_ip_packet_source START\n"; + //open the ethernet device + if (open() == true) + { + // start pcap capture thread + d_pcap_thread = new boost::thread(boost::bind(&gr_complex_ip_packet_source::my_pcap_loop_thread, this, descr)); + return true; + } + else + { + return false; + } +} + +//Called by gnuradio to disable drivers, etc for i/o devices. +bool gr_complex_ip_packet_source::stop() +{ + std::cout << "gr_complex_ip_packet_source STOP\n"; + if (descr != NULL) + { + pcap_breakloop(descr); + d_pcap_thread->join(); + pcap_close(descr); + } + return true; +} + +bool gr_complex_ip_packet_source::open() +{ + char errbuf[PCAP_ERRBUF_SIZE]; + boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + /* open device for reading */ + descr = pcap_open_live(d_src_device.c_str(), 1500, 1, 1000, errbuf); + if (descr == NULL) + { + std::cout << "Error openning Ethernet device " << d_src_device << std::endl; + printf("Fatal Error in pcap_open_live(): %s\n", errbuf); + return false; + } + //bind UDP port to avoid automatic reply with ICMP port ureacheable packets from kernel + d_sock_raw = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (d_sock_raw == -1) + { + std::cout << "Error openning UDP socket" << std::endl; + return false; + } + + // zero out the structure + memset((char *)&si_me, 0, sizeof(si_me)); + + si_me.sin_family = AF_INET; + si_me.sin_port = htons(d_udp_port); + si_me.sin_addr.s_addr = htonl(INADDR_ANY); + + //bind socket to port + if (bind(d_sock_raw, (struct sockaddr *)&si_me, sizeof(si_me)) == -1) + { + std::cout << "Error openning UDP socket" << std::endl; + return false; + } + return true; +} + +gr_complex_ip_packet_source::~gr_complex_ip_packet_source() +{ + if (d_pcap_thread != NULL) + { + delete d_pcap_thread; + } + delete fifo_buff; + std::cout << "Stop Ethernet packet capture\n"; +} + +void gr_complex_ip_packet_source::static_pcap_callback(u_char *args, const struct pcap_pkthdr *pkthdr, + const u_char *packet) +{ + gr_complex_ip_packet_source *bridge = (gr_complex_ip_packet_source *)args; + bridge->pcap_callback(args, pkthdr, packet); +} + +void gr_complex_ip_packet_source::pcap_callback(__attribute__((unused)) u_char *args, __attribute__((unused)) const struct pcap_pkthdr *pkthdr, + const u_char *packet) +{ + boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + + gr_ip_header *ih; + gr_udp_header *uh; + + // eth frame parameters + // **** UDP RAW PACKET DECODER **** + if ((packet[12] == 0x08) & (packet[13] == 0x00)) //IP FRAME + { + /* retireve the position of the ip header */ + ih = (gr_ip_header *)(packet + + 14); //length of ethernet header + + /* retireve the position of the udp header */ + u_int ip_len; + ip_len = (ih->ver_ihl & 0xf) * 4; + uh = (gr_udp_header *)((u_char *)ih + ip_len); + + /* convert from network byte order to host byte order */ + //u_short sport; + u_short dport; + dport = ntohs(uh->dport); + //sport = ntohs(uh->sport); + if (dport == d_udp_port) + { + // print ip addresses and udp ports + // printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n", + // ih->saddr.byte1, + // ih->saddr.byte2, + // ih->saddr.byte3, + // ih->saddr.byte4, + // sport, + // ih->daddr.byte1, + // ih->daddr.byte2, + // ih->daddr.byte3, + // ih->daddr.byte4, + // dport); + // std::cout<<"uh->len:"<len)<len) - 8; //total udp packet lenght minus the header lenght + //read the payload bytes and insert them into the shared circular buffer + u_char *udp_payload = ((u_char *)uh + sizeof(gr_udp_header)); + if (fifo_items <= (FIFO_SIZE - payload_lenght_bytes)) + { + int aligned_write_items = FIFO_SIZE - fifo_write_ptr; + if (aligned_write_items >= payload_lenght_bytes) + { + //write all in a single memcpy + memcpy(&fifo_buff[fifo_write_ptr], &udp_payload[0], payload_lenght_bytes); //size in bytes + fifo_write_ptr += payload_lenght_bytes; + if (fifo_write_ptr == FIFO_SIZE) fifo_write_ptr = 0; + fifo_items += payload_lenght_bytes; + } + else + { + //two step wrap write + memcpy(&fifo_buff[fifo_write_ptr], &udp_payload[0], aligned_write_items); //size in bytes + fifo_write_ptr = payload_lenght_bytes - aligned_write_items; + memcpy(&fifo_buff[0], &udp_payload[aligned_write_items], fifo_write_ptr); //size in bytes + fifo_items += payload_lenght_bytes; + } + } + else + { + //notify overflow + std::cout << "O" << std::flush; + } + } + } +} + +void gr_complex_ip_packet_source::my_pcap_loop_thread(pcap_t *pcap_handle) + +{ + pcap_loop(pcap_handle, -1, gr_complex_ip_packet_source::static_pcap_callback, (u_char *)this); +} + +void gr_complex_ip_packet_source::demux_samples(gr_vector_void_star output_items, int num_samples_readed) +{ + int8_t real; + int8_t imag; + uint8_t tmp_char2; + for (int n = 0; n < num_samples_readed; n++) + { + switch (d_wire_sample_type) + { + case 1: //interleaved byte samples + for (int i = 0; i < output_items.size(); i++) + { + real = fifo_buff[fifo_read_ptr++]; + imag = fifo_buff[fifo_read_ptr++]; + if (d_IQ_swap) + { + ((gr_complex *)output_items[i])[n] = gr_complex(real, imag); + } + else + { + ((gr_complex *)output_items[i])[n] = gr_complex(imag, real); + } + } + break; + case 2: // 4bits samples + for (int i = 0; i < output_items.size(); i++) + { + tmp_char2 = fifo_buff[fifo_read_ptr] & 0x0F; + if (tmp_char2 >= 8) + { + real = 2 * (tmp_char2 - 16) + 1; + } + else + { + real = 2 * tmp_char2 + 1; + } + tmp_char2 = fifo_buff[fifo_read_ptr++] >> 4; + tmp_char2 = tmp_char2 & 0x0F; + if (tmp_char2 >= 8) + { + imag = 2 * (tmp_char2 - 16) + 1; + } + else + { + imag = 2 * tmp_char2 + 1; + } + if (d_IQ_swap) + { + ((gr_complex *)output_items[i])[n] = gr_complex(imag, real); + } + else + { + ((gr_complex *)output_items[i])[n] = gr_complex(real, imag); + } + } + break; + default: + std::cout << "Unknown wire sample type\n"; + exit(0); + } + if (fifo_read_ptr == FIFO_SIZE) fifo_read_ptr = 0; + } +} + +int gr_complex_ip_packet_source::work(int noutput_items, + __attribute__((unused)) gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + // send samples to next GNU Radio block + boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function + if (fifo_items == 0) return 0; + + if (output_items.size() > d_n_baseband_channels) + { + std::cout << "Configuration error: more baseband channels connected than the available in the UDP source\n"; + exit(0); + } + int num_samples_readed; + int bytes_requested; + switch (d_wire_sample_type) + { + case 1: //complex byte samples + bytes_requested = noutput_items * d_bytes_per_sample; + if (bytes_requested < fifo_items) + { + num_samples_readed = noutput_items; //read all + } + else + { + num_samples_readed = fifo_items / d_bytes_per_sample; //read what we have + } + break; + case 2: //complex 4 bits samples + bytes_requested = noutput_items * d_bytes_per_sample; + if (bytes_requested < fifo_items) + { + num_samples_readed = noutput_items; //read all + } + else + { + num_samples_readed = fifo_items / d_bytes_per_sample; //read what we have + } + break; + default: //complex byte samples + bytes_requested = noutput_items * d_bytes_per_sample; + if (bytes_requested < fifo_items) + { + num_samples_readed = noutput_items; //read all + } + else + { + num_samples_readed = fifo_items / d_bytes_per_sample; //read what we have + } + } + + bytes_requested = num_samples_readed * d_bytes_per_sample; + //read all in a single loop + demux_samples(output_items, num_samples_readed); // it also increases the fifo read pointer + //update fifo items + fifo_items = fifo_items - bytes_requested; + + for (int n = 0; n < output_items.size(); n++) + { + produce(n, num_samples_readed); + } + return this->WORK_CALLED_PRODUCE; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h new file mode 100644 index 000000000..7b8d9f58e --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/gr_complex_ip_packet_source.h @@ -0,0 +1,117 @@ +/*! + * \file gr_complex_ip_packet_source.h + * + * \brief Receives ip frames containing samples in UDP frame encapsulation + * using a high performance packet capture library (libpcap) + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef INCLUDED_GR_COMPLEX_IP_PACKET_SOURCE_H +#define INCLUDED_GR_COMPLEX_IP_PACKET_SOURCE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class gr_complex_ip_packet_source : virtual public gr::sync_block +{ +private: + boost::mutex d_mutex; + pcap_t *descr; //ethernet pcap device descriptor + + char *fifo_buff; + + int fifo_read_ptr; + int fifo_write_ptr; + int fifo_items; + int d_sock_raw; + int d_udp_port; + struct sockaddr_in si_me; + std::string d_src_device; + std::string d_origin_address; + int d_udp_payload_size; + bool d_fifo_full; + + int d_n_baseband_channels; + int d_wire_sample_type; + int d_bytes_per_sample; + size_t d_item_size; + bool d_IQ_swap; + + boost::thread *d_pcap_thread; + /*! + * \brief + * Opens the ethernet device using libpcap raw capture mode + * If any of these fail, the fuction retuns the error and exits. + */ + bool open(); + + void demux_samples(gr_vector_void_star output_items, int num_samples_readed); + void my_pcap_loop_thread(pcap_t *pcap_handle); + + void pcap_callback(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet); + + static void static_pcap_callback(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet); + + +public: + typedef boost::shared_ptr sptr; + static sptr make(std::string src_device, + std::string origin_address, + int udp_port, + int udp_packet_size, + int n_baseband_channels, + std::string wire_sample_type, + size_t item_size, + bool IQ_swap_); + gr_complex_ip_packet_source(std::string src_device, + std::string origin_address, + int udp_port, + int udp_packet_size, + int n_baseband_channels, + std::string wire_sample_type, + size_t item_size, + bool IQ_swap_); + ~gr_complex_ip_packet_source(); + + // Where all the action really happens + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + //Called by gnuradio to enable drivers, etc for i/o devices. + bool start(); + //Called by gnuradio to disable drivers, etc for i/o devices. + bool stop(); +}; + +#endif /* INCLUDED_GR_COMPLEX_IP_PACKET_SOURCE_H */ diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc new file mode 100644 index 000000000..ba9f9365e --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.cc @@ -0,0 +1,86 @@ +/*! + * \file unpack_byte_4bit_samples.cc + * + * \brief Unpacks byte samples to 4 bits samples. + * Packing Order + * Packing order in Nibble I0 I1 I2 I3 I0 I1 I2 I3 + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "unpack_byte_4bit_samples.h" +#include + +unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples() +{ + return unpack_byte_4bit_samples_sptr(new unpack_byte_4bit_samples()); +} + + +unpack_byte_4bit_samples::unpack_byte_4bit_samples() : sync_interpolator("unpack_byte_4bit_samples", + gr::io_signature::make(1, 1, sizeof(signed char)), + gr::io_signature::make(1, 1, sizeof(signed char)), + 2) +{ +} + + +unpack_byte_4bit_samples::~unpack_byte_4bit_samples() +{ +} + + +int unpack_byte_4bit_samples::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const signed char *in = reinterpret_cast(input_items[0]); + signed char *out = reinterpret_cast(output_items[0]); + int n = 0; + unsigned char tmp_char2; + for (int i = 0; i < noutput_items / 2; i++) + { + tmp_char2 = in[i] & 0x0F; + if (tmp_char2 >= 8) + { + out[n++] = 2 * (tmp_char2 - 16) + 1; + } + else + { + out[n++] = 2 * tmp_char2 + 1; + } + tmp_char2 = in[i] >> 4; + tmp_char2 = tmp_char2 & 0x0F; + if (tmp_char2 >= 8) + { + out[n++] = 2 * (tmp_char2 - 16) + 1; + } + else + { + out[n++] = 2 * tmp_char2 + 1; + } + } + return noutput_items; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h new file mode 100644 index 000000000..ccfe699b5 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/unpack_byte_4bit_samples.h @@ -0,0 +1,61 @@ +/*! + * \file unpack_byte_4bit_samples.h + * + * \brief Unpacks byte samples to 4 bits samples. + * Packing Order + * Packing order in Nibble I0 I1 I2 I3 I0 I1 I2 I3 + * \author Javier Arribas jarribas (at) cttc.es + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_unpack_byte_4bit_samples_H +#define GNSS_SDR_unpack_byte_4bit_samples_H + +#include + +class unpack_byte_4bit_samples; + +typedef boost::shared_ptr unpack_byte_4bit_samples_sptr; + +unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples(); + +/*! + * \brief This class implements conversion between byte packet samples to 4bit_cpx samples + * 1 byte = 1 x complex 4bit I, + 4bit Q samples + */ +class unpack_byte_4bit_samples : public gr::sync_interpolator +{ +private: + friend unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples_sptr(); + +public: + unpack_byte_4bit_samples(); + ~unpack_byte_4bit_samples(); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif