From dd35fa5051aae5196614ed152cada17b7e0ea2ea Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Fri, 13 Dec 2024 14:19:06 +0000 Subject: [PATCH] build based on addef85 --- dev/.documenter-siteinfo.json | 2 +- dev/acquisition.html | 2 +- dev/architecture.html | 2 +- dev/assets/documenter.js | 302 +++++++++++++------------ dev/assets/resync.png | Bin 0 -> 124857 bytes dev/client.html | 102 +++++---- dev/cluster.html | 2 +- dev/connections.html | 2 +- dev/devtips.html | 2 +- dev/examples/batch.html | 4 +- dev/examples/cluster.html | 4 +- dev/examples/producerConsumer.html | 4 +- dev/examples/ramping.html | 4 +- dev/examples/resync.html | 79 +++++++ dev/examples/seqRamping.html | 4 +- dev/examples/sequence.html | 4 +- dev/examples/sequenceMultiChannel.html | 4 +- dev/examples/simple.html | 4 +- dev/examples/waveforms.html | 4 +- dev/fpga.html | 2 +- dev/generation.html | 2 +- dev/index.html | 2 +- dev/installation.html | 4 +- dev/objects.inv | Bin 2766 -> 2827 bytes dev/scpi.html | 2 +- dev/search_index.js | 2 +- 26 files changed, 322 insertions(+), 223 deletions(-) create mode 100644 dev/assets/resync.png create mode 100644 dev/examples/resync.html diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 52932eaf..2ccb7db1 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-27T13:07:51","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.2","generation_timestamp":"2024-12-13T14:18:59","documenter_version":"1.8.0"}} \ No newline at end of file diff --git a/dev/acquisition.html b/dev/acquisition.html index 0769d76d..c10372c3 100644 --- a/dev/acquisition.html +++ b/dev/acquisition.html @@ -1,2 +1,2 @@ -Data Acquisition · RP DAQ Server

Data Acquisition

The data acquisition of the RedPitayaDAQServer project is based on two data flows to and from the upper 128 MB of the RedPitaya memory. This memory region acts as a ring buffer for the acquired samples and can be queried by clients using SCPI commands.

Signal acquisition within a cluster is based on a shared clock and trigger signal distributed via cables between the RedPitayas. Once triggered, all FPGAs continuously write the samples from their ADC channel to the sample ring-buffer with each clock tick. Both ADC channels on a RedPitaya are written to the buffer at the same time. The 14-bit values of the ADCs are converted to 16-bit signed integer samples and then concatenated into one 32-bit value, which is then written to the buffer. The sampling rate of the system can be adjusted by setting a decimation parameter and the decimation itself is realized with a CIC filter.

Internally, the FPGA keeps track of a 64-bit writepointer register pointing into the ring-buffer and increments this value with each new sample pair. Additionally, the writepointer also counts the number of buffer overflows. As the size of the buffer region is a power of two, these two components of the writepointer can be interpreted as one 64-bit number counting the samples from acquisition start. For the 128 MB buffer, this means that the lower 25 bits of the writepointer are the buffer location and the remaining bits are the overflow counter.

As the writepointer is reset and incremented based on a shared clock and trigger signal, it is synchronized across all FPGA images in a cluster. The logic implemented with the reprogrammable hardware is also the only logic of the RedPitayaDAQServer with predictable timing behaviour. All other components of the system implement their (timing related) logic in reference to the current writepointer values. With a known sampling rate, the writepointer can also be seen as the clock of the server and client components.

Sample Transmission

To retrieve samples from the server a client can supply a similar pointer, called readpointer, together with the number of samples to retrieve. The server then extracts the buffer position from the readpointer and transmits the requested amount of samples over the data socket. This transmission happens either way, even if the samples are overwritten. However, the server uses the whole readpointer, including the buffer overflows, to check if the requested samples were overwritten.

If the distance between the write- and readpointer is larger than the buffer size the overflow status flag is set. If during the transmission the requested samples are overwritten the corrupted flag is set. These flags can be queried individually or together in a status byte via SCPI commands.

This distance can not only be used to see if samples were overwritten, but also to track how well the client is able to keep up with the FPGA during a series of sample transmissions. If this distance increases over time, the FPGA is creating more samples than the server can transmit to the client. To allow a client to track this value, this distance is stored as a 64-bit value deltaRead for the latest transmission and can be queried. Additionally, the server also tracks the duration of the transmission as writepointer "clock ticks" as a 64-bit value deltaSend, which is just the difference between the writepointer at the start and end of a transmission.

Considerations for Sample Transmission

There are several things to consider when attempting to retrieve samples at a high sampling rate, for larger cluster sizes or for longer periods of time. Most of the following points were implemented/considered in the Julia reference implementation, but would become relevant when implementing custom clients.

As the server will always transmit samples just based on the buffer position of a readpointer, if a client wants to only receive certain samples it needs to wait for them to exist in the buffer. This requires querying the writepointer until it is larger than the desired readpointer.

If the number of requested samples is larger than the buffer, the sample should be requested in smaller chunks as the server would otherwise return samples that were not written yet. In a cluster scenario the i-th chunk should be requested from all RedPitayas in the cluster before requesting the next chunk to avoid "starvation" effects.

The status and performance data of a transmission can only be queried after the transmission has finished, which requires additionaly communication overhead.

To help clients with these issues, the server offers a second type of sample transmission in which samples, status and performance data is pipelined. In such a query a client first transmits a readpointer, together with the number of requested samples and the number of samples belonging to a chunk. The server itself then tracks the writepointer and transmits a chunk as soon as it becomes available and immidiatey follows that up with the status and performance data of the transmission. This way additional communication overheard is reduced and after the inital request a client just needs to read data until the transmission finishes.

Frames, Periods and Voltage

The samples sent by the server are the 16-bit values of the ADC channel of a RedPitaya. However, one might want to work with voltage values instead or encapsulate samples into a repeating concept like frames. The Julia client library offers functions to convert samples into such a concept or to directly request a number of frames instead of a number of samples.

Here, frames are comprised of periods, which in turn are comprised of samples. During the conversion process the 16-bit binary values can also be converted to floating point numbers representing a voltage if the RedPitaya was calibrated beforehand. In this calibration process, a client can store scale and offset values for each channel in the EEPROM of the RedPitaya. When the client establishes a connection to the server, it reads these values and can use them to translate the 16-bit values into a respective voltage value.

Sampling and Data Rates, Transmission Speeds and Time-to-Live

The highest supported sampling rate of the RedPitayaDAQServer is 15.625 MHz or 15.625 MS/s, as this is the sampling rate at which a single RedPitaya can produce and transmit samples continously without data loss given the 1 Gbit/s limit of the ethernet connection from the RedPitaya. This rate is a achieved with a decimation of 8 from the base 125 MHz sampling rate of the RedPitaya hardware.

At this sampling rate a single RedPitaya produces new samples at a data rate of 500 Mbit/s. Furthermore at this rate, once a sample has been written to the buffer it exists for 2.15s before being overwritten again (Time-To-Live, TTL). An overview of these metrics for different decimation factors is shown in the following table:

DecimationMHzMByte/sMbit/sTTL
641.957.8162.517.18s
323.9115.631258.59s
167.8131.252504.29s
815.6362.55002.15s

The table only refers to the data rate of new samples being produced. The data rate of samples being transmitted to a client can differ greatly depending on how the client queries and processes the samples and the available network bandwidth and usage. At the higher sampling rates it is recommended to have client threads that exclusively receive samples and perform any computation on samples in different threads to maximise the transmission speed, as a server can only transmit data at a rate of just above 500 Mbit/s. This exceeds the highest supported sampling rate by only a few Mbit/s and a client with frequency interruptions of its sample reception might not be able to keep up with the sampling rate.

+Data Acquisition · RP DAQ Server

Data Acquisition

The data acquisition of the RedPitayaDAQServer project is based on two data flows to and from the upper 128 MB of the RedPitaya memory. This memory region acts as a ring buffer for the acquired samples and can be queried by clients using SCPI commands.

Signal acquisition within a cluster is based on a shared clock and trigger signal distributed via cables between the RedPitayas. Once triggered, all FPGAs continuously write the samples from their ADC channel to the sample ring-buffer with each clock tick. Both ADC channels on a RedPitaya are written to the buffer at the same time. The 14-bit values of the ADCs are converted to 16-bit signed integer samples and then concatenated into one 32-bit value, which is then written to the buffer. The sampling rate of the system can be adjusted by setting a decimation parameter and the decimation itself is realized with a CIC filter.

Internally, the FPGA keeps track of a 64-bit writepointer register pointing into the ring-buffer and increments this value with each new sample pair. Additionally, the writepointer also counts the number of buffer overflows. As the size of the buffer region is a power of two, these two components of the writepointer can be interpreted as one 64-bit number counting the samples from acquisition start. For the 128 MB buffer, this means that the lower 25 bits of the writepointer are the buffer location and the remaining bits are the overflow counter.

As the writepointer is reset and incremented based on a shared clock and trigger signal, it is synchronized across all FPGA images in a cluster. The logic implemented with the reprogrammable hardware is also the only logic of the RedPitayaDAQServer with predictable timing behaviour. All other components of the system implement their (timing related) logic in reference to the current writepointer values. With a known sampling rate, the writepointer can also be seen as the clock of the server and client components.

Sample Transmission

To retrieve samples from the server a client can supply a similar pointer, called readpointer, together with the number of samples to retrieve. The server then extracts the buffer position from the readpointer and transmits the requested amount of samples over the data socket. This transmission happens either way, even if the samples are overwritten. However, the server uses the whole readpointer, including the buffer overflows, to check if the requested samples were overwritten.

If the distance between the write- and readpointer is larger than the buffer size the overflow status flag is set. If during the transmission the requested samples are overwritten the corrupted flag is set. These flags can be queried individually or together in a status byte via SCPI commands.

This distance can not only be used to see if samples were overwritten, but also to track how well the client is able to keep up with the FPGA during a series of sample transmissions. If this distance increases over time, the FPGA is creating more samples than the server can transmit to the client. To allow a client to track this value, this distance is stored as a 64-bit value deltaRead for the latest transmission and can be queried. Additionally, the server also tracks the duration of the transmission as writepointer "clock ticks" as a 64-bit value deltaSend, which is just the difference between the writepointer at the start and end of a transmission.

Considerations for Sample Transmission

There are several things to consider when attempting to retrieve samples at a high sampling rate, for larger cluster sizes or for longer periods of time. Most of the following points were implemented/considered in the Julia reference implementation, but would become relevant when implementing custom clients.

As the server will always transmit samples just based on the buffer position of a readpointer, if a client wants to only receive certain samples it needs to wait for them to exist in the buffer. This requires querying the writepointer until it is larger than the desired readpointer.

If the number of requested samples is larger than the buffer, the sample should be requested in smaller chunks as the server would otherwise return samples that were not written yet. In a cluster scenario the i-th chunk should be requested from all RedPitayas in the cluster before requesting the next chunk to avoid "starvation" effects.

The status and performance data of a transmission can only be queried after the transmission has finished, which requires additionaly communication overhead.

To help clients with these issues, the server offers a second type of sample transmission in which samples, status and performance data is pipelined. In such a query a client first transmits a readpointer, together with the number of requested samples and the number of samples belonging to a chunk. The server itself then tracks the writepointer and transmits a chunk as soon as it becomes available and immidiatey follows that up with the status and performance data of the transmission. This way additional communication overheard is reduced and after the inital request a client just needs to read data until the transmission finishes.

Frames, Periods and Voltage

The samples sent by the server are the 16-bit values of the ADC channel of a RedPitaya. However, one might want to work with voltage values instead or encapsulate samples into a repeating concept like frames. The Julia client library offers functions to convert samples into such a concept or to directly request a number of frames instead of a number of samples.

Here, frames are comprised of periods, which in turn are comprised of samples. During the conversion process the 16-bit binary values can also be converted to floating point numbers representing a voltage if the RedPitaya was calibrated beforehand. In this calibration process, a client can store scale and offset values for each channel in the EEPROM of the RedPitaya. When the client establishes a connection to the server, it reads these values and can use them to translate the 16-bit values into a respective voltage value.

Sampling and Data Rates, Transmission Speeds and Time-to-Live

The highest supported sampling rate of the RedPitayaDAQServer is 15.625 MHz or 15.625 MS/s, as this is the sampling rate at which a single RedPitaya can produce and transmit samples continously without data loss given the 1 Gbit/s limit of the ethernet connection from the RedPitaya. This rate is a achieved with a decimation of 8 from the base 125 MHz sampling rate of the RedPitaya hardware.

At this sampling rate a single RedPitaya produces new samples at a data rate of 500 Mbit/s. Furthermore at this rate, once a sample has been written to the buffer it exists for 2.15s before being overwritten again (Time-To-Live, TTL). An overview of these metrics for different decimation factors is shown in the following table:

DecimationMHzMByte/sMbit/sTTL
641.957.8162.517.18s
323.9115.631258.59s
167.8131.252504.29s
815.6362.55002.15s

The table only refers to the data rate of new samples being produced. The data rate of samples being transmitted to a client can differ greatly depending on how the client queries and processes the samples and the available network bandwidth and usage. At the higher sampling rates it is recommended to have client threads that exclusively receive samples and perform any computation on samples in different threads to maximise the transmission speed, as a server can only transmit data at a rate of just above 500 Mbit/s. This exceeds the highest supported sampling rate by only a few Mbit/s and a client with frequency interruptions of its sample reception might not be able to keep up with the sampling rate.

diff --git a/dev/architecture.html b/dev/architecture.html index 278b7f5a..a4d80a2d 100644 --- a/dev/architecture.html +++ b/dev/architecture.html @@ -1,2 +1,2 @@ -Architecture · RP DAQ Server

Architecture

The RedPitayaDAQServer project is implemented as a distributed system in which one client connects to a cluster of RedPitaya boards. The project has four software components:

  • FPGA image running on the RedPitayas FPGA
  • C library encapsulating access to the FPGA image
  • Server running on the CPU of the RedPitayas
  • Client Julia reference library

The FPGA image is responsible for generating and acquiring synchronized out- and input signals. The server acts as an intermediary to the FPGA over a TCP/IP connection, which allows remote clients to configure the FPGA image and retrieve samples. Furthermore, the server also maintains a thread that takes part in signal generation.

The Julia client library can be used to implement a data acquisition client application, which controls a (cluster of) RedPitaya(s). This Julia library acts as a reference, but in principle it is possible to write clients in any programming language, as the communication is language agnostic. In the example directory we provide a rudimentary Python client that allows to perform a simple data acquisition experiment.

Communication

The various components of the distributed system communicate over different interfaces. Communication within a RedPitaya is based on memory-mapped I/O, while communication between the server and a client is based on SCPI commands over a TCP/IP connection, usually over Ethernet. Lastly communication between RedPitayas is limited to signals distributed over cables as described in Cluster.

FPGA and CPU

The FPGA image is directly connected to certain memory regions that can be memory mapped on the CPU side of the RedPitaya. Both the CPU and the FPGA image access the reserved main memory region as a sample buffer. The C library rp-daq-lib, which is located under src/lib/ in the project repository, encapsulates these memory accesses into a convenient C library. It is possible to use this C library directly on the RedPitaya when no communication with the host system is required, i.e. if one wants to write the acquired data into a file. When making changes to the FPGA image one may need to adapt the rp-daq-lib C library.

The server itself uses the rp-daq-lib library to interface with the FPGA image.

Client and Server

The server on each RedPitaya has two TCP sockets to which a client needs to connect. The first is the command socket on port 5025 and the second is the data socket on port 5026. Over the former, a client can send SCPI commands to the server and receive replies, while the latter is used for sending binary data such as the samples acquired by the ADCs.

SCPI commands are ASCII strings, such as RP:ADC:DECimation, which the server translates into C function calls. As an example these calls could invoke a function of the rp-daq-lib library to set the decimation of the sampling rate or instruct the server to transmit data over the data socket. A list of the available SCPI commands can be found here.

At any point a server is only connected to one client and establishing a new connection stops any current signal generation and acquisition.

+Architecture · RP DAQ Server

Architecture

The RedPitayaDAQServer project is implemented as a distributed system in which one client connects to a cluster of RedPitaya boards. The project has four software components:

  • FPGA image running on the RedPitayas FPGA
  • C library encapsulating access to the FPGA image
  • Server running on the CPU of the RedPitayas
  • Client Julia reference library

The FPGA image is responsible for generating and acquiring synchronized out- and input signals. The server acts as an intermediary to the FPGA over a TCP/IP connection, which allows remote clients to configure the FPGA image and retrieve samples. Furthermore, the server also maintains a thread that takes part in signal generation.

The Julia client library can be used to implement a data acquisition client application, which controls a (cluster of) RedPitaya(s). This Julia library acts as a reference, but in principle it is possible to write clients in any programming language, as the communication is language agnostic. In the example directory we provide a rudimentary Python client that allows to perform a simple data acquisition experiment.

Communication

The various components of the distributed system communicate over different interfaces. Communication within a RedPitaya is based on memory-mapped I/O, while communication between the server and a client is based on SCPI commands over a TCP/IP connection, usually over Ethernet. Lastly communication between RedPitayas is limited to signals distributed over cables as described in Cluster.

FPGA and CPU

The FPGA image is directly connected to certain memory regions that can be memory mapped on the CPU side of the RedPitaya. Both the CPU and the FPGA image access the reserved main memory region as a sample buffer. The C library rp-daq-lib, which is located under src/lib/ in the project repository, encapsulates these memory accesses into a convenient C library. It is possible to use this C library directly on the RedPitaya when no communication with the host system is required, i.e. if one wants to write the acquired data into a file. When making changes to the FPGA image one may need to adapt the rp-daq-lib C library.

The server itself uses the rp-daq-lib library to interface with the FPGA image.

Client and Server

The server on each RedPitaya has two TCP sockets to which a client needs to connect. The first is the command socket on port 5025 and the second is the data socket on port 5026. Over the former, a client can send SCPI commands to the server and receive replies, while the latter is used for sending binary data such as the samples acquired by the ADCs.

SCPI commands are ASCII strings, such as RP:ADC:DECimation, which the server translates into C function calls. As an example these calls could invoke a function of the rp-daq-lib library to set the decimation of the sampling rate or instruct the server to transmit data over the data socket. A list of the available SCPI commands can be found here.

At any point a server is only connected to one client and establishing a new connection stops any current signal generation and acquisition.

diff --git a/dev/assets/documenter.js b/dev/assets/documenter.js index 82252a11..7d68cd80 100644 --- a/dev/assets/documenter.js +++ b/dev/assets/documenter.js @@ -612,176 +612,194 @@ function worker_function(documenterSearchIndex, documenterBaseURL, filters) { }; } -// `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript! -const filters = [ - ...new Set(documenterSearchIndex["docs"].map((x) => x.category)), -]; -const worker_str = - "(" + - worker_function.toString() + - ")(" + - JSON.stringify(documenterSearchIndex["docs"]) + - "," + - JSON.stringify(documenterBaseURL) + - "," + - JSON.stringify(filters) + - ")"; -const worker_blob = new Blob([worker_str], { type: "text/javascript" }); -const worker = new Worker(URL.createObjectURL(worker_blob)); - /////// SEARCH MAIN /////// -// Whether the worker is currently handling a search. This is a boolean -// as the worker only ever handles 1 or 0 searches at a time. -var worker_is_running = false; - -// The last search text that was sent to the worker. This is used to determine -// if the worker should be launched again when it reports back results. -var last_search_text = ""; - -// The results of the last search. This, in combination with the state of the filters -// in the DOM, is used compute the results to display on calls to update_search. -var unfiltered_results = []; - -// Which filter is currently selected -var selected_filter = ""; - -$(document).on("input", ".documenter-search-input", function (event) { - if (!worker_is_running) { - launch_search(); - } -}); - -function launch_search() { - worker_is_running = true; - last_search_text = $(".documenter-search-input").val(); - worker.postMessage(last_search_text); -} - -worker.onmessage = function (e) { - if (last_search_text !== $(".documenter-search-input").val()) { - launch_search(); - } else { - worker_is_running = false; - } - - unfiltered_results = e.data; - update_search(); -}; +function runSearchMainCode() { + // `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript! + const filters = [ + ...new Set(documenterSearchIndex["docs"].map((x) => x.category)), + ]; + const worker_str = + "(" + + worker_function.toString() + + ")(" + + JSON.stringify(documenterSearchIndex["docs"]) + + "," + + JSON.stringify(documenterBaseURL) + + "," + + JSON.stringify(filters) + + ")"; + const worker_blob = new Blob([worker_str], { type: "text/javascript" }); + const worker = new Worker(URL.createObjectURL(worker_blob)); + + // Whether the worker is currently handling a search. This is a boolean + // as the worker only ever handles 1 or 0 searches at a time. + var worker_is_running = false; + + // The last search text that was sent to the worker. This is used to determine + // if the worker should be launched again when it reports back results. + var last_search_text = ""; + + // The results of the last search. This, in combination with the state of the filters + // in the DOM, is used compute the results to display on calls to update_search. + var unfiltered_results = []; + + // Which filter is currently selected + var selected_filter = ""; + + $(document).on("input", ".documenter-search-input", function (event) { + if (!worker_is_running) { + launch_search(); + } + }); -$(document).on("click", ".search-filter", function () { - if ($(this).hasClass("search-filter-selected")) { - selected_filter = ""; - } else { - selected_filter = $(this).text().toLowerCase(); + function launch_search() { + worker_is_running = true; + last_search_text = $(".documenter-search-input").val(); + worker.postMessage(last_search_text); } - // This updates search results and toggles classes for UI: - update_search(); -}); + worker.onmessage = function (e) { + if (last_search_text !== $(".documenter-search-input").val()) { + launch_search(); + } else { + worker_is_running = false; + } -/** - * Make/Update the search component - */ -function update_search() { - let querystring = $(".documenter-search-input").val(); + unfiltered_results = e.data; + update_search(); + }; - if (querystring.trim()) { - if (selected_filter == "") { - results = unfiltered_results; + $(document).on("click", ".search-filter", function () { + if ($(this).hasClass("search-filter-selected")) { + selected_filter = ""; } else { - results = unfiltered_results.filter((result) => { - return selected_filter == result.category.toLowerCase(); - }); + selected_filter = $(this).text().toLowerCase(); } - let search_result_container = ``; - let modal_filters = make_modal_body_filters(); - let search_divider = `
`; + // This updates search results and toggles classes for UI: + update_search(); + }); - if (results.length) { - let links = []; - let count = 0; - let search_results = ""; - - for (var i = 0, n = results.length; i < n && count < 200; ++i) { - let result = results[i]; - if (result.location && !links.includes(result.location)) { - search_results += result.div; - count++; - links.push(result.location); - } - } + /** + * Make/Update the search component + */ + function update_search() { + let querystring = $(".documenter-search-input").val(); - if (count == 1) { - count_str = "1 result"; - } else if (count == 200) { - count_str = "200+ results"; + if (querystring.trim()) { + if (selected_filter == "") { + results = unfiltered_results; } else { - count_str = count + " results"; + results = unfiltered_results.filter((result) => { + return selected_filter == result.category.toLowerCase(); + }); } - let result_count = `
${count_str}
`; - search_result_container = ` + let search_result_container = ``; + let modal_filters = make_modal_body_filters(); + let search_divider = `
`; + + if (results.length) { + let links = []; + let count = 0; + let search_results = ""; + + for (var i = 0, n = results.length; i < n && count < 200; ++i) { + let result = results[i]; + if (result.location && !links.includes(result.location)) { + search_results += result.div; + count++; + links.push(result.location); + } + } + + if (count == 1) { + count_str = "1 result"; + } else if (count == 200) { + count_str = "200+ results"; + } else { + count_str = count + " results"; + } + let result_count = `
${count_str}
`; + + search_result_container = ` +
+ ${modal_filters} + ${search_divider} + ${result_count} +
+ ${search_results} +
+
+ `; + } else { + search_result_container = `
${modal_filters} ${search_divider} - ${result_count} -
- ${search_results} -
-
+
0 result(s)
+ +
No result found!
`; - } else { - search_result_container = ` -
- ${modal_filters} - ${search_divider} -
0 result(s)
-
-
No result found!
- `; - } + } - if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { - $(".search-modal-card-body").removeClass("is-justify-content-center"); - } + if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").removeClass("is-justify-content-center"); + } - $(".search-modal-card-body").html(search_result_container); - } else { - if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { - $(".search-modal-card-body").addClass("is-justify-content-center"); + $(".search-modal-card-body").html(search_result_container); + } else { + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(` +
Type something to get started!
+ `); } + } - $(".search-modal-card-body").html(` -
Type something to get started!
- `); + /** + * Make the modal filter html + * + * @returns string + */ + function make_modal_body_filters() { + let str = filters + .map((val) => { + if (selected_filter == val.toLowerCase()) { + return `${val}`; + } else { + return `${val}`; + } + }) + .join(""); + + return ` +
+ Filters: + ${str} +
`; } } -/** - * Make the modal filter html - * - * @returns string - */ -function make_modal_body_filters() { - let str = filters - .map((val) => { - if (selected_filter == val.toLowerCase()) { - return `${val}`; - } else { - return `${val}`; - } - }) - .join(""); - - return ` -
- Filters: - ${str} -
`; +function waitUntilSearchIndexAvailable() { + // It is possible that the documenter.js script runs before the page + // has finished loading and documenterSearchIndex gets defined. + // So we need to wait until the search index actually loads before setting + // up all the search-related stuff. + if (typeof documenterSearchIndex !== "undefined") { + runSearchMainCode(); + } else { + console.warn("Search Index not available, waiting"); + setTimeout(waitUntilSearchIndexAvailable, 1000); + } } +// The actual entry point to the search code +waitUntilSearchIndexAvailable(); + }) //////////////////////////////////////////////////////////////////////////////// require(['jquery'], function($) { diff --git a/dev/assets/resync.png b/dev/assets/resync.png new file mode 100644 index 0000000000000000000000000000000000000000..85296d1419f13bfa6922542847bb1b7254e9f74c GIT binary patch literal 124857 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 z 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

JwS>45 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 mX_5aq5EK7S8uS1Bm`HBQHF_ literal 0 HcmV?d00001 diff --git a/dev/client.html b/dev/client.html index e0fbdde8..cc4febbe 100644 --- a/dev/client.html +++ b/dev/client.html @@ -1,173 +1,175 @@ -Client Library · RP DAQ Server

Client

This page contains documentation of the public API of the Julia client. In the Julia REPL one can access this documentation by entering the help mode with ? and then writing the function for which the documentation should be shown.

Connection and Communication

RedPitayaDAQServer.RedPitayaType
RedPitaya

Struct representing a connection to a RedPitayaDAQServer.

Contains the sockets used for communication and connection related metadata. Also contains fields for client specific concepts such as periods, frames and calibration values.

source
RedPitayaDAQServer.RedPitayaMethod
RedPitaya(ip [, port = 5025, dataPort=5026, isMaster = false])

Construct a RedPitaya.

During the construction the connection is established and the calibration values are loaded from the RedPitayas EEPROM. Throws an error if a timeout occurs while attempting to connect.

Examples

julia> rp = RedPitaya("192.168.1.100");
+Client Library · RP DAQ Server

Client

This page contains documentation of the public API of the Julia client. In the Julia REPL one can access this documentation by entering the help mode with ? and then writing the function for which the documentation should be shown.

Connection and Communication

RedPitayaDAQServer.RedPitayaType
RedPitaya

Struct representing a connection to a RedPitayaDAQServer.

Contains the sockets used for communication and connection related metadata. Also contains fields for client specific concepts such as periods, frames and calibration values.

source
RedPitayaDAQServer.RedPitayaMethod
RedPitaya(ip [, port = 5025, dataPort=5026, isMaster = false])

Construct a RedPitaya.

During the construction the connection is established and the calibration values are loaded from the RedPitayas EEPROM. Throws an error if a timeout occurs while attempting to connect.

Examples

julia> rp = RedPitaya("192.168.1.100");
 
 julia> decimation!(rp, 8)
 true
 
 julia> decimation(rp)
-8
source
Sockets.sendMethod
send(rp::RedPitaya, cmd::String)

Send a command to the RedPitaya. Appends delimiter.

source
RedPitayaDAQServer.queryFunction
query(rp::RedPitaya, cmd [, timeout = 5.0, N = 100])

Send a query to the RedPitaya command socket. Return reply as String.

Waits for timeout seconds and checks every timeout/N seconds.

See also receive.

source
query(rp::RedPitaya, cmd, T::Type [timeout = 5.0, N = 100])

Send a query to the RedPitaya. Parse reply as T.

Waits for timeout seconds and checks every timeout/N seconds.

source
RedPitayaDAQServer.receiveFunction
receive(rp::RedPitaya)

Receive a String from the RedPitaya command socket. Reads until a whole line is received

source
receive(rp::RedPitaya, ch::Channel)

Receive a String from the RedPitaya command socket. Reads until a whole line is received and puts it in the supplied channel ch.

source
receive(rp::RedPitaya, timeout::Number)

Receive a string from the RedPitaya command socket. Reads until a whole line is received or timeout seconds passed. In the latter case an error is thrown.

source
Sockets.sendMethod
send(rp::RedPitaya, cmd::String)

Send a command to the RedPitaya. Appends delimiter.

source
RedPitayaDAQServer.queryFunction
query(rp::RedPitaya, cmd [, timeout = 5.0, N = 100])

Send a query to the RedPitaya command socket. Return reply as String.

Waits for timeout seconds and checks every timeout/N seconds.

See also receive.

source
query(rp::RedPitaya, cmd, T::Type [timeout = 5.0, N = 100])

Send a query to the RedPitaya. Parse reply as T.

Waits for timeout seconds and checks every timeout/N seconds.

source
RedPitayaDAQServer.receiveFunction
receive(rp::RedPitaya)

Receive a String from the RedPitaya command socket. Reads until a whole line is received

source
receive(rp::RedPitaya, ch::Channel)

Receive a String from the RedPitaya command socket. Reads until a whole line is received and puts it in the supplied channel ch.

source
receive(rp::RedPitaya, timeout::Number)

Receive a string from the RedPitaya command socket. Reads until a whole line is received or timeout seconds passed. In the latter case an error is thrown.

source
RedPitayaDAQServer.serverModeFunction
serverMode(rp::RedPitaya)

Return the mode of the server.

Examples

julia> serverMode!(rp, ACQUISITION);
 true
 
 julia> serverMode(rp)
