diff --git a/Readme.md b/Readme.md
index cc27b7e91..1cb6b5c7a 100644
--- a/Readme.md
+++ b/Readme.md
@@ -105,7 +105,9 @@ HackRF is better used with a sampling rate of 4.8 MS/s and above. The 2.4 and 3.
⚠ The plugins should work normally when running as single instances. Support of many Rx and/or Tx instances running concurrently is considered experimental.
-You will need a minimal installation of LimeSuite. Presently version 17.12.1 should be used with its corresponding firmware (v4) and gateware (v2.12) installed in the LimeSDR device:
+⚠ It seems LimeSDR mini has trouble working with host sample rates lower than 3 MS/s particularly in Tx mode.
+
+You will need a minimal installation of LimeSuite. Presently commit 04b57e0 or later should be used with its corresponding firmware (v4) and gateware (v2.12) installed in the LimeSDR device:
- `sudo apt-get install libsqlite3-dev`
- `git clone https://github.com/myriadrf/LimeSuite.git`
diff --git a/swagger/sdrangel/examples/Readme.md b/swagger/sdrangel/examples/Readme.md
index 825938eac..de30f081e 100644
--- a/swagger/sdrangel/examples/Readme.md
+++ b/swagger/sdrangel/examples/Readme.md
@@ -35,6 +35,33 @@ It uses the following APIs:
- URI: `/sdrangel/deviceset/{deviceSetIndex}/device/run`
- HTTP method: `POST`
+limesdr_tx.py
+
+Create a Tx device set with a LimeSDR Tx device and a NFM modulator channel configured to send some beacon Morse code. Then starts the Tx.
+
+It uses the following APIs:
+
+ - To create a new device set:
+ - OperationID: `instanceDeviceSetsPost`
+ - URI: `/sdrangel/devicesets`
+ - HTTP method: `POST`
+ - To select a device in a device set:
+ - Operation ID: `devicesetDevicePut`
+ - URI: `/sdrangel/deviceset/{deviceSetIndex}/device`
+ - HTTP method: `PUT`
+ - To create a new channel:
+ - Operation ID: `devicesetChannelPost`
+ - URI: `/sdrangel/deviceset/{deviceSetIndex}/channel`
+ - HTTP method: `POST`
+ - To change the settings of a channel:
+ - OperationID: `devicesetChannelSettingsPatch`
+ - URI: `/sdrangel/deviceset/{deviceSetIndex}/channel/{channelIndex}/settings`
+ - HTTP method: `PATCH`
+ - Start a device streaming
+ - OperationID: `devicesetDeviceRunPost`
+ - URI: `/sdrangel/deviceset/{deviceSetIndex}/device/run`
+ - HTTP method: `POST`
+
nfm_test.py
Example of creating NFM channels (demodulator and modulator) and changing the settings
diff --git a/swagger/sdrangel/examples/limesdr_tx.py b/swagger/sdrangel/examples/limesdr_tx.py
new file mode 100644
index 000000000..c61830e75
--- /dev/null
+++ b/swagger/sdrangel/examples/limesdr_tx.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+
+import requests, json, traceback, sys
+from optparse import OptionParser
+
+base_url = "http://127.0.0.1:8091/sdrangel"
+
+requests_methods = {
+ "GET": requests.get,
+ "PATCH": requests.patch,
+ "POST": requests.post,
+ "PUT": requests.put,
+ "DELETE": requests.delete
+}
+
+# ======================================================================
+def getInputOptions():
+
+ parser = OptionParser(usage="usage: %%prog [-t]\n")
+ parser.add_option("-a", "--address", dest="address", help="address and port", metavar="ADDRESS", type="string")
+
+ (options, args) = parser.parse_args()
+
+ if (options.address == None):
+ options.address = "127.0.0.1:8091"
+
+ return options
+
+# ======================================================================
+def printResponse(response):
+ content_type = response.headers.get("Content-Type", None)
+ if content_type is not None:
+ if "application/json" in content_type:
+ print(json.dumps(response.json(), indent=4, sort_keys=True))
+ elif "text/plain" in content_type:
+ print(response.text)
+
+# ======================================================================
+def callAPI(url, method, params, json, text):
+ request_method = requests_methods.get(method, None)
+ if request_method is not None:
+ r = request_method(url=base_url+url, params=params, json=json)
+ if r.status_code == 200:
+ print(text + " succeeded")
+ printResponse(r)
+ return r.json() # all 200 yield application/json response
+ else:
+ print(text + " failed")
+ printResponse(r)
+ return None
+
+# ======================================================================
+def main():
+ try:
+ options = getInputOptions()
+
+ global base_url
+ base_url = "http://%s/sdrangel" % options.address
+
+ r = callAPI("/devicesets", "POST", {"tx": 1}, None, "Add Tx device set")
+ if r is None:
+ exit(-1)
+
+ r = callAPI("/deviceset/1/device", "PUT", None, {"hwType": "LimeSDR", "tx": 1}, "setup LimeSDR on Tx 1")
+ if r is None:
+ exit(-1)
+
+ settings = callAPI("/deviceset/1/device/settings", "GET", None, None, "Get LimeSDR Tx settings")
+ if settings is None:
+ exit(-1)
+
+ settings["limeSdrOutputSettings"]["antennaPath"] = 1
+ settings["limeSdrOutputSettings"]["devSampleRate"] = 3200000
+ settings["limeSdrOutputSettings"]["log2SoftInterp"] = 4
+ settings["limeSdrOutputSettings"]["ncoEnable"] = 1
+ settings["limeSdrOutputSettings"]["ncoFrequency"] = -500000
+ settings["limeSdrOutputSettings"]["lpfFIRBW"] = 100000
+ settings["limeSdrOutputSettings"]["lpfFIREnable"] = 1
+
+ r = callAPI("/deviceset/1/device/settings", "PATCH", None, settings, "Patch LimeSDR Tx settings")
+ if r is None:
+ exit(-1)
+
+ settings = callAPI("/deviceset/1/channel", "POST", None, {"channelType": "NFMMod", "tx": 1}, "Create NFM mod")
+ if settings is None:
+ exit(-1)
+
+ settings["NFMModSettings"]["cwKeyer"]["text"] = "VVV DE F4EXB "
+ settings["NFMModSettings"]["cwKeyer"]["loop"] = 1
+ settings["NFMModSettings"]["cwKeyer"]["mode"] = 1 # text
+ settings["NFMModSettings"]["modAFInput"] = 4 # CW text
+ settings["NFMModSettings"]["toneFrequency"] = 600
+
+ r = callAPI("/deviceset/1/channel/0/settings", "PATCH", None, settings, "Change NFM mod")
+ if r is None:
+ exit(-1)
+
+ r = callAPI("/deviceset/1/device/run", "POST", None, None, "Start device on deviceset R1")
+ if r is None:
+ exit(-1)
+
+ except Exception, msg:
+ tb = traceback.format_exc()
+ print >> sys.stderr, tb
+
+
+if __name__ == "__main__":
+ main()
+