/** \mainpage

 <img src="img/libm2k_logo.png" alt="libm2k_logo" width="1000"/>

 @tableofcontents

 @section license License
 libm2k is licensed under the GNU Lesser General Public License v2.1

 @section architecture Architecture
 libm2k is a C++ library for interfacing with the ADALM2000, splitted into more correlated components, interconnected by a context. These M2K components represent the functionalities of ADALM2000:

   - **AnalogIn** - oscilloscope or voltmeter \n
   - **AnalogOut** - signal generator \n
   - **Digital** - logic analyzer or pattern generator \n
   - **PowerSupply** - constant voltage generator \n
   - **DMM** - digital multimeter \n


 @subsection class-diagram Class Diagram
 The class diagram containing details for all public classes of libm2k.

 ![libm2k Class Diagram](img/libm2k_class_diagram.png)

 @subsection package-diagram Top Level Diagram
 The top level diagram provides an overview for the library structure. The components are organized in their corresponding namespaces.

 ![libm2k Top Level Diagram](img/libm2k_top_level.png)

 @subsection libm2k-m2k-open M2K Open Sequence Diagram
 In this diagram the necessary steps to create an M2K context and get a specific device are presented.
 ![libm2k M2K Open Sequence Diagram](img/libm2k_m2k_open.png)


 @subsection libm2k-async-acq Asynchronous Acquisition Sequence Diagram
 The sequence diagram shows an example to the asynchronous acquisition flow for Analog In or Digital In. Running "startAcquisition(number_of_samples)" will create, initialize and populate the available kernel buffers with data. Everytime we call "getSamples", we retrieve data from those kernel buffers, which will automatically be refilled.
 ![libm2k Asynchronous Acquisition Sequence Diagram](img/libm2k_async_acq.png)


 @subsection libm2k-sync-acq Synchronous Acquisition Sequence Diagram
 The sequence diagram shows an example to the synchronous acquisition flow for Analog In or Digital In. Running "getSamples(number_of_samples)" will create and initialize, but it will also populate all the available kernel buffers with data and it will return one buffer to the user.
 ![libm2k Synchronous Acquisition Sequence Diagram](img/libm2k_sync_acq.png)


 @section python Python Bindings

 <img src="img/libm2k-python_logo.png" alt="libm2k-python_logo" width="1000"/>

 In order to use libm2k in Python applications please check the [libm2k Python Bindings API]

[libm2k Python Bindings API]: python/html/sphinx/build/html/index.html "libm2k Python Bindings API Sphinx"

 @section example Example
 The following code shows a simple example on how to use libm2k together with the digital side of ADALM2000.

 There are multiple examples provided for libm2k and can be found on the Github [libm2k examples] page. The examples are created to ease the work for a libm2k user. To get familiar with libm2k API, the examples can be modified and built out of the libm2k source code tree by keeping the CMake configuration file provided for each example.

[libm2k examples]: https://github.com/analogdevicesinc/libm2k/tree/main/examples "libm2k official Github page"

~~~{.cpp}
// This example will generate a binary counter on the first N_BITS of the
// digital interface and read them back - no additional connection required

#include <iostream>
#include <libm2k/m2k.hpp>
#include <libm2k/context.hpp>
#include <libm2k/contextbuilder.hpp>
#include <libm2k/digital/m2kdigital.hpp>
#include <bitset>

using namespace std;
using namespace libm2k;
using namespace libm2k::digital;
using namespace libm2k::context;

#define N_BITS (4)

int main()

{
	Context *c = contextOpen();
	if (!c) {
		std::cout << "Connection Error: No ADALM2000 device available/connected to your PC." << std::endl;
		return 1;
	}

	M2k* ctx = c->toM2k();

	M2kDigital *dig = ctx->getDigital();

	dig->setSampleRateIn(100000);
	dig->setSampleRateOut(100000);

	for(int i=0;i<N_BITS;i++)
	{
		dig->setDirection(i, DIO_OUTPUT);
		dig->enableChannel(i, true);
	}

	vector<unsigned short> bufferOut;
	vector<unsigned short> bufferIn;

	for(int i=0;i< (1<<N_BITS); i++)
	{
		bufferOut.push_back(i);
	}
	dig->setCyclic(true);
	dig->push(bufferOut);

	bufferIn = dig->getSamples(1000);
	for(auto val : bufferIn)
	{
		cout<<bitset<16>(val)<<endl;
	}
	dig->stopBufferOut();
	contextClose(ctx);

	return 0;
}
~~~

 @section faq FAQ
 Useful questions and answers for the libm2k API usage and ADALM2000 manipulation

 @subsection faq-data-conversion How can I acquire raw data fast and convert it to the corresponding value in Volts (in Python)?
 The Python bindings API are not a 100% mirror of the C++ code. Therefore, some methods might have a slightly different return type for Python (it is necessary to check the Python Bindings API Documentation listed above). 
 For example, the getSamplesRawInterleaved() method will return **4*nb_samples** elements in the Python list. In order to make the acquisition faster, all the samples are returned in a bytes list. One sample for one channel (for AnalogIn) is represented using 2 bytes. The returned list of bytes will be **interleaved**, this meaning that it should be interpreted as one sample from CHANNEL_1, one sample from CHANNEL_2 and so on. One thing to keep in mind is that a sample corresponds to 2 elements in the list.

 Let's take an example:

~~~{.py}
 samples = getSamplesRawInterleaved(10) 
 samples.tolist()
 #will return:
 [243, 255, 2, 0, 246, 255, 2, 0, 244, 255, 2, 0, 246, 255, 2, 0, 244, 255, 2, 0, 244, 255, 1, 0, 243, 255, 0, 0, 245, 255, 3, 0, 245, 255, 2, 0, 245, 255, 2, 0]
 samples.tobytes()
 #will return:
 b'\xf3\xff\x02\x00\xf6\xff\x02\x00\xf4\xff\x02\x00\xf6\xff\x02\x00\xf4\xff\x02\x00\xf4\xff\x01\x00\xf3\xff\x00\x00\xf5\xff\x03\x00\xf5\xff\x02\x00\xf5\xff\x02\x00'
 #[243, 255] corresponds to the first sample on CHANNEL_1
 #[2, 0] corresponds to the first sample on CHANNEL_2
~~~

In order to convert all the samples you can use the following chunk of Python code:

~~~{.py}
import struct
#enable channels, acquire samples
samples = samples.tobytes()
count = int(len(samples)/2)
value_list = struct.unpack('h'*count, samples)   #'h' is the format for short
#value_list will be similar to the following: (-13, 2, -10, 2, -12, 2, -10, 2, -12, 2, -12, 1, -13, 0, -11, 3, -11, 2, -11, 2)
~~~

Next thing is to convert it into Volts. In Python, for AnalogIn() you have 2 exposed methods:  libm2k::analog::M2kAnalogIn::convertVoltsToRaw(unsigned int channel, double voltage) and  libm2k::analog::M2kAnalogIn::convertRawToVolts(unsigned int channel, short raw). Running convertRawToVolts(0, value_list[0]) should provide the needed Volts value for CHANNEL_1. 

 */