-ACQUISITION
source
serverMode(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.serverMode!Function
serverMode!(rp::RedPitaya, mode::ServerMode)

Set the mode of the server. Valid values are "CONFIGURATION" and "ACQUISITION".

Examples

julia> serverMode!(rp, ACQUISITION);
+ACQUISITION
source
serverMode(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.serverMode!Function
serverMode!(rp::RedPitaya, mode::ServerMode)

Set the mode of the server. Valid values are "CONFIGURATION" and "ACQUISITION".

Examples

julia> serverMode!(rp, ACQUISITION);
 true
 
 julia> serverMode(rp)
-ACQUISITION
source
serverMode!(rp::RedPitaya, mode::ServerMode)

Set the mode of the server.

Examples

julia> serverMode!(rp, ACQUISITION);
+ACQUISITION
source
serverMode!(rp::RedPitaya, mode::ServerMode)

Set the mode of the server.

Examples

julia> serverMode!(rp, ACQUISITION);
 true
 
 julia> serverMode(rp)
-ACQUISITION
source
serverMode!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.ScpiBatchType
ScpiBatch

Struct representing a batch of SCPI commands for a RedPitaya. Only commands that interact exclusively with the command socket should be used in a batch.

source
RedPitayaDAQServer.@add_batchMacro
@add_batch batch cmd

Append a usual RedPitaya function to the given batch instead of evaluating it directly.

See also ScpiBatch, push!, execute!

Examples

julia>  execute!(rp) do b
+ACQUISITION
source
serverMode!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.ScpiBatchType
ScpiBatch

Struct representing a batch of SCPI commands for a RedPitaya. Only commands that interact exclusively with the command socket should be used in a batch.

source
RedPitayaDAQServer.execute!Function
execute!(rp::RedPitaya, batch::ScpiBatch)

Executes all commands of the given batch. Returns an array of the results in the order of the commands. An element is nothing if the command has no return value.

source
execute!(rpc::RedPitayaCluster, batch::ScpiBatch)

Executes all commands of the given batch. Returns an array of the results in the order of the commands.

Each element of the result array is again an array containing the return values of the RedPitayas. An element of an inner array is nothing if the command has no return value.

source
execute!(f::Function, rp::Union{RedPitaya, RedPitayaCluster})

Open a ScpiBatch and evaluate the function f. If no exception was thrown, execute the opened batch.

See also ScpiBatch, push!, @add_batch

Examples

julia>  execute!(rp) do b
+        end
source
RedPitayaDAQServer.execute!Function
execute!(rp::RedPitaya, batch::ScpiBatch)

Executes all commands of the given batch. Returns an array of the results in the order of the commands. An element is nothing if the command has no return value.

source
execute!(rpc::RedPitayaCluster, batch::ScpiBatch)

Executes all commands of the given batch. Returns an array of the results in the order of the commands.

Each element of the result array is again an array containing the return values of the RedPitayas. An element of an inner array is nothing if the command has no return value.

source
execute!(f::Function, rp::Union{RedPitaya, RedPitayaCluster})

Open a ScpiBatch and evaluate the function f. If no exception was thrown, execute the opened batch.

See also ScpiBatch, push!, @add_batch

Examples

julia>  execute!(rp) do b
           @add_batch b serverMode!(rp, CONFIGURATION)
           @add_batch b amplitudeDAC!(rp, 1, 1, 0.2)
-        end
source
Base.push!Method
push!(batch::ScpiBatch, cmd::Pair{K, T}) where {K<:Function, T<:Tuple}

Add the given function and arguments to the batch

Examples

julia> batch = ScpiBatch() 
+        end
source
Base.push!Method
push!(batch::ScpiBatch, cmd::Pair{K, T}) where {K<:Function, T<:Tuple}

Add the given function and arguments to the batch

Examples

julia> batch = ScpiBatch() 
 
-julia> push!(batch, amplitudeDAC! => (1, 1, 0.2))
source
Base.pop!Method
pop!(batch::ScpiBatch)

Remove the last added command from the batch

source
RedPitayaDAQServer.RedPitayaClusterType
RedPitayaCluster

Struct representing a cluster of RedPitayas. Such a cluster should share a common clock and master trigger.

The structure implements the indexing and iterable interfaces.

source
RedPitayaDAQServer.RedPitayaClusterMethod
RedPitayaCluster(hosts::Vector{String} [, port = 5025])

Construct a RedPitayaCluster.

During the construction the first host is labelled the master RedPitaya of a cluster and all RedPitayas are set to using the EXTERNAL trigger mode.

See also RedPitaya, master.

Examples

julia> rpc = RedPitayaCluster(["192.168.1.100", "192.168.1.101"]);
+julia> push!(batch, amplitudeDAC! => (1, 1, 0.2))
source
Base.pop!Method
pop!(batch::ScpiBatch)

Remove the last added command from the batch

source
RedPitayaDAQServer.RedPitayaClusterType
RedPitayaCluster

Struct representing a cluster of RedPitayas. Such a cluster should share a common clock and master trigger.

The structure implements the indexing and iterable interfaces.

source
RedPitayaDAQServer.RedPitayaClusterMethod
RedPitayaCluster(hosts::Vector{String} [, port = 5025])

Construct a RedPitayaCluster.

During the construction the first host is labelled the master RedPitaya of a cluster and all RedPitayas are set to using the EXTERNAL trigger mode.

See also RedPitaya, master.

Examples

julia> rpc = RedPitayaCluster(["192.168.1.100", "192.168.1.101"]);
 
 julia> rp = master(rpc)
 
 julia> rp == rpc[1]
-true
source
Base.lengthMethod
length(rpc::RedPitayaCluster)

Return the number of RedPitayas in cluster rpc.

source

ADC Configuration

RedPitayaDAQServer.triggerMode!Function
triggerMode!(rp::RedPitaya, mode::String)

Set the trigger mode of the RedPitaya. Return true if the command was successful.

source
triggerMode!(rp::RedPitaya, mode::String)

Set the trigger mode of the RedPitaya. Return true if the command was successful.

source
triggerMode!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.keepAliveResetFunction
keepAliveReset(rp::RedPitaya)

Determine whether the keepAliveReset is set.

source
keepAliveReset(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.keepAliveReset!Function
keepAliveReset!(rp::RedPitaya, val::Bool)

Set the keepAliveReset to val.

source
keepAliveReset!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
Base.lengthMethod
length(rpc::RedPitayaCluster)

Return the number of RedPitayas in cluster rpc.

source

ADC Configuration

RedPitayaDAQServer.triggerMode!Function
triggerMode!(rp::RedPitaya, mode::String)

Set the trigger mode of the RedPitaya. Return true if the command was successful.

source
triggerMode!(rp::RedPitaya, mode::String)

Set the trigger mode of the RedPitaya. Return true if the command was successful.

source
triggerMode!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.keepAliveResetFunction
keepAliveReset(rp::RedPitaya)

Determine whether the keepAliveReset is set.

source
keepAliveReset(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.keepAliveReset!Function
keepAliveReset!(rp::RedPitaya, val::Bool)

Set the keepAliveReset to val.

source
keepAliveReset!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.decimationFunction
decimation(rp::RedPitaya)

Return the decimation of the RedPitaya.

Examples

julia> decimation!(rp, 8)
 true
 
 julia> decimation(rp)
-8
source
decimation(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.decimation!Function
decimation!(rp::RedPitaya, dec)

Set the decimation of the RedPitaya. Return true if the command was successful.

Examples

julia> decimation!(rp, 8)
+8
source
decimation(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.decimation!Function
decimation!(rp::RedPitaya, dec)

Set the decimation of the RedPitaya. Return true if the command was successful.

Examples

julia> decimation!(rp, 8)
 true
 
 julia> decimation(rp)
-8
source
decimation!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.samplesPerPeriodFunction
samplesPerPeriod(rp::RedPitaya)

Return the number of samples per period.

Example

julia> samplesPerPeriod!(rp, 256)
+8
source
decimation!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.samplesPerPeriodFunction
samplesPerPeriod(rp::RedPitaya)

Return the number of samples per period.

Example

julia> samplesPerPeriod!(rp, 256)
 true
 
 julia> samplesPerPeriod(rp)
 256
-
source
samplesPerPeriod(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.samplesPerPeriod!Function
samplesPerPeriod!(rp::RedPitaya, value)

Set the number of samples per period.

Example

julia> samplesPerPeriod!(rp, 256)
+
source
samplesPerPeriod(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.samplesPerPeriod!Function
samplesPerPeriod!(rp::RedPitaya, value)

Set the number of samples per period.

Example

julia> samplesPerPeriod!(rp, 256)
 true
 
 julia> samplesPerPeriod(rp)
 256
-
source
samplesPerPeriod!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.periodsPerFrameFunction
periodsPerFrame(rp::RedPitaya)

Return the number of periods per frame.

Example

julia> periodsPerFrame!(rp, 16)
+
source
samplesPerPeriod!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.periodsPerFrameFunction
periodsPerFrame(rp::RedPitaya)

Return the number of periods per frame.

Example

julia> periodsPerFrame!(rp, 16)
 
 julia> periodsPerFrame(rp)
 16
-
source
periodsPerFrame(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.periodsPerFrame!Function
periodsPerFrame(rp::RedPitaya, value)

Set the number of periods per frame.

Example

julia> periodsPerFrame!(rp, 16)
+
source
periodsPerFrame(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.periodsPerFrame!Function
periodsPerFrame(rp::RedPitaya, value)

Set the number of periods per frame.

Example

julia> periodsPerFrame!(rp, 16)
 
 julia> periodsPerFrame(rp)
 16
-
source
periodsPerFrame!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source

DAC Configuration

RedPitayaDAQServer.amplitudeDACFunction
amplitudeDAC(rp::RedPitaya, channel, component)

Return the amplitude of composite waveform component for channel.

See amplitudeDAC!.

Examples

julia> amplitudeDAC!(rp, 1, 1, 0.5);
+
source
periodsPerFrame!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source

DAC Configuration

RedPitayaDAQServer.amplitudeDACFunction
amplitudeDAC(rp::RedPitaya, channel, component)

Return the amplitude of composite waveform component for channel.

See amplitudeDAC!.

Examples

julia> amplitudeDAC!(rp, 1, 1, 0.5);
 true
 
 julia> amplitudeDAC(rp, 1, 1)
-0.5
source
amplitudeDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.amplitudeDAC!Function
amplitudeDAC!(rp::RedPitaya, channel, component, value)

Set the amplitude of composite waveform component for channel. Return true if the command was successful.

See amplitudeDAC.

Examples

julia> amplitudeDAC!(rp, 1, 1, 0.5);
+0.5
source
amplitudeDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.amplitudeDAC!Function
amplitudeDAC!(rp::RedPitaya, channel, component, value)

Set the amplitude of composite waveform component for channel. Return true if the command was successful.

See amplitudeDAC.

Examples

julia> amplitudeDAC!(rp, 1, 1, 0.5);
 true
 
 julia> amplitudeDAC(rp, 1, 1)
-0.5
source
amplitudeDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.offsetDACFunction
offsetDAC(rp::RedPitaya, channel)

Return the offset for channel.

See offsetDAC!.

Examples

julia> offsetDAC!(rp, 1, 0.2);
+0.5
source
amplitudeDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.offsetDACFunction
offsetDAC(rp::RedPitaya, channel)

Return the offset for channel.

See offsetDAC!.

Examples

julia> offsetDAC!(rp, 1, 0.2);
 true
 
 julia> offsetDAC(rp, 1)
-0.2
source
offsetDAC(rpc::RedPitayaCluster, chan::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.offsetDAC!Function
offsetDAC!(rp::RedPitaya, channel, value)

Set the offset for channel. Return true if the command was successful.

See offsetDAC.

Examples

julia> offsetDAC!(rp, 1, 0.2);
+0.2
source
offsetDAC(rpc::RedPitayaCluster, chan::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.offsetDAC!Function
offsetDAC!(rp::RedPitaya, channel, value)

Set the offset for channel. Return true if the command was successful.

See offsetDAC.

Examples

julia> offsetDAC!(rp, 1, 0.2);
 true
 
 julia> offsetDAC(rp, 1)
-0.2
source
offsetDAC!(rpc::RedPitayaCluster, chan::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.frequencyDACFunction
frequencyDAC(rp::RedPitaya, channel, component)

Return the frequency of composite waveform component for channel.

See frequencyDAC!.

Examples

julia> frequencyDAC!(rp, 1, 1, 2400);
+0.2
source
offsetDAC!(rpc::RedPitayaCluster, chan::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.frequencyDACFunction
frequencyDAC(rp::RedPitaya, channel, component)

Return the frequency of composite waveform component for channel.

See frequencyDAC!.

Examples

julia> frequencyDAC!(rp, 1, 1, 2400);
 true
 
 julia> frequencyDAC(rp, 1, 1)
-2400
source
frequencyDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.frequencyDAC!Function
frequencyDAC!(rp::RedPitaya, channel, component, value)

Set the frequency of composite waveform component for channel. Return true if the command was successful.

See frequencyDAC.

Examples

julia> frequencyDAC!(rp, 1, 1, 2400);
+2400
source
frequencyDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.frequencyDAC!Function
frequencyDAC!(rp::RedPitaya, channel, component, value)

Set the frequency of composite waveform component for channel. Return true if the command was successful.

See frequencyDAC.

Examples

julia> frequencyDAC!(rp, 1, 1, 2400);
 true
 
 julia> frequencyDAC(rp, 1, 1)
-2400
source
frequencyDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.phaseDACFunction
phaseDAC(rp::RedPitaya, channel, component)

Return the phase of composite waveform component for channel.

See phaseDAC!.

Examples

julia> phaseDAC!(rp, 1, 1, 0.0);
+2400
source
frequencyDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.phaseDACFunction
phaseDAC(rp::RedPitaya, channel, component)

Return the phase of composite waveform component for channel.

See phaseDAC!.

Examples

julia> phaseDAC!(rp, 1, 1, 0.0);
 true
 
 julia> phaseDAC(rp, 1, 0.0)
-0.0
source
phaseDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.phaseDAC!Function
phaseDAC!(rp::RedPitaya, channel, component, value)

Set the phase of composite waveform component for channel. Return true if the command was successful.

See phaseDAC.

Examples

julia> phaseDAC!(rp, 1, 1, 0.0);
+0.0
source
phaseDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.phaseDAC!Function
phaseDAC!(rp::RedPitaya, channel, component, value)

Set the phase of composite waveform component for channel. Return true if the command was successful.

See phaseDAC.

Examples

julia> phaseDAC!(rp, 1, 1, 0.0);
 true
 
 julia> phaseDAC(rp, 1, 0.0)
-0.0
source
phaseDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.signalTypeDACFunction
signalTypeDAC!(rp::RedPitaya, channel, value)

Return the signalType of composite waveform for channel.

See signalTypeDAC!.

Examples

julia> signalTypeDAC!(rp, 1, SINE);
+0.0
source
phaseDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.signalTypeDACFunction
signalTypeDAC!(rp::RedPitaya, channel, value)

Return the signalType of composite waveform for channel.

See signalTypeDAC!.

Examples

julia> signalTypeDAC!(rp, 1, SINE);
 true
 
 julia> signalTypeDAC(rp, 1)
-SINE
source
signalTypeDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.signalTypeDAC!Function
signalTypeDAC!(rp::RedPitaya, channel, value)

Set the signalType of composite waveform for channel. Return true if the command was successful.

See signalTypeDAC.

Examples

julia> signalTypeDAC!(rp, 1, SINE);
+SINE
source
signalTypeDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.signalTypeDAC!Function
signalTypeDAC!(rp::RedPitaya, channel, value)

Set the signalType of composite waveform for channel. Return true if the command was successful.

See signalTypeDAC.

Examples

julia> signalTypeDAC!(rp, 1, SINE);
 true
 
 julia> signalTypeDAC(rp, 1)
-SINE
source
signalTypeDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.seqChan!Function
seqChan!(rp::RedPitaya, value)

Set the number of sequence channel. Valid values are between 1 and 6. Return true if the command was successful.

source
RedPitayaDAQServer.samplesPerStepFunction
samplesPerStep(rp::RedPitaya)

Return the number of samples per sequence step.

source
samplesPerStep(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.samplesPerStep!Function
samplesPerStep!(rp::RedPitaya, value::Integer)

Set the number of samples per sequence step. Return true if the command was successful.

source
samplesPerStep!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.clearSequence!Function
clearSequence!(rp::RedPitaya)

Instruct the server to remove all sequences from its list. Return true if the command was successful.

source
clearSequence!(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.sequence!Function
sequence!(rp::RedPitaya, seq::AbstractSequence)

Transmit the client-side representation seq to the server and append it to the current list of sequences. Return true if the required commands were successful.

source
sequence!(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.calibDACOffset!Function
calibDACOffset!(rp::RedPitaya, channel::Integer, val)

Store calibration DAC offset val for given channel into the RedPitayas EEPROM. This value is used by the server to offset the output voltage. Absolute value has to be smaller than 1.0 V.

source
RedPitayaDAQServer.calibDACScale!Function
calibDACScale(rp::RedPitaya, channel::Integer)

Store calibration DAC scale val for given channel into the RedPitayas EEPROM. This value is used by the server to scale the output voltage.

source
RedPitayaDAQServer.calibDACUpperLimit!Function
calibDACUpperLimit!(rp::RedPitaya, channel::Integer)

Store calibration DAC upper limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.

source
RedPitayaDAQServer.calibDACLowerLimit!Function
calibDACLowerLimit!(rp::RedPitaya, channel::Integer)

Store calibration DAC lower limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.

source

Measurement and Transmission

RedPitayaDAQServer.masterTriggerFunction
masterTrigger(rp::RedPitaya)

Determine whether the master trigger is set.

Example

julia> masterTrigger!(rp, true)
+SINE
source
signalTypeDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)

As with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.

source
RedPitayaDAQServer.seqChan!Function
seqChan!(rp::RedPitaya, value)

Set the number of sequence channel. Valid values are between 1 and 6. Return true if the command was successful.

source
RedPitayaDAQServer.samplesPerStepFunction
samplesPerStep(rp::RedPitaya)

Return the number of samples per sequence step.

source
samplesPerStep(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.samplesPerStep!Function
samplesPerStep!(rp::RedPitaya, value::Integer)

Set the number of samples per sequence step. Return true if the command was successful.

source
samplesPerStep!(rpc::RedPitayaCluster, value)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.clearSequence!Function
clearSequence!(rp::RedPitaya)

Instruct the server to remove all sequences from its list. Return true if the command was successful.

source
clearSequence!(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.sequence!Function
sequence!(rp::RedPitaya, seq::AbstractSequence)

Transmit the client-side representation seq to the server and append it to the current list of sequences. Return true if the required commands were successful.

source
sequence!(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to all RedPitayas in a cluster.

source
RedPitayaDAQServer.calibDACOffset!Function
calibDACOffset!(rp::RedPitaya, channel::Integer, val)

Store calibration DAC offset val for given channel into the RedPitayas EEPROM. This value is used by the server to offset the output voltage. Absolute value has to be smaller than 1.0 V.

source
RedPitayaDAQServer.calibDACScale!Function
calibDACScale(rp::RedPitaya, channel::Integer)

Store calibration DAC scale val for given channel into the RedPitayas EEPROM. This value is used by the server to scale the output voltage.

source
RedPitayaDAQServer.calibDACUpperLimit!Function
calibDACUpperLimit!(rp::RedPitaya, channel::Integer)

Store calibration DAC upper limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.

source
RedPitayaDAQServer.calibDACLowerLimit!Function
calibDACLowerLimit!(rp::RedPitaya, channel::Integer)

Store calibration DAC lower limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.

source

Measurement and Transmission

RedPitayaDAQServer.masterTriggerFunction
masterTrigger(rp::RedPitaya)

Determine whether the master trigger is set.

Example

julia> masterTrigger!(rp, true)
 
 julia>masterTrigger(rp)
-true
source
masterTrigger(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.masterTrigger!Function
masterTrigger!(rp::RedPitaya, val::Bool)

Set the master trigger of the RedPitaya to val. Return true if the command was successful.

Example

julia> masterTrigger!(rp, true)
+true
source
masterTrigger(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.masterTrigger!Function
masterTrigger!(rp::RedPitaya, val::Bool)

Set the master trigger of the RedPitaya to val. Return true if the command was successful.

Example

julia> masterTrigger!(rp, true)
 true
 
 julia>masterTrigger(rp)
-true
source
masterTrigger(rpc::RedPitayaCluster, val::Bool)

Set the master trigger of the cluster to val.

For val equals to true this is the same as calling the function on the RedPitaya returned by master(rpc). If val is false then the keepAliveReset is set to true for all RedPitayas in the cluster before the master trigger is disabled. Afterwards the keepAliveReset is set to false again.

See also master, keepAliveReset!.

source
RedPitayaDAQServer.currentWPFunction
currentWP(rp::RedPitaya)

Return the current writepointer of the RedPitaya.

source
currentWP(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.SampleChunkType
SampleChunk

Struct containing a matrix of samples and associated PerformanceData

Fields

  • samples::Matrix{Int16}: nxm matrix containing m samples for n channel
  • performance::Vector{PerformanceData}: PerformanceData object for each RedPitaya that transmitted samples
source
RedPitayaDAQServer.readSamplesFunction
readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64; chunkSize::Int64 = 25000, rpInfo=nothing)

Request and receive numOfRequestedSamples samples from wpStart on in a pipelined fashion. Return a matrix of samples.

If rpInfo is set to a RPInfo, the PerformanceData sent after every chunkSize samples will be pushed into rpInfo.

source
readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64, channel::Channel; chunkSize::Int64 = 25000)

Request and receive numOfRequestedSamples samples from wpStart on in a pipelined fashion. The samples and associated PerformanceData are pushed into channel as a SampleChunk.

See SampleChunk.

source
RedPitayaDAQServer.readFramesFunction
readFrames(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startFrame, numFrames, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false)

Request and receive numFrames frames from startFrame on.

See readSamples, convertSamplesToFrames, samplesPerPeriod, periodsPerFrame, updateCalib!.

Arguments

  • rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}: RedPitayas to receive samples from.
  • startFrame: frame from which to start transmitting
  • numFrames: number of frames to read
  • numBlockAverages=1: see convertSamplesToFrames
  • numPeriodsPerPatch=1: see convertSamplesToFrames
  • chunkSize=50000: see readSamples
  • rpInfo=nothing: see readSamples
  • useCalibration: convert from Int16 samples to Float32 values based on RedPitayas calibration
source
RedPitayaDAQServer.readPeriodsFunction
readPeriods(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startPeriod, numPeriods, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false)

Request and receive numPeriods Periods from startPeriod on.

See readSamples, convertSamplesToPeriods!, samplesPerPeriod.

Arguments

  • rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}: RedPitayas to receive samples from.
  • startPeriod: period from which to start transmitting
  • numPeriods: number of periods to read
  • numBlockAverages=1: see convertSamplesToPeriods
  • chunkSize=50000: see readSamples
  • rpInfo=nothing: see readSamples
  • useCalibration: convert samples based on RedPitayas calibration
source
RedPitayaDAQServer.convertSamplesToFramesMethod
convertSamplesToFrames(rpu::Union{RedPitayaCluster, RedPitayaClusterView}, samples, numChan, numSampPerPeriod, numPeriods, numFrames, numBlockAverages=1, numPeriodsPerPatch=1)

Converts a given set of samples to frames.

See readFrames

source

Slow IO

RedPitayaDAQServer.DIO!Method

DIO!(rp::RedPitaya, pin::DIOPins, val::Bool)

Set the value of DIO pin pin to the value val.

Example

julia> DIO!(rp, DIO7_P, true)
-true
source
RedPitayaDAQServer.DIODirection!Method

DIODirection!(rp::RedPitaya, pin::DIOPins, direction::DIODirectionType)

Set the direction of DIO pin pin to the value direction.

Example

julia> DIODirection!(rp, DIO7_P, DIO_OUT)
+true
source
masterTrigger(rpc::RedPitayaCluster, val::Bool)

Set the master trigger of the cluster to val.

For val equals to true this is the same as calling the function on the RedPitaya returned by master(rpc). If val is false then the keepAliveReset is set to true for all RedPitayas in the cluster before the master trigger is disabled. Afterwards the keepAliveReset is set to false again.

See also master, keepAliveReset!.

source
RedPitayaDAQServer.currentWPFunction
currentWP(rp::RedPitaya)

Return the current writepointer of the RedPitaya.

source
currentWP(rpc::RedPitayaCluster)

As with single RedPitaya, but applied to only the master.

source
RedPitayaDAQServer.SampleChunkType
SampleChunk

Struct containing a matrix of samples and associated PerformanceData

Fields

  • samples::Matrix{Int16}: nxm matrix containing m samples for n channel
  • performance::Vector{PerformanceData}: PerformanceData object for each RedPitaya that transmitted samples
source
RedPitayaDAQServer.readSamplesFunction
readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64; chunkSize::Int64 = 25000, rpInfo=nothing)

Request and receive numOfRequestedSamples samples from wpStart on in a pipelined fashion. Return a matrix of samples.

If rpInfo is set to a RPInfo, the PerformanceData sent after every chunkSize samples will be pushed into rpInfo.

source
readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64, channel::Channel; chunkSize::Int64 = 25000)

Request and receive numOfRequestedSamples samples from wpStart on in a pipelined fashion. The samples and associated PerformanceData are pushed into channel as a SampleChunk.

See SampleChunk.

source
RedPitayaDAQServer.readFramesFunction
readFrames(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startFrame, numFrames, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false)

Request and receive numFrames frames from startFrame on.

See readSamples, convertSamplesToFrames, samplesPerPeriod, periodsPerFrame, updateCalib!.

Arguments

  • rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}: RedPitayas to receive samples from.
  • startFrame: frame from which to start transmitting
  • numFrames: number of frames to read
  • numBlockAverages=1: see convertSamplesToFrames
  • numPeriodsPerPatch=1: see convertSamplesToFrames
  • chunkSize=50000: see readSamples
  • rpInfo=nothing: see readSamples
  • useCalibration: convert from Int16 samples to Float32 values based on RedPitayas calibration
source
RedPitayaDAQServer.readPeriodsFunction
readPeriods(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startPeriod, numPeriods, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false)

Request and receive numPeriods Periods from startPeriod on.

See readSamples, convertSamplesToPeriods!, samplesPerPeriod.

Arguments

  • rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}: RedPitayas to receive samples from.
  • startPeriod: period from which to start transmitting
  • numPeriods: number of periods to read
  • numBlockAverages=1: see convertSamplesToPeriods
  • chunkSize=50000: see readSamples
  • rpInfo=nothing: see readSamples
  • useCalibration: convert samples based on RedPitayas calibration
source
RedPitayaDAQServer.convertSamplesToFramesMethod
convertSamplesToFrames(rpu::Union{RedPitayaCluster, RedPitayaClusterView}, samples, numChan, numSampPerPeriod, numPeriods, numFrames, numBlockAverages=1, numPeriodsPerPatch=1)

Converts a given set of samples to frames.

See readFrames

source

Slow IO

RedPitayaDAQServer.DIO!Method

DIO!(rp::RedPitaya, pin::DIOPins, val::Bool)

Set the value of DIO pin pin to the value val.

Example

julia> DIO!(rp, DIO7_P, true)
+true
source
RedPitayaDAQServer.DIODirection!Method

DIODirection!(rp::RedPitaya, pin::DIOPins, direction::DIODirectionType)

Set the direction of DIO pin pin to the value direction.

Example

julia> DIODirection!(rp, DIO7_P, DIO_OUT)
 
 julia>DIODirection(rp, DIO7_P)
-DIO_OUT
source
RedPitayaDAQServer.DIODirectionMethod

DIODirection(rp::RedPitaya, pin::DIOPins)

Get the direction of DIO pin pin.

Example

julia> DIODirection!(rp, DIO7_P, DIO_OUT)
 
 julia>DIODirection(rp, DIO7_P)
-DIO_OUT
source
RedPitayaDAQServer.slowDAC!Method
slowDAC!(rp::RedPitaya, channel::Int64, val::Int64)

Set the value of the slow DAC channel channel to the value val. Return true if the command was successful.

Example

julia> slowDAC!(rp, 1, 500)
-true
source
RedPitayaDAQServer.DIOHBridge!Method

DIOHBridge!(rp::RedPitaya, pin::DIOPins, val::Bool)

Set the value of DIOHBridge pin pin to the value val.

Example

julia> DIOHBridge!(rp, DIO7_P, true)
+true
source
RedPitayaDAQServer.slowDAC!Method
slowDAC!(rp::RedPitaya, channel::Int64, val::Int64)

Set the value of the slow DAC channel channel to the value val. Return true if the command was successful.

Example

julia> slowDAC!(rp, 1, 500)
+true
source

EEPROM and Calibration

RedPitayaDAQServer.calibDACLowerLimit!Method
calibDACLowerLimit!(rp::RedPitaya, channel::Integer)

Store calibration DAC lower limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.

source
RedPitayaDAQServer.calibDACOffset!Method
calibDACOffset!(rp::RedPitaya, channel::Integer, val)

Store calibration DAC offset val for given channel into the RedPitayas EEPROM. This value is used by the server to offset the output voltage. Absolute value has to be smaller than 1.0 V.

source
RedPitayaDAQServer.calibDACScale!Method
calibDACScale(rp::RedPitaya, channel::Integer)

Store calibration DAC scale val for given channel into the RedPitayas EEPROM. This value is used by the server to scale the output voltage.

source
RedPitayaDAQServer.calibDACUpperLimit!Method
calibDACUpperLimit!(rp::RedPitaya, channel::Integer)

Store calibration DAC upper limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.

source

Counter Trigger

RedPitayaDAQServer.counterTrigger_arm!Function
counterTrigger_arm!(rp::RedPitaya, val::Bool)

Set whether the counter trigger is armed or not. Return true if the command was successful.

Examples

julia> counterTrigger_arm!(rp, true)
+8
source

EEPROM and Calibration

RedPitayaDAQServer.calibDACLowerLimit!Method
calibDACLowerLimit!(rp::RedPitaya, channel::Integer)

Store calibration DAC lower limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.

source
RedPitayaDAQServer.calibDACOffset!Method
calibDACOffset!(rp::RedPitaya, channel::Integer, val)

Store calibration DAC offset val for given channel into the RedPitayas EEPROM. This value is used by the server to offset the output voltage. Absolute value has to be smaller than 1.0 V.

source
RedPitayaDAQServer.calibDACScale!Method
calibDACScale(rp::RedPitaya, channel::Integer)

Store calibration DAC scale val for given channel into the RedPitayas EEPROM. This value is used by the server to scale the output voltage.

source
RedPitayaDAQServer.calibDACUpperLimit!Method
calibDACUpperLimit!(rp::RedPitaya, channel::Integer)

Store calibration DAC upper limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.

source

Counter Trigger

RedPitayaDAQServer.counterTrigger_arm!Function
counterTrigger_arm!(rp::RedPitaya, val::Bool)

Set whether the counter trigger is armed or not. Return true if the command was successful.

Examples

julia> counterTrigger_arm!(rp, true)
 true
 
 julia> counterTrigger_isArmed(rp)
-true
source
RedPitayaDAQServer.counterTrigger_enabled!Method

counterTrigger_enabled!(rp::RedPitaya, val)

Set whether the counter trigger is enabled or not. Return true if the command was successful.

Examples

julia> counterTrigger_enabled!(rp, true)
+true
source
RedPitayaDAQServer.counterTrigger_enabled!Method

counterTrigger_enabled!(rp::RedPitaya, val)

Set whether the counter trigger is enabled or not. Return true if the command was successful.

Examples

julia> counterTrigger_enabled!(rp, true)
 true
 
 julia> counterTrigger_enabled(rp)
-true
source
RedPitayaDAQServer.counterTrigger_enabledMethod
counterTrigger_enabled(rp::RedPitaya)

Return whether the counter trigger is enabled or not.

Examples

julia> counterTrigger_enabled!(rp, true)
 true
 
 julia> counterTrigger_enabled(rp)
-true
source
RedPitayaDAQServer.counterTrigger_isArmedMethod
counterTrigger_isArmed(rp::RedPitaya)

Return whether the counter trigger is armed or not.

Examples

julia> counterTrigger_arm!(rp, true)
 true
 
 julia> counterTrigger_isArmed(rp)
-true
source
RedPitayaDAQServer.counterTrigger_lastCounterMethod

counterTrigger_lastCounter(rp::RedPitaya)

Return the number of samples that the counter trigger should trigger prior to reaching the reference counter.

Examples

julia> counterTrigger_lastCounter(rp)
-123456
source
RedPitayaDAQServer.counterTrigger_presamples!Method
counterTrigger_presamples!(rp::RedPitaya, presamples)

Set the number of samples that the counter trigger should trigger prior to reaching the reference counter.

Examples

julia> counterTrigger_presamples!(rp, 50)
+true
source
RedPitayaDAQServer.counterTrigger_lastCounterMethod

counterTrigger_lastCounter(rp::RedPitaya)

Return the number of samples that the counter trigger should trigger prior to reaching the reference counter.

Examples

julia> counterTrigger_lastCounter(rp)
+123456
source
RedPitayaDAQServer.counterTrigger_presamples!Method
counterTrigger_presamples!(rp::RedPitaya, presamples)

Set the number of samples that the counter trigger should trigger prior to reaching the reference counter.

Examples

julia> counterTrigger_presamples!(rp, 50)
 true
 
 julia> counterTrigger_presamples(rp)
-50
source
RedPitayaDAQServer.counterTrigger_presamplesMethod
counterTrigger_presamples(rp::RedPitaya)

Return the number of samples that the counter trigger should trigger prior to reaching the reference counter.

Examples

julia> counterTrigger_presamples!(rp, 50)
+50
source
RedPitayaDAQServer.counterTrigger_presamplesMethod
counterTrigger_presamples(rp::RedPitaya)

Return the number of samples that the counter trigger should trigger prior to reaching the reference counter.

Examples

julia> counterTrigger_presamples!(rp, 50)
 true
 
 julia> counterTrigger_presamples(rp)
-50
source
RedPitayaDAQServer.counterTrigger_referenceCounter!Method

counterTrigger_referenceCounter!(rp::RedPitaya, presamples)

Set the number of samples that the counter trigger should trigger on.

Examples

julia> counterTrigger_referenceCounter(rp, 250)
 true
 
 julia> counterTrigger_referenceCounter!(rp)
-250
source
RedPitayaDAQServer.counterTrigger_referenceCounterMethod
counterTrigger_referenceCounter(rp::RedPitaya)

Return the counter value that the counter trigger should trigger on.

Examples

julia> counterTrigger_referenceCounter!(rp, 250)
 true
 
 julia> counterTrigger_referenceCounter(rp)
-250
source
RedPitayaDAQServer.counterTrigger_reset!Method
counterTrigger_reset!(rp::RedPitaya, val::Bool)

Set the reset of the counter trigger to val. Return true if the command was successful.

Example

julia> counterTrigger_reset!(rp, true)
+250
source
RedPitayaDAQServer.counterTrigger_reset!Method
counterTrigger_reset!(rp::RedPitaya, val::Bool)

Set the reset of the counter trigger to val. Return true if the command was successful.

Example

julia> counterTrigger_reset!(rp, true)
 true
 
 julia>counterTrigger_reset(rp)
-true
source
RedPitayaDAQServer.counterTrigger_sourceChannel!Method

counterTrigger_sourceChannel!(rp::RedPitaya, sourceChannel::) //TODO

Set the source channel of the counter trigger to sourceChannel.

Example

julia> counterTrigger_sourceChannel!(rp, COUNTER_TRIGGER_ADC)
+true
source
RedPitayaDAQServer.counterTrigger_sourceChannel!Method

counterTrigger_sourceChannel!(rp::RedPitaya, sourceChannel::) //TODO

Set the source channel of the counter trigger to sourceChannel.

Example

julia> counterTrigger_sourceChannel!(rp, COUNTER_TRIGGER_ADC)
 
 julia>counterTrigger_sourceChannel(rp)
-COUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1 //TODO
source
RedPitayaDAQServer.counterTrigger_sourceChannelMethod

counterTrigger_sourceChannel(rp::RedPitaya)

Get the source channel of the counter trigger.

Example

julia> counterTrigger_sourceChannel!(rp, COUNTER_TRIGGER_IN2)
+COUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1 //TODO
source
RedPitayaDAQServer.counterTrigger_sourceChannelMethod

counterTrigger_sourceChannel(rp::RedPitaya)

Get the source channel of the counter trigger.

Example

julia> counterTrigger_sourceChannel!(rp, COUNTER_TRIGGER_IN2)
 
 julia>counterTrigger_sourceChannel(rp)
-COUNTER_TRIGGER_IN2::CounterTriggerSourceADCChannel = 2
source
RedPitayaDAQServer.counterTrigger_sourceType!Method
counterTrigger_sourceType!(rp::RedPitaya, sourceType::CounterTriggerSourceType)

Set the source type of the counter trigger to sourceType.

Example

julia> counterTrigger_sourceType!(rp, COUNTER_TRIGGER_ADC)
+COUNTER_TRIGGER_IN2::CounterTriggerSourceADCChannel = 2
source
RedPitayaDAQServer.counterTrigger_sourceType!Method
counterTrigger_sourceType!(rp::RedPitaya, sourceType::CounterTriggerSourceType)

Set the source type of the counter trigger to sourceType.

Example

julia> counterTrigger_sourceType!(rp, COUNTER_TRIGGER_ADC)
 
 julia>counterTrigger_sourceType(rp)
-COUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1
source
RedPitayaDAQServer.counterTrigger_sourceTypeMethod
counterTrigger_sourceType(rp::RedPitaya)

Get the source type of the counter trigger.

Example

julia> counterTrigger_sourceType!(rp, COUNTER_TRIGGER_ADC)
+COUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1
source
RedPitayaDAQServer.counterTrigger_sourceTypeMethod
counterTrigger_sourceType(rp::RedPitaya)

Get the source type of the counter trigger.

Example

julia> counterTrigger_sourceType!(rp, COUNTER_TRIGGER_ADC)
 
 julia>counterTrigger_sourceType(rp)
-COUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1
source
+COUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1
source
diff --git a/dev/cluster.html b/dev/cluster.html index dbf75a9b..f8457bc1 100644 --- a/dev/cluster.html +++ b/dev/cluster.html @@ -1,2 +1,2 @@ -Cluster · RP DAQ Server

Cluster

The RedPitayaDAQServer allows to use multiple RedPitayas in a fully synchronized fashion. One of the RedPitayas will act as the master and distribute its clock to all other RedPitayas acting as slaves.

Prerequisites

Unfortunately, the STEMlab 125-4 does not allow cluster synchronization without hardware modifications. It is therefore necessary to resolder all slaves according to this documentation. The required mode for this project is 'Directly from FPGA' which requires resistors on R27 and R28. The heatsink has to be removed temporarily in order to unsolder the two resistor below it. In the following image you can see the new position of the 0 Ohm 0402 resistors. Since they get lost easily, make sure you have some in stock.

Cluster

Connections

To run a cluster of RedPitayas one needs to connect the devices using different cables. An exemplary cluster with 3 devices is shown in the following image.

Cluster

The clock is distributed from the master to the first slave via an SATA cable (green). Additional slaves can be used by connecting the next slave to the previous one. Additionally all slaves have connection from +3.3 Volt to DIO0_N.

In order to send a mutual trigger signal for starting the acquisition and the signal generation, you also have to connect the master's DIO5_P pin with the DIO0_P pin of all devices including the master.

+Cluster · RP DAQ Server

Cluster

The RedPitayaDAQServer allows to use multiple RedPitayas in a fully synchronized fashion. One of the RedPitayas will act as the master and distribute its clock to all other RedPitayas acting as slaves.

Prerequisites

Unfortunately, the STEMlab 125-4 does not allow cluster synchronization without hardware modifications. It is therefore necessary to resolder all slaves according to this documentation. The required mode for this project is 'Directly from FPGA' which requires resistors on R27 and R28. The heatsink has to be removed temporarily in order to unsolder the two resistor below it. In the following image you can see the new position of the 0 Ohm 0402 resistors. Since they get lost easily, make sure you have some in stock.

Cluster

Connections

To run a cluster of RedPitayas one needs to connect the devices using different cables. An exemplary cluster with 3 devices is shown in the following image.

Cluster

The clock is distributed from the master to the first slave via an SATA cable (green). Additional slaves can be used by connecting the next slave to the previous one. Additionally all slaves have connection from +3.3 Volt to DIO0_N.

In order to send a mutual trigger signal for starting the acquisition and the signal generation, you also have to connect the master's DIO5_P pin with the DIO0_P pin of all devices including the master.

diff --git a/dev/connections.html b/dev/connections.html index b8a8b8c3..fcacb999 100644 --- a/dev/connections.html +++ b/dev/connections.html @@ -1,2 +1,2 @@ -Connections · RP DAQ Server

Connections

An overview of the extension connectors (see also here) is given in the following image

Connectors

The project uses most but not all connections that are used in the original RedPitaya image. From the connector E2 only the analog inputs and outputs are used. From the connector E1 several pins are reserved for the following purposes:

  • DIO0_P for the ADC and DAC trigger. Connect it with the master's DIO5_P to distribute the trigger signal to all RedPitayas in a cluster. As long as the input is high, the DACs and ADCs are running.
  • DIO1_P is the input for the watchdog (see configuration register section for further details)
  • DIO2_P is used to acknowledge a received watchdog signal.
  • DIO3_P can be set to high, to stop all DACs instantly.
  • DIO4_P outputs a high for 10 ms after a 100 ms pause on low to provide an alive signal.
  • DIO5_P can be set to high via the configuration register to provide the mutual trigger signal.
  • DIO7_P, DIO7_N, DIO6_P, DIO6_N, DIO5_N, DIO4_N, DIO3_N, DIO2_N can be used as arbitrary outputs set via the server.
  • DIO0_N and DIO1_N are used for the clock selection in a cluster.
+Connections · RP DAQ Server

Connections

An overview of the extension connectors (see also here) is given in the following image

Connectors

The project uses most but not all connections that are used in the original RedPitaya image. From the connector E2 only the analog inputs and outputs are used. From the connector E1 several pins are reserved for the following purposes:

  • DIO0_P for the ADC and DAC trigger. Connect it with the master's DIO5_P to distribute the trigger signal to all RedPitayas in a cluster. As long as the input is high, the DACs and ADCs are running.
  • DIO1_P is the input for the watchdog (see configuration register section for further details)
  • DIO2_P is used to acknowledge a received watchdog signal.
  • DIO3_P can be set to high, to stop all DACs instantly.
  • DIO4_P outputs a high for 10 ms after a 100 ms pause on low to provide an alive signal.
  • DIO5_P can be set to high via the configuration register to provide the mutual trigger signal.
  • DIO7_P, DIO7_N, DIO6_P, DIO6_N, DIO5_N, DIO4_N, DIO3_N, DIO2_N can be used as arbitrary outputs set via the server.
  • DIO0_N and DIO1_N are used for the clock selection in a cluster.
diff --git a/dev/devtips.html b/dev/devtips.html index ba99d576..573942f0 100644 --- a/dev/devtips.html +++ b/dev/devtips.html @@ -1,2 +1,2 @@ -Development Tips · RP DAQ Server

Development Hints

On this slide some development hints are summarized. These might change regularely if things are properly integrated into the framework.

Alpine Linux

  • The Alpine linux as currently a root folder with only 185.8M free space, which disallows installing more

applications. To change this one can do

mount -o remount,size=1G /
+Development Tips · RP DAQ Server

Development Hints

On this slide some development hints are summarized. These might change regularely if things are properly integrated into the framework.

Alpine Linux

  • The Alpine linux as currently a root folder with only 185.8M free space, which disallows installing more

applications. To change this one can do

mount -o remount,size=1G /
diff --git a/dev/examples/batch.html b/dev/examples/batch.html index 38267c03..ebe5dc45 100644 --- a/dev/examples/batch.html +++ b/dev/examples/batch.html @@ -1,5 +1,5 @@ -Batch · RP DAQ Server

Batch Example

In this example we recreate the first example using the batch functionality offered by the Julia client. Note that all commands are still executed in order from the RedPitayas perspective, only the client communication is more efficient within a batch.

To run this example connect the RedPitaya in the following way.

RedPitaya

It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+Batch · RP DAQ Server

Batch Example

In this example we recreate the first example using the batch functionality offered by the Julia client. Note that all commands are still executed in order from the RedPitayas perspective, only the client communication is more efficient within a batch.

To run this example connect the RedPitaya in the following way.

RedPitaya

It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
 using CairoMakie
 
 include("config.jl")
@@ -65,4 +65,4 @@
 lines!(plot.axis, vec(uLastPeriod[:,1,:,:]), label = "last period")
 axislegend(plot.axis)
 save(joinpath(@__DIR__(), "images", "batch.png"), plot)
-plot

Batch Example Results

+plot

Batch Example Results

diff --git a/dev/examples/cluster.html b/dev/examples/cluster.html index 894c3272..645fa701 100644 --- a/dev/examples/cluster.html +++ b/dev/examples/cluster.html @@ -1,5 +1,5 @@ -Cluster · RP DAQ Server

Cluster Example

In this example we generate and acquire sine waves, similar to to the first example. However, this time we use two RedPitayas sychronized in a cluster. The example will create a sine wave on the first DAC channel of the first RedPitaya and a phase shifted sine wave on the first channel of the second RedPitaya. To run this example connect the RedPitayas in the following way:

RedPitaya

Note that while the example only plots the first channel of the RedPitaya, both channels are transmitted to the clients.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+Cluster · RP DAQ Server

Cluster Example

In this example we generate and acquire sine waves, similar to to the first example. However, this time we use two RedPitayas sychronized in a cluster. The example will create a sine wave on the first DAC channel of the first RedPitaya and a phase shifted sine wave on the first channel of the second RedPitaya. To run this example connect the RedPitayas in the following way:

RedPitaya

Note that while the example only plots the first channel of the RedPitaya, both channels are transmitted to the clients.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
 using CairoMakie
 
 # obtain the URL of the RedPitaya
@@ -53,4 +53,4 @@
 lines!(plot.axis, vec(uCurrentPeriod[:,3,:,:]), label = "Channel 3")
 axislegend(plot.axis)
 save(joinpath(@__DIR__(), "images", "cluster.png"), fig)
-fig
+fig
diff --git a/dev/examples/producerConsumer.html b/dev/examples/producerConsumer.html index 5d7b815c..ee44e3cd 100644 --- a/dev/examples/producerConsumer.html +++ b/dev/examples/producerConsumer.html @@ -1,5 +1,5 @@ -Continous Signal Acquisition · RP DAQ Server

Continous Signal Acquisition Example

As is mentioned in the Acquisition section, the transmission rate of the server heavily depends on the available network and the way a client processes the samples. This example shows how one can write a thread dedicated to just receiving samples and one (or more) threads dedicated to processing samples. As the example contains no visualization, there is no need for a specific RedPitaya setup.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+Continous Signal Acquisition · RP DAQ Server

Continous Signal Acquisition Example

As is mentioned in the Acquisition section, the transmission rate of the server heavily depends on the available network and the way a client processes the samples. This example shows how one can write a thread dedicated to just receiving samples and one (or more) threads dedicated to processing samples. As the example contains no visualization, there is no need for a specific RedPitaya setup.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
 using ThreadPools
 using CairoMakie
 
@@ -145,4 +145,4 @@
     # Frame dimensions are [samples, chan, periods, frames]
     plot = lines(vec(buffer[:, 1, :, :]))
     save(joinpath(@__DIR__(), "images", "producerConsumer.png"), plot)
-end
+end
diff --git a/dev/examples/ramping.html b/dev/examples/ramping.html index c72a1e54..9bb0f9f3 100644 --- a/dev/examples/ramping.html +++ b/dev/examples/ramping.html @@ -1,5 +1,5 @@ -Ramping · RP DAQ Server

Ramping Example

In this example we ramp up the amplitude of our signal over 10 periods and we retrieve the first 12 periods of samples. Then after a wait we receive the next 12 periods. Afterwards we trigger the ramp down of the signal. As this is triggered by a command that is sent over the network it varies when the ramp down actually start. A ramp down can be triggered at a specific point with the help of a sequence.

To run this example connect the RedPitaya in the following way.

RedPitaya

It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+Ramping · RP DAQ Server

Ramping Example

In this example we ramp up the amplitude of our signal over 10 periods and we retrieve the first 12 periods of samples. Then after a wait we receive the next 12 periods. Afterwards we trigger the ramp down of the signal. As this is triggered by a command that is sent over the network it varies when the ramp down actually start. A ramp down can be triggered at a specific point with the help of a sequence.

To run this example connect the RedPitaya in the following way.

RedPitaya

It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
 using CairoMakie
 
 # obtain the URL of the RedPitaya
@@ -58,4 +58,4 @@
 lines!(plot.axis, vec(uLastPeriod[:,1,:,:]), label = "end")
 axislegend(plot.axis)
 save(joinpath(@__DIR__(), "images", "asyncRamping.png"), plot)
-plot

Ramping Example Results

+plot

Ramping Example Results

diff --git a/dev/examples/resync.html b/dev/examples/resync.html new file mode 100644 index 00000000..6fd89e76 --- /dev/null +++ b/dev/examples/resync.html @@ -0,0 +1,79 @@ + +Resync · RP DAQ Server

Resync Example

In this example we add a resync signal to a sequence to create a signal that resynchronizes phase and frequency of the DACs after every frame. This can be used to change the frequency and phase of a signal during measurement. While the resynchronization is synchronous due to the sequences, the actual new frequency and phase information is asynchronous as they are transmitted via SCPI.

The example constructs a sequence with no offset and the very last step has the resync flag enabled. Note that during the resync-step the DAC outputs zero.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+using CairoMakie
+
+# obtain the URL of the RedPitaya
+include("config.jl")
+
+rp = RedPitaya(URLs[1])
+serverMode!(rp, CONFIGURATION)
+
+dec = 32
+modulus = 124800
+base_frequency = 125000000
+periods_per_step = 5
+samples_per_period = div(modulus, dec)
+periods_per_frame = 50
+frame_period = dec*samples_per_period*periods_per_frame / base_frequency
+steps_per_frame = div(50, periods_per_step)
+
+decimation!(rp, dec)
+samplesPerPeriod!(rp, samples_per_period)
+periodsPerFrame!(rp, periods_per_frame)
+
+for i in 1:2
+  frequencyDAC!(rp, i, 1, base_frequency / modulus)
+  signalTypeDAC!(rp, i, 1, "SINE")
+  amplitudeDAC!(rp, i, 1, 0.2)
+  phaseDAC!(rp, i, 1, 0)
+end
+triggerMode!(rp, INTERNAL)
+
+# Sequence Configuration
+clearSequence!(rp)
+stepsPerFrame!(rp, steps_per_frame)
+seqChan!(rp, 2)
+lut = reshape(fill(0.0f0, steps_per_frame), 1, :)
+lut = repeat(lut, outer = 2)
+enable = collect(fill(true, steps_per_frame))
+enable = reshape(enable, 1, :)
+enable = repeat(enable, outer = 2)
+# In the last step of each frame we resync the DACs 
+resync = vcat(fill(false, steps_per_frame - 1), [true])
+resync = reshape(resync, 1, :)
+resync = repeat(resync, outer = 2)
+seq = SimpleSequence(lut, 2, enable, resync)
+sequence!(rp, seq)
+
+samples_per_frame = samples_per_period * periods_per_frame
+target = samples_per_frame * 0.3 # After a third of a frame we want to switch frequency
+
+serverMode!(rp, ACQUISITION)
+masterTrigger!(rp, true)
+
+# Wait until we reach the target sample
+curr = currentWP(rp)
+while curr < target
+  # NOP
+  global curr = currentWP(rp)
+  sleep(0.01)
+end
+
+# Update the phase and frequency of the second channel
+frequencyDAC!(rp, 2, 1, base_frequency / (2*modulus))
+phaseDAC!(rp, 2, 1, pi)
+
+data = readFrames(rp, 0, 2)
+
+masterTrigger!(rp, false)
+serverMode!(rp, CONFIGURATION)
+
+
+fig = Figure()
+lines(fig[1, 1], vec(data[:, 2, :, 1]), axis = (ylabel = "First Frame", title = "All Periods"))
+lines(fig[1, 2], vec(data[:, 2, 1:5, 1]), axis = (ylabel = "First Frame", title = "First Periods"))
+lines(fig[2, 1], vec(data[:, 2, :, 2]), axis = (ylabel = "Second Frame",))
+lines(fig[2, 2], vec(data[:, 2, 1:5, 2]), axis = (ylabel = "Second Frame",))
+
+save(joinpath(@__DIR__(), "images", "resync.png"), fig)
+fig

Resync Example Results

diff --git a/dev/examples/seqRamping.html b/dev/examples/seqRamping.html index ae1531ab..c1caff4c 100644 --- a/dev/examples/seqRamping.html +++ b/dev/examples/seqRamping.html @@ -1,5 +1,5 @@ -Sequence Ramping · RP DAQ Server

Sequence Ramping Example

In this example we combine the ramping and the sequence example to create a signal with known/predictable ramping behaviour. The ramping period is independant of the sequence. The sequence we use is a sequence that holds the first value of our intended sequence for the duration of the given number of ramping steps, which spans the ramp up period.

At the end of the "regular" sequence portion, the ramp down is triggered and the sequence holds the last value of the "regular" sequence until the end of the ramp down.

RedPitaya

It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+Sequence Ramping · RP DAQ Server

Sequence Ramping Example

In this example we combine the ramping and the sequence example to create a signal with known/predictable ramping behaviour. The ramping period is independant of the sequence. The sequence we use is a sequence that holds the first value of our intended sequence for the duration of the given number of ramping steps, which spans the ramp up period.

At the end of the "regular" sequence portion, the ramp down is triggered and the sequence holds the last value of the "regular" sequence until the end of the ramp down.

RedPitaya

It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
 using CairoMakie
 
 # obtain the URL of the RedPitaya
@@ -55,4 +55,4 @@
 plot = lines(vec(uCurrentFrame[:,1,:,1:4]))
 
 save(joinpath(@__DIR__(), "images", "seqRamping.png"), plot)
-plot

Sequence Ramping Example Results

+plot

Sequence Ramping Example Results

diff --git a/dev/examples/sequence.html b/dev/examples/sequence.html index 8f00c045..17b2d016 100644 --- a/dev/examples/sequence.html +++ b/dev/examples/sequence.html @@ -1,5 +1,5 @@ -Sequence · RP DAQ Server

Sequence Example

In this example we generate a 10 kHz sine wave on DAC channel 1 and also construct a sequence with a climbing offset every 5 periods. We receive this signal on ADC channel 1. To run this example connect the RedPitaya in the following way.

RedPitaya

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+Sequence · RP DAQ Server

Sequence Example

In this example we generate a 10 kHz sine wave on DAC channel 1 and also construct a sequence with a climbing offset every 5 periods. We receive this signal on ADC channel 1. To run this example connect the RedPitaya in the following way.

RedPitaya

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
 using CairoMakie
 
 # obtain the URL of the RedPitaya
@@ -50,4 +50,4 @@
 lines!(plot.axis, vec(uCurrentFrame[:,2,:,:]), label = "Rx2")
 axislegend(plot.axis)
 save(joinpath(@__DIR__(), "images", "sequence.png"), plot)
-plot

Simple Example Results

+plot

Simple Example Results

diff --git a/dev/examples/sequenceMultiChannel.html b/dev/examples/sequenceMultiChannel.html index 07f64bbb..018a4c3b 100644 --- a/dev/examples/sequenceMultiChannel.html +++ b/dev/examples/sequenceMultiChannel.html @@ -1,5 +1,5 @@ -Sequence Multi-Channel and Waveform Enable · RP DAQ Server

Sequence Multi-Channel and Waveform Enable Example

This examples combines concepts from the three examples and additionally uses the signal enable feature of the sequences. This example uses both DAC and ADC channels of the RedPitaya. On the first DAC channel we output a sine waveform together with a climbing sequence. On the second channel we output just a sequence with a constant value and no waveforms at all. The signal enable flags of the sequences are set in such a way, that the two channels alternate being enabled with each step.

RedPitaya

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+Sequence Multi-Channel and Waveform Enable · RP DAQ Server

Sequence Multi-Channel and Waveform Enable Example

This examples combines concepts from the three examples and additionally uses the signal enable feature of the sequences. This example uses both DAC and ADC channels of the RedPitaya. On the first DAC channel we output a sine waveform together with a climbing sequence. On the second channel we output just a sequence with a constant value and no waveforms at all. The signal enable flags of the sequences are set in such a way, that the two channels alternate being enabled with each step.

RedPitaya

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
 using CairoMakie
 
 # obtain the URL of the RedPitaya
@@ -50,4 +50,4 @@
 lines!(plot.axis, vec(uCurrentFrame[:,2,:,:]), label = "Rx2")
 axislegend(plot.axis)
 save(joinpath(@__DIR__(), "images", "sequence.png"), plot)
-plot

Simple Example Results

+plot

Simple Example Results

diff --git a/dev/examples/simple.html b/dev/examples/simple.html index 88c4cc45..f66eb5a2 100644 --- a/dev/examples/simple.html +++ b/dev/examples/simple.html @@ -1,5 +1,5 @@ -Simple · RP DAQ Server

Simple Example

In the first example we connect to a single RedPitaya and generate a sinus signal of frequency 10 kHz on DAC channel 1 and receive the same signal on the ADC channel 1. To run this example connect the RedPitaya in the following way.

RedPitaya

Note that while the example only plots the first channel of the RedPitaya, both channels are transmitted to the clients.

Julia Client

This and all other examples are located in the examples directory.

using RedPitayaDAQServer
+Simple · RP DAQ Server

Simple Example

In the first example we connect to a single RedPitaya and generate a sinus signal of frequency 10 kHz on DAC channel 1 and receive the same signal on the ADC channel 1. To run this example connect the RedPitaya in the following way.

RedPitaya

Note that while the example only plots the first channel of the RedPitaya, both channels are transmitted to the clients.

Julia Client

This and all other examples are located in the examples directory.

using RedPitayaDAQServer
 using CairoMakie
 
 # obtain the URL of the RedPitaya
@@ -122,4 +122,4 @@
 plt.savefig("simple.png")
 
 plt.show()
-
+
diff --git a/dev/examples/waveforms.html b/dev/examples/waveforms.html index 6a7914a5..f395ca8d 100644 --- a/dev/examples/waveforms.html +++ b/dev/examples/waveforms.html @@ -1,5 +1,5 @@ -Waveforms · RP DAQ Server

Waveforms Example

In this example we generate different signals with a base frequency of 10 kHz on DAC channel 1 and receive the same signals on the ADC channel 1. To run this example connect the RedPitaya in the following way.

RedPitaya

It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
+Waveforms · RP DAQ Server

Waveforms Example

In this example we generate different signals with a base frequency of 10 kHz on DAC channel 1 and receive the same signals on the ADC channel 1. To run this example connect the RedPitaya in the following way.

RedPitaya

It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.

Julia Client

This and all other examples are located in the examples directory

using RedPitayaDAQServer
 using CairoMakie
 
 # obtain the URL of the RedPitaya
@@ -70,4 +70,4 @@
 lines(fig[2, 2], vec(uFirstPeriod[:,1,:,:]), axis = (title = "ARBITRARY",))
 
 save(joinpath(@__DIR__(), "images", "waveforms.png"), fig)
-fig

Simple Example Results

+fig

Simple Example Results

diff --git a/dev/fpga.html b/dev/fpga.html index e70994fd..48467b3b 100644 --- a/dev/fpga.html +++ b/dev/fpga.html @@ -1,2 +1,2 @@ -FPGA Development · RP DAQ Server

FPGA Development

There may be needs to change the FPGA image. The following explains how this can be done.

Preparation

If you want to make changes to the FPGA design, you need to install Vivado 2021.2. More infos for setting up a development machine we refer to the following resource and here.

After following the installation steps, you need to clone the repository into a directory of your choice and then regenerate the IP cores and the project by running

make daq_bitfiles.

Afterwards you can start Vivado and open the recreated project in ./build/fpga/<xc7z010clg400-1,xc7z020clg400-1>/firmware/RedPitayaDAQServer.xpr. Apply the changes you need and then create the bitfile by using 'Flow -> Generate Bitstream'. This runs the synthesis and implementation steps and output the Bitfile to ./build/fpga/firmware/RedPitayaDAQServer.runs/impl_1/system_wrapper.bit.

After creating the respective bitfile you need to copy it to your Red Pitayas. You can use

scp ./build/fpga/<xc7z010clg400-1,xc7z020clg400-1>/firmware/RedPitayaDAQServer.runs/impl_1/system_wrapper.bit root@<IP>:/root/RedPitayaDAQServer/bitfiles/daq_<xc7z010clg400-1,xc7z020clg400-1>.bit

for this. Set your IP and FPGA version accordingly. Another option is to fully regenerate the Linux image with make all and copy it to the SD card.

Since using git with Vivado can be annoying here are some hints how you can make your changes ready for git:

  • If you only changed some stuff in the blockdesign, you just have to export the blockdesign to ./src/fpga/bd/bd.tcl by using 'File -> Export -> Export Block Design' in Vivado.
  • Changes to the project settings have to be done in ./src/fpga/build.tcl in order to not lose the ability to recreate your changed project.
  • For your own IP cores, just create a new directory in ./src/fpga/cores and copy and adapt the core_config.tcl of another core. Afterwards re-run make cores.
+FPGA Development · RP DAQ Server

FPGA Development

There may be needs to change the FPGA image. The following explains how this can be done.

Preparation

If you want to make changes to the FPGA design, you need to install Vivado 2021.2. More infos for setting up a development machine we refer to the following resource and here.

After following the installation steps, you need to clone the repository into a directory of your choice and then regenerate the IP cores and the project by running

make daq_bitfiles.

Afterwards you can start Vivado and open the recreated project in ./build/fpga/<xc7z010clg400-1,xc7z020clg400-1>/firmware/RedPitayaDAQServer.xpr. Apply the changes you need and then create the bitfile by using 'Flow -> Generate Bitstream'. This runs the synthesis and implementation steps and output the Bitfile to ./build/fpga/firmware/RedPitayaDAQServer.runs/impl_1/system_wrapper.bit.

After creating the respective bitfile you need to copy it to your Red Pitayas. You can use

scp ./build/fpga/<xc7z010clg400-1,xc7z020clg400-1>/firmware/RedPitayaDAQServer.runs/impl_1/system_wrapper.bit root@<IP>:/root/RedPitayaDAQServer/bitfiles/daq_<xc7z010clg400-1,xc7z020clg400-1>.bit

for this. Set your IP and FPGA version accordingly. Another option is to fully regenerate the Linux image with make all and copy it to the SD card.

Since using git with Vivado can be annoying here are some hints how you can make your changes ready for git:

  • If you only changed some stuff in the blockdesign, you just have to export the blockdesign to ./src/fpga/bd/bd.tcl by using 'File -> Export -> Export Block Design' in Vivado.
  • Changes to the project settings have to be done in ./src/fpga/build.tcl in order to not lose the ability to recreate your changed project.
  • For your own IP cores, just create a new directory in ./src/fpga/cores and copy and adapt the core_config.tcl of another core. Afterwards re-run make cores.
diff --git a/dev/generation.html b/dev/generation.html index d2688b91..0e0339b1 100644 --- a/dev/generation.html +++ b/dev/generation.html @@ -1,2 +1,2 @@ -Signal Generation · RP DAQ Server

Signal Generation

Once the acquisition is triggered, each RedPitaya also starts producing signals on their output channels. Each RedPitaya features six such channels, two of those are the 16-bit DAC channel and four of those are digital pins using PDM, see Connections. The output signals are composed of three parts: parameterized waveforms $W_i(t)$, an offset $o_i$ and repeating arbitrary LUT tables. The latter are called sequences $seq_i(t)$. The resulting signal of the DAC channel can be described as:

\[S_i(t) = seq_i(t) + o_i + W_i(t)\]

Waveforms

Each of the 16-bit DAC channel can output a compositve waveform with four components. Each component can be parametrized by its amplitude $a_{i,j}$, frequency $f_{i,j}$ and phase $\varphi_{i,j}$, which can all be changed via SCPI commands. Furthermore, each component also offers different waveforms $w_{i,j}$(sine, triangle, sawtooth):

\[W_i(t) = \sum_{j=1}^{4}a_{i,j} w_{i,j}(2\pi f_{i,j}t + \varphi_{i, j})\]

Ramping

The signals output on the DAC channel can also be multiplied with an increasing/decreasing ramping factor $r(t)$. Ramping and the ramping duration can be enabled and set on a per channel basis. The increasing factor starts from 0 and goes to 1 from the acquisition start on. The decreasing factor goes from 1 to 0.

\[S_i'(t) = r(t)S(t)\]

The ramp down has to be started either by a SCPI command or by a flag from a sequence. Disabling the acquisition trigger removes the ramp down flag, but not the flag that enables ramping itself.

Sequences

The FPGA image features a LUT containing values for all output channels. This LUT is treated as a ring-buffer through which the image iterates and outputs the values on their respective channel. The image can be configured to increment its LUT access every n samples. One period of a value is also called a step. A sequence is a series of steps and the number of times this series is to be repeated.

As the LUT used by the FPGA image is small in comparison with the main memory and in order to support longer series of steps, the server itselfs maintains a sequence in its main memory and periodically reads the next steps from its sequence and writes them to the LUT of the image.

Comparable to the sample transmission of the acquisition, this updating of the LUT is also a process with timing uncertainty as it is affected by the scheduling and execution of the RedPitayas CPU. While during the sample transmission samples could be lost because they were overwritten, in the signal generation wrong signals could be output because the server was too slow in updating the values. Here, the server tracks similar performance metrics and also features a status flag lostSteps for exactly this case. In its current implementation a safe step rate is at 12 kHz.

Sequences and their steps also have additional features. A step can be marked such that during its duration the signal is set to 0. Furthermore, a step can be marked such that it triggers the ramp down. To make this easier to manage the server actually manages three sequences, that can be set individually: A ramp up, regular and ramp down sequence. The ramp up sequence is moved to the FPGA LUT at the acquisition start, followed by the regular sequence. Afterwards the ramp down sequence is started and during its execution the ramp down flag is set.

Calibration

Similar to the signal acquisition, there are also calibration scale $c_{i, scale}$ and offset $c_{i, offset}$ values for the signal generation. These are stored in the EEPROM of the RedPitaya and can be updated by a client. The calibration values are always applied, even when the master trigger is off.

Thus the total signal can be described as:

\[S_i''(t) = c_{i, scale} S_i'(t) + c_{i, offset}\]

+Signal Generation · RP DAQ Server

Signal Generation

Once the acquisition is triggered, each RedPitaya also starts producing signals on their output channels. Each RedPitaya features six such channels, two of those are the 16-bit DAC channel and four of those are digital pins using PDM, see Connections. The output signals are composed of three parts: parameterized waveforms $W_i(t)$, an offset $o_i$ and repeating arbitrary LUT tables. The latter are called sequences $seq_i(t)$. The resulting signal of the DAC channel can be described as:

\[S_i(t) = seq_i(t) + o_i + W_i(t)\]

Waveforms

Each of the 16-bit DAC channel can output a compositve waveform with four components. Each component can be parametrized by its amplitude $a_{i,j}$, frequency $f_{i,j}$ and phase $\varphi_{i,j}$, which can all be changed via SCPI commands. Furthermore, each component also offers different waveforms $w_{i,j}$(sine, triangle, sawtooth):

\[W_i(t) = \sum_{j=1}^{4}a_{i,j} w_{i,j}(2\pi f_{i,j}t + \varphi_{i, j})\]

Ramping

The signals output on the DAC channel can also be multiplied with an increasing/decreasing ramping factor $r(t)$. Ramping and the ramping duration can be enabled and set on a per channel basis. The increasing factor starts from 0 and goes to 1 from the acquisition start on. The decreasing factor goes from 1 to 0.

\[S_i'(t) = r(t)S(t)\]

The ramp down has to be started either by a SCPI command or by a flag from a sequence. Disabling the acquisition trigger removes the ramp down flag, but not the flag that enables ramping itself.

Sequences

The FPGA image features a LUT containing values for all output channels. This LUT is treated as a ring-buffer through which the image iterates and outputs the values on their respective channel. The image can be configured to increment its LUT access every n samples. One period of a value is also called a step. A sequence is a series of steps and the number of times this series is to be repeated.

As the LUT used by the FPGA image is small in comparison with the main memory and in order to support longer series of steps, the server itselfs maintains a sequence in its main memory and periodically reads the next steps from its sequence and writes them to the LUT of the image.

Comparable to the sample transmission of the acquisition, this updating of the LUT is also a process with timing uncertainty as it is affected by the scheduling and execution of the RedPitayas CPU. While during the sample transmission samples could be lost because they were overwritten, in the signal generation wrong signals could be output because the server was too slow in updating the values. Here, the server tracks similar performance metrics and also features a status flag lostSteps for exactly this case. In its current implementation a safe step rate is at 12 kHz.

Sequences and their steps also have additional features. A step can be marked such that during its duration the signal is set to 0. Furthermore, a step can be marked such that it triggers the ramp down. To make this easier to manage the server actually manages three sequences, that can be set individually: A ramp up, regular and ramp down sequence. The ramp up sequence is moved to the FPGA LUT at the acquisition start, followed by the regular sequence. Afterwards the ramp down sequence is started and during its execution the ramp down flag is set. Steps can also be marked to resync the fast DACs. During a resync, the signals are set to 0 and afterwards start again with their set phase and frequency. This can be used to change frequency and phase during measurements and s.t. the new phase and frequency is synchronous to the steps.

Calibration

Similar to the signal acquisition, there are also calibration scale $c_{i, scale}$ and offset $c_{i, offset}$ values for the signal generation. These are stored in the EEPROM of the RedPitaya and can be updated by a client. The calibration values are always applied, even when the master trigger is off.

Thus the total signal can be described as:

\[S_i''(t) = c_{i, scale} S_i'(t) + c_{i, offset}\]

diff --git a/dev/index.html b/dev/index.html index e5ce1629..15e903d4 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Home · RP DAQ Server

RedPitayaDAQServer

Advanced DAQ Tools for the RedPitaya (STEMlab 125-14)

Introduction

This project contains software to be used with the STEMlab 125-14 device from RedPitaya. It allows for continuous generation and measurement of signals with up to 15.625 MS/s, which is not possible with the standard image of the RedPitaya. In addition, the software allows to synchronize a cluster of multiple RedPitayas. This project contains the following parts:

  • Alpine Linux image for the RedPitaya
  • FPGA images for the 7010 and 7020
  • Library written in C to interact with the FPGA image on the RedPitaya
  • SCPI Server for accessing the functionality over TCP/IP
  • SCPI Client to access the server

The code is contained in this repository.

License / Terms of Usage

The source code of this project is licensed under the MIT license. This implies that you are free to use, share, and adapt it. However, please give appropriate credit by citing the project.

Contact

If you have problems using the software, find mistakes, or have general questions please use the issue tracker to contact us.

Contributors

Credit

This package is partly based on work of Koheron [1] and Pavel Demin [2]

[1] https://www.koheron.com/blog/2016/11/29/red-pitaya-cluster [2] https://github.com/pavel-demin/red-pitaya-notes

+Home · RP DAQ Server

RedPitayaDAQServer

Advanced DAQ Tools for the RedPitaya (STEMlab 125-14)

Introduction

This project contains software to be used with the STEMlab 125-14 device from RedPitaya. It allows for continuous generation and measurement of signals with up to 15.625 MS/s, which is not possible with the standard image of the RedPitaya. In addition, the software allows to synchronize a cluster of multiple RedPitayas. This project contains the following parts:

  • Alpine Linux image for the RedPitaya
  • FPGA images for the 7010 and 7020
  • Library written in C to interact with the FPGA image on the RedPitaya
  • SCPI Server for accessing the functionality over TCP/IP
  • SCPI Client to access the server

The code is contained in this repository.

License / Terms of Usage

The source code of this project is licensed under the MIT license. This implies that you are free to use, share, and adapt it. However, please give appropriate credit by citing the project.

Contact

If you have problems using the software, find mistakes, or have general questions please use the issue tracker to contact us.

Contributors

Credit

This package is partly based on work of Koheron [1] and Pavel Demin [2]

[1] https://www.koheron.com/blog/2016/11/29/red-pitaya-cluster [2] https://github.com/pavel-demin/red-pitaya-notes

diff --git a/dev/installation.html b/dev/installation.html index 4bfff5e0..dcccce2d 100644 --- a/dev/installation.html +++ b/dev/installation.html @@ -1,5 +1,5 @@ -Installation · RP DAQ Server

Installation

The RedPitayaDAQServer project uses a custom RedPitaya image that was derived from the red-pitaya-notes project. It consists of an Alpine Linux with some development tools installed, as well as the server and the FPGA images. The Linux image reserves the upper 128 MB of main memory for the FPGA, which is used as a buffer for recording the data from the ADCs. The latest releases of the project can be downloaded here.

To install the project on a RedPitaya, format an SD card in FAT32 and enable the bootable flag. On Linux this can be done with:

sudo fdisk /dev/sdb

on the correct device. In the prompt create a new partition with n and change its type to FAT32 with the t command and the hex code b. With the command a the bootable flag can be toggled. Finish formatting with the w command.

Afterwards a file system can be created with:

sudo mkfs -t vfat /dev/sdb1

To finish installing the RedPitaya, simply unzip one of the releases and copy the files into the now empty and formatted SD card.

When the RedPitaya is now booted, the server should start. One can then use a client to connect, at which point the FPGA image is loaded.

The client library provided with the project is not an executable program, but it can be used to implement one. The library encapsulates the communication with the server and implements various optimizations. As the communication with the server is language agnostic one could therefore implement their own client in a different language. The Julia reference client library found in src/client/julia, the SCPI commands and the sections on the signal acquisition and generation are starting points for such a custom client.

Julia Client

To use the provided Julia client library you need to install RedPitayaDAQServer Julia package within Julia. To this end download Julia 1.5 or later and go into the package manager mode by intering ]. Then with

add RedPitayaDAQServer

the latest release of the Julia client is added. To install a different version, please consult the Pkg documentation. The Julia client and the RedPitaya image should be from the same release to avoid errors due to communication protocol changes.

To try out the Julia examples one can either download them from Github directly, clone the whole repository or use the alternative way of installing Julia packages described here.

Updating

The Julia client offers function to automatically update the server and FPGA of a RedPitaya. More on this can be found here. Note that this process deletes all data in the RedPitayaDAQServer folder on the RedPitaya.

Network Connection

The system as provided here should not be made accessible from the internet since it uses a default public password and ssh-key.

One possible configuration to run single or a cluster of RedPitayas is to directly connect them with the measurement computer. In case of a cluster one can use a switch such that only a single network connector is required. In case that the measurement computer has no free ethernet port one can use a USB network adapter.

In order to get this setup running you need to install a dhcp server on the measurement computer, such as dhcpd, and give the measurement computer a static IP address (e.g. 192.168.1.1). This can be installed with

sudo apt-get install isc-dhcp-server

One can then edit the /etc/dhcp/dhcpd.conf configuration file with a setup similar to the following example:

subnet 192.168.1.0 netmask 255.255.255.0 {
+Installation · RP DAQ Server

Installation

The RedPitayaDAQServer project uses a custom RedPitaya image that was derived from the red-pitaya-notes project. It consists of an Alpine Linux with some development tools installed, as well as the server and the FPGA images. The Linux image reserves the upper 128 MB of main memory for the FPGA, which is used as a buffer for recording the data from the ADCs. The latest releases of the project can be downloaded here.

To install the project on a RedPitaya, format an SD card in FAT32 and enable the bootable flag. On Linux this can be done with:

sudo fdisk /dev/sdb

on the correct device. In the prompt create a new partition with n and change its type to FAT32 with the t command and the hex code b. With the command a the bootable flag can be toggled. Finish formatting with the w command.

Afterwards a file system can be created with:

sudo mkfs -t vfat /dev/sdb1

To finish installing the RedPitaya, simply unzip one of the releases and copy the files into the now empty and formatted SD card.

When the RedPitaya is now booted, the server should start. One can then use a client to connect, at which point the FPGA image is loaded.

The client library provided with the project is not an executable program, but it can be used to implement one. The library encapsulates the communication with the server and implements various optimizations. As the communication with the server is language agnostic one could therefore implement their own client in a different language. The Julia reference client library found in src/client/julia, the SCPI commands and the sections on the signal acquisition and generation are starting points for such a custom client.

Julia Client

To use the provided Julia client library you need to install RedPitayaDAQServer Julia package within Julia. To this end download Julia 1.5 or later and go into the package manager mode by intering ]. Then with

add RedPitayaDAQServer

the latest release of the Julia client is added. To install a different version, please consult the Pkg documentation. The Julia client and the RedPitaya image should be from the same release to avoid errors due to communication protocol changes.

To try out the Julia examples one can either download them from Github directly, clone the whole repository or use the alternative way of installing Julia packages described here.

Updating

The Julia client offers function to automatically update the server and FPGA of a RedPitaya. More on this can be found here. Note that this process deletes all data in the RedPitayaDAQServer folder on the RedPitaya.

Network Connection

The system as provided here should not be made accessible from the internet since it uses a default public password and ssh-key.

One possible configuration to run single or a cluster of RedPitayas is to directly connect them with the measurement computer. In case of a cluster one can use a switch such that only a single network connector is required. In case that the measurement computer has no free ethernet port one can use a USB network adapter.

In order to get this setup running you need to install a dhcp server on the measurement computer, such as dhcpd, and give the measurement computer a static IP address (e.g. 192.168.1.1). This can be installed with

sudo apt-get install isc-dhcp-server

One can then edit the /etc/dhcp/dhcpd.conf configuration file with a setup similar to the following example:

subnet 192.168.1.0 netmask 255.255.255.0 {
         interface ????;
 
         #range dynamic-bootp 192.168.1.100 192.168.1.102;
@@ -27,4 +27,4 @@
   xvfb fontconfig libxrender1 libxtst6 libxi6 make \
   bc u-boot-tools device-tree-compiler libncurses5-dev \
   libssl-dev qemu-user-static binfmt-support zip \
-  squashfs-tools dosfstools parted debootstrap zerofree

in order to get the essential tools. Afterwards clone the project with

git clone https://github.com/tknopp/RedPitayaDAQServer

Then switch into this directory. You can build the whole project using

make all

With

make daq_bitfiles

one can build both the 7010 and the 7020 versions of the FPGA image. For different build targets consult the Makefiles.

Note: make has to be run as root if you want to build the Linux image, since chroot requires root privileges.

Server

To build the RedPitaya server connect the RedPitaya to your local network and access the device via ssh:

ssh root@rp-f?????.local

where ????? is the ID that is printed on the RedPitaya. The default password is root. After logging into the RedPitaya go to the folder

/root/apps/

and clone the RedPitayaDAQServer project if it does not exist already:

git clone https://github.com/tknopp/RedPitayaDAQServer

Sometimes you might need to make the file system writable by entering

mount -o remount,rw /dev/mmcblk0p1

Then cd into RedPitayaDAQServer

cd /root/apps/RedPitayaDAQServer

and enter make server. This will compile the library, the server, and some example applications. After you restart the RedPitaya the DAQ server will automatically run and you can access it via TCP.

Developing Julia Client Library

Another option when installing the Julia client is to add the package with the dev command:

dev RedPitayaDAQServer

in the package mode ].

This installs the package in development mode and puts the files into ~/.julia/dev/RedPitayaDAQServer/. There you can the also modify the files, which is handy when trying out the examples. You need to manually git pull if you want to get updates, i.e. Julia will not update developed packages automatically.

+ squashfs-tools dosfstools parted debootstrap zerofree

in order to get the essential tools. Afterwards clone the project with

git clone https://github.com/tknopp/RedPitayaDAQServer

Then switch into this directory. You can build the whole project using

make all

With

make daq_bitfiles

one can build both the 7010 and the 7020 versions of the FPGA image. For different build targets consult the Makefiles.

Note: make has to be run as root if you want to build the Linux image, since chroot requires root privileges.

Server

To build the RedPitaya server connect the RedPitaya to your local network and access the device via ssh:

ssh root@rp-f?????.local

where ????? is the ID that is printed on the RedPitaya. The default password is root. After logging into the RedPitaya go to the folder

/root/apps/

and clone the RedPitayaDAQServer project if it does not exist already:

git clone https://github.com/tknopp/RedPitayaDAQServer

Sometimes you might need to make the file system writable by entering

mount -o remount,rw /dev/mmcblk0p1

Then cd into RedPitayaDAQServer

cd /root/apps/RedPitayaDAQServer

and enter make server. This will compile the library, the server, and some example applications. After you restart the RedPitaya the DAQ server will automatically run and you can access it via TCP.

Developing Julia Client Library

Another option when installing the Julia client is to add the package with the dev command:

dev RedPitayaDAQServer

in the package mode ].

This installs the package in development mode and puts the files into ~/.julia/dev/RedPitayaDAQServer/. There you can the also modify the files, which is handy when trying out the examples. You need to manually git pull if you want to get updates, i.e. Julia will not update developed packages automatically.

diff --git a/dev/objects.inv b/dev/objects.inv index 8b92040b688b42c1143144ce5d76996bd34a62bf..1477da3d3c7b777650373c4450eb8570ea060ecb 100644 GIT binary patch delta 2730 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 delta 2668 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 aZhhTv&J@N(9i{$jdE -SCPI Interface · RP DAQ Server

SCPI Interface

For communication betten the server and the client an SCPI interface with custom commands is used. In the following tables an overview of the available commands and their behaviour is given. The Julia Client library encapsulates these commands into function calls, abstracting their communication details and also combining commands to manage a cluster of RedPitayas at the same time.

As a safe guard the server has different communcation modes and certain commands are only available in certain modes. To give an example, during an acquisition changing the sampling rate would result in unclear behaviour. To stop such a scenario the decimation can only be set in the CONFIGURATION mode and an acquisition can only be triggered in the ACQUISITION mode. The available modes are CONFIGURATION, ACQUISITION and TRANSMISSION (C, A, T, 😺). The former two are set by the client and the latter is set by the server during sample transmission.

After each SCPI command the server replies with true or false on the command socket depending on whether the given command was successfully excecuted. The exception to this rule are the commands which themselves just query values from the server.

ADC Configuration

CommandArgumentsDescriptionModeExample
RP:ADC:DECimationdecimation value [8, ..., n]Set the decimation factor of the base sampling rateCRP:ADC:DEC 8
RP:ADC:DECimation?Return the decimation factorAnyRP:ADC:DEC?
RP:TRIGger:MODetrigger mode (EXTERNAL, INTERNAL)Set the trigger mode, which trigger the RedPitaya listens toCRP:TRIG:MOD INTERNAL
RP:TRIGger:MODe?Return the trigger modeAnyRP:TRIG:MOD?

DAC Configuration

CommandArgumentsDescriptionModeExample
RP:DAC:CHannel#:COMPonent#:SIGnaltypechannel (0, 1), (0, 1, 2, 3), signal type (SINE, TRIANGLE, SAWTOOTH)Set signal type of first component for given channelAnyRP:DAC:CH0:SIG SINE
RP:DAC:CHannel#:COMPonent#:SIGnaltype?channel (0, 1), component (0, 1, 2, 3)Return signal type of first component of given channelAnyRP:DAC:CH1:SIG?
RP:DAC:CHannel#:OFFsetchannel (0, 1), offset [-1, ..., 1]Set offset for given channelAnyRP:DAC:CH1:OFF 0.1
RP:DAC:CHannel#:OFFset?channel (0, 1)Return offset of given channelAnyRP:DAC:CH0:OFF?
RP:DAC:CHannel#:COMPonent#:AMPlitudechannel (0, 1), component (0, 1, 2, 3), amplitude[0, ..., 1]Set amplitude of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:AMPlitude?channel (0, 1), component (0, 1, 2, 3)Return amplitude of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:FREQuencychannel (0, 1), component (0, 1, 2, 3), frequencySet frequency of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:FREQuency?channel (0, 1), component (0, 1, 2, 3)Return frequency of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:PHAsechannel (0, 1), component (0, 1, 2, 3), phaseSet phase of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:PHAse?channel (0, 1), component (0, 1, 2, 3)Return phase of given channel and componentAny
RP:DAC:CHannel#:RAMPingchannel (0, 1), ramping periodSet length of ramping periodC
RP:DAC:CHannel#:RAMPing?channel (0, 1)Get length of ramping periodAny
RP:DAC:CHannel#:RAMPing:ENablechannel (0, 1) ramping status (OFF, ON)Enable/disable ramping factor on given channelC
RP:DAC:CHannel#:RAMPing:ENable?channel (0, 1)Return enable ramping status of given channelAny
RP:DAC:CHannel#:RAMPing:DoWNchannel (0, 1), ramp down status (OFF, ON)Enable/disable ramp down flag for given channelA, T
RP:DAC:CHannel#:RAMPing:DoWN?channel (0, 1)Get ramp down flag for given channelAny
RP:DAC:RAMPing:STATus?Return the ramping statusAny

Sequence Configuration

The server maintains three acquisition sequences. When the server is in theCONFIGURATION mode a client can configure a set of three sequences. If the current configured sequences fits the desired signal, a client can intstruct the server to set the sequences. This moves the configuration sequences to the acquisition sequences and writes the first values to the FPGA buffer.

During an active trigger the buffer is periodically updated by the server. If the server recognizes the end of a sequence, it sets the amplitudes of the waveform components to 0.

CommandArgumentsDescriptionModeExample
RP:DAC:SEQ:CLocKdividerdividerSet the clock divider with which the sequence advancesC
RP:DAC:SEQ:CLocKdivider?Return the clock dividerAny
RP:DAC:SEQ:SAMPlesperstepsamples per stepSet the clock divider such that the sequence advances every given number of samples.C
RP:DAC:SEQ:SAMPlesperstep?Return the number of samples per stepAny
RP:DAC:SEQ:CHannumChan (1, 2, 3, 4)Set the number of sequence channelC
RP:DAC:SEQ:CHan?Return the number of sequence channel
RP:DAC:SEQ:LUTsteps, repetitionsInstruct the server to receive a LUT over the data socketCRP:DAC:SEQ:LUT 10,2
RP:DAC:SEQ:LUT:ENaBleInstruct the server to receive an enable LUT over the data socket of the same shape as the regular LUTC
RP:DAC:SEQ:LUT:UPsteps, repetitionsInstruct the server to receive a ramp up LUT over the data socketC
RP:DAC:SEQ:LUT:DOWNsteps, repetitionsInstruct the server to receive a ramp down LUT over the data socketC
RP:DAC:SEQ:CLEARClear the set sequence values from the FPGA bufferC
RP:DAC:SEQ:SETSet the current configured sequence as the acquisition sequenceC

Acquisition and Transmission

CommandArgumentsDescriptionModeExample
RP:TRIGgertrigger status (OFF, ON)Set the internal trigger statusARP:TRIG ON
RP:TRIGger?Return the trigger statusAnyRP:TRIG?
RP:TRIGger:ALiVekeep alive status (OFF, ON)Set the keep alive bypassARP:TRIG:ALV OFF
RP:TRIGger:ALiVe?Return the keep alive statusAnyRP:TRIG:ALV?
RP:ADC:WP:CURRent?Return the current writepointerA, TRP:ADC:WP?
RP:ADC:DATa?readpointer, number of samplesTransmit number of samples from the buffer component of the readpointer over the data socket. Return true on the command socket if transmission is started.ARP:ADC:DATa? 400,1024
RP:ADC:DATa:PIPElined?readpointer, number of samples, chunksizeTransmit number of samples from the readpointer on in chunks of chunksize over the data socket. After every chunk status and performance data is transmitted over the data socket. Return true if pipeline was started.ARP:ADC:DAT:PIPE? 400,1024,128
RP:STATus?Transmit status as one byte with flags from lower bits: overwritten, corrupted, lost steps, master trigger, sequence activeAnyRP:STAT?
RP:STATus:OVERwritten?Transmit overwritten flagAnyRP:STAT:OVER?
RP:STATus:CORRupted?Transmit corrupted flagAnyRP:STAT:CORR?
RP:STATus:LOSTSteps?Transmit lost steps flagAnyRP:STAT:LOSTS?
RP:PERF?Transmit ADC and DAC performance dataAnyRP:PERF?

Calibration

CommandArgumentsDescriptionModeExample
RP:CALib:ADC:CHannel#:OFFsetchannel (0, 1), offsetStore the ADC offset value for given channel in EEPROMCRP:CAL:ADC:CH0:OFF 0.2
RP:CALib:ADC:CHannel#:OFFset?channel (0, 1)Return the ADC offset value for given channel from EEPROMAnyRP:CAL:ADC:CH1:OFF?
RP:CALib:ADC:CHannel#:SCAlechannel (0, 1), scaleStore the ADC scale value for given channel in EEPROMCRP:CAL:ADC:CH1:SCA 1.0
RP:CALib:ADC:CHannel#:SCAle?channel (0, 1)Return the ADC scale value for given channel from EEPROMAnyRP:CAL:ADC:CH1:SCA?
RP:CALib:DAC:CHannel#:OFFsetchannel (0, 1), offsetStore the DAC offset value for given channel in EEPROMCRP:CAL:DAC:CH0:OFF 0.2
RP:CALib:DAC:CHannel#:OFFset?channel (0, 1)Return the DAC offset value for given channel from EEPROMAnyRP:CAL:DAC:CH1:OFF?
RP:CALib:DAC:CHannel#:SCAlechannel (0, 1), scaleStore the DAC scale value for given channel in EEPROMCRP:CAL:DAC:CH1:SCA 1.0
RP:CALib:DAC:CHannel#:SCAle?channel (0, 1)Return the DAC scale value for given channel from EEPROMAnyRP:CAL:DAC:CH1:SCA?

DIO

CommandArgumentsDescriptionExample
RP:DIO:DIRidentifier of pin, direction (IN/OUT)Set the direction of the DIORP:DIO:DIR DIO7_P,IN
RP:DIOidentifier of pin, value (0/1)Set the output of the DIORP:DIO DIO7_P,1
RP:DIO?identifier of pinGet the input of the DIORP:DIO? DIO7_P
+SCPI Interface · RP DAQ Server

SCPI Interface

For communication betten the server and the client an SCPI interface with custom commands is used. In the following tables an overview of the available commands and their behaviour is given. The Julia Client library encapsulates these commands into function calls, abstracting their communication details and also combining commands to manage a cluster of RedPitayas at the same time.

As a safe guard the server has different communcation modes and certain commands are only available in certain modes. To give an example, during an acquisition changing the sampling rate would result in unclear behaviour. To stop such a scenario the decimation can only be set in the CONFIGURATION mode and an acquisition can only be triggered in the ACQUISITION mode. The available modes are CONFIGURATION, ACQUISITION and TRANSMISSION (C, A, T, 😺). The former two are set by the client and the latter is set by the server during sample transmission.

After each SCPI command the server replies with true or false on the command socket depending on whether the given command was successfully excecuted. The exception to this rule are the commands which themselves just query values from the server.

ADC Configuration

CommandArgumentsDescriptionModeExample
RP:ADC:DECimationdecimation value [8, ..., n]Set the decimation factor of the base sampling rateCRP:ADC:DEC 8
RP:ADC:DECimation?Return the decimation factorAnyRP:ADC:DEC?
RP:TRIGger:MODetrigger mode (EXTERNAL, INTERNAL)Set the trigger mode, which trigger the RedPitaya listens toCRP:TRIG:MOD INTERNAL
RP:TRIGger:MODe?Return the trigger modeAnyRP:TRIG:MOD?

DAC Configuration

CommandArgumentsDescriptionModeExample
RP:DAC:CHannel#:COMPonent#:SIGnaltypechannel (0, 1), (0, 1, 2, 3), signal type (SINE, TRIANGLE, SAWTOOTH)Set signal type of first component for given channelAnyRP:DAC:CH0:SIG SINE
RP:DAC:CHannel#:COMPonent#:SIGnaltype?channel (0, 1), component (0, 1, 2, 3)Return signal type of first component of given channelAnyRP:DAC:CH1:SIG?
RP:DAC:CHannel#:OFFsetchannel (0, 1), offset [-1, ..., 1]Set offset for given channelAnyRP:DAC:CH1:OFF 0.1
RP:DAC:CHannel#:OFFset?channel (0, 1)Return offset of given channelAnyRP:DAC:CH0:OFF?
RP:DAC:CHannel#:COMPonent#:AMPlitudechannel (0, 1), component (0, 1, 2, 3), amplitude[0, ..., 1]Set amplitude of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:AMPlitude?channel (0, 1), component (0, 1, 2, 3)Return amplitude of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:FREQuencychannel (0, 1), component (0, 1, 2, 3), frequencySet frequency of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:FREQuency?channel (0, 1), component (0, 1, 2, 3)Return frequency of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:PHAsechannel (0, 1), component (0, 1, 2, 3), phaseSet phase of given channel and componentAny
RP:DAC:CHannel#:COMPonent#:PHAse?channel (0, 1), component (0, 1, 2, 3)Return phase of given channel and componentAny
RP:DAC:CHannel#:RAMPingchannel (0, 1), ramping periodSet length of ramping periodC
RP:DAC:CHannel#:RAMPing?channel (0, 1)Get length of ramping periodAny
RP:DAC:CHannel#:RAMPing:ENablechannel (0, 1) ramping status (OFF, ON)Enable/disable ramping factor on given channelC
RP:DAC:CHannel#:RAMPing:ENable?channel (0, 1)Return enable ramping status of given channelAny
RP:DAC:CHannel#:RAMPing:DoWNchannel (0, 1), ramp down status (OFF, ON)Enable/disable ramp down flag for given channelA, T
RP:DAC:CHannel#:RAMPing:DoWN?channel (0, 1)Get ramp down flag for given channelAny
RP:DAC:RAMPing:STATus?Return the ramping statusAny

Sequence Configuration

The server maintains three acquisition sequences. When the server is in theCONFIGURATION mode a client can configure a set of three sequences. If the current configured sequences fits the desired signal, a client can intstruct the server to set the sequences. This moves the configuration sequences to the acquisition sequences and writes the first values to the FPGA buffer.

During an active trigger the buffer is periodically updated by the server. If the server recognizes the end of a sequence, it sets the amplitudes of the waveform components to 0.

CommandArgumentsDescriptionModeExample
RP:DAC:SEQ:CLocKdividerdividerSet the clock divider with which the sequence advancesC
RP:DAC:SEQ:CLocKdivider?Return the clock dividerAny
RP:DAC:SEQ:SAMPlesperstepsamples per stepSet the clock divider such that the sequence advances every given number of samples.C
RP:DAC:SEQ:SAMPlesperstep?Return the number of samples per stepAny
RP:DAC:SEQ:CHannumChan (1, 2, 3, 4)Set the number of sequence channelC
RP:DAC:SEQ:CHan?Return the number of sequence channel
RP:DAC:SEQ:LUTsteps, repetitionsInstruct the server to receive a LUT over the data socketCRP:DAC:SEQ:LUT 10,2
RP:DAC:SEQ:LUT:ENaBleInstruct the server to receive an enable LUT over the data socket of the same shape as the regular LUTC
RP:DAC:SEQ:LUT:ReSYNCInstruct the server to receive a resync LUT over the data socket of the same shape as the regular LUTC
RP:DAC:SEQ:LUT:UPsteps, repetitionsInstruct the server to receive a ramp up LUT over the data socketC
RP:DAC:SEQ:LUT:DOWNsteps, repetitionsInstruct the server to receive a ramp down LUT over the data socketC
RP:DAC:SEQ:CLEARClear the set sequence values from the FPGA bufferC
RP:DAC:SEQ:SETSet the current configured sequence as the acquisition sequenceC

Acquisition and Transmission

CommandArgumentsDescriptionModeExample
RP:TRIGgertrigger status (OFF, ON)Set the internal trigger statusARP:TRIG ON
RP:TRIGger?Return the trigger statusAnyRP:TRIG?
RP:TRIGger:ALiVekeep alive status (OFF, ON)Set the keep alive bypassARP:TRIG:ALV OFF
RP:TRIGger:ALiVe?Return the keep alive statusAnyRP:TRIG:ALV?
RP:ADC:WP:CURRent?Return the current writepointerA, TRP:ADC:WP?
RP:ADC:DATa?readpointer, number of samplesTransmit number of samples from the buffer component of the readpointer over the data socket. Return true on the command socket if transmission is started.ARP:ADC:DATa? 400,1024
RP:ADC:DATa:PIPElined?readpointer, number of samples, chunksizeTransmit number of samples from the readpointer on in chunks of chunksize over the data socket. After every chunk status and performance data is transmitted over the data socket. Return true if pipeline was started.ARP:ADC:DAT:PIPE? 400,1024,128
RP:STATus?Transmit status as one byte with flags from lower bits: overwritten, corrupted, lost steps, master trigger, sequence activeAnyRP:STAT?
RP:STATus:OVERwritten?Transmit overwritten flagAnyRP:STAT:OVER?
RP:STATus:CORRupted?Transmit corrupted flagAnyRP:STAT:CORR?
RP:STATus:LOSTSteps?Transmit lost steps flagAnyRP:STAT:LOSTS?
RP:PERF?Transmit ADC and DAC performance dataAnyRP:PERF?

Calibration

CommandArgumentsDescriptionModeExample
RP:CALib:ADC:CHannel#:OFFsetchannel (0, 1), offsetStore the ADC offset value for given channel in EEPROMCRP:CAL:ADC:CH0:OFF 0.2
RP:CALib:ADC:CHannel#:OFFset?channel (0, 1)Return the ADC offset value for given channel from EEPROMAnyRP:CAL:ADC:CH1:OFF?
RP:CALib:ADC:CHannel#:SCAlechannel (0, 1), scaleStore the ADC scale value for given channel in EEPROMCRP:CAL:ADC:CH1:SCA 1.0
RP:CALib:ADC:CHannel#:SCAle?channel (0, 1)Return the ADC scale value for given channel from EEPROMAnyRP:CAL:ADC:CH1:SCA?
RP:CALib:DAC:CHannel#:OFFsetchannel (0, 1), offsetStore the DAC offset value for given channel in EEPROMCRP:CAL:DAC:CH0:OFF 0.2
RP:CALib:DAC:CHannel#:OFFset?channel (0, 1)Return the DAC offset value for given channel from EEPROMAnyRP:CAL:DAC:CH1:OFF?
RP:CALib:DAC:CHannel#:SCAlechannel (0, 1), scaleStore the DAC scale value for given channel in EEPROMCRP:CAL:DAC:CH1:SCA 1.0
RP:CALib:DAC:CHannel#:SCAle?channel (0, 1)Return the DAC scale value for given channel from EEPROMAnyRP:CAL:DAC:CH1:SCA?

DIO

CommandArgumentsDescriptionExample
RP:DIO:DIRidentifier of pin, direction (IN/OUT)Set the direction of the DIORP:DIO:DIR DIO7_P,IN
RP:DIOidentifier of pin, value (0/1)Set the output of the DIORP:DIO DIO7_P,1
RP:DIO?identifier of pinGet the input of the DIORP:DIO? DIO7_P
diff --git a/dev/search_index.js b/dev/search_index.js index 3c68883d..230206bc 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"generation.html#Signal-Generation","page":"Signal Generation","title":"Signal Generation","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Once the acquisition is triggered, each RedPitaya also starts producing signals on their output channels. Each RedPitaya features six such channels, two of those are the 16-bit DAC channel and four of those are digital pins using PDM, see Connections. The output signals are composed of three parts: parameterized waveforms W_i(t), an offset o_i and repeating arbitrary LUT tables. The latter are called sequences seq_i(t). The resulting signal of the DAC channel can be described as: ","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"S_i(t) = seq_i(t) + o_i + W_i(t)","category":"page"},{"location":"generation.html#Waveforms","page":"Signal Generation","title":"Waveforms","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Each of the 16-bit DAC channel can output a compositve waveform with four components. Each component can be parametrized by its amplitude a_ij, frequency f_ij and phase varphi_ij, which can all be changed via SCPI commands. Furthermore, each component also offers different waveforms w_ij(sine, triangle, sawtooth):","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"W_i(t) = sum_j=1^4a_ij w_ij(2pi f_ijt + varphi_i j)","category":"page"},{"location":"generation.html#Ramping","page":"Signal Generation","title":"Ramping","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"The signals output on the DAC channel can also be multiplied with an increasing/decreasing ramping factor r(t). Ramping and the ramping duration can be enabled and set on a per channel basis. The increasing factor starts from 0 and goes to 1 from the acquisition start on. The decreasing factor goes from 1 to 0.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"S_i(t) = r(t)S(t)","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"The ramp down has to be started either by a SCPI command or by a flag from a sequence. Disabling the acquisition trigger removes the ramp down flag, but not the flag that enables ramping itself.","category":"page"},{"location":"generation.html#Sequences","page":"Signal Generation","title":"Sequences","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"The FPGA image features a LUT containing values for all output channels. This LUT is treated as a ring-buffer through which the image iterates and outputs the values on their respective channel. The image can be configured to increment its LUT access every n samples. One period of a value is also called a step. A sequence is a series of steps and the number of times this series is to be repeated.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"As the LUT used by the FPGA image is small in comparison with the main memory and in order to support longer series of steps, the server itselfs maintains a sequence in its main memory and periodically reads the next steps from its sequence and writes them to the LUT of the image.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Comparable to the sample transmission of the acquisition, this updating of the LUT is also a process with timing uncertainty as it is affected by the scheduling and execution of the RedPitayas CPU. While during the sample transmission samples could be lost because they were overwritten, in the signal generation wrong signals could be output because the server was too slow in updating the values. Here, the server tracks similar performance metrics and also features a status flag lostSteps for exactly this case. In its current implementation a safe step rate is at 12 kHz.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Sequences and their steps also have additional features. A step can be marked such that during its duration the signal is set to 0. Furthermore, a step can be marked such that it triggers the ramp down. To make this easier to manage the server actually manages three sequences, that can be set individually: A ramp up, regular and ramp down sequence. The ramp up sequence is moved to the FPGA LUT at the acquisition start, followed by the regular sequence. Afterwards the ramp down sequence is started and during its execution the ramp down flag is set.","category":"page"},{"location":"generation.html#Calibration","page":"Signal Generation","title":"Calibration","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Similar to the signal acquisition, there are also calibration scale c_i scale and offset c_i offset values for the signal generation. These are stored in the EEPROM of the RedPitaya and can be updated by a client. The calibration values are always applied, even when the master trigger is off.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Thus the total signal can be described as:","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"S_i(t) = c_i scale S_i(t) + c_i offset","category":"page"},{"location":"connections.html#Connections","page":"Connections","title":"Connections","text":"","category":"section"},{"location":"connections.html","page":"Connections","title":"Connections","text":"An overview of the extension connectors (see also here) is given in the following image","category":"page"},{"location":"connections.html","page":"Connections","title":"Connections","text":"(Image: Connectors)","category":"page"},{"location":"connections.html","page":"Connections","title":"Connections","text":"The project uses most but not all connections that are used in the original RedPitaya image. From the connector E2 only the analog inputs and outputs are used. From the connector E1 several pins are reserved for the following purposes:","category":"page"},{"location":"connections.html","page":"Connections","title":"Connections","text":"DIO0_P for the ADC and DAC trigger. Connect it with the master's DIO5_P to distribute the trigger signal to all RedPitayas in a cluster. As long as the input is high, the DACs and ADCs are running.\nDIO1_P is the input for the watchdog (see configuration register section for further details)\nDIO2_P is used to acknowledge a received watchdog signal.\nDIO3_P can be set to high, to stop all DACs instantly.\nDIO4_P outputs a high for 10 ms after a 100 ms pause on low to provide an alive signal.\nDIO5_P can be set to high via the configuration register to provide the mutual trigger signal.\nDIO7_P, DIO7_N, DIO6_P, DIO6_N, DIO5_N, DIO4_N, DIO3_N, DIO2_N can be used as arbitrary outputs set via the server.\nDIO0_N and DIO1_N are used for the clock selection in a cluster.","category":"page"},{"location":"examples/cluster.html#Cluster-Example","page":"Cluster","title":"Cluster Example","text":"","category":"section"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"In this example we generate and acquire sine waves, similar to to the first example. However, this time we use two RedPitayas sychronized in a cluster. The example will create a sine wave on the first DAC channel of the first RedPitaya and a phase shifted sine wave on the first channel of the second RedPitaya. To run this example connect the RedPitayas in the following way:","category":"page"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"Note that while the example only plots the first channel of the RedPitaya, both channels are transmitted to the clients.","category":"page"},{"location":"examples/cluster.html#Julia-Client","page":"Cluster","title":"Julia Client","text":"","category":"section"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/cluster.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/sequenceMultiChannel.html#Sequence-Multi-Channel-and-Waveform-Enable-Example","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable Example","text":"","category":"section"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"This examples combines concepts from the three examples and additionally uses the signal enable feature of the sequences. This example uses both DAC and ADC channels of the RedPitaya. On the first DAC channel we output a sine waveform together with a climbing sequence. On the second channel we output just a sequence with a constant value and no waveforms at all. The signal enable flags of the sequences are set in such a way, that the two channels alternate being enabled with each step.","category":"page"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/sequenceMultiChannel.html#Julia-Client","page":"Sequence Multi-Channel and Waveform Enable","title":"Julia Client","text":"","category":"section"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/sequence.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"(Image: Simple Example Results)","category":"page"},{"location":"installation.html#Installation","page":"Installation","title":"Installation","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The RedPitayaDAQServer project uses a custom RedPitaya image that was derived from the red-pitaya-notes project. It consists of an Alpine Linux with some development tools installed, as well as the server and the FPGA images. The Linux image reserves the upper 128 MB of main memory for the FPGA, which is used as a buffer for recording the data from the ADCs. The latest releases of the project can be downloaded here.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To install the project on a RedPitaya, format an SD card in FAT32 and enable the bootable flag. On Linux this can be done with:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"sudo fdisk /dev/sdb","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"on the correct device. In the prompt create a new partition with n and change its type to FAT32 with the t command and the hex code b. With the command a the bootable flag can be toggled. Finish formatting with the w command.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Afterwards a file system can be created with:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"sudo mkfs -t vfat /dev/sdb1","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To finish installing the RedPitaya, simply unzip one of the releases and copy the files into the now empty and formatted SD card.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"When the RedPitaya is now booted, the server should start. One can then use a client to connect, at which point the FPGA image is loaded. ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The client library provided with the project is not an executable program, but it can be used to implement one. The library encapsulates the communication with the server and implements various optimizations. As the communication with the server is language agnostic one could therefore implement their own client in a different language. The Julia reference client library found in src/client/julia, the SCPI commands and the sections on the signal acquisition and generation are starting points for such a custom client.","category":"page"},{"location":"installation.html#Julia-Client","page":"Installation","title":"Julia Client","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To use the provided Julia client library you need to install RedPitayaDAQServer Julia package within Julia. To this end download Julia 1.5 or later and go into the package manager mode by intering ]. Then with ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"add RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"the latest release of the Julia client is added. To install a different version, please consult the Pkg documentation. The Julia client and the RedPitaya image should be from the same release to avoid errors due to communication protocol changes.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To try out the Julia examples one can either download them from Github directly, clone the whole repository or use the alternative way of installing Julia packages described here.","category":"page"},{"location":"installation.html#Updating","page":"Installation","title":"Updating","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The Julia client offers function to automatically update the server and FPGA of a RedPitaya. More on this can be found here. Note that this process deletes all data in the RedPitayaDAQServer folder on the RedPitaya.","category":"page"},{"location":"installation.html#Network-Connection","page":"Installation","title":"Network Connection","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The system as provided here should not be made accessible from the internet since it uses a default public password and ssh-key.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"One possible configuration to run single or a cluster of RedPitayas is to directly connect them with the measurement computer. In case of a cluster one can use a switch such that only a single network connector is required. In case that the measurement computer has no free ethernet port one can use a USB network adapter.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"In order to get this setup running you need to install a dhcp server on the measurement computer, such as dhcpd, and give the measurement computer a static IP address (e.g. 192.168.1.1). This can be installed with ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"sudo apt-get install isc-dhcp-server","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"One can then edit the /etc/dhcp/dhcpd.conf configuration file with a setup similar to the following example:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"subnet 192.168.1.0 netmask 255.255.255.0 {\n interface ????;\n\n #range dynamic-bootp 192.168.1.100 192.168.1.102;\n option broadcast-address 192.168.1.255;\n option routers 192.168.1.1;\n\n host rp1 {\n hardware ethernet 00:26:32:F0:70:83;\n fixed-address 192.168.1.100;\n }\n\n host rp2 {\n hardware ethernet 00:26:32:F0:92:97;\n fixed-address 192.168.1.101;\n }\n\n host rp3 {\n hardware ethernet 00:26:32:F0:61:F5;\n fixed-address 192.168.1.102;\n }\n}","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The example defines three fixed IP addresses for three RedPitayas based on their MAC addresses. You may also need to specify DNS servers or alternatively create a network with a range of IPs (e.g. 192.168.1.100-105).","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Afterwards with","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"service isc-dhcp-server start","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"or ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"service isc-dhcp-server restart ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"one can start the DHCP service and should see the RedPitayas using the DHCP protocol to get their IP addresses with:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"journalctl -f -u isc-dhcp-server","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"This displays the latest log messages of the DHCP service. ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"If you need internet at your RedPitaya you need to configure the firewall to allow this using iptables. In this repository there is in the scripts directory a script rp-internet.sh where you need to change the network adapters to allow traffic going from the internet network adapter to the RedPitaya network adapter.","category":"page"},{"location":"installation.html#Building-Components","page":"Installation","title":"Building Components","text":"","category":"section"},{"location":"installation.html#Linux-Image-and-FPGA-Images","page":"Installation","title":"Linux Image and FPGA Images","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"If you want to build the Linux image or the FPGA bitfiles yourself, you can install Xilinx Vitis and Vivado (2021.2) in an Ubuntu environment (bare metal or virtual machine). Then run","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"sudo apt-get update\n\nsudo apt-get --no-install-recommends install \\\n build-essential bison flex git curl ca-certificates sudo \\\n xvfb fontconfig libxrender1 libxtst6 libxi6 make \\\n bc u-boot-tools device-tree-compiler libncurses5-dev \\\n libssl-dev qemu-user-static binfmt-support zip \\\n squashfs-tools dosfstools parted debootstrap zerofree","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"in order to get the essential tools. Afterwards clone the project with","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"git clone https://github.com/tknopp/RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Then switch into this directory. You can build the whole project using","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"make all","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"With ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"make daq_bitfiles","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"one can build both the 7010 and the 7020 versions of the FPGA image. For different build targets consult the Makefiles.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Note: make has to be run as root if you want to build the Linux image, since chroot requires root privileges.","category":"page"},{"location":"installation.html#Server","page":"Installation","title":"Server","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To build the RedPitaya server connect the RedPitaya to your local network and access the device via ssh:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"ssh root@rp-f?????.local","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"where ????? is the ID that is printed on the RedPitaya. The default password is root. After logging into the RedPitaya go to the folder","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"/root/apps/","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"and clone the RedPitayaDAQServer project if it does not exist already:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"git clone https://github.com/tknopp/RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Sometimes you might need to make the file system writable by entering","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"mount -o remount,rw /dev/mmcblk0p1","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Then cd into RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"cd /root/apps/RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"and enter make server. This will compile the library, the server, and some example applications. After you restart the RedPitaya the DAQ server will automatically run and you can access it via TCP.","category":"page"},{"location":"installation.html#Developing-Julia-Client-Library","page":"Installation","title":"Developing Julia Client Library","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Another option when installing the Julia client is to add the package with the dev command:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"dev RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"in the package mode ].","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"This installs the package in development mode and puts the files into ~/.julia/dev/RedPitayaDAQServer/. There you can the also modify the files, which is handy when trying out the examples. You need to manually git pull if you want to get updates, i.e. Julia will not update developed packages automatically.","category":"page"},{"location":"examples/waveforms.html#Waveforms-Example","page":"Waveforms","title":"Waveforms Example","text":"","category":"section"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"In this example we generate different signals with a base frequency of 10 kHz on DAC channel 1 and receive the same signals on the ADC channel 1. To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.","category":"page"},{"location":"examples/waveforms.html#Julia-Client","page":"Waveforms","title":"Julia Client","text":"","category":"section"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/waveforms.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"(Image: Simple Example Results)","category":"page"},{"location":"examples/batch.html#Batch-Example","page":"Batch","title":"Batch Example","text":"","category":"section"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"In this example we recreate the first example using the batch functionality offered by the Julia client. Note that all commands are still executed in order from the RedPitayas perspective, only the client communication is more efficient within a batch.","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.","category":"page"},{"location":"examples/batch.html#Julia-Client","page":"Batch","title":"Julia Client","text":"","category":"section"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/batch.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"(Image: Batch Example Results)","category":"page"},{"location":"examples/simple.html#Simple-Example","page":"Simple","title":"Simple Example","text":"","category":"section"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"In the first example we connect to a single RedPitaya and generate a sinus signal of frequency 10 kHz on DAC channel 1 and receive the same signal on the ADC channel 1. To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"Note that while the example only plots the first channel of the RedPitaya, both channels are transmitted to the clients.","category":"page"},{"location":"examples/simple.html#Julia-Client","page":"Simple","title":"Julia Client","text":"","category":"section"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"This and all other examples are located in the examples directory.","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/simple.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"(Image: Simple Example Results)","category":"page"},{"location":"examples/simple.html#Python-Client","page":"Simple","title":"Python Client","text":"","category":"section"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"This example is located in the python examples directory. The python examples use a very reduced Python client class that is located here. The Python client only wraps the low-level socket communication.","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"using Markdown\nMarkdown.parse(\"\"\"\n```python\n$(open(f->read(f, String), \"../../../src/examples/python/simple.py\"))\n```\n\"\"\")","category":"page"},{"location":"architecture.html#Architecture","page":"Architecture","title":"Architecture","text":"","category":"section"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The RedPitayaDAQServer project is implemented as a distributed system in which one client connects to a cluster of RedPitaya boards. The project has four software components:","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"FPGA image running on the RedPitayas FPGA\nC library encapsulating access to the FPGA image\nServer running on the CPU of the RedPitayas\nClient Julia reference library ","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The FPGA image is responsible for generating and acquiring synchronized out- and input signals. The server acts as an intermediary to the FPGA over a TCP/IP connection, which allows remote clients to configure the FPGA image and retrieve samples. Furthermore, the server also maintains a thread that takes part in signal generation.","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The Julia client library can be used to implement a data acquisition client application, which controls a (cluster of) RedPitaya(s). This Julia library acts as a reference, but in principle it is possible to write clients in any programming language, as the communication is language agnostic. In the example directory we provide a rudimentary Python client that allows to perform a simple data acquisition experiment.","category":"page"},{"location":"architecture.html#Communication","page":"Architecture","title":"Communication","text":"","category":"section"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The various components of the distributed system communicate over different interfaces. Communication within a RedPitaya is based on memory-mapped I/O, while communication between the server and a client is based on SCPI commands over a TCP/IP connection, usually over Ethernet. Lastly communication between RedPitayas is limited to signals distributed over cables as described in Cluster.","category":"page"},{"location":"architecture.html#FPGA-and-CPU","page":"Architecture","title":"FPGA and CPU","text":"","category":"section"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The FPGA image is directly connected to certain memory regions that can be memory mapped on the CPU side of the RedPitaya. Both the CPU and the FPGA image access the reserved main memory region as a sample buffer. The C library rp-daq-lib, which is located under src/lib/ in the project repository, encapsulates these memory accesses into a convenient C library. It is possible to use this C library directly on the RedPitaya when no communication with the host system is required, i.e. if one wants to write the acquired data into a file. When making changes to the FPGA image one may need to adapt the rp-daq-lib C library.","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The server itself uses the rp-daq-lib library to interface with the FPGA image.","category":"page"},{"location":"architecture.html#Client-and-Server","page":"Architecture","title":"Client and Server","text":"","category":"section"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The server on each RedPitaya has two TCP sockets to which a client needs to connect. The first is the command socket on port 5025 and the second is the data socket on port 5026. Over the former, a client can send SCPI commands to the server and receive replies, while the latter is used for sending binary data such as the samples acquired by the ADCs.","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"SCPI commands are ASCII strings, such as RP:ADC:DECimation, which the server translates into C function calls. As an example these calls could invoke a function of the rp-daq-lib library to set the decimation of the sampling rate or instruct the server to transmit data over the data socket. A list of the available SCPI commands can be found here.","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"At any point a server is only connected to one client and establishing a new connection stops any current signal generation and acquisition.","category":"page"},{"location":"fpga.html#FPGA-Development","page":"FPGA Development","title":"FPGA Development","text":"","category":"section"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"There may be needs to change the FPGA image. The following explains how this can be done.","category":"page"},{"location":"fpga.html#Preparation","page":"FPGA Development","title":"Preparation","text":"","category":"section"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"If you want to make changes to the FPGA design, you need to install Vivado 2021.2. More infos for setting up a development machine we refer to the following resource and here.","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"After following the installation steps, you need to clone the repository into a directory of your choice and then regenerate the IP cores and the project by running","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"make daq_bitfiles.","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"Afterwards you can start Vivado and open the recreated project in ./build/fpga//firmware/RedPitayaDAQServer.xpr. Apply the changes you need and then create the bitfile by using 'Flow -> Generate Bitstream'. This runs the synthesis and implementation steps and output the Bitfile to ./build/fpga/firmware/RedPitayaDAQServer.runs/impl_1/system_wrapper.bit.","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"After creating the respective bitfile you need to copy it to your Red Pitayas. You can use","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"scp ./build/fpga//firmware/RedPitayaDAQServer.runs/impl_1/system_wrapper.bit root@:/root/RedPitayaDAQServer/bitfiles/daq_.bit","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"for this. Set your IP and FPGA version accordingly. Another option is to fully regenerate the Linux image with make all and copy it to the SD card.","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"Since using git with Vivado can be annoying here are some hints how you can make your changes ready for git:","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"If you only changed some stuff in the blockdesign, you just have to export the blockdesign to ./src/fpga/bd/bd.tcl by using 'File -> Export -> Export Block Design' in Vivado.\nChanges to the project settings have to be done in ./src/fpga/build.tcl in order to not lose the ability to recreate your changed project.\nFor your own IP cores, just create a new directory in ./src/fpga/cores and copy and adapt the core_config.tcl of another core. Afterwards re-run make cores.","category":"page"},{"location":"acquisition.html#Data-Acquisition","page":"Data Acquisition","title":"Data Acquisition","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The data acquisition of the RedPitayaDAQServer project is based on two data flows to and from the upper 128 MB of the RedPitaya memory. This memory region acts as a ring buffer for the acquired samples and can be queried by clients using SCPI commands.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"Signal acquisition within a cluster is based on a shared clock and trigger signal distributed via cables between the RedPitayas. Once triggered, all FPGAs continuously write the samples from their ADC channel to the sample ring-buffer with each clock tick. Both ADC channels on a RedPitaya are written to the buffer at the same time. The 14-bit values of the ADCs are converted to 16-bit signed integer samples and then concatenated into one 32-bit value, which is then written to the buffer. The sampling rate of the system can be adjusted by setting a decimation parameter and the decimation itself is realized with a CIC filter.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"Internally, the FPGA keeps track of a 64-bit writepointer register pointing into the ring-buffer and increments this value with each new sample pair. Additionally, the writepointer also counts the number of buffer overflows. As the size of the buffer region is a power of two, these two components of the writepointer can be interpreted as one 64-bit number counting the samples from acquisition start. For the 128 MB buffer, this means that the lower 25 bits of the writepointer are the buffer location and the remaining bits are the overflow counter.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"As the writepointer is reset and incremented based on a shared clock and trigger signal, it is synchronized across all FPGA images in a cluster. The logic implemented with the reprogrammable hardware is also the only logic of the RedPitayaDAQServer with predictable timing behaviour. All other components of the system implement their (timing related) logic in reference to the current writepointer values. With a known sampling rate, the writepointer can also be seen as the clock of the server and client components.","category":"page"},{"location":"acquisition.html#Sample-Transmission","page":"Data Acquisition","title":"Sample Transmission","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"To retrieve samples from the server a client can supply a similar pointer, called readpointer, together with the number of samples to retrieve. The server then extracts the buffer position from the readpointer and transmits the requested amount of samples over the data socket. This transmission happens either way, even if the samples are overwritten. However, the server uses the whole readpointer, including the buffer overflows, to check if the requested samples were overwritten.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"If the distance between the write- and readpointer is larger than the buffer size the overflow status flag is set. If during the transmission the requested samples are overwritten the corrupted flag is set. These flags can be queried individually or together in a status byte via SCPI commands.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"This distance can not only be used to see if samples were overwritten, but also to track how well the client is able to keep up with the FPGA during a series of sample transmissions. If this distance increases over time, the FPGA is creating more samples than the server can transmit to the client. To allow a client to track this value, this distance is stored as a 64-bit value deltaRead for the latest transmission and can be queried. Additionally, the server also tracks the duration of the transmission as writepointer \"clock ticks\" as a 64-bit value deltaSend, which is just the difference between the writepointer at the start and end of a transmission.","category":"page"},{"location":"acquisition.html#Considerations-for-Sample-Transmission","page":"Data Acquisition","title":"Considerations for Sample Transmission","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"There are several things to consider when attempting to retrieve samples at a high sampling rate, for larger cluster sizes or for longer periods of time. Most of the following points were implemented/considered in the Julia reference implementation, but would become relevant when implementing custom clients.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"As the server will always transmit samples just based on the buffer position of a readpointer, if a client wants to only receive certain samples it needs to wait for them to exist in the buffer. This requires querying the writepointer until it is larger than the desired readpointer.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"If the number of requested samples is larger than the buffer, the sample should be requested in smaller chunks as the server would otherwise return samples that were not written yet. In a cluster scenario the i-th chunk should be requested from all RedPitayas in the cluster before requesting the next chunk to avoid \"starvation\" effects.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The status and performance data of a transmission can only be queried after the transmission has finished, which requires additionaly communication overhead.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"To help clients with these issues, the server offers a second type of sample transmission in which samples, status and performance data is pipelined. In such a query a client first transmits a readpointer, together with the number of requested samples and the number of samples belonging to a chunk. The server itself then tracks the writepointer and transmits a chunk as soon as it becomes available and immidiatey follows that up with the status and performance data of the transmission. This way additional communication overheard is reduced and after the inital request a client just needs to read data until the transmission finishes.","category":"page"},{"location":"acquisition.html#Frames,-Periods-and-Voltage","page":"Data Acquisition","title":"Frames, Periods and Voltage","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The samples sent by the server are the 16-bit values of the ADC channel of a RedPitaya. However, one might want to work with voltage values instead or encapsulate samples into a repeating concept like frames. The Julia client library offers functions to convert samples into such a concept or to directly request a number of frames instead of a number of samples.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"Here, frames are comprised of periods, which in turn are comprised of samples. During the conversion process the 16-bit binary values can also be converted to floating point numbers representing a voltage if the RedPitaya was calibrated beforehand. In this calibration process, a client can store scale and offset values for each channel in the EEPROM of the RedPitaya. When the client establishes a connection to the server, it reads these values and can use them to translate the 16-bit values into a respective voltage value.","category":"page"},{"location":"acquisition.html#Sampling-and-Data-Rates,-Transmission-Speeds-and-Time-to-Live","page":"Data Acquisition","title":"Sampling and Data Rates, Transmission Speeds and Time-to-Live","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The highest supported sampling rate of the RedPitayaDAQServer is 15.625 MHz or 15.625 MS/s, as this is the sampling rate at which a single RedPitaya can produce and transmit samples continously without data loss given the 1 Gbit/s limit of the ethernet connection from the RedPitaya. This rate is a achieved with a decimation of 8 from the base 125 MHz sampling rate of the RedPitaya hardware.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"At this sampling rate a single RedPitaya produces new samples at a data rate of 500 Mbit/s. Furthermore at this rate, once a sample has been written to the buffer it exists for 2.15s before being overwritten again (Time-To-Live, TTL). An overview of these metrics for different decimation factors is shown in the following table:","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"Decimation MHz MByte/s Mbit/s TTL\n64 1.95 7.81 62.5 17.18s\n32 3.91 15.63 125 8.59s\n16 7.81 31.25 250 4.29s\n8 15.63 62.5 500 2.15s","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The table only refers to the data rate of new samples being produced. The data rate of samples being transmitted to a client can differ greatly depending on how the client queries and processes the samples and the available network bandwidth and usage. At the higher sampling rates it is recommended to have client threads that exclusively receive samples and perform any computation on samples in different threads to maximise the transmission speed, as a server can only transmit data at a rate of just above 500 Mbit/s. This exceeds the highest supported sampling rate by only a few Mbit/s and a client with frequency interruptions of its sample reception might not be able to keep up with the sampling rate.","category":"page"},{"location":"examples/ramping.html#Ramping-Example","page":"Ramping","title":"Ramping Example","text":"","category":"section"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"In this example we ramp up the amplitude of our signal over 10 periods and we retrieve the first 12 periods of samples. Then after a wait we receive the next 12 periods. Afterwards we trigger the ramp down of the signal. As this is triggered by a command that is sent over the network it varies when the ramp down actually start. A ramp down can be triggered at a specific point with the help of a sequence.","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.","category":"page"},{"location":"examples/ramping.html#Julia-Client","page":"Ramping","title":"Julia Client","text":"","category":"section"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/ramping.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"(Image: Ramping Example Results)","category":"page"},{"location":"cluster.html#Cluster","page":"Cluster","title":"Cluster","text":"","category":"section"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"The RedPitayaDAQServer allows to use multiple RedPitayas in a fully synchronized fashion. One of the RedPitayas will act as the master and distribute its clock to all other RedPitayas acting as slaves.","category":"page"},{"location":"cluster.html#Prerequisites","page":"Cluster","title":"Prerequisites","text":"","category":"section"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"Unfortunately, the STEMlab 125-4 does not allow cluster synchronization without hardware modifications. It is therefore necessary to resolder all slaves according to this documentation. The required mode for this project is 'Directly from FPGA' which requires resistors on R27 and R28. The heatsink has to be removed temporarily in order to unsolder the two resistor below it. In the following image you can see the new position of the 0 Ohm 0402 resistors. Since they get lost easily, make sure you have some in stock.","category":"page"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"(Image: Cluster)","category":"page"},{"location":"cluster.html#Connections","page":"Cluster","title":"Connections","text":"","category":"section"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"To run a cluster of RedPitayas one needs to connect the devices using different cables. An exemplary cluster with 3 devices is shown in the following image.","category":"page"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"(Image: Cluster)","category":"page"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"The clock is distributed from the master to the first slave via an SATA cable (green). Additional slaves can be used by connecting the next slave to the previous one. Additionally all slaves have connection from +3.3 Volt to DIO0_N.","category":"page"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"In order to send a mutual trigger signal for starting the acquisition and the signal generation, you also have to connect the master's DIO5_P pin with the DIO0_P pin of all devices including the master.","category":"page"},{"location":"client.html#Client","page":"Client Library","title":"Client","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"This page contains documentation of the public API of the Julia client. In the Julia REPL one can access this documentation by entering the help mode with ? and then writing the function for which the documentation should be shown.","category":"page"},{"location":"client.html#Connection-and-Communication","page":"Client Library","title":"Connection and Communication","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"RedPitayaDAQServer.RedPitaya\nRedPitayaDAQServer.RedPitaya(::String, ::Int64, ::Int64, ::Bool)\nRedPitayaDAQServer.send(::RedPitaya, ::String)\nRedPitayaDAQServer.query\nRedPitayaDAQServer.receive\nRedPitayaDAQServer.ServerMode\nRedPitayaDAQServer.serverMode\nRedPitayaDAQServer.serverMode!\nRedPitayaDAQServer.ScpiBatch\nRedPitayaDAQServer.@add_batch\nRedPitayaDAQServer.execute!\nRedPitayaDAQServer.push!(::ScpiBatch, ::Pair{K, T}) where {K<:Function, T<:Tuple}\nRedPitayaDAQServer.pop!(::ScpiBatch)\nRedPitayaDAQServer.clear!(::ScpiBatch)\nRedPitayaDAQServer.RedPitayaCluster\nRedPitayaDAQServer.RedPitayaCluster(::Vector{String}, ::Int64, ::Int64)\nRedPitayaDAQServer.length(::RedPitayaCluster)\nRedPitayaDAQServer.master","category":"page"},{"location":"client.html#RedPitayaDAQServer.RedPitaya","page":"Client Library","title":"RedPitayaDAQServer.RedPitaya","text":"RedPitaya\n\nStruct representing a connection to a RedPitayaDAQServer.\n\nContains the sockets used for communication and connection related metadata. Also contains fields for client specific concepts such as periods, frames and calibration values. \n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.RedPitaya-Tuple{String, Int64, Int64, Bool}","page":"Client Library","title":"RedPitayaDAQServer.RedPitaya","text":"RedPitaya(ip [, port = 5025, dataPort=5026, isMaster = false])\n\nConstruct a RedPitaya.\n\nDuring the construction the connection is established and the calibration values are loaded from the RedPitayas EEPROM. Throws an error if a timeout occurs while attempting to connect.\n\nExamples\n\njulia> rp = RedPitaya(\"192.168.1.100\");\n\njulia> decimation!(rp, 8)\ntrue\n\njulia> decimation(rp)\n8\n\n\n\n\n\n","category":"method"},{"location":"client.html#Sockets.send-Tuple{RedPitaya, String}","page":"Client Library","title":"Sockets.send","text":"send(rp::RedPitaya, cmd::String)\n\nSend a command to the RedPitaya. Appends delimiter.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.query","page":"Client Library","title":"RedPitayaDAQServer.query","text":"query(rp::RedPitaya, cmd [, timeout = 5.0, N = 100])\n\nSend a query to the RedPitaya command socket. Return reply as String.\n\nWaits for timeout seconds and checks every timeout/N seconds.\n\nSee also receive.\n\n\n\n\n\nquery(rp::RedPitaya, cmd, T::Type [timeout = 5.0, N = 100])\n\nSend a query to the RedPitaya. Parse reply as T.\n\nWaits for timeout seconds and checks every timeout/N seconds.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.receive","page":"Client Library","title":"RedPitayaDAQServer.receive","text":"receive(rp::RedPitaya)\n\nReceive a String from the RedPitaya command socket. Reads until a whole line is received\n\n\n\n\n\nreceive(rp::RedPitaya, ch::Channel)\n\nReceive a String from the RedPitaya command socket. Reads until a whole line is received and puts it in the supplied channel ch.\n\n\n\n\n\nreceive(rp::RedPitaya, timeout::Number)\n\nReceive a string from the RedPitaya command socket. Reads until a whole line is received or timeout seconds passed. In the latter case an error is thrown.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.ServerMode","page":"Client Library","title":"RedPitayaDAQServer.ServerMode","text":"ServerMode\n\nRepresent the different modes the server can be in. Valid values are CONFIGURATION, ACQUISITION and TRANSMISSION.\n\nSee also serverMode, serverMode!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.serverMode","page":"Client Library","title":"RedPitayaDAQServer.serverMode","text":"serverMode(rp::RedPitaya)\n\nReturn the mode of the server.\n\nExamples\n\njulia> serverMode!(rp, ACQUISITION);\ntrue\n\njulia> serverMode(rp)\nACQUISITION\n\n\n\n\n\nserverMode(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.serverMode!","page":"Client Library","title":"RedPitayaDAQServer.serverMode!","text":"serverMode!(rp::RedPitaya, mode::ServerMode)\n\nSet the mode of the server. Valid values are \"CONFIGURATION\" and \"ACQUISITION\".\n\nExamples\n\njulia> serverMode!(rp, ACQUISITION);\ntrue\n\njulia> serverMode(rp)\nACQUISITION\n\n\n\n\n\nserverMode!(rp::RedPitaya, mode::ServerMode)\n\nSet the mode of the server.\n\nExamples\n\njulia> serverMode!(rp, ACQUISITION);\ntrue\n\njulia> serverMode(rp)\nACQUISITION\n\n\n\n\n\nserverMode!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.ScpiBatch","page":"Client Library","title":"RedPitayaDAQServer.ScpiBatch","text":"ScpiBatch\n\nStruct representing a batch of SCPI commands for a RedPitaya. Only commands that interact exclusively with the command socket should be used in a batch.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.@add_batch","page":"Client Library","title":"RedPitayaDAQServer.@add_batch","text":"@add_batch batch cmd\n\nAppend a usual RedPitaya function to the given batch instead of evaluating it directly.\n\nSee also ScpiBatch, push!, execute!\n\nExamples\n\njulia> execute!(rp) do b\n @add_batch b serverMode!(rp, CONFIGURATION)\n end\n\n\n\n\n\n","category":"macro"},{"location":"client.html#RedPitayaDAQServer.execute!","page":"Client Library","title":"RedPitayaDAQServer.execute!","text":"execute!(rp::RedPitaya, batch::ScpiBatch)\n\nExecutes all commands of the given batch. Returns an array of the results in the order of the commands. An element is nothing if the command has no return value.\n\n\n\n\n\nexecute!(rpc::RedPitayaCluster, batch::ScpiBatch)\n\nExecutes all commands of the given batch. Returns an array of the results in the order of the commands.\n\nEach element of the result array is again an array containing the return values of the RedPitayas. An element of an inner array is nothing if the command has no return value.\n\n\n\n\n\nexecute!(f::Function, rp::Union{RedPitaya, RedPitayaCluster})\n\nOpen a ScpiBatch and evaluate the function f. If no exception was thrown, execute the opened batch.\n\nSee also ScpiBatch, push!, @add_batch\n\nExamples\n\njulia> execute!(rp) do b\n @add_batch b serverMode!(rp, CONFIGURATION)\n @add_batch b amplitudeDAC!(rp, 1, 1, 0.2)\n end\n\n\n\n\n\n","category":"function"},{"location":"client.html#Base.push!-Union{Tuple{T}, Tuple{K}, Tuple{ScpiBatch, Pair{K, T}}} where {K<:Function, T<:Tuple}","page":"Client Library","title":"Base.push!","text":"push!(batch::ScpiBatch, cmd::Pair{K, T}) where {K<:Function, T<:Tuple}\n\nAdd the given function and arguments to the batch\n\nExamples\n\njulia> batch = ScpiBatch() \n\njulia> push!(batch, amplitudeDAC! => (1, 1, 0.2))\n\n\n\n\n\n","category":"method"},{"location":"client.html#Base.pop!-Tuple{ScpiBatch}","page":"Client Library","title":"Base.pop!","text":"pop!(batch::ScpiBatch)\n\nRemove the last added command from the batch\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.clear!-Tuple{ScpiBatch}","page":"Client Library","title":"RedPitayaDAQServer.clear!","text":"clear!(batch::ScpiBatch)\n\nRemove all commands from the batch\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.RedPitayaCluster","page":"Client Library","title":"RedPitayaDAQServer.RedPitayaCluster","text":"RedPitayaCluster\n\nStruct representing a cluster of RedPitayas. Such a cluster should share a common clock and master trigger.\n\nThe structure implements the indexing and iterable interfaces.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.RedPitayaCluster-Tuple{Vector{String}, Int64, Int64}","page":"Client Library","title":"RedPitayaDAQServer.RedPitayaCluster","text":"RedPitayaCluster(hosts::Vector{String} [, port = 5025])\n\nConstruct a RedPitayaCluster.\n\nDuring the construction the first host is labelled the master RedPitaya of a cluster and all RedPitayas are set to using the EXTERNAL trigger mode.\n\nSee also RedPitaya, master.\n\nExamples\n\njulia> rpc = RedPitayaCluster([\"192.168.1.100\", \"192.168.1.101\"]);\n\njulia> rp = master(rpc)\n\njulia> rp == rpc[1]\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#Base.length-Tuple{RedPitayaCluster}","page":"Client Library","title":"Base.length","text":"length(rpc::RedPitayaCluster)\n\nReturn the number of RedPitayas in cluster rpc.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.master","page":"Client Library","title":"RedPitayaDAQServer.master","text":"master(rpc::RedPitayaCluster)\n\nReturn the master RedPitaya of the cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#ADC-Configuration","page":"Client Library","title":"ADC Configuration","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"RedPitayaDAQServer.TriggerMode\nRedPitayaDAQServer.triggerMode\nRedPitayaDAQServer.triggerMode!\nRedPitayaDAQServer.keepAliveReset\nRedPitayaDAQServer.keepAliveReset!\nRedPitayaDAQServer.decimation\nRedPitayaDAQServer.decimation!\nRedPitayaDAQServer.samplesPerPeriod\nRedPitayaDAQServer.samplesPerPeriod!\nRedPitayaDAQServer.periodsPerFrame\nRedPitayaDAQServer.periodsPerFrame!\nRedPitayaDAQServer.calibADCOffset\nRedPitayaDAQServer.calibADCOffset!\nRedPitayaDAQServer.calibADCScale\nRedPitayaDAQServer.calibADCScale!\nRedPitayaDAQServer.updateCalib!","category":"page"},{"location":"client.html#RedPitayaDAQServer.TriggerMode","page":"Client Library","title":"RedPitayaDAQServer.TriggerMode","text":"TriggerMode\n\nRepresent the different trigger modes the FPGA image can have. Valid value are INTERNAL and EXTERNAL.\n\nSee triggerMode, triggerMode!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.triggerMode","page":"Client Library","title":"RedPitayaDAQServer.triggerMode","text":"triggerMode(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.triggerMode!","page":"Client Library","title":"RedPitayaDAQServer.triggerMode!","text":"triggerMode!(rp::RedPitaya, mode::String)\n\nSet the trigger mode of the RedPitaya. Return true if the command was successful.\n\n\n\n\n\ntriggerMode!(rp::RedPitaya, mode::String)\n\nSet the trigger mode of the RedPitaya. Return true if the command was successful.\n\n\n\n\n\ntriggerMode!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.keepAliveReset","page":"Client Library","title":"RedPitayaDAQServer.keepAliveReset","text":"keepAliveReset(rp::RedPitaya)\n\nDetermine whether the keepAliveReset is set.\n\n\n\n\n\nkeepAliveReset(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.keepAliveReset!","page":"Client Library","title":"RedPitayaDAQServer.keepAliveReset!","text":"keepAliveReset!(rp::RedPitaya, val::Bool)\n\nSet the keepAliveReset to val.\n\n\n\n\n\nkeepAliveReset!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.decimation","page":"Client Library","title":"RedPitayaDAQServer.decimation","text":"decimation(rp::RedPitaya)\n\nReturn the decimation of the RedPitaya.\n\nExamples\n\njulia> decimation!(rp, 8)\ntrue\n\njulia> decimation(rp)\n8\n\n\n\n\n\ndecimation(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.decimation!","page":"Client Library","title":"RedPitayaDAQServer.decimation!","text":"decimation!(rp::RedPitaya, dec)\n\nSet the decimation of the RedPitaya. Return true if the command was successful.\n\nExamples\n\njulia> decimation!(rp, 8)\ntrue\n\njulia> decimation(rp)\n8\n\n\n\n\n\ndecimation!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.samplesPerPeriod","page":"Client Library","title":"RedPitayaDAQServer.samplesPerPeriod","text":"samplesPerPeriod(rp::RedPitaya)\n\nReturn the number of samples per period.\n\nExample\n\njulia> samplesPerPeriod!(rp, 256)\ntrue\n\njulia> samplesPerPeriod(rp)\n256\n\n\n\n\n\n\nsamplesPerPeriod(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.samplesPerPeriod!","page":"Client Library","title":"RedPitayaDAQServer.samplesPerPeriod!","text":"samplesPerPeriod!(rp::RedPitaya, value)\n\nSet the number of samples per period.\n\nExample\n\njulia> samplesPerPeriod!(rp, 256)\ntrue\n\njulia> samplesPerPeriod(rp)\n256\n\n\n\n\n\n\nsamplesPerPeriod!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.periodsPerFrame","page":"Client Library","title":"RedPitayaDAQServer.periodsPerFrame","text":"periodsPerFrame(rp::RedPitaya)\n\nReturn the number of periods per frame.\n\nExample\n\njulia> periodsPerFrame!(rp, 16)\n\njulia> periodsPerFrame(rp)\n16\n\n\n\n\n\n\nperiodsPerFrame(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.periodsPerFrame!","page":"Client Library","title":"RedPitayaDAQServer.periodsPerFrame!","text":"periodsPerFrame(rp::RedPitaya, value)\n\nSet the number of periods per frame.\n\nExample\n\njulia> periodsPerFrame!(rp, 16)\n\njulia> periodsPerFrame(rp)\n16\n\n\n\n\n\n\nperiodsPerFrame!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibADCOffset","page":"Client Library","title":"RedPitayaDAQServer.calibADCOffset","text":"calibADCOffset(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration ADC offset for given channel from the RedPitayas EEPROM.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibADCOffset!","page":"Client Library","title":"RedPitayaDAQServer.calibADCOffset!","text":"calibADCOffset!(rp::RedPitaya, channel::Integer, val)\n\nStore calibration ADC offset val for given channel into the RedPitayas EEPROM. Absolute value has to be smaller than 1.0 V.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibADCScale","page":"Client Library","title":"RedPitayaDAQServer.calibADCScale","text":"calibADCScale(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration ADC scale for given channel from the RedPitayas EEPROM.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibADCScale!","page":"Client Library","title":"RedPitayaDAQServer.calibADCScale!","text":"calibADCScale(rp::RedPitaya, channel::Integer)\n\nStore calibration ADC scale val for given channel into the RedPitayas EEPROM. See also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.updateCalib!","page":"Client Library","title":"RedPitayaDAQServer.updateCalib!","text":"updateCalib!(rp::RedPitaya)\n\nUpdate the cached calibration values.\n\nSee also calibADCScale, calibADCOffset.\n\n\n\n\n\n","category":"function"},{"location":"client.html#DAC-Configuration","page":"Client Library","title":"DAC Configuration","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"RedPitayaDAQServer.amplitudeDAC\nRedPitayaDAQServer.amplitudeDAC!\nRedPitayaDAQServer.offsetDAC\nRedPitayaDAQServer.offsetDAC!\nRedPitayaDAQServer.frequencyDAC\nRedPitayaDAQServer.frequencyDAC!\nRedPitayaDAQServer.phaseDAC\nRedPitayaDAQServer.phaseDAC!\nRedPitayaDAQServer.SignalType\nRedPitayaDAQServer.signalTypeDAC\nRedPitayaDAQServer.signalTypeDAC!\nRedPitayaDAQServer.seqChan\nRedPitayaDAQServer.seqChan!\nRedPitayaDAQServer.samplesPerStep\nRedPitayaDAQServer.samplesPerStep!\nRedPitayaDAQServer.stepsPerFrame!\nRedPitayaDAQServer.clearSequence!\nRedPitayaDAQServer.sequence!\nRedPitayaDAQServer.calibDACOffset\nRedPitayaDAQServer.calibDACOffset!\nRedPitayaDAQServer.calibDACScale\nRedPitayaDAQServer.calibDACScale!\nRedPitayaDAQServer.calibDACUpperLimit!\nRedPitayaDAQServer.calibDACLowerLimit!","category":"page"},{"location":"client.html#RedPitayaDAQServer.amplitudeDAC","page":"Client Library","title":"RedPitayaDAQServer.amplitudeDAC","text":"amplitudeDAC(rp::RedPitaya, channel, component)\n\nReturn the amplitude of composite waveform component for channel.\n\nSee amplitudeDAC!.\n\nExamples\n\njulia> amplitudeDAC!(rp, 1, 1, 0.5);\ntrue\n\njulia> amplitudeDAC(rp, 1, 1)\n0.5\n\n\n\n\n\namplitudeDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.amplitudeDAC!","page":"Client Library","title":"RedPitayaDAQServer.amplitudeDAC!","text":"amplitudeDAC!(rp::RedPitaya, channel, component, value)\n\nSet the amplitude of composite waveform component for channel. Return true if the command was successful.\n\nSee amplitudeDAC.\n\nExamples\n\njulia> amplitudeDAC!(rp, 1, 1, 0.5);\ntrue\n\njulia> amplitudeDAC(rp, 1, 1)\n0.5\n\n\n\n\n\namplitudeDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.offsetDAC","page":"Client Library","title":"RedPitayaDAQServer.offsetDAC","text":"offsetDAC(rp::RedPitaya, channel)\n\nReturn the offset for channel.\n\nSee offsetDAC!.\n\nExamples\n\njulia> offsetDAC!(rp, 1, 0.2);\ntrue\n\njulia> offsetDAC(rp, 1)\n0.2\n\n\n\n\n\noffsetDAC(rpc::RedPitayaCluster, chan::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.offsetDAC!","page":"Client Library","title":"RedPitayaDAQServer.offsetDAC!","text":"offsetDAC!(rp::RedPitaya, channel, value)\n\nSet the offset for channel. Return true if the command was successful.\n\nSee offsetDAC.\n\nExamples\n\njulia> offsetDAC!(rp, 1, 0.2);\ntrue\n\njulia> offsetDAC(rp, 1)\n0.2\n\n\n\n\n\noffsetDAC!(rpc::RedPitayaCluster, chan::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.frequencyDAC","page":"Client Library","title":"RedPitayaDAQServer.frequencyDAC","text":"frequencyDAC(rp::RedPitaya, channel, component)\n\nReturn the frequency of composite waveform component for channel.\n\nSee frequencyDAC!.\n\nExamples\n\njulia> frequencyDAC!(rp, 1, 1, 2400);\ntrue\n\njulia> frequencyDAC(rp, 1, 1)\n2400\n\n\n\n\n\nfrequencyDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.frequencyDAC!","page":"Client Library","title":"RedPitayaDAQServer.frequencyDAC!","text":"frequencyDAC!(rp::RedPitaya, channel, component, value)\n\nSet the frequency of composite waveform component for channel. Return true if the command was successful.\n\nSee frequencyDAC.\n\nExamples\n\njulia> frequencyDAC!(rp, 1, 1, 2400);\ntrue\n\njulia> frequencyDAC(rp, 1, 1)\n2400\n\n\n\n\n\nfrequencyDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.phaseDAC","page":"Client Library","title":"RedPitayaDAQServer.phaseDAC","text":"phaseDAC(rp::RedPitaya, channel, component)\n\nReturn the phase of composite waveform component for channel.\n\nSee phaseDAC!.\n\nExamples\n\njulia> phaseDAC!(rp, 1, 1, 0.0);\ntrue\n\njulia> phaseDAC(rp, 1, 0.0)\n0.0\n\n\n\n\n\nphaseDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.phaseDAC!","page":"Client Library","title":"RedPitayaDAQServer.phaseDAC!","text":"phaseDAC!(rp::RedPitaya, channel, component, value)\n\nSet the phase of composite waveform component for channel. Return true if the command was successful.\n\nSee phaseDAC.\n\nExamples\n\njulia> phaseDAC!(rp, 1, 1, 0.0);\ntrue\n\njulia> phaseDAC(rp, 1, 0.0)\n0.0\n\n\n\n\n\nphaseDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.SignalType","page":"Client Library","title":"RedPitayaDAQServer.SignalType","text":"SignalType\n\nRepresent the different types of signals the fast DAC can have. Valid values are SINE, TRIANGLE and SAWTOOTH.\n\nSee signalTypeDAC, signalTypeDAC!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.signalTypeDAC","page":"Client Library","title":"RedPitayaDAQServer.signalTypeDAC","text":"signalTypeDAC!(rp::RedPitaya, channel, value)\n\nReturn the signalType of composite waveform for channel.\n\nSee signalTypeDAC!.\n\nExamples\n\njulia> signalTypeDAC!(rp, 1, SINE);\ntrue\n\njulia> signalTypeDAC(rp, 1)\nSINE\n\n\n\n\n\nsignalTypeDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.signalTypeDAC!","page":"Client Library","title":"RedPitayaDAQServer.signalTypeDAC!","text":"signalTypeDAC!(rp::RedPitaya, channel, value)\n\nSet the signalType of composite waveform for channel. Return true if the command was successful.\n\nSee signalTypeDAC.\n\nExamples\n\njulia> signalTypeDAC!(rp, 1, SINE);\ntrue\n\njulia> signalTypeDAC(rp, 1)\nSINE\n\n\n\n\n\nsignalTypeDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.seqChan","page":"Client Library","title":"RedPitayaDAQServer.seqChan","text":"seqChan(rp::RedPitaya)\n\nReturn the number of sequence channel.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.seqChan!","page":"Client Library","title":"RedPitayaDAQServer.seqChan!","text":"seqChan!(rp::RedPitaya, value)\n\nSet the number of sequence channel. Valid values are between 1 and 6. Return true if the command was successful.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.samplesPerStep","page":"Client Library","title":"RedPitayaDAQServer.samplesPerStep","text":"samplesPerStep(rp::RedPitaya)\n\nReturn the number of samples per sequence step.\n\n\n\n\n\nsamplesPerStep(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.samplesPerStep!","page":"Client Library","title":"RedPitayaDAQServer.samplesPerStep!","text":"samplesPerStep!(rp::RedPitaya, value::Integer)\n\nSet the number of samples per sequence step. Return true if the command was successful.\n\n\n\n\n\nsamplesPerStep!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.stepsPerFrame!","page":"Client Library","title":"RedPitayaDAQServer.stepsPerFrame!","text":"stepsPerFrame!(rp::RedPitaya, stepsPerFrame)\n\nSet the number of samples per steps s.t. stepsPerFrame sequence steps in a frame.\n\nSee samplesPerPeriod!, periodsPerFrame!, samplesPerStep!.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.clearSequence!","page":"Client Library","title":"RedPitayaDAQServer.clearSequence!","text":"clearSequence!(rp::RedPitaya)\n\nInstruct the server to remove all sequences from its list. Return true if the command was successful.\n\n\n\n\n\nclearSequence!(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.sequence!","page":"Client Library","title":"RedPitayaDAQServer.sequence!","text":"sequence!(rp::RedPitaya, seq::AbstractSequence)\n\nTransmit the client-side representation seq to the server and append it to the current list of sequences. Return true if the required commands were successful.\n\n\n\n\n\nsequence!(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACOffset","page":"Client Library","title":"RedPitayaDAQServer.calibDACOffset","text":"calibDACOffset(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC offset for given channel from the RedPitayas EEPROM \n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACOffset!","page":"Client Library","title":"RedPitayaDAQServer.calibDACOffset!","text":"calibDACOffset!(rp::RedPitaya, channel::Integer, val)\n\nStore calibration DAC offset val for given channel into the RedPitayas EEPROM. This value is used by the server to offset the output voltage. Absolute value has to be smaller than 1.0 V. \n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACScale","page":"Client Library","title":"RedPitayaDAQServer.calibDACScale","text":"calibDACScale(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC scale for given channel from the RedPitayas EEPROM.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACScale!","page":"Client Library","title":"RedPitayaDAQServer.calibDACScale!","text":"calibDACScale(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC scale val for given channel into the RedPitayas EEPROM. This value is used by the server to scale the output voltage.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACUpperLimit!","page":"Client Library","title":"RedPitayaDAQServer.calibDACUpperLimit!","text":"calibDACUpperLimit!(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC upper limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACLowerLimit!","page":"Client Library","title":"RedPitayaDAQServer.calibDACLowerLimit!","text":"calibDACLowerLimit!(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC lower limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.\n\n\n\n\n\n","category":"function"},{"location":"client.html#Measurement-and-Transmission","page":"Client Library","title":"Measurement and Transmission","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"RedPitayaDAQServer.masterTrigger\nRedPitayaDAQServer.masterTrigger!\nRedPitayaDAQServer.currentWP\nRedPitayaDAQServer.currentFrame\nRedPitayaDAQServer.currentPeriod\nRedPitayaDAQServer.SampleChunk\nRedPitayaDAQServer.PerformanceData\nRedPitayaDAQServer.readSamples\nRedPitayaDAQServer.readFrames\nRedPitayaDAQServer.readPeriods\nRedPitayaDAQServer.convertSamplesToFrames(::Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any)\nRedPitayaDAQServer.convertSamplesToPeriods!(::Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any)","category":"page"},{"location":"client.html#RedPitayaDAQServer.masterTrigger","page":"Client Library","title":"RedPitayaDAQServer.masterTrigger","text":"masterTrigger(rp::RedPitaya)\n\nDetermine whether the master trigger is set.\n\nExample\n\njulia> masterTrigger!(rp, true)\n\njulia>masterTrigger(rp)\ntrue\n\n\n\n\n\nmasterTrigger(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.masterTrigger!","page":"Client Library","title":"RedPitayaDAQServer.masterTrigger!","text":"masterTrigger!(rp::RedPitaya, val::Bool)\n\nSet the master trigger of the RedPitaya to val. Return true if the command was successful.\n\nExample\n\njulia> masterTrigger!(rp, true)\ntrue\n\njulia>masterTrigger(rp)\ntrue\n\n\n\n\n\nmasterTrigger(rpc::RedPitayaCluster, val::Bool)\n\nSet the master trigger of the cluster to val.\n\nFor val equals to true this is the same as calling the function on the RedPitaya returned by master(rpc). If val is false then the keepAliveReset is set to true for all RedPitayas in the cluster before the master trigger is disabled. Afterwards the keepAliveReset is set to false again.\n\nSee also master, keepAliveReset!.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.currentWP","page":"Client Library","title":"RedPitayaDAQServer.currentWP","text":"currentWP(rp::RedPitaya)\n\nReturn the current writepointer of the RedPitaya.\n\n\n\n\n\ncurrentWP(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.currentFrame","page":"Client Library","title":"RedPitayaDAQServer.currentFrame","text":"currentFrame(rp::RedPitaya)\n\nReturn the current frame of the RedPitaya based on the current writepointer, samples per period and periods per frame.\n\nSee also currentWP, samplesPerPeriod, periodsPerFrame.\n\n\n\n\n\ncurrentFrame(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.currentPeriod","page":"Client Library","title":"RedPitayaDAQServer.currentPeriod","text":"currentPeriod(rp::RedPitaya)\n\nReturn the current period of the RedPitaya based on the current writepointer and samples per period.\n\nSee also currentWP, samplesPerPeriod.\n\n\n\n\n\ncurrentPeriod(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.SampleChunk","page":"Client Library","title":"RedPitayaDAQServer.SampleChunk","text":"SampleChunk\n\nStruct containing a matrix of samples and associated PerformanceData\n\nFields\n\nsamples::Matrix{Int16}: nxm matrix containing m samples for n channel\nperformance::Vector{PerformanceData}: PerformanceData object for each RedPitaya that transmitted samples\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.PerformanceData","page":"Client Library","title":"RedPitayaDAQServer.PerformanceData","text":"PerformanceData\n\nHolds the performance data that is used for monitoring.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.readSamples","page":"Client Library","title":"RedPitayaDAQServer.readSamples","text":"readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64; chunkSize::Int64 = 25000, rpInfo=nothing)\n\nRequest and receive numOfRequestedSamples samples from wpStart on in a pipelined fashion. Return a matrix of samples.\n\nIf rpInfo is set to a RPInfo, the PerformanceData sent after every chunkSize samples will be pushed into rpInfo.\n\n\n\n\n\nreadSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64, channel::Channel; chunkSize::Int64 = 25000)\n\nRequest and receive numOfRequestedSamples samples from wpStart on in a pipelined fashion. The samples and associated PerformanceData are pushed into channel as a SampleChunk.\n\nSee SampleChunk.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.readFrames","page":"Client Library","title":"RedPitayaDAQServer.readFrames","text":"readFrames(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startFrame, numFrames, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false)\n\nRequest and receive numFrames frames from startFrame on.\n\nSee readSamples, convertSamplesToFrames, samplesPerPeriod, periodsPerFrame, updateCalib!.\n\nArguments\n\nrpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}: RedPitayas to receive samples from.\nstartFrame: frame from which to start transmitting\nnumFrames: number of frames to read\nnumBlockAverages=1: see convertSamplesToFrames\nnumPeriodsPerPatch=1: see convertSamplesToFrames\nchunkSize=50000: see readSamples\nrpInfo=nothing: see readSamples\nuseCalibration: convert from Int16 samples to Float32 values based on RedPitayas calibration\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.readPeriods","page":"Client Library","title":"RedPitayaDAQServer.readPeriods","text":"readPeriods(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startPeriod, numPeriods, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false)\n\nRequest and receive numPeriods Periods from startPeriod on.\n\nSee readSamples, convertSamplesToPeriods!, samplesPerPeriod.\n\nArguments\n\nrpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}: RedPitayas to receive samples from.\nstartPeriod: period from which to start transmitting\nnumPeriods: number of periods to read\nnumBlockAverages=1: see convertSamplesToPeriods\nchunkSize=50000: see readSamples\nrpInfo=nothing: see readSamples\nuseCalibration: convert samples based on RedPitayas calibration\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.convertSamplesToFrames-Tuple{Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, Vararg{Any, 7}}","page":"Client Library","title":"RedPitayaDAQServer.convertSamplesToFrames","text":"convertSamplesToFrames(rpu::Union{RedPitayaCluster, RedPitayaClusterView}, samples, numChan, numSampPerPeriod, numPeriods, numFrames, numBlockAverages=1, numPeriodsPerPatch=1)\n\nConverts a given set of samples to frames.\n\nSee readFrames\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.convertSamplesToPeriods!-Tuple{Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, Vararg{Any, 6}}","page":"Client Library","title":"RedPitayaDAQServer.convertSamplesToPeriods!","text":"convertSamplesToPeriods!(rpu::Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, samples, periods, numChan, numSampPerPeriod, numPeriods, numBlockAverages=1)\n\nConverts a given set of samples to periods in-place.\n\nSee readPeriods\n\n\n\n\n\n","category":"method"},{"location":"client.html#Slow-IO","page":"Client Library","title":"Slow IO","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"Modules = [RedPitayaDAQServer]\nPages = [\"SlowIO.jl\"]","category":"page"},{"location":"client.html#RedPitayaDAQServer.DIODirectionType","page":"Client Library","title":"RedPitayaDAQServer.DIODirectionType","text":"DIODirectionType\n\nRepresent the different DIO directions. Valid value are DIO_IN and DIO_OUT.\n\nSee DIODirection, DIODirection!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.DIOPins","page":"Client Library","title":"RedPitayaDAQServer.DIOPins","text":"DIOPins\n\nRepresent the different DIO pins. Valid value are DIO7_P, DIO7_N, DIO6_P, DIO6_N, DIO5_N, DIO4_N, DIO3_N and DIO2_N.\n\nSee DIODirection, DIODirection!, DIO, DIO.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.DIO!-Tuple{RedPitaya, Any, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIO!","text":"DIO!(rp::RedPitaya, pin::DIOPins, val::Bool)\n\nSet the value of DIO pin pin to the value val.\n\nExample\n\njulia> DIO!(rp, DIO7_P, true)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.DIO-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIO","text":"DIO(rp::RedPitaya, pin::DIOPins)\n\nGet the value of DIO pin pin.\n\nExample\n\njulia>DIO(rp, DIO7_P)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.DIODirection!-Tuple{RedPitaya, Any, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIODirection!","text":"DIODirection!(rp::RedPitaya, pin::DIOPins, direction::DIODirectionType)\n\nSet the direction of DIO pin pin to the value direction.\n\nExample\n\njulia> DIODirection!(rp, DIO7_P, DIO_OUT)\n\njulia>DIODirection(rp, DIO7_P)\nDIO_OUT\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.DIODirection-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIODirection","text":"DIODirection(rp::RedPitaya, pin::DIOPins)\n\nGet the direction of DIO pin pin.\n\nExample\n\njulia> DIODirection!(rp, DIO7_P, DIO_OUT)\n\njulia>DIODirection(rp, DIO7_P)\nDIO_OUT\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.isValidDIOPin-Tuple{String}","page":"Client Library","title":"RedPitayaDAQServer.isValidDIOPin","text":"isValidDIOPin(pin::String)\n\nCheck if a given string is an allowed value for the DIO pin names.\n\nSee DIOPins.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.slowADC-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.slowADC","text":"slowADC(rp::RedPitaya, channel::Int64)\n\nGet the value of the XADC channel channel.\n\nExample\n\njulia> slowADC(rp, 1)\n0.0\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.slowDAC!-Tuple{RedPitaya, Any, Any}","page":"Client Library","title":"RedPitayaDAQServer.slowDAC!","text":"slowDAC!(rp::RedPitaya, channel::Int64, val::Int64)\n\nSet the value of the slow DAC channel channel to the value val. Return true if the command was successful.\n\nExample\n\njulia> slowDAC!(rp, 1, 500)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.slowDACClockDivider!-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.slowDACClockDivider!","text":"slowDACClockDivider!(rp::RedPitaya, val::Int32)\n\nSet the clock divider of the slow DAC.\n\nExample\n\njulia> slowDACClockDivider!(rp, 8)\n\njulia>slowDACClockDivider(rp)\n8\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.slowDACClockDivider-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.slowDACClockDivider","text":"slowDACClockDivider(rp::RedPitaya)\n\nGet the clock divider of the slow DAC.\n\nExample\n\njulia> slowDACClockDivider!(rp, 8)\n\njulia>slowDACClockDivider(rp)\n8\n\n\n\n\n\n","category":"method"},{"location":"client.html#EEPROM-and-Calibration","page":"Client Library","title":"EEPROM and Calibration","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"Modules = [RedPitayaDAQServer]\nPages = [\"EEPROM.jl\"]","category":"page"},{"location":"client.html#RedPitayaDAQServer.calibADCOffset!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibADCOffset!","text":"calibADCOffset!(rp::RedPitaya, channel::Integer, val)\n\nStore calibration ADC offset val for given channel into the RedPitayas EEPROM. Absolute value has to be smaller than 1.0 V.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibADCOffset-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibADCOffset","text":"calibADCOffset(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration ADC offset for given channel from the RedPitayas EEPROM.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibADCScale!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibADCScale!","text":"calibADCScale(rp::RedPitaya, channel::Integer)\n\nStore calibration ADC scale val for given channel into the RedPitayas EEPROM. See also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibADCScale-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibADCScale","text":"calibADCScale(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration ADC scale for given channel from the RedPitayas EEPROM.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACLimit!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACLimit!","text":"calibDACLimit!(rp::RedPitaya, channel, val)\n\nApplies val with a positive sign as the upper and with a negative sign as the lower calibration DAC limit.\n\nSee also calibDACUpperLimit!, calibDACLowerLimit!\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACLowerLimit!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACLowerLimit!","text":"calibDACLowerLimit!(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC lower limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACLowerLimit-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibDACLowerLimit","text":"calibDACLowerLimit(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC lower limit for given channel from the RedPitayas EEPROM.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACOffset!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACOffset!","text":"calibDACOffset!(rp::RedPitaya, channel::Integer, val)\n\nStore calibration DAC offset val for given channel into the RedPitayas EEPROM. This value is used by the server to offset the output voltage. Absolute value has to be smaller than 1.0 V. \n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACOffset-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibDACOffset","text":"calibDACOffset(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC offset for given channel from the RedPitayas EEPROM \n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACScale!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACScale!","text":"calibDACScale(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC scale val for given channel into the RedPitayas EEPROM. This value is used by the server to scale the output voltage.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACScale-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibDACScale","text":"calibDACScale(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC scale for given channel from the RedPitayas EEPROM.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACUpperLimit!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACUpperLimit!","text":"calibDACUpperLimit!(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC upper limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACUpperLimit-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibDACUpperLimit","text":"calibDACUpperLimit(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC upper limit for given channel from the RedPitayas EEPROM.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.updateCalib!-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.updateCalib!","text":"updateCalib!(rp::RedPitaya)\n\nUpdate the cached calibration values.\n\nSee also calibADCScale, calibADCOffset.\n\n\n\n\n\n","category":"method"},{"location":"client.html#Counter-Trigger","page":"Client Library","title":"Counter Trigger","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"Modules = [RedPitayaDAQServer]\nPages = [\"CounterTrigger.jl\"]","category":"page"},{"location":"client.html#RedPitayaDAQServer.CounterTriggerSourceADCChannel","page":"Client Library","title":"RedPitayaDAQServer.CounterTriggerSourceADCChannel","text":"CounterTriggerSourceADCChannel\n\nRepresent the different counter trigger ADC sources. Valid values are COUNTER_TRIGGER_IN1 and COUNTER_TRIGGER_IN2.\n\nSee counterTrigger_sourceChannel, counterTrigger_sourceChannel!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.CounterTriggerSourceType","page":"Client Library","title":"RedPitayaDAQServer.CounterTriggerSourceType","text":"CounterTriggerSourceType\n\nRepresent the different counter trigger source types. Valid values are COUNTER_TRIGGER_DIO and COUNTER_TRIGGER_ADC.\n\nSee counterTrigger_sourceType, counterTrigger_sourceType!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_arm!","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_arm!","text":"counterTrigger_arm!(rp::RedPitaya, val::Bool)\n\nSet whether the counter trigger is armed or not. Return true if the command was successful.\n\nExamples\n\njulia> counterTrigger_arm!(rp, true)\ntrue\n\njulia> counterTrigger_isArmed(rp)\ntrue\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_enabled!-Tuple{RedPitaya, Bool}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_enabled!","text":"counterTrigger_enabled!(rp::RedPitaya, val)\n\nSet whether the counter trigger is enabled or not. Return true if the command was successful.\n\nExamples\n\njulia> counterTrigger_enabled!(rp, true)\ntrue\n\njulia> counterTrigger_enabled(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_enabled-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_enabled","text":"counterTrigger_enabled(rp::RedPitaya)\n\nReturn whether the counter trigger is enabled or not.\n\nExamples\n\njulia> counterTrigger_enabled!(rp, true)\ntrue\n\njulia> counterTrigger_enabled(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_isArmed-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_isArmed","text":"counterTrigger_isArmed(rp::RedPitaya)\n\nReturn whether the counter trigger is armed or not.\n\nExamples\n\njulia> counterTrigger_arm!(rp, true)\ntrue\n\njulia> counterTrigger_isArmed(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_lastCounter-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_lastCounter","text":"counterTrigger_lastCounter(rp::RedPitaya)\n\nReturn the number of samples that the counter trigger should trigger prior to reaching the reference counter.\n\nExamples\n\njulia> counterTrigger_lastCounter(rp)\n123456\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_presamples!-Union{Tuple{T}, Tuple{RedPitaya, T}} where T<:Integer","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_presamples!","text":"counterTrigger_presamples!(rp::RedPitaya, presamples)\n\nSet the number of samples that the counter trigger should trigger prior to reaching the reference counter.\n\nExamples\n\njulia> counterTrigger_presamples!(rp, 50)\ntrue\n\njulia> counterTrigger_presamples(rp)\n50\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_presamples-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_presamples","text":"counterTrigger_presamples(rp::RedPitaya)\n\nReturn the number of samples that the counter trigger should trigger prior to reaching the reference counter.\n\nExamples\n\njulia> counterTrigger_presamples!(rp, 50)\ntrue\n\njulia> counterTrigger_presamples(rp)\n50\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_referenceCounter!-Union{Tuple{T}, Tuple{RedPitaya, T}} where T<:Integer","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_referenceCounter!","text":"counterTrigger_referenceCounter!(rp::RedPitaya, presamples)\n\nSet the number of samples that the counter trigger should trigger on.\n\nExamples\n\njulia> counterTrigger_referenceCounter(rp, 250)\ntrue\n\njulia> counterTrigger_referenceCounter!(rp)\n250\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_referenceCounter-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_referenceCounter","text":"counterTrigger_referenceCounter(rp::RedPitaya)\n\nReturn the counter value that the counter trigger should trigger on.\n\nExamples\n\njulia> counterTrigger_referenceCounter!(rp, 250)\ntrue\n\njulia> counterTrigger_referenceCounter(rp)\n250\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_reset!-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_reset!","text":"counterTrigger_reset!(rp::RedPitaya, val::Bool)\n\nSet the reset of the counter trigger to val. Return true if the command was successful.\n\nExample\n\njulia> counterTrigger_reset!(rp, true)\ntrue\n\njulia>counterTrigger_reset(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_reset-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_reset","text":"counterTrigger_reset(rp::RedPitaya)\n\nReturn the reset status of the counter trigger.\n\nExample\n\njulia> counterTrigger_reset!(rp, true)\n\njulia>counterTrigger_reset(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_sourceChannel!-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_sourceChannel!","text":"counterTrigger_sourceChannel!(rp::RedPitaya, sourceChannel::) //TODO\n\nSet the source channel of the counter trigger to sourceChannel.\n\nExample\n\njulia> counterTrigger_sourceChannel!(rp, COUNTER_TRIGGER_ADC)\n\njulia>counterTrigger_sourceChannel(rp)\nCOUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1 //TODO\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_sourceChannel-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_sourceChannel","text":"counterTrigger_sourceChannel(rp::RedPitaya)\n\nGet the source channel of the counter trigger.\n\nExample\n\njulia> counterTrigger_sourceChannel!(rp, COUNTER_TRIGGER_IN2)\n\njulia>counterTrigger_sourceChannel(rp)\nCOUNTER_TRIGGER_IN2::CounterTriggerSourceADCChannel = 2\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_sourceType!-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_sourceType!","text":"counterTrigger_sourceType!(rp::RedPitaya, sourceType::CounterTriggerSourceType)\n\nSet the source type of the counter trigger to sourceType.\n\nExample\n\njulia> counterTrigger_sourceType!(rp, COUNTER_TRIGGER_ADC)\n\njulia>counterTrigger_sourceType(rp)\nCOUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_sourceType-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_sourceType","text":"counterTrigger_sourceType(rp::RedPitaya)\n\nGet the source type of the counter trigger.\n\nExample\n\njulia> counterTrigger_sourceType!(rp, COUNTER_TRIGGER_ADC)\n\njulia>counterTrigger_sourceType(rp)\nCOUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1\n\n\n\n\n\n","category":"method"},{"location":"scpi.html#SCPI-Interface","page":"SCPI Interface","title":"SCPI Interface","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"For communication betten the server and the client an SCPI interface with custom commands is used. In the following tables an overview of the available commands and their behaviour is given. The Julia Client library encapsulates these commands into function calls, abstracting their communication details and also combining commands to manage a cluster of RedPitayas at the same time.","category":"page"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"As a safe guard the server has different communcation modes and certain commands are only available in certain modes. To give an example, during an acquisition changing the sampling rate would result in unclear behaviour. To stop such a scenario the decimation can only be set in the CONFIGURATION mode and an acquisition can only be triggered in the ACQUISITION mode. The available modes are CONFIGURATION, ACQUISITION and TRANSMISSION (C, A, T, 😺). The former two are set by the client and the latter is set by the server during sample transmission.","category":"page"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"After each SCPI command the server replies with true or false on the command socket depending on whether the given command was successfully excecuted. The exception to this rule are the commands which themselves just query values from the server.","category":"page"},{"location":"scpi.html#ADC-Configuration","page":"SCPI Interface","title":"ADC Configuration","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:ADC:DECimation decimation value [8, ..., n] Set the decimation factor of the base sampling rate C RP:ADC:DEC 8\nRP:ADC:DECimation? Return the decimation factor Any RP:ADC:DEC?\nRP:TRIGger:MODe trigger mode (EXTERNAL, INTERNAL) Set the trigger mode, which trigger the RedPitaya listens to C RP:TRIG:MOD INTERNAL\nRP:TRIGger:MODe? Return the trigger mode Any RP:TRIG:MOD?","category":"page"},{"location":"scpi.html#DAC-Configuration","page":"SCPI Interface","title":"DAC Configuration","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:DAC:CHannel#:COMPonent#:SIGnaltype channel (0, 1), (0, 1, 2, 3), signal type (SINE, TRIANGLE, SAWTOOTH) Set signal type of first component for given channel Any RP:DAC:CH0:SIG SINE\nRP:DAC:CHannel#:COMPonent#:SIGnaltype? channel (0, 1), component (0, 1, 2, 3) Return signal type of first component of given channel Any RP:DAC:CH1:SIG?\nRP:DAC:CHannel#:OFFset channel (0, 1), offset [-1, ..., 1] Set offset for given channel Any RP:DAC:CH1:OFF 0.1\nRP:DAC:CHannel#:OFFset? channel (0, 1) Return offset of given channel Any RP:DAC:CH0:OFF?\nRP:DAC:CHannel#:COMPonent#:AMPlitude channel (0, 1), component (0, 1, 2, 3), amplitude[0, ..., 1] Set amplitude of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:AMPlitude? channel (0, 1), component (0, 1, 2, 3) Return amplitude of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:FREQuency channel (0, 1), component (0, 1, 2, 3), frequency Set frequency of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:FREQuency? channel (0, 1), component (0, 1, 2, 3) Return frequency of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:PHAse channel (0, 1), component (0, 1, 2, 3), phase Set phase of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:PHAse? channel (0, 1), component (0, 1, 2, 3) Return phase of given channel and component Any \nRP:DAC:CHannel#:RAMPing channel (0, 1), ramping period Set length of ramping period C \nRP:DAC:CHannel#:RAMPing? channel (0, 1) Get length of ramping period Any \nRP:DAC:CHannel#:RAMPing:ENable channel (0, 1) ramping status (OFF, ON) Enable/disable ramping factor on given channel C \nRP:DAC:CHannel#:RAMPing:ENable? channel (0, 1) Return enable ramping status of given channel Any \nRP:DAC:CHannel#:RAMPing:DoWN channel (0, 1), ramp down status (OFF, ON) Enable/disable ramp down flag for given channel A, T \nRP:DAC:CHannel#:RAMPing:DoWN? channel (0, 1) Get ramp down flag for given channel Any \nRP:DAC:RAMPing:STATus? Return the ramping status Any ","category":"page"},{"location":"scpi.html#Sequence-Configuration","page":"SCPI Interface","title":"Sequence Configuration","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"The server maintains three acquisition sequences. When the server is in theCONFIGURATION mode a client can configure a set of three sequences. If the current configured sequences fits the desired signal, a client can intstruct the server to set the sequences. This moves the configuration sequences to the acquisition sequences and writes the first values to the FPGA buffer.","category":"page"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"During an active trigger the buffer is periodically updated by the server. If the server recognizes the end of a sequence, it sets the amplitudes of the waveform components to 0.","category":"page"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:DAC:SEQ:CLocKdivider divider Set the clock divider with which the sequence advances C \nRP:DAC:SEQ:CLocKdivider? Return the clock divider Any \nRP:DAC:SEQ:SAMPlesperstep samples per step Set the clock divider such that the sequence advances every given number of samples. C \nRP:DAC:SEQ:SAMPlesperstep? Return the number of samples per step Any \nRP:DAC:SEQ:CHan numChan (1, 2, 3, 4) Set the number of sequence channel C \nRP:DAC:SEQ:CHan? Return the number of sequence channel \nRP:DAC:SEQ:LUT steps, repetitions Instruct the server to receive a LUT over the data socket C RP:DAC:SEQ:LUT 10,2\nRP:DAC:SEQ:LUT:ENaBle Instruct the server to receive an enable LUT over the data socket of the same shape as the regular LUT C \nRP:DAC:SEQ:LUT:UP steps, repetitions Instruct the server to receive a ramp up LUT over the data socket C \nRP:DAC:SEQ:LUT:DOWN steps, repetitions Instruct the server to receive a ramp down LUT over the data socket C \nRP:DAC:SEQ:CLEAR Clear the set sequence values from the FPGA buffer C \nRP:DAC:SEQ:SET Set the current configured sequence as the acquisition sequence C ","category":"page"},{"location":"scpi.html#Acquisition-and-Transmission","page":"SCPI Interface","title":"Acquisition and Transmission","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:TRIGger trigger status (OFF, ON) Set the internal trigger status A RP:TRIG ON\nRP:TRIGger? Return the trigger status Any RP:TRIG?\nRP:TRIGger:ALiVe keep alive status (OFF, ON) Set the keep alive bypass A RP:TRIG:ALV OFF\nRP:TRIGger:ALiVe? Return the keep alive status Any RP:TRIG:ALV?\nRP:ADC:WP:CURRent? Return the current writepointer A, T RP:ADC:WP?\nRP:ADC:DATa? readpointer, number of samples Transmit number of samples from the buffer component of the readpointer over the data socket. Return true on the command socket if transmission is started. A RP:ADC:DATa? 400,1024\nRP:ADC:DATa:PIPElined? readpointer, number of samples, chunksize Transmit number of samples from the readpointer on in chunks of chunksize over the data socket. After every chunk status and performance data is transmitted over the data socket. Return true if pipeline was started. A RP:ADC:DAT:PIPE? 400,1024,128\nRP:STATus? Transmit status as one byte with flags from lower bits: overwritten, corrupted, lost steps, master trigger, sequence active Any RP:STAT?\nRP:STATus:OVERwritten? Transmit overwritten flag Any RP:STAT:OVER?\nRP:STATus:CORRupted? Transmit corrupted flag Any RP:STAT:CORR?\nRP:STATus:LOSTSteps? Transmit lost steps flag Any RP:STAT:LOSTS?\nRP:PERF? Transmit ADC and DAC performance data Any RP:PERF?","category":"page"},{"location":"scpi.html#Calibration","page":"SCPI Interface","title":"Calibration","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:CALib:ADC:CHannel#:OFFset channel (0, 1), offset Store the ADC offset value for given channel in EEPROM C RP:CAL:ADC:CH0:OFF 0.2\nRP:CALib:ADC:CHannel#:OFFset? channel (0, 1) Return the ADC offset value for given channel from EEPROM Any RP:CAL:ADC:CH1:OFF?\nRP:CALib:ADC:CHannel#:SCAle channel (0, 1), scale Store the ADC scale value for given channel in EEPROM C RP:CAL:ADC:CH1:SCA 1.0\nRP:CALib:ADC:CHannel#:SCAle? channel (0, 1) Return the ADC scale value for given channel from EEPROM Any RP:CAL:ADC:CH1:SCA?\nRP:CALib:DAC:CHannel#:OFFset channel (0, 1), offset Store the DAC offset value for given channel in EEPROM C RP:CAL:DAC:CH0:OFF 0.2\nRP:CALib:DAC:CHannel#:OFFset? channel (0, 1) Return the DAC offset value for given channel from EEPROM Any RP:CAL:DAC:CH1:OFF?\nRP:CALib:DAC:CHannel#:SCAle channel (0, 1), scale Store the DAC scale value for given channel in EEPROM C RP:CAL:DAC:CH1:SCA 1.0\nRP:CALib:DAC:CHannel#:SCAle? channel (0, 1) Return the DAC scale value for given channel from EEPROM Any RP:CAL:DAC:CH1:SCA?","category":"page"},{"location":"scpi.html#DIO","page":"SCPI Interface","title":"DIO","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Example\nRP:DIO:DIR identifier of pin, direction (IN/OUT) Set the direction of the DIO RP:DIO:DIR DIO7_P,IN\nRP:DIO identifier of pin, value (0/1) Set the output of the DIO RP:DIO DIO7_P,1\nRP:DIO? identifier of pin Get the input of the DIO RP:DIO? DIO7_P","category":"page"},{"location":"examples/seqRamping.html#Sequence-Ramping-Example","page":"Sequence Ramping","title":"Sequence Ramping Example","text":"","category":"section"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"In this example we combine the ramping and the sequence example to create a signal with known/predictable ramping behaviour. The ramping period is independant of the sequence. The sequence we use is a sequence that holds the first value of our intended sequence for the duration of the given number of ramping steps, which spans the ramp up period.","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"At the end of the \"regular\" sequence portion, the ramp down is triggered and the sequence holds the last value of the \"regular\" sequence until the end of the ramp down.","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.","category":"page"},{"location":"examples/seqRamping.html#Julia-Client","page":"Sequence Ramping","title":"Julia Client","text":"","category":"section"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/seqRamping.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"(Image: Sequence Ramping Example Results)","category":"page"},{"location":"examples/producerConsumer.html#Continous-Signal-Acquisition-Example","page":"Continous Signal Acquisition","title":"Continous Signal Acquisition Example","text":"","category":"section"},{"location":"examples/producerConsumer.html","page":"Continous Signal Acquisition","title":"Continous Signal Acquisition","text":"As is mentioned in the Acquisition section, the transmission rate of the server heavily depends on the available network and the way a client processes the samples. This example shows how one can write a thread dedicated to just receiving samples and one (or more) threads dedicated to processing samples. As the example contains no visualization, there is no need for a specific RedPitaya setup.","category":"page"},{"location":"examples/producerConsumer.html#Julia-Client","page":"Continous Signal Acquisition","title":"Julia Client","text":"","category":"section"},{"location":"examples/producerConsumer.html","page":"Continous Signal Acquisition","title":"Continous Signal Acquisition","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/producerConsumer.html","page":"Continous Signal Acquisition","title":"Continous Signal Acquisition","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/producerConsumer.jl\"))\n```\n\"\"\")","category":"page"},{"location":"devtips.html#Development-Hints","page":"Development Tips","title":"Development Hints","text":"","category":"section"},{"location":"devtips.html","page":"Development Tips","title":"Development Tips","text":"On this slide some development hints are summarized. These might change regularely if things are properly integrated into the framework.","category":"page"},{"location":"devtips.html#Alpine-Linux","page":"Development Tips","title":"Alpine Linux","text":"","category":"section"},{"location":"devtips.html","page":"Development Tips","title":"Development Tips","text":"The Alpine linux as currently a root folder with only 185.8M free space, which disallows installing more","category":"page"},{"location":"devtips.html","page":"Development Tips","title":"Development Tips","text":"applications. To change this one can do","category":"page"},{"location":"devtips.html","page":"Development Tips","title":"Development Tips","text":"mount -o remount,size=1G /","category":"page"},{"location":"examples/sequence.html#Sequence-Example","page":"Sequence","title":"Sequence Example","text":"","category":"section"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"In this example we generate a 10 kHz sine wave on DAC channel 1 and also construct a sequence with a climbing offset every 5 periods. We receive this signal on ADC channel 1. To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/sequence.html#Julia-Client","page":"Sequence","title":"Julia Client","text":"","category":"section"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/sequence.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"(Image: Simple Example Results)","category":"page"},{"location":"index.html#RedPitayaDAQServer","page":"Home","title":"RedPitayaDAQServer","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"Advanced DAQ Tools for the RedPitaya (STEMlab 125-14)","category":"page"},{"location":"index.html#Introduction","page":"Home","title":"Introduction","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"This project contains software to be used with the STEMlab 125-14 device from RedPitaya. It allows for continuous generation and measurement of signals with up to 15.625 MS/s, which is not possible with the standard image of the RedPitaya. In addition, the software allows to synchronize a cluster of multiple RedPitayas. This project contains the following parts:","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"Alpine Linux image for the RedPitaya\nFPGA images for the 7010 and 7020\nLibrary written in C to interact with the FPGA image on the RedPitaya\nSCPI Server for accessing the functionality over TCP/IP\nSCPI Client to access the server","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"The code is contained in this repository.","category":"page"},{"location":"index.html#License-/-Terms-of-Usage","page":"Home","title":"License / Terms of Usage","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"The source code of this project is licensed under the MIT license. This implies that you are free to use, share, and adapt it. However, please give appropriate credit by citing the project.","category":"page"},{"location":"index.html#Contact","page":"Home","title":"Contact","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"If you have problems using the software, find mistakes, or have general questions please use the issue tracker to contact us.","category":"page"},{"location":"index.html#Contributors","page":"Home","title":"Contributors","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"Tobias Knopp\nNiklas Hackelberg\nJonas Schumacher\nMatthias Gräser","category":"page"},{"location":"index.html#Credit","page":"Home","title":"Credit","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"This package is partly based on work of Koheron [1] and Pavel Demin [2]","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"[1] https://www.koheron.com/blog/2016/11/29/red-pitaya-cluster [2] https://github.com/pavel-demin/red-pitaya-notes","category":"page"}] +[{"location":"generation.html#Signal-Generation","page":"Signal Generation","title":"Signal Generation","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Once the acquisition is triggered, each RedPitaya also starts producing signals on their output channels. Each RedPitaya features six such channels, two of those are the 16-bit DAC channel and four of those are digital pins using PDM, see Connections. The output signals are composed of three parts: parameterized waveforms W_i(t), an offset o_i and repeating arbitrary LUT tables. The latter are called sequences seq_i(t). The resulting signal of the DAC channel can be described as: ","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"S_i(t) = seq_i(t) + o_i + W_i(t)","category":"page"},{"location":"generation.html#Waveforms","page":"Signal Generation","title":"Waveforms","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Each of the 16-bit DAC channel can output a compositve waveform with four components. Each component can be parametrized by its amplitude a_ij, frequency f_ij and phase varphi_ij, which can all be changed via SCPI commands. Furthermore, each component also offers different waveforms w_ij(sine, triangle, sawtooth):","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"W_i(t) = sum_j=1^4a_ij w_ij(2pi f_ijt + varphi_i j)","category":"page"},{"location":"generation.html#Ramping","page":"Signal Generation","title":"Ramping","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"The signals output on the DAC channel can also be multiplied with an increasing/decreasing ramping factor r(t). Ramping and the ramping duration can be enabled and set on a per channel basis. The increasing factor starts from 0 and goes to 1 from the acquisition start on. The decreasing factor goes from 1 to 0.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"S_i(t) = r(t)S(t)","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"The ramp down has to be started either by a SCPI command or by a flag from a sequence. Disabling the acquisition trigger removes the ramp down flag, but not the flag that enables ramping itself.","category":"page"},{"location":"generation.html#Sequences","page":"Signal Generation","title":"Sequences","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"The FPGA image features a LUT containing values for all output channels. This LUT is treated as a ring-buffer through which the image iterates and outputs the values on their respective channel. The image can be configured to increment its LUT access every n samples. One period of a value is also called a step. A sequence is a series of steps and the number of times this series is to be repeated.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"As the LUT used by the FPGA image is small in comparison with the main memory and in order to support longer series of steps, the server itselfs maintains a sequence in its main memory and periodically reads the next steps from its sequence and writes them to the LUT of the image.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Comparable to the sample transmission of the acquisition, this updating of the LUT is also a process with timing uncertainty as it is affected by the scheduling and execution of the RedPitayas CPU. While during the sample transmission samples could be lost because they were overwritten, in the signal generation wrong signals could be output because the server was too slow in updating the values. Here, the server tracks similar performance metrics and also features a status flag lostSteps for exactly this case. In its current implementation a safe step rate is at 12 kHz.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Sequences and their steps also have additional features. A step can be marked such that during its duration the signal is set to 0. Furthermore, a step can be marked such that it triggers the ramp down. To make this easier to manage the server actually manages three sequences, that can be set individually: A ramp up, regular and ramp down sequence. The ramp up sequence is moved to the FPGA LUT at the acquisition start, followed by the regular sequence. Afterwards the ramp down sequence is started and during its execution the ramp down flag is set. Steps can also be marked to resync the fast DACs. During a resync, the signals are set to 0 and afterwards start again with their set phase and frequency. This can be used to change frequency and phase during measurements and s.t. the new phase and frequency is synchronous to the steps.","category":"page"},{"location":"generation.html#Calibration","page":"Signal Generation","title":"Calibration","text":"","category":"section"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Similar to the signal acquisition, there are also calibration scale c_i scale and offset c_i offset values for the signal generation. These are stored in the EEPROM of the RedPitaya and can be updated by a client. The calibration values are always applied, even when the master trigger is off.","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"Thus the total signal can be described as:","category":"page"},{"location":"generation.html","page":"Signal Generation","title":"Signal Generation","text":"S_i(t) = c_i scale S_i(t) + c_i offset","category":"page"},{"location":"connections.html#Connections","page":"Connections","title":"Connections","text":"","category":"section"},{"location":"connections.html","page":"Connections","title":"Connections","text":"An overview of the extension connectors (see also here) is given in the following image","category":"page"},{"location":"connections.html","page":"Connections","title":"Connections","text":"(Image: Connectors)","category":"page"},{"location":"connections.html","page":"Connections","title":"Connections","text":"The project uses most but not all connections that are used in the original RedPitaya image. From the connector E2 only the analog inputs and outputs are used. From the connector E1 several pins are reserved for the following purposes:","category":"page"},{"location":"connections.html","page":"Connections","title":"Connections","text":"DIO0_P for the ADC and DAC trigger. Connect it with the master's DIO5_P to distribute the trigger signal to all RedPitayas in a cluster. As long as the input is high, the DACs and ADCs are running.\nDIO1_P is the input for the watchdog (see configuration register section for further details)\nDIO2_P is used to acknowledge a received watchdog signal.\nDIO3_P can be set to high, to stop all DACs instantly.\nDIO4_P outputs a high for 10 ms after a 100 ms pause on low to provide an alive signal.\nDIO5_P can be set to high via the configuration register to provide the mutual trigger signal.\nDIO7_P, DIO7_N, DIO6_P, DIO6_N, DIO5_N, DIO4_N, DIO3_N, DIO2_N can be used as arbitrary outputs set via the server.\nDIO0_N and DIO1_N are used for the clock selection in a cluster.","category":"page"},{"location":"examples/cluster.html#Cluster-Example","page":"Cluster","title":"Cluster Example","text":"","category":"section"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"In this example we generate and acquire sine waves, similar to to the first example. However, this time we use two RedPitayas sychronized in a cluster. The example will create a sine wave on the first DAC channel of the first RedPitaya and a phase shifted sine wave on the first channel of the second RedPitaya. To run this example connect the RedPitayas in the following way:","category":"page"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"Note that while the example only plots the first channel of the RedPitaya, both channels are transmitted to the clients.","category":"page"},{"location":"examples/cluster.html#Julia-Client","page":"Cluster","title":"Julia Client","text":"","category":"section"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/cluster.html","page":"Cluster","title":"Cluster","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/cluster.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/sequenceMultiChannel.html#Sequence-Multi-Channel-and-Waveform-Enable-Example","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable Example","text":"","category":"section"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"This examples combines concepts from the three examples and additionally uses the signal enable feature of the sequences. This example uses both DAC and ADC channels of the RedPitaya. On the first DAC channel we output a sine waveform together with a climbing sequence. On the second channel we output just a sequence with a constant value and no waveforms at all. The signal enable flags of the sequences are set in such a way, that the two channels alternate being enabled with each step.","category":"page"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/sequenceMultiChannel.html#Julia-Client","page":"Sequence Multi-Channel and Waveform Enable","title":"Julia Client","text":"","category":"section"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/sequence.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/sequenceMultiChannel.html","page":"Sequence Multi-Channel and Waveform Enable","title":"Sequence Multi-Channel and Waveform Enable","text":"(Image: Simple Example Results)","category":"page"},{"location":"installation.html#Installation","page":"Installation","title":"Installation","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The RedPitayaDAQServer project uses a custom RedPitaya image that was derived from the red-pitaya-notes project. It consists of an Alpine Linux with some development tools installed, as well as the server and the FPGA images. The Linux image reserves the upper 128 MB of main memory for the FPGA, which is used as a buffer for recording the data from the ADCs. The latest releases of the project can be downloaded here.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To install the project on a RedPitaya, format an SD card in FAT32 and enable the bootable flag. On Linux this can be done with:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"sudo fdisk /dev/sdb","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"on the correct device. In the prompt create a new partition with n and change its type to FAT32 with the t command and the hex code b. With the command a the bootable flag can be toggled. Finish formatting with the w command.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Afterwards a file system can be created with:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"sudo mkfs -t vfat /dev/sdb1","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To finish installing the RedPitaya, simply unzip one of the releases and copy the files into the now empty and formatted SD card.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"When the RedPitaya is now booted, the server should start. One can then use a client to connect, at which point the FPGA image is loaded. ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The client library provided with the project is not an executable program, but it can be used to implement one. The library encapsulates the communication with the server and implements various optimizations. As the communication with the server is language agnostic one could therefore implement their own client in a different language. The Julia reference client library found in src/client/julia, the SCPI commands and the sections on the signal acquisition and generation are starting points for such a custom client.","category":"page"},{"location":"installation.html#Julia-Client","page":"Installation","title":"Julia Client","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To use the provided Julia client library you need to install RedPitayaDAQServer Julia package within Julia. To this end download Julia 1.5 or later and go into the package manager mode by intering ]. Then with ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"add RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"the latest release of the Julia client is added. To install a different version, please consult the Pkg documentation. The Julia client and the RedPitaya image should be from the same release to avoid errors due to communication protocol changes.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To try out the Julia examples one can either download them from Github directly, clone the whole repository or use the alternative way of installing Julia packages described here.","category":"page"},{"location":"installation.html#Updating","page":"Installation","title":"Updating","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The Julia client offers function to automatically update the server and FPGA of a RedPitaya. More on this can be found here. Note that this process deletes all data in the RedPitayaDAQServer folder on the RedPitaya.","category":"page"},{"location":"installation.html#Network-Connection","page":"Installation","title":"Network Connection","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The system as provided here should not be made accessible from the internet since it uses a default public password and ssh-key.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"One possible configuration to run single or a cluster of RedPitayas is to directly connect them with the measurement computer. In case of a cluster one can use a switch such that only a single network connector is required. In case that the measurement computer has no free ethernet port one can use a USB network adapter.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"In order to get this setup running you need to install a dhcp server on the measurement computer, such as dhcpd, and give the measurement computer a static IP address (e.g. 192.168.1.1). This can be installed with ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"sudo apt-get install isc-dhcp-server","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"One can then edit the /etc/dhcp/dhcpd.conf configuration file with a setup similar to the following example:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"subnet 192.168.1.0 netmask 255.255.255.0 {\n interface ????;\n\n #range dynamic-bootp 192.168.1.100 192.168.1.102;\n option broadcast-address 192.168.1.255;\n option routers 192.168.1.1;\n\n host rp1 {\n hardware ethernet 00:26:32:F0:70:83;\n fixed-address 192.168.1.100;\n }\n\n host rp2 {\n hardware ethernet 00:26:32:F0:92:97;\n fixed-address 192.168.1.101;\n }\n\n host rp3 {\n hardware ethernet 00:26:32:F0:61:F5;\n fixed-address 192.168.1.102;\n }\n}","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"The example defines three fixed IP addresses for three RedPitayas based on their MAC addresses. You may also need to specify DNS servers or alternatively create a network with a range of IPs (e.g. 192.168.1.100-105).","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Afterwards with","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"service isc-dhcp-server start","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"or ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"service isc-dhcp-server restart ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"one can start the DHCP service and should see the RedPitayas using the DHCP protocol to get their IP addresses with:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"journalctl -f -u isc-dhcp-server","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"This displays the latest log messages of the DHCP service. ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"If you need internet at your RedPitaya you need to configure the firewall to allow this using iptables. In this repository there is in the scripts directory a script rp-internet.sh where you need to change the network adapters to allow traffic going from the internet network adapter to the RedPitaya network adapter.","category":"page"},{"location":"installation.html#Building-Components","page":"Installation","title":"Building Components","text":"","category":"section"},{"location":"installation.html#Linux-Image-and-FPGA-Images","page":"Installation","title":"Linux Image and FPGA Images","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"If you want to build the Linux image or the FPGA bitfiles yourself, you can install Xilinx Vitis and Vivado (2021.2) in an Ubuntu environment (bare metal or virtual machine). Then run","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"sudo apt-get update\n\nsudo apt-get --no-install-recommends install \\\n build-essential bison flex git curl ca-certificates sudo \\\n xvfb fontconfig libxrender1 libxtst6 libxi6 make \\\n bc u-boot-tools device-tree-compiler libncurses5-dev \\\n libssl-dev qemu-user-static binfmt-support zip \\\n squashfs-tools dosfstools parted debootstrap zerofree","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"in order to get the essential tools. Afterwards clone the project with","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"git clone https://github.com/tknopp/RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Then switch into this directory. You can build the whole project using","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"make all","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"With ","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"make daq_bitfiles","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"one can build both the 7010 and the 7020 versions of the FPGA image. For different build targets consult the Makefiles.","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Note: make has to be run as root if you want to build the Linux image, since chroot requires root privileges.","category":"page"},{"location":"installation.html#Server","page":"Installation","title":"Server","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"To build the RedPitaya server connect the RedPitaya to your local network and access the device via ssh:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"ssh root@rp-f?????.local","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"where ????? is the ID that is printed on the RedPitaya. The default password is root. After logging into the RedPitaya go to the folder","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"/root/apps/","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"and clone the RedPitayaDAQServer project if it does not exist already:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"git clone https://github.com/tknopp/RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Sometimes you might need to make the file system writable by entering","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"mount -o remount,rw /dev/mmcblk0p1","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Then cd into RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"cd /root/apps/RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"and enter make server. This will compile the library, the server, and some example applications. After you restart the RedPitaya the DAQ server will automatically run and you can access it via TCP.","category":"page"},{"location":"installation.html#Developing-Julia-Client-Library","page":"Installation","title":"Developing Julia Client Library","text":"","category":"section"},{"location":"installation.html","page":"Installation","title":"Installation","text":"Another option when installing the Julia client is to add the package with the dev command:","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"dev RedPitayaDAQServer","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"in the package mode ].","category":"page"},{"location":"installation.html","page":"Installation","title":"Installation","text":"This installs the package in development mode and puts the files into ~/.julia/dev/RedPitayaDAQServer/. There you can the also modify the files, which is handy when trying out the examples. You need to manually git pull if you want to get updates, i.e. Julia will not update developed packages automatically.","category":"page"},{"location":"examples/waveforms.html#Waveforms-Example","page":"Waveforms","title":"Waveforms Example","text":"","category":"section"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"In this example we generate different signals with a base frequency of 10 kHz on DAC channel 1 and receive the same signals on the ADC channel 1. To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.","category":"page"},{"location":"examples/waveforms.html#Julia-Client","page":"Waveforms","title":"Julia Client","text":"","category":"section"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/waveforms.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/waveforms.html","page":"Waveforms","title":"Waveforms","text":"(Image: Simple Example Results)","category":"page"},{"location":"examples/batch.html#Batch-Example","page":"Batch","title":"Batch Example","text":"","category":"section"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"In this example we recreate the first example using the batch functionality offered by the Julia client. Note that all commands are still executed in order from the RedPitayas perspective, only the client communication is more efficient within a batch.","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.","category":"page"},{"location":"examples/batch.html#Julia-Client","page":"Batch","title":"Julia Client","text":"","category":"section"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/batch.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/batch.html","page":"Batch","title":"Batch","text":"(Image: Batch Example Results)","category":"page"},{"location":"examples/simple.html#Simple-Example","page":"Simple","title":"Simple Example","text":"","category":"section"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"In the first example we connect to a single RedPitaya and generate a sinus signal of frequency 10 kHz on DAC channel 1 and receive the same signal on the ADC channel 1. To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"Note that while the example only plots the first channel of the RedPitaya, both channels are transmitted to the clients.","category":"page"},{"location":"examples/simple.html#Julia-Client","page":"Simple","title":"Julia Client","text":"","category":"section"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"This and all other examples are located in the examples directory.","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/simple.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"(Image: Simple Example Results)","category":"page"},{"location":"examples/simple.html#Python-Client","page":"Simple","title":"Python Client","text":"","category":"section"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"This example is located in the python examples directory. The python examples use a very reduced Python client class that is located here. The Python client only wraps the low-level socket communication.","category":"page"},{"location":"examples/simple.html","page":"Simple","title":"Simple","text":"using Markdown\nMarkdown.parse(\"\"\"\n```python\n$(open(f->read(f, String), \"../../../src/examples/python/simple.py\"))\n```\n\"\"\")","category":"page"},{"location":"architecture.html#Architecture","page":"Architecture","title":"Architecture","text":"","category":"section"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The RedPitayaDAQServer project is implemented as a distributed system in which one client connects to a cluster of RedPitaya boards. The project has four software components:","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"FPGA image running on the RedPitayas FPGA\nC library encapsulating access to the FPGA image\nServer running on the CPU of the RedPitayas\nClient Julia reference library ","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The FPGA image is responsible for generating and acquiring synchronized out- and input signals. The server acts as an intermediary to the FPGA over a TCP/IP connection, which allows remote clients to configure the FPGA image and retrieve samples. Furthermore, the server also maintains a thread that takes part in signal generation.","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The Julia client library can be used to implement a data acquisition client application, which controls a (cluster of) RedPitaya(s). This Julia library acts as a reference, but in principle it is possible to write clients in any programming language, as the communication is language agnostic. In the example directory we provide a rudimentary Python client that allows to perform a simple data acquisition experiment.","category":"page"},{"location":"architecture.html#Communication","page":"Architecture","title":"Communication","text":"","category":"section"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The various components of the distributed system communicate over different interfaces. Communication within a RedPitaya is based on memory-mapped I/O, while communication between the server and a client is based on SCPI commands over a TCP/IP connection, usually over Ethernet. Lastly communication between RedPitayas is limited to signals distributed over cables as described in Cluster.","category":"page"},{"location":"architecture.html#FPGA-and-CPU","page":"Architecture","title":"FPGA and CPU","text":"","category":"section"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The FPGA image is directly connected to certain memory regions that can be memory mapped on the CPU side of the RedPitaya. Both the CPU and the FPGA image access the reserved main memory region as a sample buffer. The C library rp-daq-lib, which is located under src/lib/ in the project repository, encapsulates these memory accesses into a convenient C library. It is possible to use this C library directly on the RedPitaya when no communication with the host system is required, i.e. if one wants to write the acquired data into a file. When making changes to the FPGA image one may need to adapt the rp-daq-lib C library.","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The server itself uses the rp-daq-lib library to interface with the FPGA image.","category":"page"},{"location":"architecture.html#Client-and-Server","page":"Architecture","title":"Client and Server","text":"","category":"section"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"The server on each RedPitaya has two TCP sockets to which a client needs to connect. The first is the command socket on port 5025 and the second is the data socket on port 5026. Over the former, a client can send SCPI commands to the server and receive replies, while the latter is used for sending binary data such as the samples acquired by the ADCs.","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"SCPI commands are ASCII strings, such as RP:ADC:DECimation, which the server translates into C function calls. As an example these calls could invoke a function of the rp-daq-lib library to set the decimation of the sampling rate or instruct the server to transmit data over the data socket. A list of the available SCPI commands can be found here.","category":"page"},{"location":"architecture.html","page":"Architecture","title":"Architecture","text":"At any point a server is only connected to one client and establishing a new connection stops any current signal generation and acquisition.","category":"page"},{"location":"fpga.html#FPGA-Development","page":"FPGA Development","title":"FPGA Development","text":"","category":"section"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"There may be needs to change the FPGA image. The following explains how this can be done.","category":"page"},{"location":"fpga.html#Preparation","page":"FPGA Development","title":"Preparation","text":"","category":"section"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"If you want to make changes to the FPGA design, you need to install Vivado 2021.2. More infos for setting up a development machine we refer to the following resource and here.","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"After following the installation steps, you need to clone the repository into a directory of your choice and then regenerate the IP cores and the project by running","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"make daq_bitfiles.","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"Afterwards you can start Vivado and open the recreated project in ./build/fpga//firmware/RedPitayaDAQServer.xpr. Apply the changes you need and then create the bitfile by using 'Flow -> Generate Bitstream'. This runs the synthesis and implementation steps and output the Bitfile to ./build/fpga/firmware/RedPitayaDAQServer.runs/impl_1/system_wrapper.bit.","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"After creating the respective bitfile you need to copy it to your Red Pitayas. You can use","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"scp ./build/fpga//firmware/RedPitayaDAQServer.runs/impl_1/system_wrapper.bit root@:/root/RedPitayaDAQServer/bitfiles/daq_.bit","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"for this. Set your IP and FPGA version accordingly. Another option is to fully regenerate the Linux image with make all and copy it to the SD card.","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"Since using git with Vivado can be annoying here are some hints how you can make your changes ready for git:","category":"page"},{"location":"fpga.html","page":"FPGA Development","title":"FPGA Development","text":"If you only changed some stuff in the blockdesign, you just have to export the blockdesign to ./src/fpga/bd/bd.tcl by using 'File -> Export -> Export Block Design' in Vivado.\nChanges to the project settings have to be done in ./src/fpga/build.tcl in order to not lose the ability to recreate your changed project.\nFor your own IP cores, just create a new directory in ./src/fpga/cores and copy and adapt the core_config.tcl of another core. Afterwards re-run make cores.","category":"page"},{"location":"acquisition.html#Data-Acquisition","page":"Data Acquisition","title":"Data Acquisition","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The data acquisition of the RedPitayaDAQServer project is based on two data flows to and from the upper 128 MB of the RedPitaya memory. This memory region acts as a ring buffer for the acquired samples and can be queried by clients using SCPI commands.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"Signal acquisition within a cluster is based on a shared clock and trigger signal distributed via cables between the RedPitayas. Once triggered, all FPGAs continuously write the samples from their ADC channel to the sample ring-buffer with each clock tick. Both ADC channels on a RedPitaya are written to the buffer at the same time. The 14-bit values of the ADCs are converted to 16-bit signed integer samples and then concatenated into one 32-bit value, which is then written to the buffer. The sampling rate of the system can be adjusted by setting a decimation parameter and the decimation itself is realized with a CIC filter.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"Internally, the FPGA keeps track of a 64-bit writepointer register pointing into the ring-buffer and increments this value with each new sample pair. Additionally, the writepointer also counts the number of buffer overflows. As the size of the buffer region is a power of two, these two components of the writepointer can be interpreted as one 64-bit number counting the samples from acquisition start. For the 128 MB buffer, this means that the lower 25 bits of the writepointer are the buffer location and the remaining bits are the overflow counter.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"As the writepointer is reset and incremented based on a shared clock and trigger signal, it is synchronized across all FPGA images in a cluster. The logic implemented with the reprogrammable hardware is also the only logic of the RedPitayaDAQServer with predictable timing behaviour. All other components of the system implement their (timing related) logic in reference to the current writepointer values. With a known sampling rate, the writepointer can also be seen as the clock of the server and client components.","category":"page"},{"location":"acquisition.html#Sample-Transmission","page":"Data Acquisition","title":"Sample Transmission","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"To retrieve samples from the server a client can supply a similar pointer, called readpointer, together with the number of samples to retrieve. The server then extracts the buffer position from the readpointer and transmits the requested amount of samples over the data socket. This transmission happens either way, even if the samples are overwritten. However, the server uses the whole readpointer, including the buffer overflows, to check if the requested samples were overwritten.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"If the distance between the write- and readpointer is larger than the buffer size the overflow status flag is set. If during the transmission the requested samples are overwritten the corrupted flag is set. These flags can be queried individually or together in a status byte via SCPI commands.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"This distance can not only be used to see if samples were overwritten, but also to track how well the client is able to keep up with the FPGA during a series of sample transmissions. If this distance increases over time, the FPGA is creating more samples than the server can transmit to the client. To allow a client to track this value, this distance is stored as a 64-bit value deltaRead for the latest transmission and can be queried. Additionally, the server also tracks the duration of the transmission as writepointer \"clock ticks\" as a 64-bit value deltaSend, which is just the difference between the writepointer at the start and end of a transmission.","category":"page"},{"location":"acquisition.html#Considerations-for-Sample-Transmission","page":"Data Acquisition","title":"Considerations for Sample Transmission","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"There are several things to consider when attempting to retrieve samples at a high sampling rate, for larger cluster sizes or for longer periods of time. Most of the following points were implemented/considered in the Julia reference implementation, but would become relevant when implementing custom clients.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"As the server will always transmit samples just based on the buffer position of a readpointer, if a client wants to only receive certain samples it needs to wait for them to exist in the buffer. This requires querying the writepointer until it is larger than the desired readpointer.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"If the number of requested samples is larger than the buffer, the sample should be requested in smaller chunks as the server would otherwise return samples that were not written yet. In a cluster scenario the i-th chunk should be requested from all RedPitayas in the cluster before requesting the next chunk to avoid \"starvation\" effects.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The status and performance data of a transmission can only be queried after the transmission has finished, which requires additionaly communication overhead.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"To help clients with these issues, the server offers a second type of sample transmission in which samples, status and performance data is pipelined. In such a query a client first transmits a readpointer, together with the number of requested samples and the number of samples belonging to a chunk. The server itself then tracks the writepointer and transmits a chunk as soon as it becomes available and immidiatey follows that up with the status and performance data of the transmission. This way additional communication overheard is reduced and after the inital request a client just needs to read data until the transmission finishes.","category":"page"},{"location":"acquisition.html#Frames,-Periods-and-Voltage","page":"Data Acquisition","title":"Frames, Periods and Voltage","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The samples sent by the server are the 16-bit values of the ADC channel of a RedPitaya. However, one might want to work with voltage values instead or encapsulate samples into a repeating concept like frames. The Julia client library offers functions to convert samples into such a concept or to directly request a number of frames instead of a number of samples.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"Here, frames are comprised of periods, which in turn are comprised of samples. During the conversion process the 16-bit binary values can also be converted to floating point numbers representing a voltage if the RedPitaya was calibrated beforehand. In this calibration process, a client can store scale and offset values for each channel in the EEPROM of the RedPitaya. When the client establishes a connection to the server, it reads these values and can use them to translate the 16-bit values into a respective voltage value.","category":"page"},{"location":"acquisition.html#Sampling-and-Data-Rates,-Transmission-Speeds-and-Time-to-Live","page":"Data Acquisition","title":"Sampling and Data Rates, Transmission Speeds and Time-to-Live","text":"","category":"section"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The highest supported sampling rate of the RedPitayaDAQServer is 15.625 MHz or 15.625 MS/s, as this is the sampling rate at which a single RedPitaya can produce and transmit samples continously without data loss given the 1 Gbit/s limit of the ethernet connection from the RedPitaya. This rate is a achieved with a decimation of 8 from the base 125 MHz sampling rate of the RedPitaya hardware.","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"At this sampling rate a single RedPitaya produces new samples at a data rate of 500 Mbit/s. Furthermore at this rate, once a sample has been written to the buffer it exists for 2.15s before being overwritten again (Time-To-Live, TTL). An overview of these metrics for different decimation factors is shown in the following table:","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"Decimation MHz MByte/s Mbit/s TTL\n64 1.95 7.81 62.5 17.18s\n32 3.91 15.63 125 8.59s\n16 7.81 31.25 250 4.29s\n8 15.63 62.5 500 2.15s","category":"page"},{"location":"acquisition.html","page":"Data Acquisition","title":"Data Acquisition","text":"The table only refers to the data rate of new samples being produced. The data rate of samples being transmitted to a client can differ greatly depending on how the client queries and processes the samples and the available network bandwidth and usage. At the higher sampling rates it is recommended to have client threads that exclusively receive samples and perform any computation on samples in different threads to maximise the transmission speed, as a server can only transmit data at a rate of just above 500 Mbit/s. This exceeds the highest supported sampling rate by only a few Mbit/s and a client with frequency interruptions of its sample reception might not be able to keep up with the sampling rate.","category":"page"},{"location":"examples/ramping.html#Ramping-Example","page":"Ramping","title":"Ramping Example","text":"","category":"section"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"In this example we ramp up the amplitude of our signal over 10 periods and we retrieve the first 12 periods of samples. Then after a wait we receive the next 12 periods. Afterwards we trigger the ramp down of the signal. As this is triggered by a command that is sent over the network it varies when the ramp down actually start. A ramp down can be triggered at a specific point with the help of a sequence.","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.","category":"page"},{"location":"examples/ramping.html#Julia-Client","page":"Ramping","title":"Julia Client","text":"","category":"section"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/ramping.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/ramping.html","page":"Ramping","title":"Ramping","text":"(Image: Ramping Example Results)","category":"page"},{"location":"cluster.html#Cluster","page":"Cluster","title":"Cluster","text":"","category":"section"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"The RedPitayaDAQServer allows to use multiple RedPitayas in a fully synchronized fashion. One of the RedPitayas will act as the master and distribute its clock to all other RedPitayas acting as slaves.","category":"page"},{"location":"cluster.html#Prerequisites","page":"Cluster","title":"Prerequisites","text":"","category":"section"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"Unfortunately, the STEMlab 125-4 does not allow cluster synchronization without hardware modifications. It is therefore necessary to resolder all slaves according to this documentation. The required mode for this project is 'Directly from FPGA' which requires resistors on R27 and R28. The heatsink has to be removed temporarily in order to unsolder the two resistor below it. In the following image you can see the new position of the 0 Ohm 0402 resistors. Since they get lost easily, make sure you have some in stock.","category":"page"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"(Image: Cluster)","category":"page"},{"location":"cluster.html#Connections","page":"Cluster","title":"Connections","text":"","category":"section"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"To run a cluster of RedPitayas one needs to connect the devices using different cables. An exemplary cluster with 3 devices is shown in the following image.","category":"page"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"(Image: Cluster)","category":"page"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"The clock is distributed from the master to the first slave via an SATA cable (green). Additional slaves can be used by connecting the next slave to the previous one. Additionally all slaves have connection from +3.3 Volt to DIO0_N.","category":"page"},{"location":"cluster.html","page":"Cluster","title":"Cluster","text":"In order to send a mutual trigger signal for starting the acquisition and the signal generation, you also have to connect the master's DIO5_P pin with the DIO0_P pin of all devices including the master.","category":"page"},{"location":"client.html#Client","page":"Client Library","title":"Client","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"This page contains documentation of the public API of the Julia client. In the Julia REPL one can access this documentation by entering the help mode with ? and then writing the function for which the documentation should be shown.","category":"page"},{"location":"client.html#Connection-and-Communication","page":"Client Library","title":"Connection and Communication","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"RedPitayaDAQServer.RedPitaya\nRedPitayaDAQServer.RedPitaya(::String, ::Int64, ::Int64, ::Bool)\nRedPitayaDAQServer.send(::RedPitaya, ::String)\nRedPitayaDAQServer.query\nRedPitayaDAQServer.receive\nRedPitayaDAQServer.ServerMode\nRedPitayaDAQServer.serverMode\nRedPitayaDAQServer.serverMode!\nRedPitayaDAQServer.ScpiBatch\nRedPitayaDAQServer.@add_batch\nRedPitayaDAQServer.execute!\nRedPitayaDAQServer.push!(::ScpiBatch, ::Pair{K, T}) where {K<:Function, T<:Tuple}\nRedPitayaDAQServer.pop!(::ScpiBatch)\nRedPitayaDAQServer.clear!(::ScpiBatch)\nRedPitayaDAQServer.RedPitayaCluster\nRedPitayaDAQServer.RedPitayaCluster(::Vector{String}, ::Int64, ::Int64)\nRedPitayaDAQServer.length(::RedPitayaCluster)\nRedPitayaDAQServer.master","category":"page"},{"location":"client.html#RedPitayaDAQServer.RedPitaya","page":"Client Library","title":"RedPitayaDAQServer.RedPitaya","text":"RedPitaya\n\nStruct representing a connection to a RedPitayaDAQServer.\n\nContains the sockets used for communication and connection related metadata. Also contains fields for client specific concepts such as periods, frames and calibration values. \n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.RedPitaya-Tuple{String, Int64, Int64, Bool}","page":"Client Library","title":"RedPitayaDAQServer.RedPitaya","text":"RedPitaya(ip [, port = 5025, dataPort=5026, isMaster = false])\n\nConstruct a RedPitaya.\n\nDuring the construction the connection is established and the calibration values are loaded from the RedPitayas EEPROM. Throws an error if a timeout occurs while attempting to connect.\n\nExamples\n\njulia> rp = RedPitaya(\"192.168.1.100\");\n\njulia> decimation!(rp, 8)\ntrue\n\njulia> decimation(rp)\n8\n\n\n\n\n\n","category":"method"},{"location":"client.html#Sockets.send-Tuple{RedPitaya, String}","page":"Client Library","title":"Sockets.send","text":"send(rp::RedPitaya, cmd::String)\n\nSend a command to the RedPitaya. Appends delimiter.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.query","page":"Client Library","title":"RedPitayaDAQServer.query","text":"query(rp::RedPitaya, cmd [, timeout = 5.0, N = 100])\n\nSend a query to the RedPitaya command socket. Return reply as String.\n\nWaits for timeout seconds and checks every timeout/N seconds.\n\nSee also receive.\n\n\n\n\n\nquery(rp::RedPitaya, cmd, T::Type [timeout = 5.0, N = 100])\n\nSend a query to the RedPitaya. Parse reply as T.\n\nWaits for timeout seconds and checks every timeout/N seconds.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.receive","page":"Client Library","title":"RedPitayaDAQServer.receive","text":"receive(rp::RedPitaya)\n\nReceive a String from the RedPitaya command socket. Reads until a whole line is received\n\n\n\n\n\nreceive(rp::RedPitaya, ch::Channel)\n\nReceive a String from the RedPitaya command socket. Reads until a whole line is received and puts it in the supplied channel ch.\n\n\n\n\n\nreceive(rp::RedPitaya, timeout::Number)\n\nReceive a string from the RedPitaya command socket. Reads until a whole line is received or timeout seconds passed. In the latter case an error is thrown.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.ServerMode","page":"Client Library","title":"RedPitayaDAQServer.ServerMode","text":"ServerMode\n\nRepresent the different modes the server can be in. Valid values are CONFIGURATION, ACQUISITION and TRANSMISSION.\n\nSee also serverMode, serverMode!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.serverMode","page":"Client Library","title":"RedPitayaDAQServer.serverMode","text":"serverMode(rp::RedPitaya)\n\nReturn the mode of the server.\n\nExamples\n\njulia> serverMode!(rp, ACQUISITION);\ntrue\n\njulia> serverMode(rp)\nACQUISITION\n\n\n\n\n\nserverMode(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.serverMode!","page":"Client Library","title":"RedPitayaDAQServer.serverMode!","text":"serverMode!(rp::RedPitaya, mode::ServerMode)\n\nSet the mode of the server. Valid values are \"CONFIGURATION\" and \"ACQUISITION\".\n\nExamples\n\njulia> serverMode!(rp, ACQUISITION);\ntrue\n\njulia> serverMode(rp)\nACQUISITION\n\n\n\n\n\nserverMode!(rp::RedPitaya, mode::ServerMode)\n\nSet the mode of the server.\n\nExamples\n\njulia> serverMode!(rp, ACQUISITION);\ntrue\n\njulia> serverMode(rp)\nACQUISITION\n\n\n\n\n\nserverMode!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.ScpiBatch","page":"Client Library","title":"RedPitayaDAQServer.ScpiBatch","text":"ScpiBatch\n\nStruct representing a batch of SCPI commands for a RedPitaya. Only commands that interact exclusively with the command socket should be used in a batch.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.@add_batch","page":"Client Library","title":"RedPitayaDAQServer.@add_batch","text":"@add_batch batch cmd\n\nAppend a usual RedPitaya function to the given batch instead of evaluating it directly.\n\nSee also ScpiBatch, push!, execute!\n\nExamples\n\njulia> execute!(rp) do b\n @add_batch b serverMode!(rp, CONFIGURATION)\n end\n\n\n\n\n\n","category":"macro"},{"location":"client.html#RedPitayaDAQServer.execute!","page":"Client Library","title":"RedPitayaDAQServer.execute!","text":"execute!(rp::RedPitaya, batch::ScpiBatch)\n\nExecutes all commands of the given batch. Returns an array of the results in the order of the commands. An element is nothing if the command has no return value.\n\n\n\n\n\nexecute!(rpc::RedPitayaCluster, batch::ScpiBatch)\n\nExecutes all commands of the given batch. Returns an array of the results in the order of the commands.\n\nEach element of the result array is again an array containing the return values of the RedPitayas. An element of an inner array is nothing if the command has no return value.\n\n\n\n\n\nexecute!(f::Function, rp::Union{RedPitaya, RedPitayaCluster})\n\nOpen a ScpiBatch and evaluate the function f. If no exception was thrown, execute the opened batch.\n\nSee also ScpiBatch, push!, @add_batch\n\nExamples\n\njulia> execute!(rp) do b\n @add_batch b serverMode!(rp, CONFIGURATION)\n @add_batch b amplitudeDAC!(rp, 1, 1, 0.2)\n end\n\n\n\n\n\n","category":"function"},{"location":"client.html#Base.push!-Union{Tuple{T}, Tuple{K}, Tuple{ScpiBatch, Pair{K, T}}} where {K<:Function, T<:Tuple}","page":"Client Library","title":"Base.push!","text":"push!(batch::ScpiBatch, cmd::Pair{K, T}) where {K<:Function, T<:Tuple}\n\nAdd the given function and arguments to the batch\n\nExamples\n\njulia> batch = ScpiBatch() \n\njulia> push!(batch, amplitudeDAC! => (1, 1, 0.2))\n\n\n\n\n\n","category":"method"},{"location":"client.html#Base.pop!-Tuple{ScpiBatch}","page":"Client Library","title":"Base.pop!","text":"pop!(batch::ScpiBatch)\n\nRemove the last added command from the batch\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.clear!-Tuple{ScpiBatch}","page":"Client Library","title":"RedPitayaDAQServer.clear!","text":"clear!(batch::ScpiBatch)\n\nRemove all commands from the batch\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.RedPitayaCluster","page":"Client Library","title":"RedPitayaDAQServer.RedPitayaCluster","text":"RedPitayaCluster\n\nStruct representing a cluster of RedPitayas. Such a cluster should share a common clock and master trigger.\n\nThe structure implements the indexing and iterable interfaces.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.RedPitayaCluster-Tuple{Vector{String}, Int64, Int64}","page":"Client Library","title":"RedPitayaDAQServer.RedPitayaCluster","text":"RedPitayaCluster(hosts::Vector{String} [, port = 5025])\n\nConstruct a RedPitayaCluster.\n\nDuring the construction the first host is labelled the master RedPitaya of a cluster and all RedPitayas are set to using the EXTERNAL trigger mode.\n\nSee also RedPitaya, master.\n\nExamples\n\njulia> rpc = RedPitayaCluster([\"192.168.1.100\", \"192.168.1.101\"]);\n\njulia> rp = master(rpc)\n\njulia> rp == rpc[1]\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#Base.length-Tuple{RedPitayaCluster}","page":"Client Library","title":"Base.length","text":"length(rpc::RedPitayaCluster)\n\nReturn the number of RedPitayas in cluster rpc.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.master","page":"Client Library","title":"RedPitayaDAQServer.master","text":"master(rpc::RedPitayaCluster)\n\nReturn the master RedPitaya of the cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#ADC-Configuration","page":"Client Library","title":"ADC Configuration","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"RedPitayaDAQServer.TriggerMode\nRedPitayaDAQServer.triggerMode\nRedPitayaDAQServer.triggerMode!\nRedPitayaDAQServer.keepAliveReset\nRedPitayaDAQServer.keepAliveReset!\nRedPitayaDAQServer.decimation\nRedPitayaDAQServer.decimation!\nRedPitayaDAQServer.samplesPerPeriod\nRedPitayaDAQServer.samplesPerPeriod!\nRedPitayaDAQServer.periodsPerFrame\nRedPitayaDAQServer.periodsPerFrame!\nRedPitayaDAQServer.calibADCOffset\nRedPitayaDAQServer.calibADCOffset!\nRedPitayaDAQServer.calibADCScale\nRedPitayaDAQServer.calibADCScale!\nRedPitayaDAQServer.updateCalib!","category":"page"},{"location":"client.html#RedPitayaDAQServer.TriggerMode","page":"Client Library","title":"RedPitayaDAQServer.TriggerMode","text":"TriggerMode\n\nRepresent the different trigger modes the FPGA image can have. Valid value are INTERNAL and EXTERNAL.\n\nSee triggerMode, triggerMode!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.triggerMode","page":"Client Library","title":"RedPitayaDAQServer.triggerMode","text":"triggerMode(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.triggerMode!","page":"Client Library","title":"RedPitayaDAQServer.triggerMode!","text":"triggerMode!(rp::RedPitaya, mode::String)\n\nSet the trigger mode of the RedPitaya. Return true if the command was successful.\n\n\n\n\n\ntriggerMode!(rp::RedPitaya, mode::String)\n\nSet the trigger mode of the RedPitaya. Return true if the command was successful.\n\n\n\n\n\ntriggerMode!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.keepAliveReset","page":"Client Library","title":"RedPitayaDAQServer.keepAliveReset","text":"keepAliveReset(rp::RedPitaya)\n\nDetermine whether the keepAliveReset is set.\n\n\n\n\n\nkeepAliveReset(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.keepAliveReset!","page":"Client Library","title":"RedPitayaDAQServer.keepAliveReset!","text":"keepAliveReset!(rp::RedPitaya, val::Bool)\n\nSet the keepAliveReset to val.\n\n\n\n\n\nkeepAliveReset!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.decimation","page":"Client Library","title":"RedPitayaDAQServer.decimation","text":"decimation(rp::RedPitaya)\n\nReturn the decimation of the RedPitaya.\n\nExamples\n\njulia> decimation!(rp, 8)\ntrue\n\njulia> decimation(rp)\n8\n\n\n\n\n\ndecimation(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.decimation!","page":"Client Library","title":"RedPitayaDAQServer.decimation!","text":"decimation!(rp::RedPitaya, dec)\n\nSet the decimation of the RedPitaya. Return true if the command was successful.\n\nExamples\n\njulia> decimation!(rp, 8)\ntrue\n\njulia> decimation(rp)\n8\n\n\n\n\n\ndecimation!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.samplesPerPeriod","page":"Client Library","title":"RedPitayaDAQServer.samplesPerPeriod","text":"samplesPerPeriod(rp::RedPitaya)\n\nReturn the number of samples per period.\n\nExample\n\njulia> samplesPerPeriod!(rp, 256)\ntrue\n\njulia> samplesPerPeriod(rp)\n256\n\n\n\n\n\n\nsamplesPerPeriod(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.samplesPerPeriod!","page":"Client Library","title":"RedPitayaDAQServer.samplesPerPeriod!","text":"samplesPerPeriod!(rp::RedPitaya, value)\n\nSet the number of samples per period.\n\nExample\n\njulia> samplesPerPeriod!(rp, 256)\ntrue\n\njulia> samplesPerPeriod(rp)\n256\n\n\n\n\n\n\nsamplesPerPeriod!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.periodsPerFrame","page":"Client Library","title":"RedPitayaDAQServer.periodsPerFrame","text":"periodsPerFrame(rp::RedPitaya)\n\nReturn the number of periods per frame.\n\nExample\n\njulia> periodsPerFrame!(rp, 16)\n\njulia> periodsPerFrame(rp)\n16\n\n\n\n\n\n\nperiodsPerFrame(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.periodsPerFrame!","page":"Client Library","title":"RedPitayaDAQServer.periodsPerFrame!","text":"periodsPerFrame(rp::RedPitaya, value)\n\nSet the number of periods per frame.\n\nExample\n\njulia> periodsPerFrame!(rp, 16)\n\njulia> periodsPerFrame(rp)\n16\n\n\n\n\n\n\nperiodsPerFrame!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibADCOffset","page":"Client Library","title":"RedPitayaDAQServer.calibADCOffset","text":"calibADCOffset(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration ADC offset for given channel from the RedPitayas EEPROM.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibADCOffset!","page":"Client Library","title":"RedPitayaDAQServer.calibADCOffset!","text":"calibADCOffset!(rp::RedPitaya, channel::Integer, val)\n\nStore calibration ADC offset val for given channel into the RedPitayas EEPROM. Absolute value has to be smaller than 1.0 V.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibADCScale","page":"Client Library","title":"RedPitayaDAQServer.calibADCScale","text":"calibADCScale(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration ADC scale for given channel from the RedPitayas EEPROM.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibADCScale!","page":"Client Library","title":"RedPitayaDAQServer.calibADCScale!","text":"calibADCScale(rp::RedPitaya, channel::Integer)\n\nStore calibration ADC scale val for given channel into the RedPitayas EEPROM. See also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.updateCalib!","page":"Client Library","title":"RedPitayaDAQServer.updateCalib!","text":"updateCalib!(rp::RedPitaya)\n\nUpdate the cached calibration values.\n\nSee also calibADCScale, calibADCOffset.\n\n\n\n\n\n","category":"function"},{"location":"client.html#DAC-Configuration","page":"Client Library","title":"DAC Configuration","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"RedPitayaDAQServer.amplitudeDAC\nRedPitayaDAQServer.amplitudeDAC!\nRedPitayaDAQServer.offsetDAC\nRedPitayaDAQServer.offsetDAC!\nRedPitayaDAQServer.frequencyDAC\nRedPitayaDAQServer.frequencyDAC!\nRedPitayaDAQServer.phaseDAC\nRedPitayaDAQServer.phaseDAC!\nRedPitayaDAQServer.SignalType\nRedPitayaDAQServer.signalTypeDAC\nRedPitayaDAQServer.signalTypeDAC!\nRedPitayaDAQServer.seqChan\nRedPitayaDAQServer.seqChan!\nRedPitayaDAQServer.samplesPerStep\nRedPitayaDAQServer.samplesPerStep!\nRedPitayaDAQServer.stepsPerFrame!\nRedPitayaDAQServer.clearSequence!\nRedPitayaDAQServer.sequence!\nRedPitayaDAQServer.calibDACOffset\nRedPitayaDAQServer.calibDACOffset!\nRedPitayaDAQServer.calibDACScale\nRedPitayaDAQServer.calibDACScale!\nRedPitayaDAQServer.calibDACUpperLimit!\nRedPitayaDAQServer.calibDACLowerLimit!","category":"page"},{"location":"client.html#RedPitayaDAQServer.amplitudeDAC","page":"Client Library","title":"RedPitayaDAQServer.amplitudeDAC","text":"amplitudeDAC(rp::RedPitaya, channel, component)\n\nReturn the amplitude of composite waveform component for channel.\n\nSee amplitudeDAC!.\n\nExamples\n\njulia> amplitudeDAC!(rp, 1, 1, 0.5);\ntrue\n\njulia> amplitudeDAC(rp, 1, 1)\n0.5\n\n\n\n\n\namplitudeDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.amplitudeDAC!","page":"Client Library","title":"RedPitayaDAQServer.amplitudeDAC!","text":"amplitudeDAC!(rp::RedPitaya, channel, component, value)\n\nSet the amplitude of composite waveform component for channel. Return true if the command was successful.\n\nSee amplitudeDAC.\n\nExamples\n\njulia> amplitudeDAC!(rp, 1, 1, 0.5);\ntrue\n\njulia> amplitudeDAC(rp, 1, 1)\n0.5\n\n\n\n\n\namplitudeDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.offsetDAC","page":"Client Library","title":"RedPitayaDAQServer.offsetDAC","text":"offsetDAC(rp::RedPitaya, channel)\n\nReturn the offset for channel.\n\nSee offsetDAC!.\n\nExamples\n\njulia> offsetDAC!(rp, 1, 0.2);\ntrue\n\njulia> offsetDAC(rp, 1)\n0.2\n\n\n\n\n\noffsetDAC(rpc::RedPitayaCluster, chan::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.offsetDAC!","page":"Client Library","title":"RedPitayaDAQServer.offsetDAC!","text":"offsetDAC!(rp::RedPitaya, channel, value)\n\nSet the offset for channel. Return true if the command was successful.\n\nSee offsetDAC.\n\nExamples\n\njulia> offsetDAC!(rp, 1, 0.2);\ntrue\n\njulia> offsetDAC(rp, 1)\n0.2\n\n\n\n\n\noffsetDAC!(rpc::RedPitayaCluster, chan::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.frequencyDAC","page":"Client Library","title":"RedPitayaDAQServer.frequencyDAC","text":"frequencyDAC(rp::RedPitaya, channel, component)\n\nReturn the frequency of composite waveform component for channel.\n\nSee frequencyDAC!.\n\nExamples\n\njulia> frequencyDAC!(rp, 1, 1, 2400);\ntrue\n\njulia> frequencyDAC(rp, 1, 1)\n2400\n\n\n\n\n\nfrequencyDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.frequencyDAC!","page":"Client Library","title":"RedPitayaDAQServer.frequencyDAC!","text":"frequencyDAC!(rp::RedPitaya, channel, component, value)\n\nSet the frequency of composite waveform component for channel. Return true if the command was successful.\n\nSee frequencyDAC.\n\nExamples\n\njulia> frequencyDAC!(rp, 1, 1, 2400);\ntrue\n\njulia> frequencyDAC(rp, 1, 1)\n2400\n\n\n\n\n\nfrequencyDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.phaseDAC","page":"Client Library","title":"RedPitayaDAQServer.phaseDAC","text":"phaseDAC(rp::RedPitaya, channel, component)\n\nReturn the phase of composite waveform component for channel.\n\nSee phaseDAC!.\n\nExamples\n\njulia> phaseDAC!(rp, 1, 1, 0.0);\ntrue\n\njulia> phaseDAC(rp, 1, 0.0)\n0.0\n\n\n\n\n\nphaseDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.phaseDAC!","page":"Client Library","title":"RedPitayaDAQServer.phaseDAC!","text":"phaseDAC!(rp::RedPitaya, channel, component, value)\n\nSet the phase of composite waveform component for channel. Return true if the command was successful.\n\nSee phaseDAC.\n\nExamples\n\njulia> phaseDAC!(rp, 1, 1, 0.0);\ntrue\n\njulia> phaseDAC(rp, 1, 0.0)\n0.0\n\n\n\n\n\nphaseDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.SignalType","page":"Client Library","title":"RedPitayaDAQServer.SignalType","text":"SignalType\n\nRepresent the different types of signals the fast DAC can have. Valid values are SINE, TRIANGLE and SAWTOOTH.\n\nSee signalTypeDAC, signalTypeDAC!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.signalTypeDAC","page":"Client Library","title":"RedPitayaDAQServer.signalTypeDAC","text":"signalTypeDAC!(rp::RedPitaya, channel, value)\n\nReturn the signalType of composite waveform for channel.\n\nSee signalTypeDAC!.\n\nExamples\n\njulia> signalTypeDAC!(rp, 1, SINE);\ntrue\n\njulia> signalTypeDAC(rp, 1)\nSINE\n\n\n\n\n\nsignalTypeDAC(rpc::RedPitayaCluster, chan::Integer, component::Integer)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.signalTypeDAC!","page":"Client Library","title":"RedPitayaDAQServer.signalTypeDAC!","text":"signalTypeDAC!(rp::RedPitaya, channel, value)\n\nSet the signalType of composite waveform for channel. Return true if the command was successful.\n\nSee signalTypeDAC.\n\nExamples\n\njulia> signalTypeDAC!(rp, 1, SINE);\ntrue\n\njulia> signalTypeDAC(rp, 1)\nSINE\n\n\n\n\n\nsignalTypeDAC!(rpc::RedPitayaCluster, chan::Integer, component::Integer, value)\n\nAs with single RedPitaya. The chan index refers to the total channel available in a cluster, two per RedPitaya. For example channel 4 would refer to the second channel of the second RedPitaya.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.seqChan","page":"Client Library","title":"RedPitayaDAQServer.seqChan","text":"seqChan(rp::RedPitaya)\n\nReturn the number of sequence channel.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.seqChan!","page":"Client Library","title":"RedPitayaDAQServer.seqChan!","text":"seqChan!(rp::RedPitaya, value)\n\nSet the number of sequence channel. Valid values are between 1 and 6. Return true if the command was successful.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.samplesPerStep","page":"Client Library","title":"RedPitayaDAQServer.samplesPerStep","text":"samplesPerStep(rp::RedPitaya)\n\nReturn the number of samples per sequence step.\n\n\n\n\n\nsamplesPerStep(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.samplesPerStep!","page":"Client Library","title":"RedPitayaDAQServer.samplesPerStep!","text":"samplesPerStep!(rp::RedPitaya, value::Integer)\n\nSet the number of samples per sequence step. Return true if the command was successful.\n\n\n\n\n\nsamplesPerStep!(rpc::RedPitayaCluster, value)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.stepsPerFrame!","page":"Client Library","title":"RedPitayaDAQServer.stepsPerFrame!","text":"stepsPerFrame!(rp::RedPitaya, stepsPerFrame)\n\nSet the number of samples per steps s.t. stepsPerFrame sequence steps in a frame.\n\nSee samplesPerPeriod!, periodsPerFrame!, samplesPerStep!.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.clearSequence!","page":"Client Library","title":"RedPitayaDAQServer.clearSequence!","text":"clearSequence!(rp::RedPitaya)\n\nInstruct the server to remove all sequences from its list. Return true if the command was successful.\n\n\n\n\n\nclearSequence!(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.sequence!","page":"Client Library","title":"RedPitayaDAQServer.sequence!","text":"sequence!(rp::RedPitaya, seq::AbstractSequence)\n\nTransmit the client-side representation seq to the server and append it to the current list of sequences. Return true if the required commands were successful.\n\n\n\n\n\nsequence!(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to all RedPitayas in a cluster.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACOffset","page":"Client Library","title":"RedPitayaDAQServer.calibDACOffset","text":"calibDACOffset(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC offset for given channel from the RedPitayas EEPROM \n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACOffset!","page":"Client Library","title":"RedPitayaDAQServer.calibDACOffset!","text":"calibDACOffset!(rp::RedPitaya, channel::Integer, val)\n\nStore calibration DAC offset val for given channel into the RedPitayas EEPROM. This value is used by the server to offset the output voltage. Absolute value has to be smaller than 1.0 V. \n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACScale","page":"Client Library","title":"RedPitayaDAQServer.calibDACScale","text":"calibDACScale(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC scale for given channel from the RedPitayas EEPROM.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACScale!","page":"Client Library","title":"RedPitayaDAQServer.calibDACScale!","text":"calibDACScale(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC scale val for given channel into the RedPitayas EEPROM. This value is used by the server to scale the output voltage.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACUpperLimit!","page":"Client Library","title":"RedPitayaDAQServer.calibDACUpperLimit!","text":"calibDACUpperLimit!(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC upper limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.calibDACLowerLimit!","page":"Client Library","title":"RedPitayaDAQServer.calibDACLowerLimit!","text":"calibDACLowerLimit!(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC lower limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.\n\n\n\n\n\n","category":"function"},{"location":"client.html#Measurement-and-Transmission","page":"Client Library","title":"Measurement and Transmission","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"RedPitayaDAQServer.masterTrigger\nRedPitayaDAQServer.masterTrigger!\nRedPitayaDAQServer.currentWP\nRedPitayaDAQServer.currentFrame\nRedPitayaDAQServer.currentPeriod\nRedPitayaDAQServer.SampleChunk\nRedPitayaDAQServer.PerformanceData\nRedPitayaDAQServer.readSamples\nRedPitayaDAQServer.readFrames\nRedPitayaDAQServer.readPeriods\nRedPitayaDAQServer.convertSamplesToFrames(::Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any)\nRedPitayaDAQServer.convertSamplesToPeriods!(::Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, ::Any, ::Any, ::Any, ::Any, ::Any, ::Any)","category":"page"},{"location":"client.html#RedPitayaDAQServer.masterTrigger","page":"Client Library","title":"RedPitayaDAQServer.masterTrigger","text":"masterTrigger(rp::RedPitaya)\n\nDetermine whether the master trigger is set.\n\nExample\n\njulia> masterTrigger!(rp, true)\n\njulia>masterTrigger(rp)\ntrue\n\n\n\n\n\nmasterTrigger(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.masterTrigger!","page":"Client Library","title":"RedPitayaDAQServer.masterTrigger!","text":"masterTrigger!(rp::RedPitaya, val::Bool)\n\nSet the master trigger of the RedPitaya to val. Return true if the command was successful.\n\nExample\n\njulia> masterTrigger!(rp, true)\ntrue\n\njulia>masterTrigger(rp)\ntrue\n\n\n\n\n\nmasterTrigger(rpc::RedPitayaCluster, val::Bool)\n\nSet the master trigger of the cluster to val.\n\nFor val equals to true this is the same as calling the function on the RedPitaya returned by master(rpc). If val is false then the keepAliveReset is set to true for all RedPitayas in the cluster before the master trigger is disabled. Afterwards the keepAliveReset is set to false again.\n\nSee also master, keepAliveReset!.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.currentWP","page":"Client Library","title":"RedPitayaDAQServer.currentWP","text":"currentWP(rp::RedPitaya)\n\nReturn the current writepointer of the RedPitaya.\n\n\n\n\n\ncurrentWP(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.currentFrame","page":"Client Library","title":"RedPitayaDAQServer.currentFrame","text":"currentFrame(rp::RedPitaya)\n\nReturn the current frame of the RedPitaya based on the current writepointer, samples per period and periods per frame.\n\nSee also currentWP, samplesPerPeriod, periodsPerFrame.\n\n\n\n\n\ncurrentFrame(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.currentPeriod","page":"Client Library","title":"RedPitayaDAQServer.currentPeriod","text":"currentPeriod(rp::RedPitaya)\n\nReturn the current period of the RedPitaya based on the current writepointer and samples per period.\n\nSee also currentWP, samplesPerPeriod.\n\n\n\n\n\ncurrentPeriod(rpc::RedPitayaCluster)\n\nAs with single RedPitaya, but applied to only the master.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.SampleChunk","page":"Client Library","title":"RedPitayaDAQServer.SampleChunk","text":"SampleChunk\n\nStruct containing a matrix of samples and associated PerformanceData\n\nFields\n\nsamples::Matrix{Int16}: nxm matrix containing m samples for n channel\nperformance::Vector{PerformanceData}: PerformanceData object for each RedPitaya that transmitted samples\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.PerformanceData","page":"Client Library","title":"RedPitayaDAQServer.PerformanceData","text":"PerformanceData\n\nHolds the performance data that is used for monitoring.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.readSamples","page":"Client Library","title":"RedPitayaDAQServer.readSamples","text":"readSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64; chunkSize::Int64 = 25000, rpInfo=nothing)\n\nRequest and receive numOfRequestedSamples samples from wpStart on in a pipelined fashion. Return a matrix of samples.\n\nIf rpInfo is set to a RPInfo, the PerformanceData sent after every chunkSize samples will be pushed into rpInfo.\n\n\n\n\n\nreadSamples(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, wpStart::Int64, numOfRequestedSamples::Int64, channel::Channel; chunkSize::Int64 = 25000)\n\nRequest and receive numOfRequestedSamples samples from wpStart on in a pipelined fashion. The samples and associated PerformanceData are pushed into channel as a SampleChunk.\n\nSee SampleChunk.\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.readFrames","page":"Client Library","title":"RedPitayaDAQServer.readFrames","text":"readFrames(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startFrame, numFrames, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false)\n\nRequest and receive numFrames frames from startFrame on.\n\nSee readSamples, convertSamplesToFrames, samplesPerPeriod, periodsPerFrame, updateCalib!.\n\nArguments\n\nrpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}: RedPitayas to receive samples from.\nstartFrame: frame from which to start transmitting\nnumFrames: number of frames to read\nnumBlockAverages=1: see convertSamplesToFrames\nnumPeriodsPerPatch=1: see convertSamplesToFrames\nchunkSize=50000: see readSamples\nrpInfo=nothing: see readSamples\nuseCalibration: convert from Int16 samples to Float32 values based on RedPitayas calibration\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.readPeriods","page":"Client Library","title":"RedPitayaDAQServer.readPeriods","text":"readPeriods(rpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}, startPeriod, numPeriods, numBlockAverages=1, numPeriodsPerPatch=1; rpInfo=nothing, chunkSize = 50000, useCalibration = false)\n\nRequest and receive numPeriods Periods from startPeriod on.\n\nSee readSamples, convertSamplesToPeriods!, samplesPerPeriod.\n\nArguments\n\nrpu::Union{RedPitaya,RedPitayaCluster, RedPitayaClusterView}: RedPitayas to receive samples from.\nstartPeriod: period from which to start transmitting\nnumPeriods: number of periods to read\nnumBlockAverages=1: see convertSamplesToPeriods\nchunkSize=50000: see readSamples\nrpInfo=nothing: see readSamples\nuseCalibration: convert samples based on RedPitayas calibration\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.convertSamplesToFrames-Tuple{Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, Vararg{Any, 7}}","page":"Client Library","title":"RedPitayaDAQServer.convertSamplesToFrames","text":"convertSamplesToFrames(rpu::Union{RedPitayaCluster, RedPitayaClusterView}, samples, numChan, numSampPerPeriod, numPeriods, numFrames, numBlockAverages=1, numPeriodsPerPatch=1)\n\nConverts a given set of samples to frames.\n\nSee readFrames\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.convertSamplesToPeriods!-Tuple{Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, Vararg{Any, 6}}","page":"Client Library","title":"RedPitayaDAQServer.convertSamplesToPeriods!","text":"convertSamplesToPeriods!(rpu::Union{RedPitaya, RedPitayaCluster, RedPitayaClusterView}, samples, periods, numChan, numSampPerPeriod, numPeriods, numBlockAverages=1)\n\nConverts a given set of samples to periods in-place.\n\nSee readPeriods\n\n\n\n\n\n","category":"method"},{"location":"client.html#Slow-IO","page":"Client Library","title":"Slow IO","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"Modules = [RedPitayaDAQServer]\nPages = [\"SlowIO.jl\"]","category":"page"},{"location":"client.html#RedPitayaDAQServer.DIODirectionType","page":"Client Library","title":"RedPitayaDAQServer.DIODirectionType","text":"DIODirectionType\n\nRepresent the different DIO directions. Valid value are DIO_IN and DIO_OUT.\n\nSee DIODirection, DIODirection!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.DIOPins","page":"Client Library","title":"RedPitayaDAQServer.DIOPins","text":"DIOPins\n\nRepresent the different DIO pins. Valid value are DIO7_P, DIO7_N, DIO6_P, DIO6_N, DIO5_N, DIO4_N, DIO3_N and DIO2_N.\n\nSee DIODirection, DIODirection!, DIO, DIO.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.DIO!-Tuple{RedPitaya, Any, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIO!","text":"DIO!(rp::RedPitaya, pin::DIOPins, val::Bool)\n\nSet the value of DIO pin pin to the value val.\n\nExample\n\njulia> DIO!(rp, DIO7_P, true)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.DIO-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIO","text":"DIO(rp::RedPitaya, pin::DIOPins)\n\nGet the value of DIO pin pin.\n\nExample\n\njulia>DIO(rp, DIO7_P)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.DIODirection!-Tuple{RedPitaya, Any, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIODirection!","text":"DIODirection!(rp::RedPitaya, pin::DIOPins, direction::DIODirectionType)\n\nSet the direction of DIO pin pin to the value direction.\n\nExample\n\njulia> DIODirection!(rp, DIO7_P, DIO_OUT)\n\njulia>DIODirection(rp, DIO7_P)\nDIO_OUT\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.DIODirection-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIODirection","text":"DIODirection(rp::RedPitaya, pin::DIOPins)\n\nGet the direction of DIO pin pin.\n\nExample\n\njulia> DIODirection!(rp, DIO7_P, DIO_OUT)\n\njulia>DIODirection(rp, DIO7_P)\nDIO_OUT\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.DIOHBridge!-Tuple{RedPitaya, Any, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIOHBridge!","text":"DIOHBridge!(rp::RedPitaya, pin::DIOPins, val::Bool)\n\nSet the value of DIOHBridge pin pin to the value val.\n\nExample\n\njulia> DIOHBridge!(rp, DIO7_P, true)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.DIOHBridge-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.DIOHBridge","text":"DIOHBridge(rp::RedPitaya, pin::DIOPins)\n\nGet the value of DIOHBridge pin pin.\n\nExample\n\njulia>DIOHBridge(rp, DIO7_P)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.isValidDIOPin-Tuple{String}","page":"Client Library","title":"RedPitayaDAQServer.isValidDIOPin","text":"isValidDIOPin(pin::String)\n\nCheck if a given string is an allowed value for the DIO pin names.\n\nSee DIOPins.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.slowADC-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.slowADC","text":"slowADC(rp::RedPitaya, channel::Int64)\n\nGet the value of the XADC channel channel.\n\nExample\n\njulia> slowADC(rp, 1)\n0.0\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.slowDAC!-Tuple{RedPitaya, Any, Any}","page":"Client Library","title":"RedPitayaDAQServer.slowDAC!","text":"slowDAC!(rp::RedPitaya, channel::Int64, val::Int64)\n\nSet the value of the slow DAC channel channel to the value val. Return true if the command was successful.\n\nExample\n\njulia> slowDAC!(rp, 1, 500)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.slowDACClockDivider!-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.slowDACClockDivider!","text":"slowDACClockDivider!(rp::RedPitaya, val::Int32)\n\nSet the clock divider of the slow DAC.\n\nExample\n\njulia> slowDACClockDivider!(rp, 8)\n\njulia>slowDACClockDivider(rp)\n8\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.slowDACClockDivider-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.slowDACClockDivider","text":"slowDACClockDivider(rp::RedPitaya)\n\nGet the clock divider of the slow DAC.\n\nExample\n\njulia> slowDACClockDivider!(rp, 8)\n\njulia>slowDACClockDivider(rp)\n8\n\n\n\n\n\n","category":"method"},{"location":"client.html#EEPROM-and-Calibration","page":"Client Library","title":"EEPROM and Calibration","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"Modules = [RedPitayaDAQServer]\nPages = [\"EEPROM.jl\"]","category":"page"},{"location":"client.html#RedPitayaDAQServer.calibADCOffset!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibADCOffset!","text":"calibADCOffset!(rp::RedPitaya, channel::Integer, val)\n\nStore calibration ADC offset val for given channel into the RedPitayas EEPROM. Absolute value has to be smaller than 1.0 V.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibADCOffset-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibADCOffset","text":"calibADCOffset(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration ADC offset for given channel from the RedPitayas EEPROM.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibADCScale!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibADCScale!","text":"calibADCScale(rp::RedPitaya, channel::Integer)\n\nStore calibration ADC scale val for given channel into the RedPitayas EEPROM. See also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibADCScale-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibADCScale","text":"calibADCScale(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration ADC scale for given channel from the RedPitayas EEPROM.\n\nSee also convertSamplesToPeriods!,convertSamplesToFrames.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACLimit!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACLimit!","text":"calibDACLimit!(rp::RedPitaya, channel, val)\n\nApplies val with a positive sign as the upper and with a negative sign as the lower calibration DAC limit.\n\nSee also calibDACUpperLimit!, calibDACLowerLimit!\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACLowerLimit!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACLowerLimit!","text":"calibDACLowerLimit!(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC lower limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACLowerLimit-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibDACLowerLimit","text":"calibDACLowerLimit(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC lower limit for given channel from the RedPitayas EEPROM.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACOffset!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACOffset!","text":"calibDACOffset!(rp::RedPitaya, channel::Integer, val)\n\nStore calibration DAC offset val for given channel into the RedPitayas EEPROM. This value is used by the server to offset the output voltage. Absolute value has to be smaller than 1.0 V. \n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACOffset-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibDACOffset","text":"calibDACOffset(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC offset for given channel from the RedPitayas EEPROM \n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACScale!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACScale!","text":"calibDACScale(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC scale val for given channel into the RedPitayas EEPROM. This value is used by the server to scale the output voltage.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACScale-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibDACScale","text":"calibDACScale(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC scale for given channel from the RedPitayas EEPROM.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACUpperLimit!-Tuple{RedPitaya, Integer, Any}","page":"Client Library","title":"RedPitayaDAQServer.calibDACUpperLimit!","text":"calibDACUpperLimit!(rp::RedPitaya, channel::Integer)\n\nStore calibration DAC upper limit val for given channel into the RedPitayas EEPROM. This value is used by the server to limit the output voltage.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.calibDACUpperLimit-Tuple{RedPitaya, Integer}","page":"Client Library","title":"RedPitayaDAQServer.calibDACUpperLimit","text":"calibDACUpperLimit(rp::RedPitaya, channel::Integer)\n\nRetrieve the calibration DAC upper limit for given channel from the RedPitayas EEPROM.\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.updateCalib!-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.updateCalib!","text":"updateCalib!(rp::RedPitaya)\n\nUpdate the cached calibration values.\n\nSee also calibADCScale, calibADCOffset.\n\n\n\n\n\n","category":"method"},{"location":"client.html#Counter-Trigger","page":"Client Library","title":"Counter Trigger","text":"","category":"section"},{"location":"client.html","page":"Client Library","title":"Client Library","text":"Modules = [RedPitayaDAQServer]\nPages = [\"CounterTrigger.jl\"]","category":"page"},{"location":"client.html#RedPitayaDAQServer.CounterTriggerSourceADCChannel","page":"Client Library","title":"RedPitayaDAQServer.CounterTriggerSourceADCChannel","text":"CounterTriggerSourceADCChannel\n\nRepresent the different counter trigger ADC sources. Valid values are COUNTER_TRIGGER_IN1 and COUNTER_TRIGGER_IN2.\n\nSee counterTrigger_sourceChannel, counterTrigger_sourceChannel!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.CounterTriggerSourceType","page":"Client Library","title":"RedPitayaDAQServer.CounterTriggerSourceType","text":"CounterTriggerSourceType\n\nRepresent the different counter trigger source types. Valid values are COUNTER_TRIGGER_DIO and COUNTER_TRIGGER_ADC.\n\nSee counterTrigger_sourceType, counterTrigger_sourceType!.\n\n\n\n\n\n","category":"type"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_arm!","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_arm!","text":"counterTrigger_arm!(rp::RedPitaya, val::Bool)\n\nSet whether the counter trigger is armed or not. Return true if the command was successful.\n\nExamples\n\njulia> counterTrigger_arm!(rp, true)\ntrue\n\njulia> counterTrigger_isArmed(rp)\ntrue\n\n\n\n\n\n","category":"function"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_enabled!-Tuple{RedPitaya, Bool}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_enabled!","text":"counterTrigger_enabled!(rp::RedPitaya, val)\n\nSet whether the counter trigger is enabled or not. Return true if the command was successful.\n\nExamples\n\njulia> counterTrigger_enabled!(rp, true)\ntrue\n\njulia> counterTrigger_enabled(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_enabled-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_enabled","text":"counterTrigger_enabled(rp::RedPitaya)\n\nReturn whether the counter trigger is enabled or not.\n\nExamples\n\njulia> counterTrigger_enabled!(rp, true)\ntrue\n\njulia> counterTrigger_enabled(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_isArmed-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_isArmed","text":"counterTrigger_isArmed(rp::RedPitaya)\n\nReturn whether the counter trigger is armed or not.\n\nExamples\n\njulia> counterTrigger_arm!(rp, true)\ntrue\n\njulia> counterTrigger_isArmed(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_lastCounter-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_lastCounter","text":"counterTrigger_lastCounter(rp::RedPitaya)\n\nReturn the number of samples that the counter trigger should trigger prior to reaching the reference counter.\n\nExamples\n\njulia> counterTrigger_lastCounter(rp)\n123456\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_presamples!-Union{Tuple{T}, Tuple{RedPitaya, T}} where T<:Integer","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_presamples!","text":"counterTrigger_presamples!(rp::RedPitaya, presamples)\n\nSet the number of samples that the counter trigger should trigger prior to reaching the reference counter.\n\nExamples\n\njulia> counterTrigger_presamples!(rp, 50)\ntrue\n\njulia> counterTrigger_presamples(rp)\n50\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_presamples-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_presamples","text":"counterTrigger_presamples(rp::RedPitaya)\n\nReturn the number of samples that the counter trigger should trigger prior to reaching the reference counter.\n\nExamples\n\njulia> counterTrigger_presamples!(rp, 50)\ntrue\n\njulia> counterTrigger_presamples(rp)\n50\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_referenceCounter!-Union{Tuple{T}, Tuple{RedPitaya, T}} where T<:Integer","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_referenceCounter!","text":"counterTrigger_referenceCounter!(rp::RedPitaya, presamples)\n\nSet the number of samples that the counter trigger should trigger on.\n\nExamples\n\njulia> counterTrigger_referenceCounter(rp, 250)\ntrue\n\njulia> counterTrigger_referenceCounter!(rp)\n250\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_referenceCounter-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_referenceCounter","text":"counterTrigger_referenceCounter(rp::RedPitaya)\n\nReturn the counter value that the counter trigger should trigger on.\n\nExamples\n\njulia> counterTrigger_referenceCounter!(rp, 250)\ntrue\n\njulia> counterTrigger_referenceCounter(rp)\n250\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_reset!-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_reset!","text":"counterTrigger_reset!(rp::RedPitaya, val::Bool)\n\nSet the reset of the counter trigger to val. Return true if the command was successful.\n\nExample\n\njulia> counterTrigger_reset!(rp, true)\ntrue\n\njulia>counterTrigger_reset(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_reset-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_reset","text":"counterTrigger_reset(rp::RedPitaya)\n\nReturn the reset status of the counter trigger.\n\nExample\n\njulia> counterTrigger_reset!(rp, true)\n\njulia>counterTrigger_reset(rp)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_sourceChannel!-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_sourceChannel!","text":"counterTrigger_sourceChannel!(rp::RedPitaya, sourceChannel::) //TODO\n\nSet the source channel of the counter trigger to sourceChannel.\n\nExample\n\njulia> counterTrigger_sourceChannel!(rp, COUNTER_TRIGGER_ADC)\n\njulia>counterTrigger_sourceChannel(rp)\nCOUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1 //TODO\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_sourceChannel-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_sourceChannel","text":"counterTrigger_sourceChannel(rp::RedPitaya)\n\nGet the source channel of the counter trigger.\n\nExample\n\njulia> counterTrigger_sourceChannel!(rp, COUNTER_TRIGGER_IN2)\n\njulia>counterTrigger_sourceChannel(rp)\nCOUNTER_TRIGGER_IN2::CounterTriggerSourceADCChannel = 2\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_sourceType!-Tuple{RedPitaya, Any}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_sourceType!","text":"counterTrigger_sourceType!(rp::RedPitaya, sourceType::CounterTriggerSourceType)\n\nSet the source type of the counter trigger to sourceType.\n\nExample\n\njulia> counterTrigger_sourceType!(rp, COUNTER_TRIGGER_ADC)\n\njulia>counterTrigger_sourceType(rp)\nCOUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1\n\n\n\n\n\n","category":"method"},{"location":"client.html#RedPitayaDAQServer.counterTrigger_sourceType-Tuple{RedPitaya}","page":"Client Library","title":"RedPitayaDAQServer.counterTrigger_sourceType","text":"counterTrigger_sourceType(rp::RedPitaya)\n\nGet the source type of the counter trigger.\n\nExample\n\njulia> counterTrigger_sourceType!(rp, COUNTER_TRIGGER_ADC)\n\njulia>counterTrigger_sourceType(rp)\nCOUNTER_TRIGGER_ADC::CounterTriggerSourceType = 1\n\n\n\n\n\n","category":"method"},{"location":"scpi.html#SCPI-Interface","page":"SCPI Interface","title":"SCPI Interface","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"For communication betten the server and the client an SCPI interface with custom commands is used. In the following tables an overview of the available commands and their behaviour is given. The Julia Client library encapsulates these commands into function calls, abstracting their communication details and also combining commands to manage a cluster of RedPitayas at the same time.","category":"page"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"As a safe guard the server has different communcation modes and certain commands are only available in certain modes. To give an example, during an acquisition changing the sampling rate would result in unclear behaviour. To stop such a scenario the decimation can only be set in the CONFIGURATION mode and an acquisition can only be triggered in the ACQUISITION mode. The available modes are CONFIGURATION, ACQUISITION and TRANSMISSION (C, A, T, 😺). The former two are set by the client and the latter is set by the server during sample transmission.","category":"page"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"After each SCPI command the server replies with true or false on the command socket depending on whether the given command was successfully excecuted. The exception to this rule are the commands which themselves just query values from the server.","category":"page"},{"location":"scpi.html#ADC-Configuration","page":"SCPI Interface","title":"ADC Configuration","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:ADC:DECimation decimation value [8, ..., n] Set the decimation factor of the base sampling rate C RP:ADC:DEC 8\nRP:ADC:DECimation? Return the decimation factor Any RP:ADC:DEC?\nRP:TRIGger:MODe trigger mode (EXTERNAL, INTERNAL) Set the trigger mode, which trigger the RedPitaya listens to C RP:TRIG:MOD INTERNAL\nRP:TRIGger:MODe? Return the trigger mode Any RP:TRIG:MOD?","category":"page"},{"location":"scpi.html#DAC-Configuration","page":"SCPI Interface","title":"DAC Configuration","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:DAC:CHannel#:COMPonent#:SIGnaltype channel (0, 1), (0, 1, 2, 3), signal type (SINE, TRIANGLE, SAWTOOTH) Set signal type of first component for given channel Any RP:DAC:CH0:SIG SINE\nRP:DAC:CHannel#:COMPonent#:SIGnaltype? channel (0, 1), component (0, 1, 2, 3) Return signal type of first component of given channel Any RP:DAC:CH1:SIG?\nRP:DAC:CHannel#:OFFset channel (0, 1), offset [-1, ..., 1] Set offset for given channel Any RP:DAC:CH1:OFF 0.1\nRP:DAC:CHannel#:OFFset? channel (0, 1) Return offset of given channel Any RP:DAC:CH0:OFF?\nRP:DAC:CHannel#:COMPonent#:AMPlitude channel (0, 1), component (0, 1, 2, 3), amplitude[0, ..., 1] Set amplitude of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:AMPlitude? channel (0, 1), component (0, 1, 2, 3) Return amplitude of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:FREQuency channel (0, 1), component (0, 1, 2, 3), frequency Set frequency of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:FREQuency? channel (0, 1), component (0, 1, 2, 3) Return frequency of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:PHAse channel (0, 1), component (0, 1, 2, 3), phase Set phase of given channel and component Any \nRP:DAC:CHannel#:COMPonent#:PHAse? channel (0, 1), component (0, 1, 2, 3) Return phase of given channel and component Any \nRP:DAC:CHannel#:RAMPing channel (0, 1), ramping period Set length of ramping period C \nRP:DAC:CHannel#:RAMPing? channel (0, 1) Get length of ramping period Any \nRP:DAC:CHannel#:RAMPing:ENable channel (0, 1) ramping status (OFF, ON) Enable/disable ramping factor on given channel C \nRP:DAC:CHannel#:RAMPing:ENable? channel (0, 1) Return enable ramping status of given channel Any \nRP:DAC:CHannel#:RAMPing:DoWN channel (0, 1), ramp down status (OFF, ON) Enable/disable ramp down flag for given channel A, T \nRP:DAC:CHannel#:RAMPing:DoWN? channel (0, 1) Get ramp down flag for given channel Any \nRP:DAC:RAMPing:STATus? Return the ramping status Any ","category":"page"},{"location":"scpi.html#Sequence-Configuration","page":"SCPI Interface","title":"Sequence Configuration","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"The server maintains three acquisition sequences. When the server is in theCONFIGURATION mode a client can configure a set of three sequences. If the current configured sequences fits the desired signal, a client can intstruct the server to set the sequences. This moves the configuration sequences to the acquisition sequences and writes the first values to the FPGA buffer.","category":"page"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"During an active trigger the buffer is periodically updated by the server. If the server recognizes the end of a sequence, it sets the amplitudes of the waveform components to 0.","category":"page"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:DAC:SEQ:CLocKdivider divider Set the clock divider with which the sequence advances C \nRP:DAC:SEQ:CLocKdivider? Return the clock divider Any \nRP:DAC:SEQ:SAMPlesperstep samples per step Set the clock divider such that the sequence advances every given number of samples. C \nRP:DAC:SEQ:SAMPlesperstep? Return the number of samples per step Any \nRP:DAC:SEQ:CHan numChan (1, 2, 3, 4) Set the number of sequence channel C \nRP:DAC:SEQ:CHan? Return the number of sequence channel \nRP:DAC:SEQ:LUT steps, repetitions Instruct the server to receive a LUT over the data socket C RP:DAC:SEQ:LUT 10,2\nRP:DAC:SEQ:LUT:ENaBle Instruct the server to receive an enable LUT over the data socket of the same shape as the regular LUT C \nRP:DAC:SEQ:LUT:ReSYNC Instruct the server to receive a resync LUT over the data socket of the same shape as the regular LUT C \nRP:DAC:SEQ:LUT:UP steps, repetitions Instruct the server to receive a ramp up LUT over the data socket C \nRP:DAC:SEQ:LUT:DOWN steps, repetitions Instruct the server to receive a ramp down LUT over the data socket C \nRP:DAC:SEQ:CLEAR Clear the set sequence values from the FPGA buffer C \nRP:DAC:SEQ:SET Set the current configured sequence as the acquisition sequence C ","category":"page"},{"location":"scpi.html#Acquisition-and-Transmission","page":"SCPI Interface","title":"Acquisition and Transmission","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:TRIGger trigger status (OFF, ON) Set the internal trigger status A RP:TRIG ON\nRP:TRIGger? Return the trigger status Any RP:TRIG?\nRP:TRIGger:ALiVe keep alive status (OFF, ON) Set the keep alive bypass A RP:TRIG:ALV OFF\nRP:TRIGger:ALiVe? Return the keep alive status Any RP:TRIG:ALV?\nRP:ADC:WP:CURRent? Return the current writepointer A, T RP:ADC:WP?\nRP:ADC:DATa? readpointer, number of samples Transmit number of samples from the buffer component of the readpointer over the data socket. Return true on the command socket if transmission is started. A RP:ADC:DATa? 400,1024\nRP:ADC:DATa:PIPElined? readpointer, number of samples, chunksize Transmit number of samples from the readpointer on in chunks of chunksize over the data socket. After every chunk status and performance data is transmitted over the data socket. Return true if pipeline was started. A RP:ADC:DAT:PIPE? 400,1024,128\nRP:STATus? Transmit status as one byte with flags from lower bits: overwritten, corrupted, lost steps, master trigger, sequence active Any RP:STAT?\nRP:STATus:OVERwritten? Transmit overwritten flag Any RP:STAT:OVER?\nRP:STATus:CORRupted? Transmit corrupted flag Any RP:STAT:CORR?\nRP:STATus:LOSTSteps? Transmit lost steps flag Any RP:STAT:LOSTS?\nRP:PERF? Transmit ADC and DAC performance data Any RP:PERF?","category":"page"},{"location":"scpi.html#Calibration","page":"SCPI Interface","title":"Calibration","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Mode Example\nRP:CALib:ADC:CHannel#:OFFset channel (0, 1), offset Store the ADC offset value for given channel in EEPROM C RP:CAL:ADC:CH0:OFF 0.2\nRP:CALib:ADC:CHannel#:OFFset? channel (0, 1) Return the ADC offset value for given channel from EEPROM Any RP:CAL:ADC:CH1:OFF?\nRP:CALib:ADC:CHannel#:SCAle channel (0, 1), scale Store the ADC scale value for given channel in EEPROM C RP:CAL:ADC:CH1:SCA 1.0\nRP:CALib:ADC:CHannel#:SCAle? channel (0, 1) Return the ADC scale value for given channel from EEPROM Any RP:CAL:ADC:CH1:SCA?\nRP:CALib:DAC:CHannel#:OFFset channel (0, 1), offset Store the DAC offset value for given channel in EEPROM C RP:CAL:DAC:CH0:OFF 0.2\nRP:CALib:DAC:CHannel#:OFFset? channel (0, 1) Return the DAC offset value for given channel from EEPROM Any RP:CAL:DAC:CH1:OFF?\nRP:CALib:DAC:CHannel#:SCAle channel (0, 1), scale Store the DAC scale value for given channel in EEPROM C RP:CAL:DAC:CH1:SCA 1.0\nRP:CALib:DAC:CHannel#:SCAle? channel (0, 1) Return the DAC scale value for given channel from EEPROM Any RP:CAL:DAC:CH1:SCA?","category":"page"},{"location":"scpi.html#DIO","page":"SCPI Interface","title":"DIO","text":"","category":"section"},{"location":"scpi.html","page":"SCPI Interface","title":"SCPI Interface","text":"Command Arguments Description Example\nRP:DIO:DIR identifier of pin, direction (IN/OUT) Set the direction of the DIO RP:DIO:DIR DIO7_P,IN\nRP:DIO identifier of pin, value (0/1) Set the output of the DIO RP:DIO DIO7_P,1\nRP:DIO? identifier of pin Get the input of the DIO RP:DIO? DIO7_P","category":"page"},{"location":"examples/seqRamping.html#Sequence-Ramping-Example","page":"Sequence Ramping","title":"Sequence Ramping Example","text":"","category":"section"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"In this example we combine the ramping and the sequence example to create a signal with known/predictable ramping behaviour. The ramping period is independant of the sequence. The sequence we use is a sequence that holds the first value of our intended sequence for the duration of the given number of ramping steps, which spans the ramp up period.","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"At the end of the \"regular\" sequence portion, the ramp down is triggered and the sequence holds the last value of the \"regular\" sequence until the end of the ramp down.","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"It is also possible to update the signal type during the acquisition without going back to the CONFIGURATION mode.","category":"page"},{"location":"examples/seqRamping.html#Julia-Client","page":"Sequence Ramping","title":"Julia Client","text":"","category":"section"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/seqRamping.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/seqRamping.html","page":"Sequence Ramping","title":"Sequence Ramping","text":"(Image: Sequence Ramping Example Results)","category":"page"},{"location":"examples/producerConsumer.html#Continous-Signal-Acquisition-Example","page":"Continous Signal Acquisition","title":"Continous Signal Acquisition Example","text":"","category":"section"},{"location":"examples/producerConsumer.html","page":"Continous Signal Acquisition","title":"Continous Signal Acquisition","text":"As is mentioned in the Acquisition section, the transmission rate of the server heavily depends on the available network and the way a client processes the samples. This example shows how one can write a thread dedicated to just receiving samples and one (or more) threads dedicated to processing samples. As the example contains no visualization, there is no need for a specific RedPitaya setup.","category":"page"},{"location":"examples/producerConsumer.html#Julia-Client","page":"Continous Signal Acquisition","title":"Julia Client","text":"","category":"section"},{"location":"examples/producerConsumer.html","page":"Continous Signal Acquisition","title":"Continous Signal Acquisition","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/producerConsumer.html","page":"Continous Signal Acquisition","title":"Continous Signal Acquisition","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/producerConsumer.jl\"))\n```\n\"\"\")","category":"page"},{"location":"devtips.html#Development-Hints","page":"Development Tips","title":"Development Hints","text":"","category":"section"},{"location":"devtips.html","page":"Development Tips","title":"Development Tips","text":"On this slide some development hints are summarized. These might change regularely if things are properly integrated into the framework.","category":"page"},{"location":"devtips.html#Alpine-Linux","page":"Development Tips","title":"Alpine Linux","text":"","category":"section"},{"location":"devtips.html","page":"Development Tips","title":"Development Tips","text":"The Alpine linux as currently a root folder with only 185.8M free space, which disallows installing more","category":"page"},{"location":"devtips.html","page":"Development Tips","title":"Development Tips","text":"applications. To change this one can do","category":"page"},{"location":"devtips.html","page":"Development Tips","title":"Development Tips","text":"mount -o remount,size=1G /","category":"page"},{"location":"examples/resync.html#Resync-Example","page":"Resync","title":"Resync Example","text":"","category":"section"},{"location":"examples/resync.html","page":"Resync","title":"Resync","text":"In this example we add a resync signal to a sequence to create a signal that resynchronizes phase and frequency of the DACs after every frame. This can be used to change the frequency and phase of a signal during measurement. While the resynchronization is synchronous due to the sequences, the actual new frequency and phase information is asynchronous as they are transmitted via SCPI.","category":"page"},{"location":"examples/resync.html","page":"Resync","title":"Resync","text":"The example constructs a sequence with no offset and the very last step has the resync flag enabled. Note that during the resync-step the DAC outputs zero.","category":"page"},{"location":"examples/resync.html#Julia-Client","page":"Resync","title":"Julia Client","text":"","category":"section"},{"location":"examples/resync.html","page":"Resync","title":"Resync","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/resync.html","page":"Resync","title":"Resync","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/resync.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/resync.html","page":"Resync","title":"Resync","text":"(Image: Resync Example Results)","category":"page"},{"location":"examples/sequence.html#Sequence-Example","page":"Sequence","title":"Sequence Example","text":"","category":"section"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"In this example we generate a 10 kHz sine wave on DAC channel 1 and also construct a sequence with a climbing offset every 5 periods. We receive this signal on ADC channel 1. To run this example connect the RedPitaya in the following way.","category":"page"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"(Image: RedPitaya)","category":"page"},{"location":"examples/sequence.html#Julia-Client","page":"Sequence","title":"Julia Client","text":"","category":"section"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"This and all other examples are located in the examples directory","category":"page"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499\nusing Markdown\nMarkdown.parse(\"\"\"\n```julia\n$(open(f->read(f, String), \"../../../src/examples/julia/sequence.jl\"))\n```\n\"\"\")","category":"page"},{"location":"examples/sequence.html","page":"Sequence","title":"Sequence","text":"(Image: Simple Example Results)","category":"page"},{"location":"index.html#RedPitayaDAQServer","page":"Home","title":"RedPitayaDAQServer","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"Advanced DAQ Tools for the RedPitaya (STEMlab 125-14)","category":"page"},{"location":"index.html#Introduction","page":"Home","title":"Introduction","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"This project contains software to be used with the STEMlab 125-14 device from RedPitaya. It allows for continuous generation and measurement of signals with up to 15.625 MS/s, which is not possible with the standard image of the RedPitaya. In addition, the software allows to synchronize a cluster of multiple RedPitayas. This project contains the following parts:","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"Alpine Linux image for the RedPitaya\nFPGA images for the 7010 and 7020\nLibrary written in C to interact with the FPGA image on the RedPitaya\nSCPI Server for accessing the functionality over TCP/IP\nSCPI Client to access the server","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"The code is contained in this repository.","category":"page"},{"location":"index.html#License-/-Terms-of-Usage","page":"Home","title":"License / Terms of Usage","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"The source code of this project is licensed under the MIT license. This implies that you are free to use, share, and adapt it. However, please give appropriate credit by citing the project.","category":"page"},{"location":"index.html#Contact","page":"Home","title":"Contact","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"If you have problems using the software, find mistakes, or have general questions please use the issue tracker to contact us.","category":"page"},{"location":"index.html#Contributors","page":"Home","title":"Contributors","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"Tobias Knopp\nNiklas Hackelberg\nJonas Schumacher\nMatthias Gräser","category":"page"},{"location":"index.html#Credit","page":"Home","title":"Credit","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"This package is partly based on work of Koheron [1] and Pavel Demin [2]","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"[1] https://www.koheron.com/blog/2016/11/29/red-pitaya-cluster [2] https://github.com/pavel-demin/red-pitaya-notes","category":"page"}] }