C# and BladeRF

Discussions related to embedded firmware, driver, and user mode application software development
dave0160
Posts: 8
Joined: Tue Dec 09, 2014 7:45 am
Location: Bloomington, IN

C# and BladeRF

Post by dave0160 »

Hello All,

First let me say that I'm a complete newbie to the whole SDR world, but looking forward to jumping in feet first.

I've got 2 BladeRF's that I'd like to get running under a custom C# / Windows 7/8.1 application. I've got access to VS2010 and VS2013. I'm going with C# because ultimately I'd like to port the code over to Java and run on an Android OS device.

My question is, besides SDR# has anyone else created any code using C#? I've taken a look at the SDR# code for BladeRF support and it looks very nice, but I think that it would take a lot of trimming to get it down to where I would like the code to be especially since it looks like it is an add-on to a larger entity and I don't fully understand everything that he's doing.

I'm basically looking for any wisdom or guidance or even the basics on how to set the center frequency and read in 1024 samples without bladerf-cli or SDR#.

Thanks,
Dave
bpadalino
Posts: 303
Joined: Mon Mar 04, 2013 4:53 pm

Re: C# and BladeRF

Post by bpadalino »

Do you know how to interact with a C library from C#?

I am not sure how to do that, but that sort of encapsulation is what you'll probably need to do.

That same type of encapsulation is done with the gr-osmosdr source/sink code.

Good luck and let us know how it goes!

Brian
jump
Posts: 58
Joined: Mon Mar 03, 2014 5:31 pm
Contact:

Re: C# and BladeRF

Post by jump »

You're right saying that the code for SDR# is a plugin but you should be able to reuse the code in the NativeMethods class because this is the one which provides all the bindings between the C library and the managed C# world. Other classes implements interfaces for SDR#.
You may also be able to reuse the configuration form to some extent but you will need to change some callbacks that are specific to SDR#

To start your project, use the NativeMethods.cs file and look at BladeRFDevice.cs file about how to use it.
More specifically, you may be interested in the lookup table computation in "static unsafe BladeRFDevice()", the function ReceiveSamples_sync() which converts the samples to pass them to SDR# and the Start()/Stop() functions.
The trick here is that SDR# uses an asynchronous reception method whereas bladeRF's interface is designed around a synchronous API. Therefore, in Start() you can see all the device configuration happening and the creation of a Thread (look for the comment "new sync interface" in the code) to bridge bladeRF's sync API and SDR# asynchronous callbacks. This bridge is implemented in the ReceiveSamples_sync() function which is basically a while loop (stop condition is set by shared boolean across threads) that will call NativeMethods.bladerf_sync_rx() method, convert the samples with the LUT into Complex numbers and then notify SDR# of available samples by calling ComplexSamplesAvailable(). There is also some code I had to add at the beginning of the loop to reallocate the buffers to handle changing the sample rate on-the-fly without restarting the thread.

BladeRFIO.cs is nothing more that than a wrapper between SDR# interfaces and BladeRFDevice.cs so you don't need it.

I hope this makes more sense now.
dave0160
Posts: 8
Joined: Tue Dec 09, 2014 7:45 am
Location: Bloomington, IN

Re: C# and BladeRF

Post by dave0160 »

Brian,

I think that I stumbled into by accident. One thing that I found is that the instructions for how to link a non-COM or .NET dll is not straight forward. After looking through the API documentation and bouncing that against Jean-Michel Picod's SDR# plugin code and much web crawling I finally figured out how to talk to the BladeRF. On my first post I didn't realize that the way he has it setup is extremely modular and easier that I thought to use. The main file that I needed was the NativeMethods,cs file, (located here: https://github.com/jmichelp/sdrsharp-bl ... er/BladeRF).

I'll walk through what I've done so far:
1. Created a VS2010 Windows console project.
2. Copy bladerf.dll, libusb-1.0.dll, pthreadVC2.dll into the project directory (I know I need the bladerf.dll file, but not sure about the others. I just added them for good measure.)
3. Take the three dll's and drag them into the VS project.
4. Save the NativeMethods.cs file into your project directory.
5. Drag the NativeMethods.cs file into the VS project.

I've got some basic code hacked together to open a connection get the FGPA firmware and then close the connection:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Threading;
using SDRSharp.BladeRF;


namespace SDR_Test
{
    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine();

            string serial = "";
            IntPtr _dev, dev_list;
            string devspec = "";

            status = NativeMethods.bladerf_open(out _dev, devspec);
            //status = NativeMethods.bladerf_get_serial(_dev, out serial);   
             
            bladerf_version fpga_version = NativeMethods.bladerf_fpga_version(_dev);
            Console.WriteLine("fpga version: {0}.{1}.{2}", fpga_version.major, fpga_version.minor, fpga_version.patch);

            NativeMethods.bladerf_close(_dev);

            Console.ReadKey(true);
        }
}
I'm having a problem with the serial number but it seems to be a pointer issue more than a communications issue.

