libm2k
libm2k Documentation
libm2k_logo

License

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

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
  • AnalogOut - signal generator
  • Digital - logic analyzer or pattern generator
  • PowerSupply - constant voltage generator
  • DMM - digital multimeter

Class Diagram

The class diagram containing details for all public classes of libm2k.

libm2k Class 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

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

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

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

Python Bindings

libm2k-python_logo

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

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.

// 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();
return 0;
}

FAQ

Useful questions and answers for the libm2k API usage and ADALM2000 manipulation

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:

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:

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.