Compare commits

..

No commits in common. "master" and "v2.0.6" have entirely different histories.

26 changed files with 331 additions and 794 deletions

View File

@ -1,27 +1,25 @@
name: CI Build Wheel name: Build Python Wheels
on: on:
push: push:
# branches: [master] #branches: [master]
tags: ["v[0-9]+.[0-9]+.[0-9]+"] tags: ["v[0-9]+.[0-9]+.[0-9]+"]
jobs: jobs:
build_setup: build_setup:
name: Prepare environment for wheel builds name: Prepare environment for wheel builds
runs-on: ubuntu-24.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Prepare wheel build - name: Prepare wheel build
run: make -C python/ setup run: make -C python/ setup
- name: Store wheel configuration files - name: Store wheel configuration files
uses: actions/upload-artifact@v4.6.0 uses: actions/upload-artifact@v2
with: with:
name: wheel-config name: wheel-config
path: python/ path: python/
- name: Display files
run: ls -lR
build_wheels: build_wheels:
name: Build binary wheels on ${{ matrix.os }} name: Build binary wheels on ${{ matrix.os }}
@ -29,7 +27,8 @@ jobs:
needs: [build_setup] needs: [build_setup]
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest] os: [ubuntu-20.04, windows-2019]
arch: [auto32, auto64, aarch64]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -37,29 +36,31 @@ jobs:
- name: Install cibuildwheel - name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.1.2 run: python -m pip install cibuildwheel==2.1.2
- name: Get wheel configuration files - name: Get wheel configuration files
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v2
with: with:
name: wheel-config name: wheel-config
path: python/ path: python/
- name: Build wheels - name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse run: python -m cibuildwheel --output-dir wheelhouse
working-directory: python/ working-directory: python/
# env:
# CIBW_BUILD: cp36-* cp37-* cp38-* cp39-* cp310-*
- name: Store binary wheels - name: Store binary wheels
uses: actions/upload-artifact@v4.6.0 uses: actions/upload-artifact@v2
with: with:
name: binary-wheels-${{matrix.os}}-${{ strategy.job-index }} name: binary-wheels
path: python/wheelhouse/*.whl path: python/wheelhouse/*.whl
build_sdist: build_sdist:
name: Build source distribution name: Build source distribution
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
needs: [build_setup] needs: [build_setup]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install cython - name: Install cython
run: python -m pip install cython==0.29.24 run: python -m pip install cython==0.29.24
- name: Get wheel configuration files - name: Get wheel configuration files
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v2
with: with:
name: wheel-config name: wheel-config
path: python/ path: python/
@ -67,33 +68,28 @@ jobs:
run: python setup.py sdist run: python setup.py sdist
working-directory: python/ working-directory: python/
- name: Store source wheels - name: Store source wheels
uses: actions/upload-artifact@v4.6.0 uses: actions/upload-artifact@v2
with: with:
name: source-wheels name: source-wheels
path: python/dist/*.tar.gz path: python/dist/*.tar.gz
- name: Display files
run: ls -lR
upload_pypi: upload_pypi:
name: Upload wheels to PyPI name: Upload binary wheels to PyPI
runs-on: ubuntu-24.04 runs-on: ubuntu-20.04
needs: [build_wheels, build_sdist] needs: [build_wheels, build_sdist]
steps: steps:
- name: Get source wheels - name: Get source wheels
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v2
with: with:
name: source-wheels name: source-wheels
path: dist/ path: dist/
- name: Get binary wheels - name: Get binary wheels
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v2
with: with:
name: binary-wheels
path: dist/ path: dist/
pattern: binary-wheels-*
merge-multiple: true
- name: Display files
run: ls -lR
- uses: pypa/gh-action-pypi-publish@release/v1 - uses: pypa/gh-action-pypi-publish@release/v1
with: with:

View File

@ -1,13 +1,15 @@
[![Total alerts](https://img.shields.io/lgtm/alerts/g/RecordEvolution/IMCtermite.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/RecordEvolution/IMCtermite/alerts/)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/RecordEvolution/IMCtermite.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/RecordEvolution/IMCtermite/context:cpp)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/RecordEvolution/IMCtermite.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/RecordEvolution/IMCtermite/context:python)
[![LICENSE](https://img.shields.io/github/license/RecordEvolution/IMCtermite)](https://img.shields.io/github/license/RecordEvolution/IMCtermite) [![LICENSE](https://img.shields.io/github/license/RecordEvolution/IMCtermite)](https://img.shields.io/github/license/RecordEvolution/IMCtermite)
[![STARS](https://img.shields.io/github/stars/RecordEvolution/IMCtermite)](https://img.shields.io/github/stars/RecordEvolution/IMCtermite) [![STARS](https://img.shields.io/github/stars/RecordEvolution/IMCtermite)](https://img.shields.io/github/stars/RecordEvolution/IMCtermite)
![CI Build Wheel](https://github.com/RecordEvolution/IMCtermite/actions/workflows/pypi-deploy.yml/badge.svg?branch=&event=push) ![Build Python Wheels](https://github.com/RecordEvolution/IMCtermite/actions/workflows/pypi-deploy.yml/badge.svg)
[![PYPI](https://img.shields.io/pypi/v/IMCtermite.svg)](https://pypi.org/project/imctermite/)
# IMCtermite # IMCtermite
_IMCtermite_ provides access to the proprietary data format _IMCtermite_ provides access to the proprietary data format
_IMC2 Data Format_ with the file extension _.raw_ (or .dat) introduced and developed by _IMC Bus Format_ with the file extension _.raw_ introduced and developed by
[imc Test & Measurement GmbH](https://www.imc-tm.de/). This data format is [imc Test & Measurement GmbH](https://www.imc-tm.de/). This data format is
employed i.a. by the measurement hardware employed i.a. by the measurement hardware
[imc CRONOSflex](https://www.imc-tm.de/produkte/messtechnik-hardware/imc-cronosflex/ueberblick/) [imc CRONOSflex](https://www.imc-tm.de/produkte/messtechnik-hardware/imc-cronosflex/ueberblick/)
@ -18,9 +20,7 @@ for measurement data control and analysis. Thanks to the integrated Python modul
the extracted measurement data can be stored in any open-source file format the extracted measurement data can be stored in any open-source file format
accessible by Python like i.a. _csv_, _json_ or _parquet_. accessible by Python like i.a. _csv_, _json_ or _parquet_.
On the [Record Evolution Platform](https://www.record-evolution.de/en/home-en/), On the [Record Evolution Platform](https://www.record-evolution.de/en/home-en/), the library can be used both as a command line tool for interactive usage and as a Python module to integrate the _.raw_ format into any ETL workflow.
the library can be used both as a command line tool for interactive usage and as a
Python module to integrate the _.raw_ format into any ETL workflow.
## Overview ## Overview
@ -31,11 +31,12 @@ Python module to integrate the _.raw_ format into any ETL workflow.
## File format ## File format
A file of the _IMC2 Data Format_ type with extension _.raw_ (or .dat) is a _mixed text/binary [Warning: Take a look at [this issue](https://github.com/RecordEvolution/IMCtermite/issues/14) when reading this section regarding the file format.]
A data file of the _IMC Bus Format_ type with the extension _.raw_ is a _mixed text/binary
file_ featuring a set of markers (keys) that indicate the start of various blocks file_ featuring a set of markers (keys) that indicate the start of various blocks
of data that provide meta information and the actual measurement data. Every single of data that provide meta information and the actual measurement data. Every single
marker is introduced by the character `"|" = 0x 7c` followed by two uppercase letters that marker is introduced by the character `"|" = 0x 7c` followed by two uppercase letters that characterize the type of marker. Each block is further divided into several
characterize the type of marker. Each block is further divided into several
parameters separated by commata `"," = 0x 2c` and terminated by a semicolon parameters separated by commata `"," = 0x 2c` and terminated by a semicolon
`";" = 0x 3b`. For instance, the header - first 600 bytes - of a raw file may `";" = 0x 3b`. For instance, the header - first 600 bytes - of a raw file may
look like this (in UTF-8 encoding): look like this (in UTF-8 encoding):
@ -131,21 +132,24 @@ which may require root permissions.
### Python ### Python
To integrate the library into a customized ETL toolchain, several python targets To integrate the library into a customized ETL toolchain, several cython targets
are available. For a local build that enables you to run the examples, use: are available. For a local build that enables you to run the examples, use:
``` ```
make python-build make cython-build
``` ```
However, in a production environment, a proper installation of the module with
`make cython-install` is recommended for system-wide availability of the module.
#### Installation with pip #### Installation with pip
The package is also available in the [Python Package Index](https://pypi.org) The package is also available in the [Python Package Index](https://pypi.org)
at [imctermite](https://pypi.org/project/imctermite/). at [IMCtermite](https://pypi.org/project/IMCtermite/).
To install the latest version simply do To install the latest version simply do
```Shell ```Shell
python3 -m pip install imctermite python3 -m pip install IMCtermite
``` ```
which provides binary wheels for multiple architectures on _Windows_ and _Linux_ which provides binary wheels for multiple architectures on _Windows_ and _Linux_
@ -192,9 +196,9 @@ Given the `IMCtermite` module is available, we can import it and declare an inst
of it by passing a _raw_ file to the constructor: of it by passing a _raw_ file to the constructor:
```Python ```Python
import imctermite import IMCtermite
imcraw = imctermite.imctermite(b"sample/sampleA.raw") imcraw = IMCtermite.imctermite(b"sample/sampleA.raw")
``` ```
An example of how to create an instance and obtain the list of channels is: An example of how to create an instance and obtain the list of channels is:
@ -219,31 +223,13 @@ can be found in the `python/examples` folder.
## References ## References
### IMC
- https://www.imc-tm.de/produkte/messtechnik-software/imc-famos/funktionen/im-und-export/ - https://www.imc-tm.de/produkte/messtechnik-software/imc-famos/funktionen/im-und-export/
- https://www.imc-tm.de/produkte/messtechnik-hardware/imc-cronosflex/ueberblick/ - https://www.imc-tm.de/produkte/messtechnik-hardware/imc-cronosflex/ueberblick/
- https://www.imc-tm.de/download-center/produkt-downloads/imc-famos/handbuecher - https://cython.readthedocs.io/en/latest/src/userguide/wrapping_CPlusPlus.html
- https://www.imc-tm.de/fileadmin/Public/Downloads/Manuals/imc_FAMOS/imcGemeinsameKomponenten.pdf
- https://github.com/Apollo3zehn/ImcFamosFile - https://github.com/Apollo3zehn/ImcFamosFile
- https://apollo3zehn.github.io/ImcFamosFile/api/ImcFamosFile.FamosFileKeyType.html - https://apollo3zehn.github.io/ImcFamosFile/api/ImcFamosFile.FamosFileKeyType.html
### Cython
- https://cython.readthedocs.io/en/latest/src/userguide/wrapping_CPlusPlus.html
### PyPI
- https://pypi.org/help/#apitoken - https://pypi.org/help/#apitoken
- https://sgoel.dev/posts/uploading-binary-wheels-to-pypi-from-github-actions/ - https://sgoel.dev/posts/uploading-binary-wheels-to-pypi-from-github-actions/
- https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsrun - https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- https://github.com/pypa/cibuildwheel/blob/main/examples/github-deploy.yml - https://github.com/pypa/cibuildwheel/blob/main/examples/github-deploy.yml
- https://cibuildwheel.readthedocs.io/en/stable/deliver-to-pypi/ - https://cibuildwheel.readthedocs.io/en/stable/deliver-to-pypi/
- https://github.com/actions/download-artifact#download-all-artifacts
- https://github.com/actions/download-artifact?tab=readme-ov-file#download-multiple-filtered-artifacts-to-the-same-directory
### iconv
- https://www.gnu.org/software/libiconv/
- https://vcpkg.io/en/packages.html
- https://vcpkg.io/en/getting-started

View File

@ -5,78 +5,43 @@
#include "imc_datatype.hpp" #include "imc_datatype.hpp"
#include "imc_conversion.hpp" #include "imc_conversion.hpp"
#include "imc_block.hpp"
#include <sstream> #include <sstream>
#include <math.h> #include <math.h>
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
#include <time.h>
#if defined(__linux__) || defined(__APPLE__)
#include <iconv.h>
#elif defined(__WIN32__) || defined(_WIN32)
#define timegm _mkgmtime
#endif
//---------------------------------------------------------------------------// //---------------------------------------------------------------------------//
namespace imc namespace imc
{ {
struct component_env
{
std::string uuid_;
// required channel components for CG channels only
std::string CCuuid_, CPuuid_;
// optional channel components for CG channels only
std::string CDuuid_, NTuuid_;
std::string Cbuuid_, CRuuid_;
// reset all members
void reset()
{
uuid_.clear();
CCuuid_.clear();
CPuuid_.clear();
CDuuid_.clear();
Cbuuid_.clear();
CRuuid_.clear();
NTuuid_.clear();
}
};
// collect uuid's of blocks required for full channel reconstruction // collect uuid's of blocks required for full channel reconstruction
struct channel_env struct channel_env
{ {
// define unique identifer for channel_env // define unique identifer for channel_env
std::string uuid_; std::string uuid_;
// collect common affiliate blocks for every channel
std::string NOuuid_, NLuuid_;
// collect affiliate blocks for a single channel // collect affiliate blocks for a single channel
// channel types std::string CBuuid_, CGuuid_, CCuuid_, CNuuid_;
std::string CBuuid_, CGuuid_, CIuuid_, CTuuid_; std::string CDuuid_, CTuuid_, Cbuuid_, CPuuid_, CRuuid_, CSuuid_;
std::string CNuuid_, CDuuid_, NTuuid_; std::string NTuuid_, NOuuid_, NLuuid_;
std::string CSuuid_;
component_env compenv1_;
component_env compenv2_;
// reset all members // reset all members
void reset() void reset()
{ {
uuid_.clear(); uuid_.clear();
NOuuid_.clear();
NLuuid_.clear();
CBuuid_.clear(); CBuuid_.clear();
CGuuid_.clear(); CGuuid_.clear();
CIuuid_.clear(); CCuuid_.clear();
CTuuid_.clear();
CNuuid_.clear(); CNuuid_.clear();
CDuuid_.clear(); CDuuid_.clear();
NTuuid_.clear(); CTuuid_.clear();
Cbuuid_.clear();
CPuuid_.clear();
CRuuid_.clear();
CSuuid_.clear(); CSuuid_.clear();
compenv1_.reset(); NTuuid_.clear();
compenv2_.reset(); NOuuid_.clear();
NLuuid_.clear();
} }
// get info // get info
@ -84,23 +49,21 @@ namespace imc
{ {
std::stringstream ss; std::stringstream ss;
ss<<std::setw(width)<<std::left<<"uuid:"<<uuid_<<"\n" ss<<std::setw(width)<<std::left<<"uuid:"<<uuid_<<"\n"
<<std::setw(width)<<std::left<<"NOuuid:"<<NOuuid_<<"\n"
<<std::setw(width)<<std::left<<"NLuuid:"<<NLuuid_<<"\n"
//
<<std::setw(width)<<std::left<<"CBuuid:"<<CBuuid_<<"\n" <<std::setw(width)<<std::left<<"CBuuid:"<<CBuuid_<<"\n"
<<std::setw(width)<<std::left<<"CGuuid:"<<CGuuid_<<"\n" <<std::setw(width)<<std::left<<"CGuuid:"<<CGuuid_<<"\n"
<<std::setw(width)<<std::left<<"CIuuid:"<<CIuuid_<<"\n" <<std::setw(width)<<std::left<<"CCuuid:"<<CCuuid_<<"\n"
<<std::setw(width)<<std::left<<"CTuuid:"<<CTuuid_<<"\n"
<<std::setw(width)<<std::left<<"CNuuid:"<<CNuuid_<<"\n" <<std::setw(width)<<std::left<<"CNuuid:"<<CNuuid_<<"\n"
// //
<<std::setw(width)<<std::left<<"CCuuid:"<<compenv1_.CCuuid_<<"\n" <<std::setw(width)<<std::left<<"CDuuid:"<<CDuuid_<<"\n"
<<std::setw(width)<<std::left<<"CPuuid:"<<compenv1_.CPuuid_<<"\n" <<std::setw(width)<<std::left<<"CTuuid:"<<CTuuid_<<"\n"
<<std::setw(width)<<std::left<<"Cbuuid:"<<Cbuuid_<<"\n"
<<std::setw(width)<<std::left<<"CPuuid:"<<CPuuid_<<"\n"
<<std::setw(width)<<std::left<<"CRuuid:"<<CRuuid_<<"\n"
<<std::setw(width)<<std::left<<"CSuuid:"<<CSuuid_<<"\n"
// //
<<std::setw(width)<<std::left<<"CDuuid:"<<compenv1_.CDuuid_<<"\n" <<std::setw(width)<<std::left<<"NTuuid:"<<NTuuid_<<"\n"
<<std::setw(width)<<std::left<<"Cbuuid:"<<compenv1_.Cbuuid_<<"\n" <<std::setw(width)<<std::left<<"NOuuid:"<<NOuuid_<<"\n"
<<std::setw(width)<<std::left<<"CRuuid:"<<compenv1_.CRuuid_<<"\n" <<std::setw(width)<<std::left<<"NLuuid:"<<NLuuid_<<"\n";
<<std::setw(width)<<std::left<<"NTuuid:"<<compenv1_.NTuuid_<<"\n"
<<std::setw(width)<<std::left<<"CSuuid:"<<CSuuid_<<"\n";
return ss.str(); return ss.str();
} }
@ -109,20 +72,19 @@ namespace imc
{ {
std::stringstream ss; std::stringstream ss;
ss<<"{"<<"\"uuid\":\""<<uuid_ ss<<"{"<<"\"uuid\":\""<<uuid_
<<"\",\"NOuuid\":\""<<NOuuid_
<<"\",\"NLuuid\":\""<<NLuuid_
<<"\",\"CBuuid\":\""<<CBuuid_ <<"\",\"CBuuid\":\""<<CBuuid_
<<"\",\"CGuuid\":\""<<CGuuid_ <<"\",\"CGuuid\":\""<<CGuuid_
<<"\",\"CIuuid\":\""<<CIuuid_ <<"\",\"CCuuid\":\""<<CCuuid_
<<"\",\"CTuuid\":\""<<CTuuid_
<<"\",\"CNuuid\":\""<<CNuuid_ <<"\",\"CNuuid\":\""<<CNuuid_
<<"\",\"CCuuid\":\""<<compenv1_.CCuuid_ <<"\",\"CDuuid\":\""<<CDuuid_
<<"\",\"CPuuid\":\""<<compenv1_.CPuuid_ <<"\",\"CTuuid\":\""<<CTuuid_
<<"\",\"CDuuid\":\""<<compenv1_.CDuuid_ <<"\",\"Cbuuid\":\""<<Cbuuid_
<<"\",\"Cbuuid\":\""<<compenv1_.Cbuuid_ <<"\",\"CPuuid\":\""<<CPuuid_
<<"\",\"CRuuid\":\""<<compenv1_.CRuuid_ <<"\",\"CRuuid\":\""<<CRuuid_
<<"\",\"NTuuid\":\""<<compenv1_.NTuuid_
<<"\",\"CSuuid\":\""<<CSuuid_ <<"\",\"CSuuid\":\""<<CSuuid_
<<"\",\"NTuuid\":\""<<NTuuid_
<<"\",\"NOuuid\":\""<<NOuuid_
<<"\",\"NLuuid\":\""<<NLuuid_
<<"\"}"; <<"\"}";
return ss.str(); return ss.str();
} }
@ -180,131 +142,6 @@ namespace imc
return sumstr; return sumstr;
} }
#if defined(__linux__) || defined(__APPLE__)
// convert encoding of any descriptions, channel-names, units etc.
class iconverter
{
std::string in_enc_, out_enc_;
iconv_t cd_;
size_t out_buffer_size_;
public:
iconverter(std::string in_enc, std::string out_enc, size_t out_buffer_size = 1024) :
in_enc_(in_enc), out_enc_(out_enc), out_buffer_size_(out_buffer_size)
{
// allocate descriptor for character set conversion
// (https://man7.org/linux/man-pages/man3/iconv_open.3.html)
cd_ = iconv_open(out_enc.c_str(), in_enc.c_str());
if ( (iconv_t)-1 == cd_ )
{
if ( errno == EINVAL )
{
std::string errmsg = std::string("The encoding conversion from ") + in_enc
+ std::string(" to ") + out_enc + std::string(" is not supported by the implementation.");
throw std::runtime_error(errmsg);
}
}
}
void convert(std::string &astring)
{
if ( astring.empty() ) return;
std::vector<char> in_buffer(astring.begin(),astring.end());
char *inbuf = &in_buffer[0];
size_t inbytes = in_buffer.size();
std::vector<char> out_buffer(out_buffer_size_);
char *outbuf = &out_buffer[0];
size_t outbytes = out_buffer.size();
// perform character set conversion
// ( - https://man7.org/linux/man-pages/man3/iconv.3.html
// - https://www.ibm.com/docs/en/zos/2.2.0?topic=functions-iconv-code-conversion )
while ( inbytes > 0 )
{
size_t res = iconv(cd_,&inbuf,&inbytes,&outbuf,&outbytes);
if ( (size_t)-1 == res )
{
std::string errmsg;
if ( errno == EILSEQ )
{
errmsg = std::string("An invalid multibyte sequence is encountered in the input.");
throw std::runtime_error(errmsg);
}
else if ( errno == EINVAL )
{
errmsg = std::string("An incomplete multibyte sequence is encountered in the input")
+ std::string(" and the input byte sequence terminates after it.");
}
else if ( errno == E2BIG )
{
errmsg = std::string("The output buffer has no more room for the next converted character.");
}
throw std::runtime_error(errmsg);
}
}
std::string outstring(out_buffer.begin(),out_buffer.end()-outbytes);
astring = outstring;
}
};
#elif defined(__WIN32__) || defined(_WIN32)
class iconverter
{
public:
iconverter(std::string in_enc, std::string out_enc, size_t out_buffer_size = 1024) {}
void convert(std::string &astring) {}
};
#endif
struct component_group
{
imc::component CC_;
imc::packaging CP_;
imc::abscissa CD_;
imc::buffer Cb_;
imc::range CR_;
imc::channelobj CN_;
imc::triggertime NT_;
component_env compenv_;
// Constructor to parse the associated blocks
component_group(component_env &compenv, std::map<std::string, imc::block>* blocks, std::vector<unsigned char>* buffer)
: compenv_(compenv)
{
if (blocks->count(compenv.CCuuid_) == 1)
{
CC_.parse(buffer, blocks->at(compenv.CCuuid_).get_parameters());
}
if (blocks->count(compenv.CPuuid_) == 1)
{
CP_.parse(buffer, blocks->at(compenv.CPuuid_).get_parameters());
}
if (blocks->count(compenv.CDuuid_) == 1)
{
CD_.parse(buffer, blocks->at(compenv.CDuuid_).get_parameters());
}
if (blocks->count(compenv.Cbuuid_) == 1)
{
Cb_.parse(buffer, blocks->at(compenv.Cbuuid_).get_parameters());
}
if (blocks->count(compenv.CRuuid_) == 1)
{
CR_.parse(buffer, blocks->at(compenv.CRuuid_).get_parameters());
}
if (blocks->count(compenv.NTuuid_) == 1)
{
NT_.parse(buffer, blocks->at(compenv.NTuuid_).get_parameters());
}
}
};
// channel // channel
struct channel struct channel
{ {
@ -313,16 +150,8 @@ namespace imc
std::map<std::string,imc::block>* blocks_; std::map<std::string,imc::block>* blocks_;
std::vector<unsigned char>* buffer_; std::vector<unsigned char>* buffer_;
imc::origin_data NO_;
imc::language NL_;
imc::text CT_;
imc::groupobj CB_;
imc::datafield CG_;
imc::channelobj CN_;
// collect meta-data of channels according to env, // collect meta-data of channels according to env,
// just everything valueable in here // just everything valueable in here
// TODO: is this necessary?
std::string uuid_; std::string uuid_;
std::string name_, comment_; std::string name_, comment_;
std::string origin_, origin_comment_, text_; std::string origin_, origin_comment_, text_;
@ -331,330 +160,243 @@ namespace imc
std::string language_code_, codepage_; std::string language_code_, codepage_;
std::string yname_, yunit_; std::string yname_, yunit_;
std::string xname_, xunit_; std::string xname_, xunit_;
double xstepwidth_, xstart_; double xstepwidth_, xoffset_;
int xprec_; int xprec_;
int dimension_;
// buffer and data // buffer and data
int xsignbits_, xnum_bytes_; int signbits_, num_bytes_;
int ysignbits_, ynum_bytes_;
// unsigned long int byte_offset_; // unsigned long int byte_offset_;
unsigned long int xbuffer_offset_, ybuffer_offset_; unsigned long int buffer_offset_, buffer_size_;
unsigned long int xbuffer_size_, ybuffer_size_;
long int addtime_; long int addtime_;
imc::numtype xdatatp_, ydatatp_; int datatp_;
std::vector<imc::datatype> xdata_, ydata_; imc::datatype dattyp_;
std::vector<imc::datatype> ydata_;
std::vector<double> xdata_;
// range, factor and offset // range, factor and offset
double xfactor_, yfactor_; double factor_, offset_;
double xoffset_, yoffset_;
// group reference the channel belongs to // group reference the channel belongs to
unsigned long int group_index_; int group_index_;
std::string group_uuid_, group_name_, group_comment_; std::string group_uuid_, group_name_, group_comment_;
// constructor takes channel's block environment // constructor takes channel's block environment
channel(channel_env &chnenv, std::map<std::string,imc::block>* blocks, channel(channel_env &chnenv, std::map<std::string,imc::block>* blocks,
std::vector<unsigned char>* buffer): std::vector<unsigned char>* buffer):
chnenv_(chnenv), blocks_(blocks), buffer_(buffer), chnenv_(chnenv), blocks_(blocks), buffer_(buffer),
xfactor_(1.), yfactor_(1.), xoffset_(0.), yoffset_(0.), factor_(1.), offset_(0.),
group_index_(-1) group_index_(-1)
{ {
// declare list of block parameters
std::vector<imc::parameter> prms;
// use uuid from CN block // use uuid from CN block
uuid_ = chnenv_.CNuuid_; uuid_ = chnenv_.CNuuid_;
// extract associated NO data
if ( blocks_->count(chnenv_.NOuuid_) == 1 )
{
NO_.parse(buffer_, blocks_->at(chnenv_.NOuuid_).get_parameters());
origin_ = NO_.generator_;
comment_ = NO_.comment_;
}
// extract associated NL data
if ( blocks_->count(chnenv_.NLuuid_) == 1 )
{
NL_.parse(buffer_, blocks_->at(chnenv_.NLuuid_).get_parameters());
codepage_ = NL_.codepage_;
language_code_ = NL_.language_code_;
}
// extract associated CB data // extract associated CB data
if ( blocks_->count(chnenv_.CBuuid_) == 1 ) if ( blocks_->count(chnenv_.CBuuid_) == 1 )
{ {
CB_.parse(buffer_, blocks_->at(chnenv_.CBuuid_).get_parameters()); prms = blocks_->at(chnenv_.CBuuid_).get_parameters();
group_index_ = std::stoi(blocks_->at(chnenv_.CBuuid_).get_parameter(prms[2]));
group_name_ = blocks_->at(chnenv_.CBuuid_).get_parameter(prms[4]);
group_comment_ = blocks_->at(chnenv_.CBuuid_).get_parameter(prms[6]);
} }
// extract associated CT data // extract associated CT data
if ( blocks_->count(chnenv_.CTuuid_) == 1 ) if ( blocks_->count(chnenv_.CTuuid_) == 1 )
{ {
CT_.parse(buffer_, blocks_->at(chnenv_.CTuuid_).get_parameters()); prms = blocks_->at(chnenv_.CTuuid_).get_parameters();
text_ = CT_.name_ + std::string(" - ") text_ = blocks_->at(chnenv_.CTuuid_).get_parameter(prms[4]) + std::string(" - ")
+ CT_.text_ + std::string(" - ") + blocks_->at(chnenv_.CTuuid_).get_parameter(prms[6]) + std::string(" - ")
+ CT_.comment_; + blocks_->at(chnenv_.CTuuid_).get_parameter(prms[8]);
}
// extract associated CD data
if ( blocks_->count(chnenv_.CDuuid_) == 1 )
{
prms = blocks_->at(chnenv_.CDuuid_).get_parameters();
xstepwidth_ = std::stod(blocks_->at(chnenv_.CDuuid_).get_parameter(prms[2]));
xunit_ = blocks_->at(chnenv_.CDuuid_).get_parameter(prms[5]);
// TODO
// xname_ = std::string("time");
// find appropriate precision for "xdata_" by means of "xstepwidth_"
xprec_ = (xstepwidth_ > 0 ) ? (int)ceil(fabs(log10(xstepwidth_))) : 10;
}
// extract associated CP data
if ( blocks_->count(chnenv_.CPuuid_) == 1 )
{
prms = blocks_->at(chnenv_.CPuuid_).get_parameters();
num_bytes_ = std::stoi(blocks_->at(chnenv_.CPuuid_).get_parameter(prms[3]));
datatp_ = std::stoi(blocks_->at(chnenv_.CPuuid_).get_parameter(prms[4]));
signbits_ = std::stoi(blocks_->at(chnenv_.CPuuid_).get_parameter(prms[5]));
// byte_offset_ = std::stoul(blocks_->at(chnenv_.CPuuid_).get_parameter(prms[7]));
}
// extract associated Cb data
if ( blocks_->count(chnenv_.Cbuuid_) == 1 )
{
prms = blocks_->at(chnenv_.Cbuuid_).get_parameters();
buffer_offset_ = std::stoul(blocks_->at(chnenv_.Cbuuid_).get_parameter(prms[6]));
buffer_size_ = std::stoul(blocks_->at(chnenv_.Cbuuid_).get_parameter(prms[7]));
xoffset_ = std::stod(blocks_->at(chnenv_.Cbuuid_).get_parameter(prms[11]));
addtime_ = (long int)std::stod(blocks_->at(chnenv_.Cbuuid_).get_parameter(prms[12]));
}
// extract associated CR data
if ( blocks_->count(chnenv_.CRuuid_) == 1 )
{
prms = blocks_->at(chnenv_.CRuuid_).get_parameters();
factor_ = std::stod(blocks_->at(chnenv_.CRuuid_).get_parameter(prms[3]));
offset_ = std::stod(blocks_->at(chnenv_.CRuuid_).get_parameter(prms[4]));
yunit_ = blocks_->at(chnenv_.CRuuid_).get_parameter(prms[7]);
} }
// extract associated CN data // extract associated CN data
if ( blocks_->count(chnenv_.CNuuid_) == 1 ) if ( blocks_->count(chnenv_.CNuuid_) == 1 )
{ {
CN_.parse(buffer_, blocks_->at(chnenv_.CNuuid_).get_parameters()); prms = blocks_->at(chnenv_.CNuuid_).get_parameters();
group_index_ = CN_.group_index_; name_ = blocks_->at(chnenv_.CNuuid_).get_parameter(prms[6]);
group_name_ = CN_.name_; yname_ = name_;
group_comment_ = CN_.comment_; comment_ = blocks_->at(chnenv_.CNuuid_).get_parameter(prms[8]);
// group_index_ = std::stoi(blocks_->at(chnenv_.CNuuid_).get_parameter(prms[2]));
} }
if ( !chnenv_.compenv1_.uuid_.empty() && chnenv_.compenv2_.uuid_.empty() ) // extract associated NO data
if ( blocks_->count(chnenv_.NOuuid_) == 1 )
{ {
// normal dataset (single component) prms = blocks_->at(chnenv_.NOuuid_).get_parameters();
// set common NT and CD keys if no others are specified origin_ = blocks_->at(chnenv_.NOuuid_).get_parameter(prms[4]);
if (chnenv_.compenv1_.NTuuid_.empty()) chnenv_.compenv1_.NTuuid_ = chnenv_.NTuuid_; origin_comment_ = blocks_->at(chnenv_.NOuuid_).get_parameter(prms[6]);
if (chnenv_.compenv1_.CDuuid_.empty()) chnenv_.compenv1_.CDuuid_ = chnenv_.CDuuid_; }
// comp_group1 contains y-data, x-data is based on xstepwidth_, xstart_ and the length of y-data // extract associated NL data
component_group comp_group1(chnenv_.compenv1_, blocks_, buffer_); // codepage:
dimension_ = 1; // - http://www.iana.org/assignments/character-sets/character-sets.xhtml
// - https://de.wikipedia.org/wiki/Zeichensatztabelle
// language-code:
// - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c?redirectedfrom=MSDN
if ( blocks_->count(chnenv_.NLuuid_) == 1 )
{
prms = blocks_->at(chnenv_.NLuuid_).get_parameters();
codepage_ = blocks_->at(chnenv_.NLuuid_).get_parameter(prms[2]);
language_code_ = blocks_->at(chnenv_.NLuuid_).get_parameter(prms[3]);
}
// obtain NT data
// - https://en.cppreference.com/w/cpp/chrono/c/tm
// - https://en.cppreference.com/w/cpp/io/manip/put_time
if ( blocks_->count(chnenv_.NTuuid_) == 1 )
{
prms = blocks_->at(chnenv_.NTuuid_).get_parameters();
//std::tm tm{};
std::tm tms = std::tm();
tms.tm_mday = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[2]));
tms.tm_mon = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[3])) - 1;
tms.tm_year = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[4])) - 1900;
tms.tm_hour = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[5]));
tms.tm_min = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[6]));
long double secs = std::stold(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[7]));
double secs_int;
trigger_time_frac_secs_ = modf((double)secs,&secs_int);
tms.tm_sec = (int)secs_int;
xstepwidth_ = comp_group1.CD_.dx_;
xunit_ = comp_group1.CD_.unit_;
ybuffer_offset_ = comp_group1.Cb_.offset_buffer_;
ybuffer_size_ = comp_group1.Cb_.number_bytes_;
xstart_ = comp_group1.Cb_.x0_;
yfactor_ = comp_group1.CR_.factor_;
yoffset_ = comp_group1.CR_.offset_;
yunit_ = comp_group1.CR_.unit_;
name_ = comp_group1.CN_.name_;
yname_ = comp_group1.CN_.name_;
comment_ = comp_group1.CN_.comment_;
ynum_bytes_ = comp_group1.CP_.bytes_;
ydatatp_ = comp_group1.CP_.numeric_type_;
ysignbits_ = comp_group1.CP_.signbits_;
// generate std::chrono::system_clock::time_point type // generate std::chrono::system_clock::time_point type
std::time_t ts = timegm(&comp_group1.NT_.tms_); // std::mktime(&tms); std::time_t ts = std::mktime(&tms);
trigger_time_ = std::chrono::system_clock::from_time_t(ts); trigger_time_ = std::chrono::system_clock::from_time_t(ts);
trigger_time_frac_secs_ = comp_group1.NT_.trigger_time_frac_secs_;
// calculate absolute trigger-time
addtime_ = static_cast<long int>(comp_group1.Cb_.add_time_);
absolute_trigger_time_ = trigger_time_ + std::chrono::seconds(addtime_);
// + std::chrono::nanoseconds((long int)(trigger_time_frac_secs_*1.e9));
}
else if ( !chnenv_.compenv1_.uuid_.empty() && !chnenv_.compenv2_.uuid_.empty() )
{
// XY dataset (two components)
// set common NT and CD keys if no others are specified
if (chnenv_.compenv1_.NTuuid_.empty()) chnenv_.compenv1_.NTuuid_ = chnenv_.NTuuid_;
if (chnenv_.compenv1_.CDuuid_.empty()) chnenv_.compenv1_.CDuuid_ = chnenv_.CDuuid_;
if (chnenv_.compenv2_.NTuuid_.empty()) chnenv_.compenv2_.NTuuid_ = chnenv_.NTuuid_;
if (chnenv_.compenv2_.CDuuid_.empty()) chnenv_.compenv2_.CDuuid_ = chnenv_.CDuuid_;
// comp_group1 contains x-data, comp_group2 contains y-data
component_group comp_group1(chnenv_.compenv1_, blocks_, buffer_);
component_group comp_group2(chnenv_.compenv2_, blocks_, buffer_);
dimension_ = 2;
xbuffer_offset_ = comp_group2.Cb_.offset_buffer_;
xbuffer_size_ = comp_group2.Cb_.number_bytes_;
ybuffer_offset_ = comp_group1.Cb_.offset_buffer_;
ybuffer_size_ = comp_group1.Cb_.number_bytes_;
xfactor_ = comp_group2.CR_.factor_;
xoffset_ = comp_group2.CR_.offset_;
yfactor_ = comp_group1.CR_.factor_;
yoffset_ = comp_group1.CR_.offset_;
xdatatp_ = comp_group2.CP_.numeric_type_;
xsignbits_ = comp_group2.CP_.signbits_;
ydatatp_ = comp_group1.CP_.numeric_type_;
ysignbits_ = comp_group1.CP_.signbits_;
// generate std::chrono::system_clock::time_point type
std::time_t ts = timegm(&comp_group2.NT_.tms_); // std::mktime(&tms);
trigger_time_ = std::chrono::system_clock::from_time_t(ts);
trigger_time_frac_secs_ = comp_group2.NT_.trigger_time_frac_secs_;
absolute_trigger_time_ = trigger_time_;
}
else
{
// no datafield
} }
// start converting binary buffer to imc::datatype // start converting binary buffer to imc::datatype
if ( !chnenv_.CSuuid_.empty() ) convert_buffer(); if ( !chnenv_.CSuuid_.empty() ) convert_buffer();
// convert any non-UTF-8 codepage to UTF-8 and cleanse any text // calculate absolute trigger-time
convert_encoding(); absolute_trigger_time_ = trigger_time_ + std::chrono::seconds(addtime_);
cleanse_text(); // + std::chrono::nanoseconds((long int)(trigger_time_frac_secs_*1.e9));
} }
// convert buffer to actual datatype // convert buffer to actual datatype
void convert_buffer() void convert_buffer()
{ {
// TODO no clue how/if/when to handle buffer offset/mask/subsequent_bytes
// etc. and whatever that shit is!
std::vector<imc::parameter> prms = blocks_->at(chnenv_.CSuuid_).get_parameters(); std::vector<imc::parameter> prms = blocks_->at(chnenv_.CSuuid_).get_parameters();
if ( prms.size() < 4) if ( prms.size() < 4)
{ {
throw std::runtime_error("CS block is invalid and features to few parameters"); throw std::runtime_error("CS block is invalid and features to few parameters");
} }
// extract (channel dependent) part of buffer
unsigned long int buffstrt = prms[3].begin(); unsigned long int buffstrt = prms[3].begin();
std::vector<unsigned char> yCSbuffer( buffer_->begin()+buffstrt+ybuffer_offset_+1, std::vector<unsigned char> CSbuffer( buffer_->begin()+buffstrt+1,
buffer_->begin()+buffstrt+ybuffer_offset_+ybuffer_size_+1 ); buffer_->begin()+buffstrt+buffer_size_+1 );
// determine number of values in buffer // determine number of values in buffer
unsigned long int ynum_values = (unsigned long int)(yCSbuffer.size()/(ysignbits_/8)); unsigned long int num_values = (unsigned long int)(CSbuffer.size()/(signbits_/8));
if ( ynum_values*(ysignbits_/8) != yCSbuffer.size() ) if ( num_values*(signbits_/8) != CSbuffer.size() )
{ {
throw std::runtime_error("CSbuffer and significant bits of y datatype don't match"); throw std::runtime_error("CSbuffer and significant bits of datatype don't match");
} }
// adjust size of ydata
ydata_.resize(num_values);
if (dimension_ == 1) // distinguish numeric datatypes included in "imc_datatype"
if ( datatp_ == 1 )
{ {
// process y-data imc::convert_data_to_type<imc_Ubyte>(CSbuffer,ydata_);
process_data(ydata_, ynum_values, ydatatp_, yCSbuffer);
// find appropriate precision for "xdata_" by means of "xstepwidth_"
xprec_ = (xstepwidth_ > 0 ) ? (int)ceil(fabs(log10(xstepwidth_))) : 10;
// fill xdata_
for ( unsigned long int i = 0; i < ynum_values; i++ )
{
xdata_.push_back(xstart_+(double)i*xstepwidth_);
}
} }
else if (dimension_ == 2) else if ( datatp_ == 2 )
{ {
// process x- and y-data imc::convert_data_to_type<imc_Sbyte>(CSbuffer,ydata_);
std::vector<unsigned char> xCSbuffer( buffer_->begin()+buffstrt+xbuffer_offset_+1, }
buffer_->begin()+buffstrt+xbuffer_offset_+xbuffer_size_+1 ); else if ( datatp_ == 3 )
{
// determine number of values in buffer imc::convert_data_to_type<imc_Ushort>(CSbuffer,ydata_);
unsigned long int xnum_values = (unsigned long int)(xCSbuffer.size()/(xsignbits_/8)); }
if ( xnum_values*(xsignbits_/8) != xCSbuffer.size() ) else if ( datatp_ == 4 )
{ {
throw std::runtime_error("CSbuffer and significant bits of x datatype don't match"); imc::convert_data_to_type<imc_Sshort>(CSbuffer,ydata_);
} }
if ( xnum_values != ynum_values ) else if ( datatp_ == 5 )
{ {
throw std::runtime_error("x and y data have different number of values"); imc::convert_data_to_type<imc_Ulongint>(CSbuffer,ydata_);
} }
else if ( datatp_ == 6 )
xprec_ = 9; {
imc::convert_data_to_type<imc_Slongint>(CSbuffer,ydata_);
process_data(xdata_, xnum_values, xdatatp_, xCSbuffer); }
process_data(ydata_, ynum_values, ydatatp_, yCSbuffer); else if ( datatp_ == 7 )
{
imc::convert_data_to_type<imc_float>(CSbuffer,ydata_);
}
else if ( datatp_ == 8 )
{
imc::convert_data_to_type<imc_double>(CSbuffer,ydata_);
}
// ...
else if ( datatp_ == 11 )
{
imc::convert_data_to_type<imc_digital>(CSbuffer,ydata_);
} }
else else
{ {
throw std::runtime_error("unsupported dimension"); throw std::runtime_error(std::string("unsupported/unknown datatype") + std::to_string(datatp_));
} }
transformData(xdata_, xfactor_, xoffset_); // fill xdata_
transformData(ydata_, yfactor_, yoffset_); for ( unsigned long int i = 0; i < num_values; i++ )
}
// handle data type conversion
void process_data(std::vector<imc::datatype>& data_, size_t num_values, numtype datatp_, std::vector<unsigned char>& CSbuffer)
{
// adjust size of data
data_.resize(num_values);
// handle data type conversion
switch (datatp_)
{ {
case numtype::unsigned_byte: xdata_.push_back(xoffset_+(double)i*xstepwidth_);
imc::convert_data_to_type<imc_Ubyte>(CSbuffer, data_);
break;
case numtype::signed_byte:
imc::convert_data_to_type<imc_Sbyte>(CSbuffer, data_);
break;
case numtype::unsigned_short:
imc::convert_data_to_type<imc_Ushort>(CSbuffer, data_);
break;
case numtype::signed_short:
imc::convert_data_to_type<imc_Sshort>(CSbuffer, data_);
break;
case numtype::unsigned_long:
imc::convert_data_to_type<imc_Ulongint>(CSbuffer, data_);
break;
case numtype::signed_long:
imc::convert_data_to_type<imc_Slongint>(CSbuffer, data_);
break;
case numtype::ffloat:
imc::convert_data_to_type<imc_float>(CSbuffer, data_);
break;
case numtype::ddouble:
imc::convert_data_to_type<imc_double>(CSbuffer, data_);
break;
case numtype::two_byte_word_digital:
imc::convert_data_to_type<imc_digital>(CSbuffer, data_);
break;
case numtype::six_byte_unsigned_long:
imc::convert_data_to_type<imc_sixbyte>(CSbuffer, data_);
break;
default:
throw std::runtime_error(std::string("unsupported/unknown datatype ") + std::to_string(datatp_));
} }
}
void transformData(std::vector<imc::datatype>& data, double factor, double offset) { // employ data transformation
if (factor != 1.0 || offset != 0.0) { if ( factor_ != 1.0 || offset_ != 0.0 )
for (imc::datatype& el : data) { {
double fact = (factor == 0.0) ? 1.0 : factor; for ( imc::datatype& el: ydata_ )
el = imc::datatype(el.as_double() * fact + offset); {
} //std::cout<<"value:"<<el.as_double()<<"\n";
double fact = ( factor_ == 0.0 ) ? 1.0 : factor_;
el = imc::datatype(el.as_double()*fact + offset_);
} }
}
// convert any description, units etc. to UTF-8 (by default)
void convert_encoding()
{
if ( !codepage_.empty() )
{
// construct iconv-compatible name for respective codepage
std::string cpn = std::string("CP") + codepage_;
// set up converter
std::string utf = std::string("UTF-8");
iconverter conv(cpn,utf);
conv.convert(name_);
conv.convert(comment_);
conv.convert(origin_);
conv.convert(origin_comment_);
conv.convert(text_);
conv.convert(language_code_);
conv.convert(yname_);
conv.convert(yunit_);
conv.convert(xname_);
conv.convert(xunit_);
conv.convert(group_name_);
conv.convert(group_comment_);
}
}
void cleanse_text()
{
escape_backslash(name_);
escape_backslash(comment_);
escape_backslash(origin_);
escape_backslash(origin_comment_);
escape_backslash(text_);
escape_backslash(language_code_);
escape_backslash(yname_);
escape_backslash(yunit_);
escape_backslash(xname_);
escape_backslash(xunit_);
escape_backslash(group_name_);
escape_backslash(group_comment_);
}
void escape_backslash(std::string &text)
{
char backslash = 0x5c;
std::string doublebackslash("\\\\");
for ( std::string::iterator it = text.begin(); it != text.end(); ++it )
{
if ( int(*it) == backslash ) {
text.replace(it,it+1,doublebackslash);
++it;
}
} }
} }
@ -670,28 +412,28 @@ namespace imc
<<std::setw(width)<<std::left<<"name:"<<name_<<"\n" <<std::setw(width)<<std::left<<"name:"<<name_<<"\n"
<<std::setw(width)<<std::left<<"comment:"<<comment_<<"\n" <<std::setw(width)<<std::left<<"comment:"<<comment_<<"\n"
<<std::setw(width)<<std::left<<"origin:"<<origin_<<"\n" <<std::setw(width)<<std::left<<"origin:"<<origin_<<"\n"
<<std::setw(width)<<std::left<<"origin-comment:"<<origin_comment_<<"\n"
<<std::setw(width)<<std::left<<"description:"<<text_<<"\n" <<std::setw(width)<<std::left<<"description:"<<text_<<"\n"
<<std::setw(width)<<std::left<<"trigger-time-nt:"<<std::put_time(std::gmtime(&tt),"%FT%T")<<"\n" <<std::setw(width)<<std::left<<"trigger-time-nt:"<<std::put_time(std::localtime(&tt),"%FT%T")<<"\n"
<<std::setw(width)<<std::left<<"trigger-time:"<<std::put_time(std::gmtime(&att),"%FT%T")<<"\n" <<std::setw(width)<<std::left<<"trigger-time:"<<std::put_time(std::localtime(&att),"%FT%T")<<"\n"
<<std::setw(width)<<std::left<<"language-code:"<<language_code_<<"\n" <<std::setw(width)<<std::left<<"language-code:"<<language_code_<<"\n"
<<std::setw(width)<<std::left<<"codepage:"<<codepage_<<"\n" <<std::setw(width)<<std::left<<"codepage:"<<codepage_<<"\n"
<<std::setw(width)<<std::left<<"yname:"<<yname_<<"\n" <<std::setw(width)<<std::left<<"yname:"<<yname_<<"\n"
<<std::setw(width)<<std::left<<"yunit:"<<yunit_<<"\n" <<std::setw(width)<<std::left<<"yunit:"<<yunit_<<"\n"
<<std::setw(width)<<std::left<<"datatype:"<<ydatatp_<<"\n" <<std::setw(width)<<std::left<<"datatype:"<<datatp_<<"\n"
<<std::setw(width)<<std::left<<"significant bits:"<<ysignbits_<<"\n" <<std::setw(width)<<std::left<<"significant bits:"<<signbits_<<"\n"
<<std::setw(width)<<std::left<<"buffer-offset:"<<ybuffer_offset_<<"\n" <<std::setw(width)<<std::left<<"buffer-offset:"<<buffer_offset_<<"\n"
<<std::setw(width)<<std::left<<"buffer-size:"<<ybuffer_size_<<"\n" <<std::setw(width)<<std::left<<"buffer-size:"<<buffer_size_<<"\n"
<<std::setw(width)<<std::left<<"add-time:"<<addtime_<<"\n"
<<std::setw(width)<<std::left<<"xname:"<<xname_<<"\n" <<std::setw(width)<<std::left<<"xname:"<<xname_<<"\n"
<<std::setw(width)<<std::left<<"xunit:"<<xunit_<<"\n" <<std::setw(width)<<std::left<<"xunit:"<<xunit_<<"\n"
<<std::setw(width)<<std::left<<"xstepwidth:"<<xstepwidth_<<"\n" <<std::setw(width)<<std::left<<"xstepwidth:"<<xstepwidth_<<"\n"
<<std::setw(width)<<std::left<<"xoffset:"<<xstart_<<"\n" <<std::setw(width)<<std::left<<"xoffset:"<<xoffset_<<"\n"
<<std::setw(width)<<std::left<<"factor:"<<yfactor_<<"\n" <<std::setw(width)<<std::left<<"factor:"<<factor_<<"\n"
<<std::setw(width)<<std::left<<"offset:"<<yoffset_<<"\n" <<std::setw(width)<<std::left<<"offset:"<<offset_<<"\n"
<<std::setw(width)<<std::left<<"group:"<<"("<<group_index_<<","<<group_name_ <<std::setw(width)<<std::left<<"group:"<<"("<<group_index_<<","<<group_name_
<<","<<group_comment_<<")"<<"\n" <<","<<group_comment_<<")"<<"\n"
<<std::setw(width)<<std::left<<"ydata:"<<imc::joinvec<imc::datatype>(ydata_,6,9,true)<<"\n" <<std::setw(width)<<std::left<<"ydata:"<<imc::joinvec<imc::datatype>(ydata_,6,9,true)<<"\n"
<<std::setw(width)<<std::left<<"xdata:"<<imc::joinvec<imc::datatype>(xdata_,6,xprec_,true)<<"\n"; <<std::setw(width)<<std::left<<"xdata:"<<imc::joinvec<double>(xdata_,6,xprec_,true)<<"\n";
// <<std::setw(width)<<std::left<<"aff. blocks:"<<chnenv_.get_json()<<"\n"; // <<std::setw(width)<<std::left<<"aff. blocks:"<<chnenv_.get_json()<<"\n";
return ss.str(); return ss.str();
} }
@ -708,27 +450,26 @@ namespace imc
<<"\",\"name\":\""<<name_ <<"\",\"name\":\""<<name_
<<"\",\"comment\":\""<<comment_ <<"\",\"comment\":\""<<comment_
<<"\",\"origin\":\""<<origin_ <<"\",\"origin\":\""<<origin_
<<"\",\"origin-comment\":\""<<origin_comment_
<<"\",\"description\":\""<<text_ <<"\",\"description\":\""<<text_
<<"\",\"trigger-time-nt\":\""<<std::put_time(std::gmtime(&tt),"%FT%T") <<"\",\"trigger-time-nt\":\""<<std::put_time(std::localtime(&tt),"%FT%T")
<<"\",\"trigger-time\":\""<<std::put_time(std::gmtime(&att),"%FT%T") <<"\",\"trigger-time\":\""<<std::put_time(std::localtime(&att),"%FT%T")
<<"\",\"language-code\":\""<<language_code_ <<"\",\"language-code\":\""<<language_code_
<<"\",\"codepage\":\""<<codepage_ <<"\",\"codepage\":\""<<codepage_
<<"\",\"yname\":\""<<prepjsonstr(yname_) <<"\",\"yname\":\""<<prepjsonstr(yname_)
<<"\",\"yunit\":\""<<prepjsonstr(yunit_) <<"\",\"yunit\":\""<<prepjsonstr(yunit_)
<<"\",\"significantbits\":\""<<ysignbits_ <<"\",\"significantbits\":\""<<signbits_
<<"\",\"buffer-size\":\""<<ybuffer_size_ <<"\",\"addtime\":\""<<addtime_
<<"\",\"xname\":\""<<prepjsonstr(xname_) <<"\",\"xname\":\""<<prepjsonstr(xname_)
<<"\",\"xunit\":\""<<prepjsonstr(xunit_) <<"\",\"xunit\":\""<<prepjsonstr(xunit_)
<<"\",\"xstepwidth\":\""<<xstepwidth_ <<"\",\"xstepwidth\":\""<<xstepwidth_
<<"\",\"xoffset\":\""<<xstart_ <<"\",\"xoffset\":\""<<xoffset_
<<"\",\"group\":{"<<"\"index\":\""<<group_index_ <<"\",\"group\":{"<<"\"index\":\""<<group_index_
<<"\",\"name\":\""<<group_name_ <<"\",\"name\":\""<<group_name_
<<"\",\"comment\":\""<<group_comment_<<"\""<<"}"; <<"\",\"comment\":\""<<group_comment_<<"\""<<"}";
if ( include_data ) if ( include_data )
{ {
ss<<",\"ydata\":"<<imc::joinvec<imc::datatype>(ydata_,0,9,true) ss<<",\"ydata\":"<<imc::joinvec<imc::datatype>(ydata_,0,9,true)
<<",\"xdata\":"<<imc::joinvec<imc::datatype>(xdata_,0,xprec_,true); <<",\"xdata\":"<<imc::joinvec<double>(xdata_,0,xprec_,true);
} }
// ss<<"\",\"aff. blocks\":\""<<chnenv_.get_json() // ss<<"\",\"aff. blocks\":\""<<chnenv_.get_json()
ss<<"}"; ss<<"}";

View File

@ -16,12 +16,12 @@ namespace imc
// //
// e.g. ARM Cortex-A72 armv7l gcc version 10.2.0 (Ubuntu 10.2.0-13ubuntu1) // e.g. ARM Cortex-A72 armv7l gcc version 10.2.0 (Ubuntu 10.2.0-13ubuntu1)
// #ifdef __arm__ // #ifdef __arm__
// typedef unsigned long int imc_Ulongint; typedef unsigned long int imc_Ulongint;
// typedef signed long int imc_Slongint; typedef signed long int imc_Slongint;
// e.g. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz x86_64 gcc version 10.2.0 (Ubuntu 10.2.0-13ubuntu1) // e.g. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz x86_64 gcc version 10.2.0 (Ubuntu 10.2.0-13ubuntu1)
// #ifdef i386 __i386 __i386__ // #ifdef i386 __i386 __i386__
typedef unsigned int imc_Ulongint; // typedef unsigned int imc_Ulongint;
typedef signed int imc_Slongint; // typedef signed int imc_Slongint;
// //
typedef float imc_float; typedef float imc_float;
typedef double imc_double; typedef double imc_double;
@ -30,11 +30,7 @@ namespace imc
// typedef <whatever that is ->... > "imc Devices Transitional Recording" // typedef <whatever that is ->... > "imc Devices Transitional Recording"
// typedf <sometimestamptype> "Timestamp Ascii" // typedf <sometimestamptype> "Timestamp Ascii"
typedef char16_t imc_digital; typedef char16_t imc_digital;
// // typedef < > imc_sixbyte "6byte unsigned long"
typedef struct {
unsigned char bytes[6];
} imc_sixbyte;
class datatype class datatype
{ {
@ -48,14 +44,13 @@ namespace imc
imc_float sfloat_; // 6 imc_float sfloat_; // 6
imc_double sdouble_; // 7 imc_double sdouble_; // 7
imc_digital sdigital_; // 10 imc_digital sdigital_; // 10
imc_sixbyte sixbyte_; // 13 short int dtidx_; // \in \{0,...,7,10\}
short int dtidx_; // \in \{0,...,7,10,13\}
public: public:
datatype(): ubyte_(0), sbyte_(0), datatype(): ubyte_(0), sbyte_(0),
ushort_(0), sshort_(0), ushort_(0), sshort_(0),
ulint_(0), slint_(0), ulint_(0), slint_(0),
sfloat_(0.0), sdouble_(0.0), sfloat_(0.0), sdouble_(0.0),
sdigital_(0), sixbyte_({0}), sdigital_(0),
dtidx_(0) { }; dtidx_(0) { };
// every supported datatype gets its own constructor // every supported datatype gets its own constructor
datatype(imc_Ubyte num): ubyte_(num), dtidx_(0) {}; datatype(imc_Ubyte num): ubyte_(num), dtidx_(0) {};
@ -67,13 +62,10 @@ namespace imc
datatype(imc_float num): sfloat_(num), dtidx_(6) {}; datatype(imc_float num): sfloat_(num), dtidx_(6) {};
datatype(imc_double num): ubyte_(0), sbyte_(0), ushort_(0), sshort_(0), datatype(imc_double num): ubyte_(0), sbyte_(0), ushort_(0), sshort_(0),
ulint_(0), slint_(0), sfloat_(0.0), sdouble_(num), ulint_(0), slint_(0), sfloat_(0.0), sdouble_(num),
sdigital_(0), sixbyte_({0}), dtidx_(7) {}; sdigital_(0), dtidx_(7) {};
datatype(imc_digital num): ubyte_(0), sbyte_(0), ushort_(0), sshort_(0), datatype(imc_digital num): ubyte_(0), sbyte_(0), ushort_(0), sshort_(0),
ulint_(0), slint_(0), sfloat_(0.0), sdouble_(0.0), ulint_(0), slint_(0), sfloat_(0.0), sdouble_(num),
sdigital_(num), sixbyte_({0}), dtidx_(10) {}; sdigital_(num), dtidx_(10) {};
datatype(imc_sixbyte num): ubyte_(0), sbyte_(0), ushort_(0), sshort_(0),
ulint_(0), slint_(0), sfloat_(0.0), sdouble_(0.0),
sdigital_(0), sixbyte_(num), dtidx_(13) {};
// identify type // identify type
short int& dtype() { return dtidx_; } short int& dtype() { return dtidx_; }
@ -90,7 +82,6 @@ namespace imc
this->sfloat_ = num.sfloat_; this->sfloat_ = num.sfloat_;
this->sdouble_ = num.sdouble_; this->sdouble_ = num.sdouble_;
this->sdigital_ = num.sdigital_; this->sdigital_ = num.sdigital_;
this->sixbyte_ = num.sixbyte_;
this->dtidx_ = num.dtidx_; this->dtidx_ = num.dtidx_;
} }
@ -108,7 +99,6 @@ namespace imc
this->sfloat_ = num.sfloat_; this->sfloat_ = num.sfloat_;
this->sdouble_ = num.sdouble_; this->sdouble_ = num.sdouble_;
this->sdigital_ = num.sdigital_; this->sdigital_ = num.sdigital_;
this->sixbyte_ = num.sixbyte_;
this->dtidx_ = num.dtidx_; this->dtidx_ = num.dtidx_;
} }
@ -170,12 +160,6 @@ namespace imc
this->dtidx_ = 10; this->dtidx_ = 10;
return *this; return *this;
} }
datatype& operator=(const imc_sixbyte &num)
{
this->sixbyte_ = num;
this->dtidx_ = 13;
return *this;
}
// obtain number as double // obtain number as double
double as_double() double as_double()
@ -190,13 +174,6 @@ namespace imc
else if ( dtidx_ == 6 ) num = (double)sfloat_; else if ( dtidx_ == 6 ) num = (double)sfloat_;
else if ( dtidx_ == 7 ) num = (double)sdouble_; else if ( dtidx_ == 7 ) num = (double)sdouble_;
else if ( dtidx_ == 10 ) num = static_cast<double>(sdigital_); else if ( dtidx_ == 10 ) num = static_cast<double>(sdigital_);
else if ( dtidx_ == 13 ) {
unsigned long long value = 0;
for (int i = 0; i < 6; ++i) {
value |= static_cast<unsigned long long>(sixbyte_.bytes[i]) << (8 * i);
}
num = static_cast<double>(value);
}
return num; return num;
} }
@ -212,13 +189,6 @@ namespace imc
else if ( num.dtidx_ == 6 ) out<<num.sfloat_; else if ( num.dtidx_ == 6 ) out<<num.sfloat_;
else if ( num.dtidx_ == 7 ) out<<num.sdouble_; else if ( num.dtidx_ == 7 ) out<<num.sdouble_;
else if ( num.dtidx_ == 10 ) out<<static_cast<double>(num.sdigital_); else if ( num.dtidx_ == 10 ) out<<static_cast<double>(num.sdigital_);
else if ( num.dtidx_ == 13 ) {
unsigned long long value = 0;
for (int i = 0; i < 6; ++i) {
value |= static_cast<unsigned long long>(num.sixbyte_.bytes[i]) << (8 * i);
}
out<<static_cast<double>(value);
}
return out; return out;
} }

View File

@ -4,7 +4,6 @@
#define IMCOBJECT #define IMCOBJECT
#include <time.h> #include <time.h>
#include <math.h>
#include "imc_key.hpp" #include "imc_key.hpp"
//---------------------------------------------------------------------------// //---------------------------------------------------------------------------//
@ -246,7 +245,7 @@ namespace imc
// construct members by parsing particular parameters from buffer // construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters) void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{ {
if ( parameters.size() < 4 ) throw std::runtime_error("invalid number of parameters in CC"); if ( parameters.size() < 4 ) throw std::runtime_error("invalid number of parameters in CD2");
component_index_ = std::stoi(get_parameter(buffer,&parameters[2])); component_index_ = std::stoi(get_parameter(buffer,&parameters[2]));
analog_digital_ = ( std::stoi(get_parameter(buffer,&parameters[3])) == 2 ); analog_digital_ = ( std::stoi(get_parameter(buffer,&parameters[3])) == 2 );
} }
@ -273,9 +272,7 @@ namespace imc
imc_devices_transitional_recording, imc_devices_transitional_recording,
timestamp_ascii, timestamp_ascii,
two_byte_word_digital, two_byte_word_digital,
eight_byte_unsigned_long, six_byte_unsigned_long
six_byte_unsigned_long,
eight_byte_signed_long
}; };
// packaging information of component (corresponds to key CP) // packaging information of component (corresponds to key CP)
@ -295,8 +292,8 @@ namespace imc
{ {
if ( parameters.size() < 10 ) throw std::runtime_error("invalid number of parameters in CP"); if ( parameters.size() < 10 ) throw std::runtime_error("invalid number of parameters in CP");
buffer_reference_ = std::stoi(get_parameter(buffer,&parameters[2])); buffer_reference_ = std::stoi(get_parameter(buffer,&parameters[2]));
bytes_ = std::stoi(get_parameter(buffer,&parameters[3])); numeric_type_ = (numtype)std::stoi(get_parameter(buffer,&parameters[3]));
numeric_type_ = (numtype)std::stoi(get_parameter(buffer,&parameters[4])); bytes_ = std::stoi(get_parameter(buffer,&parameters[4]));
signbits_ = std::stoi(get_parameter(buffer,&parameters[5])); signbits_ = std::stoi(get_parameter(buffer,&parameters[5]));
mask_ = std::stoi(get_parameter(buffer,&parameters[6])); mask_ = std::stoi(get_parameter(buffer,&parameters[6]));
offset_ = std::stoul(get_parameter(buffer,&parameters[7])); offset_ = std::stoul(get_parameter(buffer,&parameters[7]));
@ -339,7 +336,7 @@ namespace imc
// construct members by parsing particular parameters from buffer // construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters) void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{ {
if ( parameters.size() < 13 ) throw std::runtime_error("invalid number of parameters in Cb"); if ( parameters.size() < 13 ) throw std::runtime_error("invalid number of parameters in CD2");
number_buffers_ = std::stoul(get_parameter(buffer,&parameters[2])); number_buffers_ = std::stoul(get_parameter(buffer,&parameters[2]));
bytes_userinfo_ = std::stoul(get_parameter(buffer,&parameters[3])); bytes_userinfo_ = std::stoul(get_parameter(buffer,&parameters[3]));
buffer_reference_ = std::stoul(get_parameter(buffer,&parameters[4])); buffer_reference_ = std::stoul(get_parameter(buffer,&parameters[4]));
@ -381,7 +378,7 @@ namespace imc
// construct members by parsing particular parameters from buffer // construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters) void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{ {
if ( parameters.size() < 8 ) throw std::runtime_error("invalid number of parameters in CR"); if ( parameters.size() < 8 ) throw std::runtime_error("invalid number of parameters in CD2");
transform_ = (get_parameter(buffer,&parameters[2]) == std::string("1")); transform_ = (get_parameter(buffer,&parameters[2]) == std::string("1"));
factor_ = std::stod(get_parameter(buffer,&parameters[3])); factor_ = std::stod(get_parameter(buffer,&parameters[3]));
offset_ = std::stod(get_parameter(buffer,&parameters[4])); offset_ = std::stod(get_parameter(buffer,&parameters[4]));
@ -413,7 +410,7 @@ namespace imc
// construct members by parsing particular parameters from buffer // construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters) void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{ {
if ( parameters.size() < 9 ) throw std::runtime_error("invalid number of parameters in CN"); if ( parameters.size() < 9 ) throw std::runtime_error("invalid number of parameters in CD2");
group_index_ = std::stoul(get_parameter(buffer,&parameters[2])); group_index_ = std::stoul(get_parameter(buffer,&parameters[2]));
index_bit_ = (get_parameter(buffer,&parameters[4]) == std::string("1")); index_bit_ = (get_parameter(buffer,&parameters[4]) == std::string("1"));
name_ = get_parameter(buffer,&parameters[6]); name_ = get_parameter(buffer,&parameters[6]);
@ -442,7 +439,7 @@ namespace imc
// construct members by parsing particular parameters from buffer // construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters) void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{ {
if ( parameters.size() < 4 ) throw std::runtime_error("invalid number of parameters in CS"); if ( parameters.size() < 4 ) throw std::runtime_error("invalid number of parameters in CD2");
index_ = std::stoul(get_parameter(buffer,&parameters[2])); index_ = std::stoul(get_parameter(buffer,&parameters[2]));
} }
@ -457,21 +454,6 @@ namespace imc
} }
}; };
// language (corresponds to key NL)
struct language
{
std::string codepage_;
std::string language_code_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if (parameters.size() < 4) throw std::runtime_error("invalid number of parameters in NL");
codepage_ = get_parameter(buffer, &parameters[2]);
language_code_ = get_parameter(buffer, &parameters[3]);
}
};
// origin of data (corresponds to key NO) // origin of data (corresponds to key NO)
struct origin_data struct origin_data
{ {
@ -482,7 +464,7 @@ namespace imc
// construct members by parsing particular parameters from buffer // construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters) void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{ {
if ( parameters.size() < 7 ) throw std::runtime_error("invalid number of parameters in NO"); if ( parameters.size() < 7 ) throw std::runtime_error("invalid number of parameters in CD2");
origin_ = ( get_parameter(buffer,&parameters[2]) == std::string("1") ); origin_ = ( get_parameter(buffer,&parameters[2]) == std::string("1") );
generator_ = get_parameter(buffer,&parameters[4]); generator_ = get_parameter(buffer,&parameters[4]);
comment_ = get_parameter(buffer,&parameters[6]); comment_ = get_parameter(buffer,&parameters[6]);
@ -502,30 +484,45 @@ namespace imc
// trigger timestamp (corresponds to key NT1) // trigger timestamp (corresponds to key NT1)
struct triggertime struct triggertime
{ {
std::tm tms_; int day_, month_, year_;
double trigger_time_frac_secs_; int hour_, minute_;
double second_;
std::string timestamp_;
// construct members by parsing particular parameters from buffer // construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters) void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{ {
if ( parameters.size() < 8 ) throw std::runtime_error("invalid number of parameters in NT1"); if ( parameters.size() < 8 ) throw std::runtime_error("invalid number of parameters in CD2");
tms_ = std::tm(); day_ = std::stoi( get_parameter(buffer,&parameters[2]) );
tms_.tm_mday = std::stoi( get_parameter(buffer,&parameters[2]) ); month_ = std::stoi( get_parameter(buffer,&parameters[3]) );
tms_.tm_mon = std::stoi( get_parameter(buffer,&parameters[3]) ) - 1; year_ = std::stoi( get_parameter(buffer,&parameters[4]) );
tms_.tm_year = std::stoi( get_parameter(buffer,&parameters[4]) ) - 1900; hour_ = std::stoi( get_parameter(buffer,&parameters[5]) );
tms_.tm_hour = std::stoi( get_parameter(buffer,&parameters[5]) ); minute_ = std::stoi( get_parameter(buffer,&parameters[6]) );
tms_.tm_min = std::stoi( get_parameter(buffer,&parameters[6]) ); second_ = std::stod( get_parameter(buffer,&parameters[7]) );
long double secs = std::stold( get_parameter(buffer,&parameters[7]) );
double secs_int; //time_t rawtime;
trigger_time_frac_secs_ = modf((double)secs,&secs_int); //struct tm ts;
tms_.tm_sec = (int)secs_int; //time(&rawtime);
//localtime_r(&rawtime,&ts);
//ts.tm_mday = day_;
//ts.tm_mon = month_-1;
//ts.tm_year = year_-1900;
//ts.tm_hour = hour_;
//ts.tm_min = minute_;
//ts.tm_sec = (int)second_;
//asctime_r(&ts,&timestamp_[0]);
timestamp_ = std::to_string(year_) + std::string("-") + std::to_string(month_)
+ std::string("-") + std::to_string(day_)
+ std::string("T") + std::to_string(hour_)
+ std::string(":") + std::to_string(minute_)
+ std::string(":") + std::to_string(second_);
} }
// get info string // get info string
std::string get_info(int width = 20) std::string get_info(int width = 20)
{ {
std::stringstream ss; std::stringstream ss;
ss<<std::setw(width)<<std::left<<"timestamp:"<<std::put_time(&tms_, "%Y-%m-%dT%H:%M:%S")<<"\n"; ss<<std::setw(width)<<std::left<<"timestamp:"<<timestamp_<<"\n";
return ss.str(); return ss.str();
} }
}; };

View File

@ -211,61 +211,29 @@ namespace imc
imc::channel_env chnenv; imc::channel_env chnenv;
chnenv.reset(); chnenv.reset();
imc::component_env *compenv_ptr = nullptr;
// collect affiliate blocks for every channel WITH CHANNEL and AFFILIATE // collect affiliate blocks for every channel WITH CHANNEL and AFFILIATE
// BLOCK CORRESPONDENCE GOVERNED BY BLOCK ORDER IN BUFFER!! // BLOCK CORRESPONDENCE GOVERNED BY BLOCK ORDER IN BUFFER!!
for ( imc::block blk: rawblocks_ ) for ( imc::block blk: rawblocks_ )
{ {
if ( blk.get_key().name_ == "NO" ) chnenv.NOuuid_ = blk.get_uuid(); if ( blk.get_key().name_ == "CN" ) chnenv.CNuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CD" ) chnenv.CDuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CT" ) chnenv.CTuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "Cb" ) chnenv.Cbuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CP" ) chnenv.CPuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CR" ) chnenv.CRuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CS" ) chnenv.CSuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "NT" ) chnenv.NTuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "NO" ) chnenv.NOuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "NL" ) chnenv.NLuuid_ = blk.get_uuid(); else if ( blk.get_key().name_ == "NL" ) chnenv.NLuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CB" ) chnenv.CBuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CG" ) chnenv.CGuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CI" ) chnenv.CIuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CT" ) chnenv.CTuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CN" ) chnenv.CNuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CS" ) chnenv.CSuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CC" )
{
// a new component group is started
// TODO: can we avoid to parse the whole component here?
imc::component component;
component.parse(&buffer_, blk.get_parameters());
if ( component.component_index_ == 1 ) compenv_ptr = &chnenv.compenv1_;
else if ( component.component_index_ == 2 ) compenv_ptr = &chnenv.compenv2_;
else throw std::runtime_error("invalid component index in CC block");
compenv_ptr->CCuuid_ = blk.get_uuid();
compenv_ptr->uuid_ = compenv_ptr->CCuuid_;
}
else if ( blk.get_key().name_ == "CD" )
{
if (compenv_ptr == nullptr) chnenv.CDuuid_ = blk.get_uuid();
else compenv_ptr->CDuuid_ = blk.get_uuid();
}
else if ( blk.get_key().name_ == "NT" )
{
if (compenv_ptr == nullptr) chnenv.NTuuid_ = blk.get_uuid();
else compenv_ptr->NTuuid_ = blk.get_uuid();
}
else if ( blk.get_key().name_ == "Cb" ) compenv_ptr->Cbuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CP" ) compenv_ptr->CPuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CR" ) compenv_ptr->CRuuid_ = blk.get_uuid();
// check for currently associated channel // check for currently associated channel
// TODO: CNuuid is not unique for multichannel data
if ( !chnenv.CNuuid_.empty() ) if ( !chnenv.CNuuid_.empty() )
{ {
// at the moment only a single channel is supported // any component/channel is closed by any of {CS, CC, CG, CB}
// any channel is closed by any of {CB, CG, CI, CT, CS} if ( blk.get_key().name_ == "CS" || blk.get_key().name_ == "CC"
if ( blk.get_key().name_ == "CB" || blk.get_key().name_ == "CG" || blk.get_key().name_ == "CG" || blk.get_key().name_ == "CB" )
|| blk.get_key().name_ == "CI" || blk.get_key().name_ == "CT"
|| blk.get_key().name_ == "CS" )
{ {
// provide UUID for channel // provide UUID for channel
// for multi component channels exactly one CN is available
chnenv.uuid_ = chnenv.CNuuid_; chnenv.uuid_ = chnenv.CNuuid_;
// for multichannel data there may be multiple channels referring to // for multichannel data there may be multiple channels referring to
@ -287,15 +255,8 @@ namespace imc
); );
// reset channel uuid // reset channel uuid
chnenv.CNuuid_.clear(); chnenv.reset();
//chnenv.CNuuid_.clear();
chnenv.CBuuid_.clear();
chnenv.CGuuid_.clear();
chnenv.CIuuid_.clear();
chnenv.CTuuid_.clear();
chnenv.CSuuid_.clear();
compenv_ptr = nullptr;
} }
} }
@ -303,8 +264,7 @@ namespace imc
// already belong to NEXT component // already belong to NEXT component
if ( blk.get_key().name_ == "CB" ) chnenv.CBuuid_ = blk.get_uuid(); if ( blk.get_key().name_ == "CB" ) chnenv.CBuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CG" ) chnenv.CGuuid_ = blk.get_uuid(); else if ( blk.get_key().name_ == "CG" ) chnenv.CGuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CI" ) chnenv.CIuuid_ = blk.get_uuid(); else if ( blk.get_key().name_ == "CC" ) chnenv.CCuuid_ = blk.get_uuid();
else if ( blk.get_key().name_ == "CT" ) chnenv.CTuuid_ = blk.get_uuid();
} }
} }

View File

@ -10,11 +10,8 @@ SRC = src/
LIB = lib/ LIB = lib/
PYT = python/ PYT = python/
# list headers and include directories # list headers
HPP = $(wildcard $(LIB)/*.hpp) HPP = $(wildcard $(LIB)/*.hpp)
IPP = $(shell find $(LIB) -type f -name '*.hpp')
KIB = $(shell find $(LIB) -type d)
MIB = $(foreach dir,$(KIB),-I $(dir))
# choose compiler and its options # choose compiler and its options
CC = g++ -std=c++17 CC = g++ -std=c++17
@ -39,12 +36,12 @@ $(EXE): check-tags $(GVSN) main.o
$(CC) $(OPT) main.o -o $@ $(CC) $(OPT) main.o -o $@
# build main.cpp and include git version/commit tag # build main.cpp and include git version/commit tag
main.o: src/main.cpp $(IPP) main.o: src/main.cpp $(HPP)
@cp $< $<.cpp @cp $< $<.cpp
@sed -i 's/TAGSTRING/$(GTAG)/g' $<.cpp @sed -i 's/TAGSTRING/$(GTAG)/g' $<.cpp
@sed -i 's/HASHSTRING/$(GHSH)/g' $<.cpp @sed -i 's/HASHSTRING/$(GHSH)/g' $<.cpp
@sed -i 's/TIMESTAMPSTRING/$(TMS)/g' $<.cpp @sed -i 's/TIMESTAMPSTRING/$(TMS)/g' $<.cpp
$(CC) -c $(OPT) $(MIB) $<.cpp -o $@ $(CC) -c $(OPT) -I $(LIB) $<.cpp -o $@
@rm $<.cpp @rm $<.cpp
install: $(EXE) install: $(EXE)
@ -88,11 +85,11 @@ docker-run:
python-build: check-tags $(GVSN) python-build: check-tags $(GVSN)
make -C python/ build-inplace make -C python/ build-inplace
cp python/imctermite*.so ./ -v cp python/IMCtermite*.so ./ -v
python-clean: python-clean:
make -C python/ clean make -C python/ clean
rm -vf imctermite*.so rm -vf IMCtermite*.so
python-test: python-test:
PYTHONPATH=./ python python/examples/usage.py PYTHONPATH=./ python python/examples/usage.py

View File

@ -1,20 +1,10 @@
# distutils: language = c++ # distutils: language = c++
# cython: language_level = 3 # cython: language_level = 3
from imctermite cimport cppimctermite from IMCtermite cimport cppimctermite
import json as jn import json as jn
import decimal import decimal
import platform
# auxiliary function for codepage conversion
def get_codepage(chn) :
if platform == 'Windows' :
chndec = jn.loads(chn.decode(errors="ignore"))
chncdp = chndec["codepage"]
return 'utf-8' if chncdp is None else chncdp
else :
return 'utf-8'
cdef class imctermite: cdef class imctermite:
@ -32,7 +22,7 @@ cdef class imctermite:
# get JSON list of channels # get JSON list of channels
def get_channels(self, bool include_data): def get_channels(self, bool include_data):
chnlst = self.cppimc.get_channels(True,include_data) chnlst = self.cppimc.get_channels(True,include_data)
chnlstjn = [jn.loads(chn.decode(get_codepage(chn),errors="ignore")) for chn in chnlst] chnlstjn = [jn.loads(chn.decode(errors="ignore")) for chn in chnlst]
return chnlstjn return chnlstjn
# print single channel/all channels # print single channel/all channels

View File

@ -2,4 +2,3 @@ include lib/*.hpp
include *.cpp include *.cpp
include *.pyx include *.pyx
include *.pxd include *.pxd
include VERSION

View File

@ -1 +1 @@
2.1.18 2.0.6

View File

@ -1,43 +0,0 @@
import imctermite
import pandas
import datetime
def add_trigger_time(trigger_time, add_time) :
trgts = datetime.datetime.strptime(trigger_time,'%Y-%m-%dT%H:%M:%S')
dt = datetime.timedelta(seconds=add_time)
return (trgts + dt).strftime('%Y-%m-%dT%H:%M:%S:%f')
if __name__ == "__main__" :
# read file and extract data
imctm = imctermite.imctermite(b"Measurement.raw")
chns = imctm.get_channels(True)
# prepare abscissa
xcol = "time ["+chns[0]['xunit']+"]"
#xcol = "timestamp"
xsts = [add_trigger_time(chns[0]['trigger-time'],tm) for tm in chns[0]['xdata']]
# sort channels
chnnms = sorted([chn['name'] for chn in chns], reverse=False)
chnsdict = {}
for chn in chns :
chnsdict[chn['name']] = chn
# construct dataframe
df = pandas.DataFrame()
df[xcol] = pandas.Series(chns[0]['xdata'])
#df[xcol] = pandas.Series(xsts)
#for idx,chn in enumerate(chns) :
for chnnm in chnnms :
chn = chnsdict[chnnm]
#xcol = (chn['xname'] if chn['xname'] != '' else "x_"+str(idx))+" ["+chn['xunit']+"]"
#df[xcol] = pandas.Series(chn['xdata'])
ycol = chn['yname']+" ["+chn['yunit']+"]"
df[ycol] = pandas.Series(chn['ydata'])
# show entire dataframe and write file
print(df)
df.to_csv("Measurement.csv",header=True,sep='\t',index=False)

View File

@ -1,11 +1,11 @@
import imctermite import IMCtermite
import json import json
import os import os
# declare and initialize instance of "imctermite" by passing a raw-file # declare and initialize instance of "imctermite" by passing a raw-file
try : try :
imcraw = imctermite.imctermite(b"samples/exampleB.raw") imcraw = IMCtermite.imctermite(b"samples/exampleB.raw")
except RuntimeError as e : except RuntimeError as e :
raise Exception("failed to load/parse raw-file: " + str(e)) raise Exception("failed to load/parse raw-file: " + str(e))

View File

@ -1,5 +1,5 @@
import imctermite import IMCtermite
import json import json
import os import os
@ -15,7 +15,7 @@ for fl in rawlist1:
# declare and initialize instance of "imctermite" by passing a raw-file # declare and initialize instance of "imctermite" by passing a raw-file
try : try :
imcraw = imctermite.imctermite(fl.encode()) imcraw = IMCtermite.imctermite(fl.encode())
except RuntimeError as e : except RuntimeError as e :
raise Exception("failed to load/parse raw-file: " + str(e)) raise Exception("failed to load/parse raw-file: " + str(e))

View File

@ -1,12 +1,12 @@
import imctermite import IMCtermite
import json import json
import os import os
import datetime import datetime
# declare and initialize instance of "imctermite" by passing a raw-file # declare and initialize instance of "imctermite" by passing a raw-file
try : try :
imcraw = imctermite.imctermite(b"samples/sampleB.raw") imcraw = IMCtermite.imctermite(b"samples/sampleB.raw")
except RuntimeError as e : except RuntimeError as e :
raise Exception("failed to load/parse raw-file: " + str(e)) raise Exception("failed to load/parse raw-file: " + str(e))

View File

@ -1,5 +1,5 @@
import imctermite import imctermite from IMCtermite import imctermite
def show_results(imcraw) : def show_results(imcraw) :

View File

@ -29,7 +29,6 @@ build-clean:
rm -vf imctermite*.so imctermite*.cpp rm -vf imctermite*.so imctermite*.cpp
rm -vf IMCtermite*.so IMCtermite*.cpp rm -vf IMCtermite*.so IMCtermite*.cpp
rm -rvf dist/ IMCtermite.egg-info/ rm -rvf dist/ IMCtermite.egg-info/
rm -rvf dist/ imctermite.egg-info/
cibuildwheel-build: setup cibuildwheel-build: setup
cibuildwheel --platform linux cibuildwheel --platform linux

View File

@ -1,6 +1,6 @@
[metadata] [metadata]
name = imctermite name = IMCtermite
description = Enables extraction of measurement data from binary files with extension 'raw' used by proprietary software imcFAMOS and imcSTUDIO and facilitates its storage in open source file formats description = Enables extraction of measurement data from binary files with extension 'raw' used by proprietary software imcFAMOS and imcSTUDIO and facilitates its storage in open source file formats
long_description = file: README.md long_description = file: README.md
# long_description_content_type = text/x-rst # long_description_content_type = text/x-rst

View File

@ -11,8 +11,8 @@ cmpArgs = {
} }
extension = Extension( extension = Extension(
"imctermite", "IMCtermite",
sources=["imctermite.pyx"], sources=["IMCtermite.pyx"],
extra_compile_args=cmpArgs[sys.platform] extra_compile_args=cmpArgs[sys.platform]
) )

Binary file not shown.

View File

@ -1,14 +0,0 @@
|CF,2,1,1;|CK,1,3,1,1;
|Nv,1,12,7,3,4,64,1,0;
|NO,1,12,1,5,FAMOS,0,;
|NL,1,10,1252,0x407;
|CG,1,5,1,1,1;
|CD,1,13,1,1,1,s,0,0,0;
|NT,1,19, 6, 4,2018,11,33,54;
|CC,1,3,1,1;
|CP,1,16,1,8,8,64,0,0,1,0;
|Cb,1,22,1,0,1,1,0,8,0,8,1,0,0,;
|CR,1,11,0,0,0,1,1,V;
|CN,1,35,0,0,0,7,Average,16,Measurement 0815;
|CT,1,43,0,8,TxTester,8,E. Smith,16,Measurement 0815;
|CS,1,10,1,ÍÌÌÌÌÌ(@;

View File

@ -1,24 +0,0 @@
|CF,2,1,1;|CK,1,3,1,1;
|Nv,1,12,7,3,4,64,1,0;
|NO,1,12,1,5,FAMOS,0,;
|NL,1,10,1252,0x407;
|CB,1,12,1,5,Meas1,0,;
|CG,1,5,1,1,1;
|CD,1,16,5E-1,1,1,2,0,0,0;
|NT,1,19, 6, 4,2018,11,24,18;
|CC,1,3,1,1;
|CP,1,15,1,1,2,8,0,0,1,0;
|Cb,1,22,1,0,1,1,0,3,0,3,1,3,0,;
|CR,1,30,1,3.937007874015748E-2,5,1,1,V;
|ND,1,15,-1,-1,-1,0,1E+1;
|CN,1,16,1,0,0,5,Chan1,0,;
|CG,1,5,1,1,1;
|CD,1,16,5E-1,1,1,2,0,0,0;
|NT,1,19, 6, 4,2018,11,24,18;
|CC,1,3,1,1;
|CP,1,15,2,1,2,8,0,0,1,0;
|Cb,1,22,1,0,2,1,3,3,0,3,1,3,0,;
|CR,1,30,1,3.937007874015748E-2,5,1,1,V;
|ND,1,15,-1,-1,-1,0,1E+1;
|CN,1,16,1,0,0,5,Chan2,0,;
|CS,1,8,1, šš šš;

View File

@ -8,7 +8,7 @@
|CR,1,49,1,3.921568627450980E-2,0.000000000000000E+0,1,1,V; |CR,1,49,1,3.921568627450980E-2,0.000000000000000E+0,1,1,V;
|ND,1,50,-1,-1,-1,0.000000000000000E+0,1.000000000000000E+1;|CN,1,17,1,0,0,6,kanal2,0,; |ND,1,50,-1,-1,-1,0.000000000000000E+0,1.000000000000000E+1;|CN,1,17,1,0,0,6,kanal2,0,;
|CS,1,8,1,leclass="Code Example" translate="true"> |CS,1,8,1,leclass="Code Example" translate="true">
|NO,1,37,1,9,imc-FAMOS,20,Erzeugt:E.Mustermann; |CG,1,5,2,2,2; |NO,1,37,1,9, imc-FAMOS,20,Erzeugt:E.Mustermann; |CG,1,5,2,2,2;
|CD,1,31,1.000000000000000E-1,1,0,,0,0,0;|NT,1,27,10, 6,1993,19,18,20.0000000; |CD,1,31,1.000000000000000E-1,1,0,,0,0,0;|NT,1,27,10, 6,1993,19,18,20.0000000;
|CC,1,3,1,1;|CP,1,16,1,4,7,32,0,0,1,0;|Cb,1,40,1,0,1,1,0,16,0,16,1,0.000000000000E+0,0,; |CC,1,3,1,1;|CP,1,16,1,4,7,32,0,0,1,0;|Cb,1,40,1,0,1,1,0,16,0,16,1,0.000000000000E+0,0,;
|CR,1,11,0,0,0,1,1,V;|CN,1,20,0,0,0,9,E06_6_121,0,;|CC,1,3,2,1;|CP,1,16,2,4,5,32,0,0,1,0; |CR,1,11,0,0,0,1,1,V;|CN,1,20,0,0,0,9,E06_6_121,0,;|CC,1,3,2,1;|CP,1,16,2,4,5,32,0,0,1,0;

View File

@ -1,17 +0,0 @@
|CF,2,1,1;|CK,1,3,1,1;
|Nv,1,12,7,3,4,64,1,0;
|NO,1,12,1,5,FAMOS,0,;
|NL,1,10,1252,0x407;
|CG,1,5,2,2,2;
|CD,1,12,1,1,0,,2,0,0;
|NT,1,18, 6, 4,2018,11,37,1;
|CC,1,3,1,1;
|CP,1,16,1,4,7,32,0,0,1,0;
|Cb,1,24,1,0,1,1,0,16,0,16,1,0,0,;
|CR,1,11,0,0,0,1,1,V;
|CN,1,20,0,0,0,9,MyXY_plot,0,;
|CC,1,3,2,1;
|CP,1,16,2,2,3,16,0,0,1,0;
|Cb,1,23,1,0,2,1,16,8,0,8,1,0,0,;
|CR,1,30,1,4.577706569008927E-5,0,1,1,s;
|CS,1,26,1, @ €? @ffF@ UUªªÿÿ;