myriadrf / limesuite Goto Github PK
View Code? Open in Web Editor NEWDriver and GUI for LMS7002M-based SDR platforms
Home Page: https://myriadrf.org/projects/lime-suite/
License: Apache License 2.0
Driver and GUI for LMS7002M-based SDR platforms
Home Page: https://myriadrf.org/projects/lime-suite/
License: Apache License 2.0
Currently fftviewer is implemented around LMS_StreamBoard API and StreamerNovena API. But it should be generic for any board supporting streaming under IConnection.
Thoughts?
There is a use case where STREAM board is used over USB3 (only for streaming), combined with a COM connection to EVB7(for control). This is when the SPI resistors are not populated on the STREAM and/or EVB7.
For this issue we will consider supporting TTY/COM connections within the STREAM connection for the purposes of reducing existing code duplication, and future duplication inside of the SoapySDR wrapper.
If there is a general bennefit to have separate control and stream interfaces present throughout the code, then this issue is rather pointless. But if its just the STREAM + COM special use case, I think we can fix this rather elegantly (~ish).
The handle will be extended to specify an optional COM device chosen by the user. When specified, the ConnectionSTREAM will re-use the ConnectionEVB7COM code to connection to the COM device. And it will forward calls to the ConnectionEVB7COM instance for RFIC and other controls.
Even if we do not make any of the additional changes below, this particular addition will allow me to support EVB7 COM + STREAM in SoapySDR wrapper using only one connection. Otherwise, I will use some device constructor args to specify the COM device, and maintain two IConnection pointers.
More ideas below...
Determining which COM ports are actually an EVB7 is difficult. Also it cannot be known which COM ports belong to the STREAM board (in the case of multiple devices).
Currently we have two connection columns and two separate connections.
Configuring ConnectionSTREAM + COM
section). This option maintains a single connection, but allows the user to select from separate columns to eliminate M x N elements. Still, its a bit special cased...I was testing with the LMS_StreamBoard, and I couldnt figure out why it took 10 seconds to get data. I found that this seemingly innocent block of code was the culprit. Nothing to do with threads or blocking:
mRxFIFO = new LMS_StreamBoard_FIFO<SamplesPacket>(1024*2);
mTxFIFO = new LMS_StreamBoard_FIFO<SamplesPacket>(1024*2);
///calls this which takes 10 seconds or more
for (int i = 0; i < FIFO_length; ++i)
{
mElements.push_back(T());
++cnt;
}
//The packet type (T) is big... but not that big...
const static int samplesCount = 32768;
float iqdata[samplesCount];
int channel;
In addition, I have had some compiles that did not experience this delay (rearguards of master branch or connection work). Its weird... But the fix was to use a pointer instead (other changes needed to compile not shown):
diff --git a/src/LMS_StreamBoard/LMS_StreamBoard_FIFO.h b/src/LMS_StreamBoard/LMS_StreamBoard_FIFO.h
index 51d06cd..53805be 100644
--- a/src/LMS_StreamBoard/LMS_StreamBoard_FIFO.h
+++ b/src/LMS_StreamBoard/LMS_StreamBoard_FIFO.h
@@ -38,7 +38,7 @@ public:
{
for (int i = 0; i < FIFO_length; ++i)
{
- mElements.push_back(T());
+ mElements.push_back(new T());
++cnt;
}
//mElements.resize(FIFO_length, T());
@@ -131,7 +131,7 @@ protected:
uint32_t mElementsFilled;
std::mutex mElementsLock; // condition variable for critical section
- std::vector<T> mElements;
+ std::vector<T *> mElements;
std::condition_variable canWrite;
std::condition_variable canRead;
};
Ultimately, I don't think that I will use this class for the soapysdr work or the demo. I am just testing for now and I can ignore it. But this issue may come up again, so its good to keep track of stuff like this.
Just an idea, but perhaps with a firmware update, a UUID could be read/written to the FX3 flash. When the cal software sees an uninitialized UUID, it would generate a random one and write it once. This would give us a unique ID for each hardware in the future for calibration data.
It was mentioned splitting up the wx GUI into a separate library and application. The main idea here was to let the user instantiate the GUI on their own custom device, therefore re-using the library, but building a new application with the glue logic.
New thoughts: I think with the connection registry idea, this is largely no longer necessary. The connection registry will be extendible at runtime with new devices, and the IConnection will be "virtual" enough to handle any device. So the wx GUI app does not have to change. More on this in the connection registry issue. But I wanted to make a note here of the options for discussion.
The ConnectionSTREAM should support multiple + simultaneous boards. I don't think this is a priority, but lets track it here to remember.
Consider the case where multiple STREAM boards are attached VIA USB. We need a way to select a specific board. It looks like currently the Cypress API supports this using the device index, but the libusb API uses a VID/PID lookup that may be ambiguous with multiple boards.
Consider the case using simultaneous stream boards where someone may use two STREAM connections in the same process. In addition to 1), It also looks like the Cypress API implementation shares a device pointer for all open devices. So its currently limited to one device at a time.
For the soapy sdr bindings, we are going to want this use case to be some-what automated. This includes checking that the FPGA is loaded and that the correct image is loaded. When the driver is initialized, there where be some code to..
ConnectionHandle represents a discovered device. It holds serials and addresses. It can also be filled in partially to narrow down the search for a specific device.
ConnectionRegistry is the application API that allows ConnectionHandles to be discovered, and IConnections to be instantiated with the ConnectionHandle.
ConnectionRegistryEntry is a class that the hardware developer overloads to implement discovering available devices and instantiating IConnections.
The idea is to make ConnectionRegistry extensible without building the lime-suite for new devices or custom devices. Custom ConnectionRegistryEntry and associated custom IConnections can be registered with the ConnectionRegistry at runtime via LoadLibrary/dlopen(). We do this by building the ConnectionRegistryEntry into a library and installing it into a well known location to be loaded at runtime.
This issue should start by implementing the connection registry module for the Novena with spi interface only, no streaming.
However, the work for Novena LMS6 driver with streaming should be applicable to this work. Possibly using the existing FPGA driver work from LMS6, Novena has a functional streaming RX and TX channel that can be used.
It looks like only the first tab of the gui renders. Calibration is fine, but RFE, RBB, etc.. are all empty when selected. Could be a resizing hook issue -- maybe we need to force update/resize after tab changes.
Screenshot for reference in this thread, only cal tab is shown: https://discourse.myriadrf.org/t/is-limesdr-mac-compatible/329
A shared library does a few things for us:
Classes and functions in the shared library will need an export macro, example here (works windows and unix): https://gcc.gnu.org/wiki/Visibility
In terms of the build system, everything can stay in place, but we will probably build one shared library as opposed to multiple static libraries and linking them together.
Whenever there is a pause in the transmit stream, accidental/underflow or forced/end of burst, the transmit samples seem to have no effect. It looks like we just see the TX LO at whatever level was previously the last sample. The following example sleeps every 3 seconds for 3 seconds, it should cause a tone to go on an off. Once the tone appears, it goes away forever. If the zero-flush at the end is removed, the LO can be seen at full power (possibly because the last tx sample before the sleep was at full amplitude)
python demo_tx_recovery_issue.py --clockRate=32e6 --txAnt=BAND1 --txGain=40 --args="driver=lime" --freq=433.92e6 --ampl=0.7 --rate=4e6 --waveFreq=300e3
Given the new work based around the connection registry and IConnection expansion, we should be able to create a generic SoapySDR wrapper about these interfaces. This means that any device expressed under IConnection can be used under the SoapySDR API. This opens a world of possibilities for simply doing the work of filling in the IConnection and ConnectionRegistryEntry.
The TODO list:
The IQ can random swap on TX between runs. This might be an issue with GPIFIII state machine. Uncertain. To reproduce, run, ctrl+c, and re-run the siggen app. The tone should be positive of the TX LO, but will sometimes swap positions:
python lms7suite/src/SoapyLMS7/siggen_test.py \
--clockRate=40e6 --txAnt=BAND1 --txGain=52 \
--args="driver=lime" --freq=1000.5e6 \
--ampl=0.7 --rate=5e6 --waveFreq=300e3
Git subtree attempts to copy or squash another git repo -- rather than submodule which is more like a lightweight symlink. Should we consider replacing the ini parse submodule with subtree instead to
I like submodules a lot, but since this is the only case so far, it may be easier to go with subtree.
Git branches and release tags I am thinking about having a "stable" branch. At least in the future for creating releases from. In this paradigm, the "stable" branch only gets fixes applied and gets merged into the master branch (aka development branch). New development occurs on the master branch which includes API changes and breaking features.
The stable branch is periodically tagged with a new release number. And when stable becomes mature and a feature set also matures on master, we update stable branch for the latest master branch and create a new release series. The cycle continues.
This might be overkill, but something like this in mind:
http://nvie.com/posts/a-successful-git-branching-model/
Version numbering scheme Looks like we currently build version information into version.h:
https://github.com/myriadrf/LimeSuite/blob/master/src/version.h
Versioning with dates is often used and very indicative of the age of a package. Using a version scheme like version.h like "year.month.day" could work quite well.
However, I would also like to consider how fixes are handled using a similar scheme of "year.month.patch". Perhaps a release is made, lets say its named 2016.05.0. After some bug fixes, a new release is tagged 2016.05.1
Because of the re-calibrations, the streaming is disabled and enabled. This may be causing the timestamp to reset to 0. One possible fix would be to copy the last timestamp into the timestamp offset. This will make the timestamps appear monotonic from the API perspective:
Example, although this did not immediately work (caused application to exit):
diff --git a/src/ConnectionSTREAM/ConnectionSTREAMing.cpp b/src/ConnectionSTREAM/ConnectionSTREAMing.cpp
index f9a9ae1..826eabd 100644
--- a/src/ConnectionSTREAM/ConnectionSTREAMing.cpp
+++ b/src/ConnectionSTREAM/ConnectionSTREAMing.cpp
@@ -158,6 +158,10 @@ struct USBStreamService : StreamerLTE
//clear any residual data from FIFO
ResetUSBFIFO(dynamic_cast<LMS64CProtocol *>(mDataPort));
+ //hardware time resets to zero, correct with offset + 100 ms
+ mTimestampOffset += mLastRxTimestamp + mHwCounterRate*0.1;
+ mLastRxTimestamp = 0;
+
//switch on Rx
auto regVal = Reg_read(mDataPort, 0x0005);
int syncDis = txTimeEnabled?0:(1 << 5);
To add to the wishlist. If the FX3 firmware and lime suite and supported burning to flash. We could avoid booting into factory with the jumper. This may be useful for firmware updates in the future.
I was thinking of making the SoapyLime code set the default baseband bandwidth on initialization to some arbitrary default. Probably a bandwidth that is large enough to cover any host-based app. Like 30 MHz. The point being that:
Of course users can still tweak the bandwidth for out of band rejection if they want to. Thoughts?
I had a work-around checked into the siggen app thats sets a matching rx rate when the tx sample rate is set. But not every app has this work around. So it looks like the transmit waveform is unstable, almost like the PLL is not locked when the rates are different. To simulate this, I added --rxRate to the siggen app (checked in just now):
Looks good
python siggen_test.py --clockRate=40e6 --txAnt=BAND1 --txGain=52 --args="driver=lime" --freq=433.92e6 --ampl=0.7 --rate=5e6 --waveFreq=300e3 --rxRate=5e6
Looks bad, but why?
python siggen_test.py --clockRate=40e6 --txAnt=BAND1 --txGain=52 --args="driver=lime" --freq=433.92e6 --ampl=0.7 --rate=5e6 --waveFreq=300e3 --rxRate=2.5e6
This might be more of a matter of taste, but since the lime-suite is largely C++, we might want to put namespace lime {} around classes and enums found in public headers. There should not be many changes to the code-base. The implementation cpp files would gain the line using namespace lime
, and the headers would gain the line namespace lime {
and a closing bracked }
.
I was thinking about a way to remove some of the lag from the calibration sequence. Specifically stopping the threads, disabling FPGA streaming, re-enabling streaming, and then re-restarting the threads. Emphasis on the threads being brought up and down.
There is an issue of the MCLK during calibration being wrong, or too high. The LML clock dividers could be set to match, or the MCLK output could be disabled during calibration. Personally, I'm afraid of any clock glitchiness, I would have configurable enables on everything in the MCLK domain to disable the entire FPGA+LML interface during cal.
My hope is that if the changing clock rate can be removed from the list of issues, that everything else can be left "as-is" during calibration.
In order to use lime-suite as a development library for 1) developers writing drivers and 2) users instantiating lms driver in applications. All necessary headers should be installed into the system in an include/lime-suite directory.
This is more of a thought at the moment and note for the future: The current ConnectionSTREAM has a a dual implementation for both libusb and CyAPI separated by a lot of #ifdef __unix__
.
Due to the limitations of the PLL in the fpga, the minimum supported sample rate is 2.5 MSps or 5 MHz PLL. Some applications (like GSM) and user testing may require lower sample rates.
One suggested fix may be to use a clock mux to switch between the PLL and an alternative clock for lower rates. A slower clock with appropriate phase relationship could be generated in register logic by oversampling the MCLK with a faster clock and creating the required phase delay.
Create debian/ directory for building binary debs (and source packages for PPA)
We will still need fast baseband filter calibration, lets do as much as possible to speed up the algorithms.
We have a cache of LMS700m registers, so it should be possible to specify fromChip false. This should cut down the operation time of all Modify_SPI_Reg_bits() used in the filter setup.
Rather than writing out to the LMS7 registers on each call to Modify_SPI_Reg_bits(), we could also implement a toChip = false for Modify_SPI_Reg_bits(). Then perform a single bulk write of all affected registers.
Example: The readRSSI() function can be sped-up with two writes only for the capture register, and one bulk read for the 3-byte readback value.
Rather than a separate cal operation for both RFE and RBB, (and only when the requested BW is the same for both filters)... most of the calibration uses the same setup (same clock rate, same loopback, same LO). One operation with a shared initial setup should be faster.
Store all calibration results in the database. Unless the user is sweeping over possible bw settings, we are likely to see the same values come up again and again. 1) an initial value set by the driver that is good for most applications, and 2) an application specific value that is used over and over.
Can we merge Iconnection branch, and should we merge before things diverge any more? My concerns are:
We want to support dynamic expansion of the connections available in the connection registry. This is so user's can use the stock LMS7002m driver DLL/binaries and expand for their own creation.
New connection module for EVB7 + COM: As part of the connection registry work, the COM connection will be reshaped around the new connection API. The streaming calls will be default not implemented, but its discovery, factory, and communication calls will be used under the new API.
I have noticed this for a while, but I finally tried to look into it because its making the testing near impossible. It looks like wxStaticBoxSizer does not take into account the size of its label, and all of the nested box-sizers gradually loose more and more screen space the deeper they nest... just a guess. But every tab, every dialog looks like this more or less.
@rjonaitis any ideas/hints?
@rjonaitis I'm having trouble getting useful data out of the stream board. I am really looking for a positive confirmation of IQ samples. Here are the steps that I took, and whats happening:
sudo bin/lms7suite
Visible GUI update time: 0
GUI update time: 0
Create time 1172 ms
Claimed Interface
Visible GUI update time: 17
GUI update time: 264
(lms7suite:7120): Gtk-CRITICAL **: IA__gtk_window_resize: assertion 'width > 0' failed
(lms7suite:7120): Gtk-CRITICAL **: IA__gtk_window_resize: assertion 'width > 0' failed
(lms7suite:7120): Gtk-CRITICAL **: IA__gtk_window_resize: assertion 'width > 0' failed
Error: popping from RX
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
transfer timed out
Error: popping from RX
Rx: 0.0% rate: 0 kB/s failures:2
Error: popping from RX
transfer timed out
Error: popping from RX
Rx: 0.0% rate: 0 kB/s failures:2
transfer timed out
Error: popping from RX
Rx: 0.0% rate: 0 kB/s failures:2
Error: popping from RX
transfer timed out
Error: popping from RX
Rx: 0.0% rate: 0 kB/s failures:2
Error: popping from RX
transfer timed out
Error: popping from RX
Rx: 0.0% rate: 0 kB/s failures:2
Error: popping from RX
transfer timed out
Error: popping from RX
Rx: 0.0% rate: 0 kB/s failures:2
Error: popping from RX
transfer timed out
Error: popping from RX
Rx: 0.0% rate: 0 kB/s failures:2
Error: popping from RX
Processing finished
What is the purpose of the current LEDs near the usb connector. Perhaps FPGA and FX3 boot indicators? I was wondering about documenting it to help new users when they first power on the hardware.
Secondly, could any of the LEDs be re-purposed after boot as some kind of status indicator for things like:
This issue is to modify the API calls to work in units of Hz. Currently API units are in MHz. I recommend putting units in the API calls to avoid accidental breakage: Example TuneTxFilter() becomes TuneTxFilter_Hz().
Setting the rate on side B appears to readback the incorrect interpolation, and hence the wrong sample rate. Also, this sample rate is used to set the PLL, so although the correct rate is really set, the PLL is not correct. So far, affected applications end up causing a second calibration which corrects the PLL. The problem is probably in:
liblms7_status LMS7002M::SetInterfaceFrequency(
float_type cgen_freq_MHz, const uint8_t interpolation, const uint8_t decimation)
or
float_type LMS7002M::GetSampleRate(bool tx)
Seen when running osmotrx:
-- SoapyLMS7::setSampleRate(Tx, 0, 4.333333 MHz), baseRate 17.333333 MHz, factor 4.000000
LMS_StreamBoard::ConfigurePLL(tx=4.33333MHz, rx=17.3333MHz)
libusb: warning [handle_timeout] async cancel failed -5 errno=22
libusb: warning [handle_timeout] async cancel failed -5 errno=22
libusb: warning [handle_timeout] async cancel failed -5 errno=22
libusb: warning [handle_timeout] async cancel failed -5 errno=22
libusb: warning [handle_timeout] async cancel failed -5 errno=22
libusb: warning [handle_timeout] async cancel failed -5 errno=22
libusb: warning [handle_timeout] async cancel failed -5 errno=22
libusb: warning [handle_timeout] async cancel failed -5 errno=22
libusb: warning [handle_timeout] async cancel failed -5 errno=22
-- SoapyLMS7::setSampleRate(Tx, 1, 4.333333 MHz), baseRate 17.333333 MHz, factor 4.000000
LMS_StreamBoard::ConfigurePLL(tx=4.33333MHz, rx=17.3333MHz)
UHD Warning:
The hardware does not support the requested TX sample rate:
Target sample rate: 4.333333 MSps
Actual sample rate: 8.666667 MSps
The USBConnection will be be re-factored into a new Connection registry entry and IConnection that implements streaming and SPI using the LMS64C protocol
Some calls take a reference frequency, some dont:
float_type GetReferenceClk_SX(bool tx);
float_type GetFrequencyCGEN_MHz();
//...I believe this uses the ref freq that was last set by SetFrequencySX
liblms7_status SetFrequencyCGEN(float_type freq_MHz);
float_type GetFrequencySX_MHz(bool tx, float_type refClk_MHz);
liblms7_status SetFrequencySX(bool tx, float_type freq_MHz, float_type refClk_MHz);
liblms7_status SetNCOFrequency(bool tx, uint8_t index, float_type freq_MHz);
///...although this refClk_MHz is the DSP/ADC rate
float_type GetNCOFrequency_MHz(bool tx, uint8_t index, float_type refClk_MHz, bool fromChip = true);
One of the things that I did to IConnection was add a call to query the reference frequency. The reference frequency is set by the board, external to LMS7002M. Some boards will have it fixed, some will have a synthesizer like stream.
I propose that all of these calls drop the reference frequency parameter, and in addition, LMS7002M does not cache the reference freq. Ref freq is always queried from one place, the IConnection.
IConnection.h
/*!
* Query the frequency of the reference clock.
* Some implementations have a fixed reference,
* some have a programmable synthesizer like Si5351C.
* @return the reference clock rate in Hz
*/
virtual double GetReferenceClockRate(void)
Adding a new API call to LMS7002M that can lookup cached corrections in the database, perform interpolation between points, and apply the correction:
int ApplyDigitalCorrectionsFromCache(const bool isTx)
{
//get the active channel ChA or ChB (chan)
//get the current SXX/LO frequency (freq)
//search the database for the nearest two points before and after freq, given chan, and isTx
//no points found?
return ReportError("Cant find entry in db for %f MHz on Rx channel A, etc..");
//if (isTx)
{
//linear interpolate DC real correction, DC imag correction
//linear interpolate IQ balance phase, and IQ balance gain
}
else
{
//linear interpolate IQ balance phase, and IQ balance gain
}
}
using the new call in SoapyLMS7
The setFrequency() call will try to apply corrections for both channels after the LO is re-tuned. If the corrections do not have possible entries in the database, then a warning will be logged.
IConnection is our entry point for communication and streaming with a device. The LMS7 driver class uses IConnection to interface with the device; and devices creators implement IConnection's methods to specify communication specifics.
The main goals to come out of this re-work:
One or more RFICs may be present on a device. We need to enumerate the number of devices and to know which channels and slaves are present for that RFIC.
The baseband filters for RBB, RFE(TIA), and TBB should cache results in the database. Initially, we aren't looking for any fancy interpolation. Once a bandwidth is calibrated for, its RC values will be saved and applied next time.
This work will modify the existing calibration algorithms to check, retrieve, and apply RC constants from the database. If a particular bandwidth cannot be found with a few Hz of error, then the manual calibration must be performed. The result will be stored in the database.
While making the wrapper calls for various settings for the SoapySDR wrapper. I was thinking that it would make sense if this logic was embedded into the LMS7002M.h API itself for maximum re-use.
TODO checklist
Examples:
SetPathRFE(some enum)
{
//this call sets SEL_PATH_RFE as well as the required enables like EN_INSHSW_*
//Also it would call _conn->UpdateExternalBandSelect(...)
}
SetBandTRF(int band)
{
//band is 1 or 2
//set SEL_BAND1_TRF and SEL_BAND2_TRF
//also UpdateExternalBandSelect(...)
}
SetGainPGARBB(const double gain_dB)
{
//set G_PGA_RBB gain in dB
//another other enables or calibrations...
}
//Rx LNA, Tx PAD, etc...
E.g.
$ osmocom_fft -F -a "driver=lime,soapy=0,clock=40e6,cacheCalibrations=1" -s 5e6 -f 7e6
Results in:
LMS_StreamBoard::ConfigurePLL(tx=10MHz, rx=5MHz)
C[INFO] SoapyLMS7::setFrequency(Rx, 0, RF, 7.000000 MHz), ref 30.720000 MHz
[INFO] SoapyLMS7::setFrequency(Rx, 0, BB, -1897.655000 MHz), ref 30.720000 MHz
Create a command line utility that can perform loopback calibration for a specified range of frequencies. The result will be recorded to the LMS7002M sqlite database. The utility should be run on frequencies of interest before using SDR utilities. Without calibration data, the board will operate as normal, but with larger IQ imbalance and transmit DC.
At each particular frequency, the calibration algorithm can perform Rx IQ, TX IQ+DC, or all calibrations. The algorithm will use the RF loopback path in the LMS7 to send a strong tone (or tones) from the transmit path to the receiver.
To calibrate the RX IQ imbalance:
To calibrate the TX IQ and TX DC imbalance:
It might be a good follow-up task to implement this calibration into the lms7suite GUI, with displays for live FFT data and correction efficacy.
So there are a few different error enums, to name a few:
I was thinking that it might be cleaner to follow a different model for dealing with error codes and error reporting. Basically, there would be one error reporting and querying API. And most API calls would simply return pass/fail true/false 0/-1. The user would be able to query the actual error code and message string when the call failed, and if they were interested. Its a lot like errno or windows getlasterror().
list of pre-defined error codes that users will encounter when using lime suite
SUCCESS = 0
ERROR_CONNECTION,
ERROR_RANGE
ERROR_BUFFER
etc...
When API calls fail, they should first report the error code
and an optional message string with more details
void ReportError(int code, string message = "");
//variant for reporting after system call failures that use errno/getlasterror
void ReportError(int code, errno);
When a user wants to query the error:
//get the error code reported
int GetLastError(void);
//get the error code to string + any optional message reported
const char *GetLastErrorMessage(void);
The LMS API call CalibrateTx():
bool LMS7002M::CalibrateTx(float_type bandwidth_MHz)
{
if (bandwidth_MHz <= 0.0)
{
lime::ReportError(ERROR_RANGE, "LMS7002M::CalibrateTx() expects BW > 0");
return false;
}
return true;
}
The user's code:
if (not rfic->CalibrateTx(-100))
{
std::cout << "Failed to calibrate! " << lime::GetLastErrorMessage() << std::endl;
}
The error reporting API is global, its not tied to any particular class or instance. The error reporting API will store error codes and messages in thread-local-storage to make it thread-safe. As long as a user queries the error after a failure before making a new lime-suite API call, there will never be a problem.
Frequently get libusbx warnings of the sort:
2016-03-20 12:34:15 ::1: libusbx: warning [handle_timeout] async cancel failed -5 errno=22
E.g. when using PothosGui and changing settings or deactivating a topology.
One of the package components will automatically download the relevant LimeSDR (and possibly other) FPGA and firmware images using the postinst, prerm scripts. Compatible packages will always be versioned with release tags and found in predictable locations.
LMS7002M-driver is its own stand-alone C driver project for the LMS7
This may become a separate issue on the tracker, but a major benefit of this work should be creating a common calibration algorithm set for both drivers. This implies re-writing some of the calibration algorithms in C and generalizing it around the spi interface. Its definitely possible since this was actually done for the LMS7002M-driver. Hopefully we end up with a stronger and better tested calibration algorithm overall.
In SoapyLMS: Based on the desired sample rate, automatically select clock rate to make this possible with half-band chain. If the user never specifies a custom clock rate, then using sample rate hook to automatically select clock to match is a good idea. When both TX and RX rates are specified, try to make this work, error if no common clock rate can be figured out.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.