As an aside…. I wonder if the original USRP2 transport code is still captured in the public domain. This used a proprietary Ethernet transport for IQ before we switched to UDP in UHD transport.
Sent from my iPhone > On Jul 13, 2024, at 7:33 AM, Marcus Müller <mmuel...@gnuradio.org> wrote: > > Hi Walter, > > interesting project! > > The libpcap approach seems to be reasonable; backintheday, I used to capture > at Ethernet frame level using socket(PF_PACKET,…), but that's pretty > non-portable and comes with its own can of worms. pcap's the way to go there, > I'd say, unless you want add a protocol family to your operating system > (don't know whether that is Linux or Mac OS), which I kind of doubt. > > However: > The PUB/SUB scheme is almost certainly not what you want here – that is for > broadcasting data to multiple subscribers (or dropping them, when the > subscriber(s) aren't ready) from potentially multiple transmitters. You might > spot the problem here! If you attach a waterhose on one end, and the other > end doesn't fetch packets in intervals short enough for the receive buffer to > not overflow, these packets will just silently be dropped - business as usual > for a PUBlisher! Try the PUSH/PULL pattern: GNU Radio by principle will need > a block like the SUB block to fetch data as available, and call it back later > at some point. That will not work well in this use case. > > So, to your core question, writing a GNU Radio block for your device is > relatively easy, probably; data rates aren't *that* high, so an extra memory > copy here and there is something I'd live with for a prototype. > Methodology would be this, roughly: > 1. make an out-of-tree module. We cover this on > https://tutorials.gnuradio.org , specifically in [1]. In short, `gr_modtool > newmod yourmodname`. > 2. Make a source block (`gr_modtool add -t source -l c++ hose_source`) > 3. in the generated lib/something_impl.cc, add a `bool hose_source::start() > {}`, and also add tht `bool start() override;` method prototype to the _impl.h > 4. in the _impl.h add private fields: a set of buffers, one for each channel, > where you'll put the data "deinterleavedly" from the NIC. Make each buffer > some (say, 2²⁰) GNSS samples long. Also add two unsigned integer counters: > one read and one write index. And because we're lazy and don't care *that* > much about performance yet, two mutexes (one for securing access to the read > index, and one for the write index). > 5. in the constructor, you allocate these buffers, set the read index to the > length of the buffers (-1) and the write index to 0 > 6. in the start() method, you spawn a thread that, in a loop > 1. checks how much space there is between read and write index (get read > mutex, fetch read index value, release mutex, calculate difference) > 2. uses pcap to fetch packets, (but only as much as the space calculated > above allows for!), deinterleaves data onto the buffers, finally > 4. updates write index (get write mutex, update write index, release write > mutex) > 7. the block's work() method is called by GNU Radio regularly and > 1. checks how much data is between write and read indices (get write mutex, > read write index, release mutex, calculate difference) > 2. checks whether that's more or less than the space for output items > available in this current call to work(), takes the minimum of both > 3. gets that amount of items from each buffer and writes them to the output > buffer, as passed as argument to the work() method (you could do type > conversions here!) > 4. updates the read index accordingly (get read mutex, update index, release > mutex) > 5. returns the number of written items > > note that the index updating and distance calculation need to take the > "wraparound" at the end of the buffer into account. > > Also note: very similarly, you could write a **SoapySDR** driver instead of a > GNU Radio block. You could then use the Generic SoapySDR Source block to get > data from that driver, and other, non-GNU Radio programs, could be using the > driver just as well, without knowing about the hardware. I don't think the > basic principle would be much different: you need an IO thread that keeps the > NIC busy, and because readers might be slow, an internal buffer, which you > ideally use constructively (instead of just incurring a memory bandwidth > overhead), to deinterleave channels on ingress, and to convert data types on > egress, if you will. > > Note that one *could* potentially, as mentioned above write a zero-copy-ish > driver for GNU Radio 3.10+ using our custom buffer framework and something > like AF_XDP, dpdk, or io_uring, but I think that would very much a) leave the > scope of what anyone be able to assist you with – to the best of my > knowledge, you'd be the first to do that with a network device – and b) we're > "only" talking gigabit ethernet here, and you got a fast machine. As you said > in your email, in principle, things are plenty fast enough, so let's not > overcomplicate. > > [1] > https://wiki.gnuradio.org/index.php?title=Creating_C%2B%2B_OOT_with_gr-modtool > >> On 12.07.24 22:42, Walter Szeliga wrote: >> Hi all, >> I have a GNSS Firehose >> (https://transitiva.com/product/gnss-firehose-receiver-tri-band-quad-constellation/ >> >> <https://transitiva.com/product/gnss-firehose-receiver-tri-band-quad-constellation/>) >> and have been trying to get it working, in a streaming capacity, with >> Gnuradio. The Firehose sends packets over ethernet using the experimental >> ethertype 0x88b5. I've tried a few things to get data from the Firehose into >> Gnuradio, some have worked, others have not. Things that work: >> * Use tcpdump and filter on 0x88b5 and save to a file. Open and repackage >> each packet in the pcap dump as interleaved bytes of I&Q and save to a file. >> Read into Gnuradio. >> * Write a custom program using libpcap to filter on 0x88b5 on a selected >> interface, repackage the packets and write directly to a file. Read into >> Gnuradio. >> * Write a custom program using libpcap to filter on 0x88b5 on a selected >> interface, repackage the packets and PUB them using ZMQ. SUB to this PUB >> using a simple Python script and dump the message contents to a file. Read >> into Gnuradio. Both tcp and ipc PUB/SUB work equally well. >> Some things that do not work: >> * SUB to the ZMQ PUB/SUB using the Gnuradio ZMQ SUB Source block. >> * Write a custom program using libpcap to filter on 0x88b5 on a selected >> interface, repackage the packets and send them using UDP. >> The UDP approach doesn't work because too many packets get dropped and I >> have been unable to set sysctl values appropriately (on an M1 Mac) to avoid >> dropping too many packets. >> I'm not sure why the ZMQ approach does not work with Gnuradio. I've tried >> many simple flowgraphs to convert from vector to stream, ibyte to complex, >> you name it, and then dumping the data back out to a file using a File Sink >> (just to use existing software to check for data sanity). Data gets into >> Gnuradio, but it clearly loses something because constellation diagrams of >> the output data become blobs centered on the origin rather than pairs of >> point clouds offset from the origin as one would expect from the BPSK nature >> of the GNSS signals captured by the Firehose. >> I've come to the realization that it's probably best to write some sort of >> driver to get data straight from the Firehose into Gnuradio, but I have no >> idea where to start with this. Any ideas about how to fix my ZMQ approach or >> start writing a custom driver would be appreciated. There's a lot in here, >> so let me know if you would like code or flowgraph examples. >> Cheers, >> Walter >