Many thanks to Jean-Michel Picod. He's probably saved me months of hair pulling.

I'll keep every one in the loop as my project progresses.

Thanks,
Dave
dave0160
Posts: 8
Joined: Tue Dec 09, 2014 7:45 am
Location: Bloomington, IN

Re: C# and BladeRF

Post by dave0160 »

That was going to be my next step. Figured the Tx side of things was going to be easier than the Rx so I'm going to try to bring in a group of samples and run a DFT on my bins of interest. Thanks for the pointers.
jump
Posts: 58
Joined: Mon Mar 03, 2014 5:31 pm
Contact:

Re: C# and BladeRF

Post by jump »

dave0160 wrote: 2. Copy bladerf.dll, libusb-1.0.dll, pthreadVC2.dll into the project directory (I know I need the bladerf.dll file, but not sure about the others. I just added them for good measure.)
You need libusb-1.0.dll only if you are using the USB backend but if you rely on the Cypress backend, it should not be required.
pthreadVC2.dll is required by bladerf.dll (internally, the synchronous interface spawns threads using this library).

Be aware that even though I tried to wrap in C# as many functions/enums of bladerf.dll as possible, I haven't tested everything. Some wrappers might crash. If you encounter such situation, please, open a bug on the github repository and I will try to fix that as fast as I can.

As you seem to need it, I can also add the synchronous TX methods to the wrapper if you don't feel comfortable enough with PInvoke and args marshalling.
dave0160
Posts: 8
Joined: Tue Dec 09, 2014 7:45 am
Location: Bloomington, IN

Re: C# and BladeRF

Post by dave0160 »

sweep_1M_100k_20ms.png
Great Success!!!!

I finally got it working. and have grabbed a few thousand samples and saved them to a file and do an FFT in MATLAB. I'll post my code next week once I clean it up from all of the trial an error attempts.

One thing that I did see in the NativeMethods.cs file was around line 277 the Dllimport contains: EntryPoint = "bladerf_rx". I tried using the bladerf_rx function but VS through back an error saying that there was no known entry point for "bladerf_rx". If I understand the way the Dllimport is working if the function below the import does not have the same name as a function within the dll then the entry point option should be used and that should be the name of a valid function in the dll. I've never used dll's and the Dllimport is brand new to me so I could be totally off, but this might be an unfinished/abandoned piece of code?

My basic settings for this capture are:
Center Frequency: 315MHz
Bandwidth 1.5MHz
Sample Rate: 3MHz
bladerf_sync_config parameters:*
- Num_Buffers = 16
- Num_Xfers = 8
- buf_size = 65536
* I'm still playing around with these settings any insight as to how the may affect performance as I drive the sample rate up would be appreciated.

The signal parameters are as follows:
- Stepped sweep
- 1 MHz sweep span
- 100kHz step spacing
- 20ms step dwell time

I did notice that the dwell time observed was not as I had set it. The signal has been stretched by about 5-6 ms. I'm not sure if this is my sig gen acting up or something else that I've configured wrong but the 5-6 ms is there for various dwell time settings.
jump
Posts: 58
Joined: Mon Mar 03, 2014 5:31 pm
Contact:

Re: C# and BladeRF

Post by jump »

dave0160 wrote:If I understand the way the Dllimport is working if the function below the import does not have the same name as a function within the dll then the entry point option should be used and that should be the name of a valid function in the dll.
Exactly. In addition to that, when the function is manipulating strings, you have to add an extra parameter to tell the format of the string (unicode, ascii, etc.).
dave0160 wrote:I've never used dll's and the Dllimport is brand new to me so I could be totally off, but this might be an unfinished/abandoned piece of code?
It's not unfinished code but it is unmaintained. The BladeRF library is a fast evolving piece of software and it's pretty hard to keep up with the amazing amount of work that guys like jynik can do :)
When I started writing the plugin, the synchronous interface was inexistant so I started using the bladerf_rx() function. Once the synchronous interface was here, I switched to it because as far as I remember, the documentation was saying that the async API might change/disappear and never updated the prototype/wrapper. And that's probably why you should consider using the bladerf_sync_rx() function.
Again, if you need functions that are inexistant in NativeMethods.cs or that are not working, open a bug in the github project of the SDR# plugin and I will add those :)

