{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Synchronised one-pulse signal generation and acquisition\n",
    "Now that we are familiar with generating and acquiring signals with Red Pitaya, we can finally learn a few tricks for combining both and use them in practice. In this example, the acquisition is triggered together with the generation, which is used for measuring cable length and other applications where signal propagation delay is important.\n",
    "\n",
    "**Note:**  \n",
    "The voltage range of fast analog inputs on the Red Pitaya depends on the input jumper position. HV sets the input range to ±20 V, while LV sets the input range to ±1 V. For more information, please read the following [chapter](https://redpitaya.readthedocs.io/en/latest/developerGuide/hardware/125-14/fastIO.html#analog-inputs).\n",
    "\n",
    "As previously, create a loop-back from fast analog outputs to fast analog inputs, as shown in the picture below.  \n",
    "Please make sure the jumpers are set to ±1 V (LV).\n",
    "\n",
    "![Fast loop back](../img/FastIOLoopBack.png \"Example of the fast loop back.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Libraries and FPGA image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Check FPGA [OK].\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import time\n",
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "from rp_overlay import overlay\n",
    "import rp\n",
    "\n",
    "fpga = overlay()\n",
    "rp.rp_Init()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Marcos\n",
    "Throughout this tutorial we will mention macros multiple times. Here is a complete list of macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n",
    "\n",
    "**GENERATION**\n",
    "\n",
    "- **Waveforms** - RP_WAVEFORM_SINE, RP_WAVEFORM_SQUARE, RP_WAVEFORM_TRIANGLE, RP_WAVEFORM_RAMP_UP, RP_WAVEFORM_RAMP_DOWN, RP_WAVEFORM_DC, RP_WAVEFORM_PWM, RP_WAVEFORM_ARBITRARY, RP_WAVEFORM_DC_NEG, RP_WAVEFORM_SWEEP\n",
    "- **Generator modes** - RP_GEN_MODE_CONTINUOUS, RP_GEN_MODE_BURST\n",
    "- **Sweep direction** - RP_GEN_SWEEP_DIR_NORMAL, RP_GEN_SWEEP_DIR_UP_DOWN\n",
    "- **Sweep mode** - RP_GEN_SWEEP_MODE_LINEAR, RP_GEN_SWEEP_MODE_LOG\n",
    "- **Generator trigger source** - RP_GEN_TRIG_SRC_INTERNAL, RP_GEN_TRIG_SRC_EXT_PE, RP_GEN_TRIG_SRC_EXT_NE\n",
    "- **Generator triggers** - RP_T_CH_1, RP_T_CH_2, RP_T_CH_EXT\n",
    "- **Rise and fall times** - RISE_FALL_MIN_RATIO, RISE_FALL_MAX_RATIO\n",
    "\n",
    "**ACQUISITION**\n",
    "\n",
    "- **Decimation** - RP_DEC_1, RP_DEC_2, RP_DEC_4, RP_DEC_8, RP_DEC_16, RP_DEC_32, RP_DEC_64, RP_DEC_128, RP_DEC_256, RP_DEC_512, RP_DEC_1024, RP_DEC_2048, RP_DEC_4096, RP_DEC_8192, RP_DEC_16384, RP_DEC_32768, RP_DEC_65536 \n",
    "- **Acquisition trigger** - RP_TRIG_SRC_DISABLED, RP_TRIG_SRC_NOW, RP_TRIG_SRC_CHA_PE, RP_TRIG_SRC_CHA_NE, RP_TRIG_SRC_CHB_PE, RP_TRIG_SRC_CHB_NE, RP_TRIG_SRC_EXT_PE, RP_TRIG_SRC_EXT_NE, RP_TRIG_SRC_AWG_PE, RP_TRIG_SRC_AWG_NE\n",
    "- **Acquisition trigger state** - RP_TRIG_STATE_TRIGGERED, RP_TRIG_STATE_WAITING\n",
    "- **Buffer size** - ADC_BUFFER_SIZE, DAC_BUFFER_SIZE\n",
    "- **Fast analog channels** - RP_CH_1, RP_CH_2\n",
    "\n",
    "SIGNALlab 250-12 only:\n",
    "- **Input coupling** - RP_DC, RP_AC\n",
    "- **Generator gain** - RP_GAIN_1X, RP_GAIN_5X\n",
    "\n",
    "STEMlab 125-14 4-Input only:\n",
    "- **Fast analog channels** - RP_CH_3, RP_CH_4\n",
    "- **Acquisition trigger** - RP_TRIG_SRC_CHC_PE, RP_TRIG_SRC_CHC_NE, RP_TRIG_SRC_CHD_PE, RP_TRIG_SRC_CHD_NE"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Synchronising generation and acquisition\n",
    "\n",
    "The example itself is relatively trivial in comparison to others already presented during the tutorials. The only practical change is the **RP_TRIG_SOUR_AWG_PE**.\n",
    "\n",
    "Parameters:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "###### Generation #####\n",
    "channel = rp.RP_CH_1        # rp.RP_CH_2\n",
    "waveform = rp.RP_WAVEFORM_RAMP_UP\n",
    "freq = 0.1164153218269348 * 2\n",
    "ampl = 1.0\n",
    "\n",
    "ncyc = 1\n",
    "nor = 1\n",
    "period = 10\n",
    "\n",
    "gen_trig_sour = rp.RP_GEN_TRIG_SRC_INTERNAL\n",
    "\n",
    "##### Acquisition #####\n",
    "trig_lvl = 0.5\n",
    "trig_dly = 0\n",
    "dec = rp.RP_DEC_65536\n",
    "\n",
    "acq_trig_sour = rp.RP_TRIG_SRC_AWG_PE\n",
    "\n",
    "N = 32768 // 2\n",
    "\n",
    "# Reset Generation and Acquisition\n",
    "rp.rp_GenReset()\n",
    "rp.rp_AcqReset()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Setting up both the generation and acquisition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gen_start\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "###### Generation #####\n",
    "print(\"Gen_start\")\n",
    "rp.rp_GenWaveform(channel, waveform)\n",
    "rp.rp_GenFreqDirect(channel, freq)\n",
    "rp.rp_GenAmp(channel, ampl)\n",
    "\n",
    "# Change to burst mode\n",
    "rp.rp_GenMode(channel, rp.RP_GEN_MODE_BURST)\n",
    "rp.rp_GenBurstCount(channel, ncyc)                  # Ncyc\n",
    "rp.rp_GenBurstRepetitions(channel, nor)             # Nor\n",
    "rp.rp_GenBurstPeriod(channel, period)               # Period\n",
    "\n",
    "\n",
    "# Specify generator trigger source\n",
    "rp.rp_GenTriggerSource(channel, gen_trig_sour)\n",
    "\n",
    "# Enable output synchronisation\n",
    "rp.rp_GenOutEnableSync(True)\n",
    "\n",
    "\n",
    "##### Acquisition #####\n",
    "# Set Decimation\n",
    "rp.rp_AcqSetDecimation(dec)\n",
    "rp.rp_AcqSetAveraging(True)\n",
    "rp.rp_AcqSetGain(rp.RP_CH_1, rp.RP_HIGH)\n",
    "\n",
    "# Set trigger level and delay\n",
    "rp.rp_AcqSetTriggerLevel(rp.RP_T_CH_1, trig_lvl)\n",
    "rp.rp_AcqSetTriggerDelay(trig_dly)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Starting acquisition and capturing data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Acq_start\n",
      "Trigger state: 0\n",
      "Fill state: False\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 23908 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Start Acquisition\n",
    "print(\"Acq_start\")\n",
    "rp.rp_AcqStart()\n",
    "\n",
    "# Specify trigger - input 1 positive edge\n",
    "rp.rp_AcqSetTriggerSrc(acq_trig_sour)\n",
    "\n",
    "time.sleep(5)\n",
    "\n",
    "rp.rp_GenTriggerOnly(channel)       # Trigger generator\n",
    "\n",
    "print(f\"Trigger state: {rp.rp_AcqGetTriggerState()[1]}\")\n",
    "\n",
    "# Trigger state\n",
    "while 1:\n",
    "    trig_state = rp.rp_AcqGetTriggerState()[1]\n",
    "    if trig_state == rp.RP_TRIG_STATE_TRIGGERED:\n",
    "        break\n",
    "\n",
    "# Fill state\n",
    "print(f\"Fill state: {rp.rp_AcqGetBufferFillState()[1]}\")\n",
    "\n",
    "while 1:\n",
    "    if rp.rp_AcqGetBufferFillState()[1]:\n",
    "        break\n",
    "\n",
    "\n",
    "### Get data ###\n",
    "# Volts\n",
    "fbuff = rp.fBuffer(N)\n",
    "res = rp.rp_AcqGetOldestDataV(rp.RP_CH_1, N, fbuff)[1]\n",
    "\n",
    "data_V = np.zeros(N // 2, dtype = float)\n",
    "\n",
    "for i in range(0, N // 2, 1):\n",
    "    data_V[i] = fbuff[i + N // 2]\n",
    "\n",
    "plt.plot(data_V)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Release resources\n",
    "rp.rp_Release()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One of the applications for this example is to measure how many samples are taken from the triggering moment to the start of the captured pulse, which corresponds to propagation delay on the transmission line."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Note\n",
    "There are a lot of different commands for the Acquisition. The list of available functions is quite an achievement to read through, so from now on, please refer to the *C and Python API section* of the [SCPI & API command list](https://redpitaya.readthedocs.io/en/latest/appsFeatures/remoteControl/command_list.html#list-of-supported-scpi-api-commands) for all available commands.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (RP api)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