The rule of thumb I followed for NativeMethods.cs was simple: if the function from the C library requires some extra code, it is bounded to a _native() method and a method matching the C library name is implemented to wrap it's _native() version.
dave0160
Posts: 8
Joined: Tue Dec 09, 2014 7:45 am
Location: Bloomington, IN

Re: C# and BladeRF

Post by dave0160 »

That makes total sense. You've done a great job on this interface between the dll and C#. Thank you very much for the work that you've done.

As promised I'm posting my Rx code. For anyone else looking it works, but I'm sure that it could be made more efficient and less memory intensive, this is just my attempt at understanding the interface and the radio.

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Threading;
using SDRSharp.BladeRF;
using System.Runtime.InteropServices;


namespace SDR_Test
{
    class Program
    {

        static void Main(string[] args)
        {
            Int32 status;
            IntPtr _dev;
            string devspec = "";
            UInt32 idx, Frequency = 315000000U;

            status = NativeMethods.bladerf_open(out _dev, devspec);
             
            bladerf_version fpga_version = NativeMethods.bladerf_fpga_version(_dev);
            Console.WriteLine("fpga version: {0}.{1}.{2}", fpga_version.major, fpga_version.minor, fpga_version.patch);

            bladerf_rx_config(_dev, Frequency);

            UInt32 N = 4096 * 1024;
            Int16[] samples = new Int16[N*2];   // x2, one for I and one for Q

            samples = bladerf_RX(_dev, N);

            string fileName = "..\\..\\..\\sample_test1.csv";
 
            // save to a csv file
            try
            {
                StreamWriter file = new StreamWriter(fileName, false);

                for (idx = 0; idx < N*2; idx += 2)
                {
                    file.WriteLine("{0},{1}", samples[idx], samples[idx + 1]);
                }

                file.Close();
                Console.WriteLine("File saved.");
            }
            catch
            {
                Console.WriteLine("Error Opeing or writing to the file.");
            }
        
            NativeMethods.bladerf_close(_dev);
            Console.ReadKey(true);

        }


        private static void bladerf_rx_config(IntPtr dev, UInt32 Frequency)
        {
            Int32 status;
            UInt32 act_BW;
            Double act_SR;

            const Double Samplerate = 3000000D;
            const Int32 Bandwidth = 1500000;

            // Set the bandwidth
            status = NativeMethods.bladerf_set_bandwidth(dev, bladerf_module.BLADERF_MODULE_RX, Bandwidth, out act_BW);
            // perform checks to make sure that there were no errors
            if (act_BW != Bandwidth)
            {
                Console.WriteLine("Actual bandwidth does not match the set bandwidth (Actual/Set): {0}/{1}", act_BW, Bandwidth);
            }
            else if (status != 0)
            {
                Console.WriteLine("Error setting bandwidth: {0}", status);
            }
            else
            {
                Console.WriteLine("Bandwidth Set!");
            }

            // Set the Sample Rate
            status = NativeMethods.bladerf_set_sample_rate(dev, bladerf_module.BLADERF_MODULE_RX, Samplerate, out act_SR);
            // perform checks to make sure that there were no errors
            if (act_SR != Samplerate)
            {
                Console.WriteLine("Actual sample rate does not match the set sample rate (Actual/Set): {0}/{1}", act_SR, Samplerate);
            }
            else if (status != 0)
            {
                Console.WriteLine("Error setting sample rate: {0}", status);
            }
            else
            {
                Console.WriteLine("Sample Rate Set!");
            }

            // Set center Frequency
            status = NativeMethods.bladerf_set_frequency(dev, bladerf_module.BLADERF_MODULE_RX, Frequency);
            // perform check to make sure that there were no errors
            if (status != 0)
            {
                Console.WriteLine("Error setting center frequency: {0}", status);
            }
            else
            {
                Console.WriteLine("Center Frequency Set!");
            }

        }   // end of bladerf_rx_config

        private unsafe static Int16[] bladerf_RX(IntPtr dev, UInt32 N)
        {
            Int16[] samples = new Int16[N*2];
            Int32 status;

            const UInt32 timeout_ms = 5000;
            const UInt32 Num_Buffers = 16;
            const UInt32 Num_Xfers = 8;
            UInt32 buf_size = 65536;

            // configure RX module to receive data
            status = NativeMethods.bladerf_sync_config(dev, bladerf_module.BLADERF_MODULE_RX, bladerf_format.BLADERF_FORMAT_SC16_Q11, Num_Buffers, buf_size, Num_Xfers, timeout_ms);

            if (status == 0)
            {
                // enable rx module
                status = NativeMethods.bladerf_enable_module(dev, bladerf_module.BLADERF_MODULE_RX, 1);
                Thread.Sleep(10);
                fixed (Int16* _samplesPtr = &samples[0])
                {
                    status = NativeMethods.bladerf_sync_rx(dev, _samplesPtr, N, IntPtr.Zero, timeout_ms);
                }
                
                status = NativeMethods.bladerf_enable_module(dev, bladerf_module.BLADERF_MODULE_RX, 0);
            }
            else
            {
                samples = null;
                Console.WriteLine("Error configuring device: {0}", status);
            }

            return samples;
        }   // end of bladerf_RX

    }   // end of Program class

}   // end of namespace

It's very basic but it does the job.

I'm going to work more on Nuand's suggestions about reading the "in flight" data while still bringing in more data instead of bringing in a huge chunk at once. I also haven't bothered with any of the gain settings so I've got some research to do in that area as well.

Hopefully, next week I can get started on the Tx side of things.

Dave
on4bhm
Posts: 36
Joined: Thu Aug 22, 2013 12:07 pm

Re: C# and BladeRF

Post by on4bhm »

Hi,

I want to do the following:

capture some samples for the blade and send it in tcp to a websdr who is listening on the same port to rx the packets and make them available to be viewed and listen to via websdr
for more information see www.websdr.org

Can someone give me a jump start?

thanks
dave0160
Posts: 8
Joined: Tue Dec 09, 2014 7:45 am
Location: Bloomington, IN

Re: C# and BladeRF

Post by dave0160 »

on4bhm, just sent you a PM to answer your question...

The code above should work for you, but you'll have to modify to meet your requirements to sen the data over tcpip. I'm not familiar with the websdr data format.

The example just save the samples in a text based csv file, but you can use the "BinaryWriter" class in C# to write the samples in binary format which will make you files sizes more manageable over tcpip. I've switched to binary format since my recordings are around 10s @ 5MHz sample rate => 200MB per file.

Dave
ksmiller99
Posts: 10
Joined: Wed Jun 15, 2016 11:22 am

Re: C# and BladeRF

Post by ksmiller99 »

Thanks dave160 I'm just getting started on a C# bladeRF project. I used your code and because the SDR# repo is closed, I found NativeMethods.cs elsewhere (I'd prefer not to say where because there're some copyright issues involved) and it is running! Did you do anything with transmitting yet?

Kevin
jump
Posts: 58
Joined: Mon Mar 03, 2014 5:31 pm
Contact:

Re: C# and BladeRF

Post by jump »

If you took it from my repository (https://github.com/jmichelp/sdrsharp-bladerf), there's no copyright issue at all.

I think I've never found what kind of license is compatible with SDRSharp now that they are closed-source and then I was focused on development and forgot to set one.
You can safely assume it's a BSD license :) I will add corresponding headers and files on the next release.
ksmiller99
Posts: 10
Joined: Wed Jun 15, 2016 11:22 am

Re: C# and BladeRF

Post by ksmiller99 »

Thanks jump. That is the NativeMethods.cs I have been using, and the project is coming along nicely, but there's one strange problem. When I try to get the serial number using bladerf_get_serial(), the application just crashes and disappears with no messages. I'm running a debug build from MSVS 2013. Have you seen this before, or do you have any ideas on how to troubleshoot it?
jump
Posts: 58
Joined: Mon Mar 03, 2014 5:31 pm
Contact:

Re: C# and BladeRF

Post by jump »

Have looked at the way I use it in my code in order to compare with your code?
https://github.com/jmichelp/sdrsharp-bl ... ce.cs#L321

When it crashes, it basically means that something wrong happened in the native code.
This can happen in 2 cases I think:
  • Passing wrong arguments to a native call
  • Non-initialized buffers / null objects when the API is expected to write into the memory
If you're using similar code to what I did, that could mean that I got lucky with my code and that the wrapper has an issue.
No black magic to debug/trace that as far as I can tell: just use Visual Studio and its amazing debugger to run your code in debug mode and look at the crash or step into your code.

As a disclaimer, I made this wrapper to make my life easier and tried to wrap as many functions from libbladerf as I can but I never claimed it was safe to use it or that it was bug free ;)
I'm not an expert in C# by the way so I could have made big mistakes here. Exchanging data from/to native and managed code is sometimes a bit tricky.
Post Reply