Skip to content
Snippets Groups Projects
Commit eb489244 authored by Carl Philipp Klemm's avatar Carl Philipp Klemm
Browse files

Inital commit (1.0)

parents
No related branches found
No related tags found
No related merge requests found
cmake_minimum_required(VERSION 3.19)
project(relaxisloader LANGUAGES C CXX)
set(SRC_FILES
relaxisloader.c
utils.c
)
set(API_HEADERS_DIR relaxisloader/)
set(API_HEADERS_C
${API_HEADERS_DIR}/relaxisloader.h
)
find_package(PkgConfig REQUIRED)
find_package(Doxygen)
pkg_check_modules(SQL REQUIRED sqlite3)
add_library(${PROJECT_NAME} SHARED ${SRC_FILES} ${API_HEADERS_C})
target_link_libraries(${PROJECT_NAME} ${SQL_LIBRARIES})
target_include_directories(${PROJECT_NAME} PUBLIC ./${API_HEADERS_DIR} ${SQL_INCLUDE_DIRS})
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-Wall -O2 -march=native -g" LINK_FLAGS "-flto -pthread")
target_compile_definitions(${PROJECT_NAME} PRIVATE _XOPEN_SOURCE)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
install(TARGETS ${PROJECT_NAME} DESTINATION lib)
install(FILES ${API_HEADERS_C} DESTINATION include/${PROJECT_NAME})
link_directories(${CMAKE_CURRENT_BINARY_DIR})
set(SRC_FILES_TEST_APP main.c)
set(LIBS_TEST -L. -l${PROJECT_NAME})
add_executable(${PROJECT_NAME}_test ${SRC_FILES_TEST_APP})
add_dependencies(${PROJECT_NAME}_test ${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME}_test ${LIBS_TEST})
target_include_directories(${PROJECT_NAME}_test PUBLIC ./${API_HEADERS_DIR})
set_target_properties(${PROJECT_NAME}_test PROPERTIES COMPILE_FLAGS "-Wall -O2 -march=native -g" LINK_FLAGS "-flto")
install(TARGETS ${PROJECT_NAME}_test DESTINATION bin)
if (DOXYGEN_FOUND)
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/doc/librelaxisloader.doxygen.in)
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/doc/librelaxisloader.doxygen)
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
message("Doxygen build started")
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM )
else (DOXYGEN_FOUND)
message("Doxygen needs to be installed to generate the doxygen documentation")
endif (DOXYGEN_FOUND)
# librelaxisloader
librelaxisloader is a shared library that allows you to load data from RelaxIS3 files. This library supports only files with a DatabaseFormat of "1"
For questions or comments, please write to klemm@rhd-instruments.de
Full API documentation can be built with the "doc" target and is also avialable [here](http://uvos.xyz/kiss/librelaxisloaderdoc)
## Compile/Install
### Requirements
* git
* c99 capable compiler (GCC, CLANG)
* cmake 3.20 or later
* curl 7.64 or later
* (optinal) doxygen 1.8 or later to generate the documentation
### Procedure
In a console do:
* git clone https://git-ce.rwth-aachen.de/carl_philipp.klemm/librelaxisloader.git
* cd librelaxisloader
* mkdir build
* cd build
* cmake ..
* make
* sudo make install
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.9.3 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="yes" title="" intro=""/>
<tab type="modules" visible="yes" title="" intro=""/>
<tab type="namespaces" visible="yes" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="concepts" visible="yes" title="">
</tab>
<tab type="interfaces" visible="yes" title="">
<tab type="interfacelist" visible="yes" title="" intro=""/>
<tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="interfacehierarchy" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="yes" title="">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="structs" visible="yes" title="">
<tab type="structlist" visible="yes" title="" intro=""/>
<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
</tab>
<tab type="exceptions" visible="yes" title="">
<tab type="exceptionlist" visible="yes" title="" intro=""/>
<tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="yes" title="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="examples" visible="yes" title="" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_HEADERFILE"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<concepts visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a concept page -->
<concept>
<briefdescription visible="yes"/>
<includes visible="$SHOW_HEADERFILE"/>
<definition visible="yes" title=""/>
<detaileddescription title=""/>
<authorsection visible="yes"/>
</concept>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>
This diff is collapsed.
/*! \mainpage librelaxisloader manual
librelaxisloader is a shared library that allows you to load data from RelaxIS3 files. This library supports only files with DatabaseFormat of "1"
An API referance can be found here: \subpage API
*/
main.c 0 → 100644
#include <stdio.h>
#include <relaxisloader.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
if(argc < 2) {
printf("Usage %s [FILE]\n", argc == 1 ? argv[0] : "NULL");
return 1;
}
const char *error;
struct rxfile *file = rlx_open_file(argv[1], &error);
if(!file) {
printf("Unable to open %s: %s\n", argv[1], error);
return 2;
}
size_t projectCount;
struct rlx_project** projects = rlx_get_projects(file, &projectCount);
if(projectCount < 1) {
printf("File contains no projects: %s\n", rlx_get_errnum_str(rlx_get_errnum(file)));
return 4;
}
size_t idCount;
int *ids = rlx_get_spectra_ids(file, projects[0], &idCount);
for(int i = 0; i < idCount; ++i)
printf("PROJECT: %d ID: %d\n", projects[0]->id, ids[i]);
if(idCount < 1) {
printf("No spectra in project %d: %s\n", projects[0]->id, rlx_get_errnum_str(rlx_get_errnum(file)));
return 3;
}
printf("%p %d\n", projects[0], projects[0]->id);
struct rlx_spectra* spectra = rlx_get_spectra(file, projects[0], ids[0]);
if(!spectra) {
printf("Could not load spectra for %d %d: %s\n", projects[0]->id, ids[0], rlx_get_errnum_str(rlx_get_errnum(file)));
return 3;
}
printf("Spectra for PROJECT: %d ID: %d\nomega, re, im\n", projects[0]->id, ids[0]);
for(size_t i = 0; i < spectra->length; ++i) {
printf("%f,%f,%f\n", spectra->datapoints[i].omega, spectra->datapoints[i].re, spectra->datapoints[i].im);
}
size_t paramCount;
struct rlx_fitparam** params = rlx_get_fit_parameters(file, projects[0], ids[0], &paramCount);
if(!params) {
printf("Could not get parameters for project %d spectra %d: %s\n", projects[0]->id, ids[0], rlx_get_errnum_str(rlx_get_errnum(file)));
return 4;
}
for(size_t i = 0; i < paramCount; ++i) {
printf("Parameter %d: Name: %s Value: %f Error: %f\n", params[i]->p_index, params[i]->name, params[i]->value, params[i]->error);
}
rlx_project_free_array(projects);
rlx_spectra_free(spectra);
rlx_fitparam_free_array(params);
free(ids);
rlx_close_file(file);
return 0;
}
#include "relaxisloader.h"
#include <stdlib.h>
#include <math.h>
#include <sqlite3.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "utils.h"
struct rxfile
{
int error;
sqlite3 *db;
};
/**
* @brief Frees a project struct
*
* @param proj project struct to be freed, or NULL
*/
void rlx_project_free(struct rlx_project* proj)
{
if(!proj)
return;
if(proj->name)
free(proj->name);
free(proj);
}
void rlx_project_free_array(struct rlx_project** proj)
{
struct rlx_project** firstproj = proj;
while(*proj) {
rlx_project_free(*proj);
++proj;
}
free(firstproj);
}
void rlx_spectra_free(struct rlx_spectra* specta)
{
if(!specta)
return;
if(specta->circuit)
free(specta->circuit);
free(specta->datapoints);
free(specta);
}
void rlx_spectra_free_array(struct rlx_spectra** specta)
{
struct rlx_spectra** firstspectra = specta;
while(*specta) {
rlx_spectra_free(*specta);
++specta;
}
free(firstspectra);
}
void rlx_fitparam_free(struct rlx_fitparam* param)
{
if(!param)
return;
if(param->name)
free(param->name);
free(param);
}
void rlx_fitparam_free_array(struct rlx_fitparam** param)
{
struct rlx_fitparam** firstparam = param;
while(*param) {
rlx_fitparam_free(*param);
++param;
}
free(firstparam);
}
struct rxfile* rlx_open_file(const char* path, const char** error)
{
struct rxfile *file = calloc(1, sizeof(*file));
int ret = sqlite3_open_v2(path, &file->db, SQLITE_OPEN_READONLY, NULL);
if(!(ret == SQLITE_OK || ret == SQLITE_DONE)) {
if(error)
*error = sqlite3_errstr(ret);
free(file);
return NULL;
}
const char *req = "SELECT Value FROM Properties WHERE Name=\"DatabaseFormat\"";
sqlite3_stmt *ppStmt;
ret = sqlite3_prepare_v2(file->db, req, strlen(req), &ppStmt, NULL);
if(ret != SQLITE_OK) {
if(error)
*error = "Unable to read file version";
return NULL;
}
ret = sqlite3_step(ppStmt);
if((ret != SQLITE_OK && ret != SQLITE_DONE && ret != SQLITE_ROW) || sqlite3_column_count(ppStmt) != 1) {
if(error)
*error = "Unable to read file version, field missing";
return NULL;
}
int version = sqlite3_column_int(ppStmt, 0);
if(version != 1) {
if(error)
*error = "Unsupported file version";
return NULL;
}
if(error)
*error = NULL;
sqlite3_finalize(ppStmt);
return file;
}
void rlx_close_file(struct rxfile* file)
{
sqlite3_close(file->db);
free(file);
}
struct rlx_project** rlx_get_projects(struct rxfile* file, size_t* length)
{
char **table;
int rows;
int cols;
char *error;
int ret = sqlite3_get_table(file->db, "SELECT ID,NAME,DATE FROM Projects", &table, &rows, &cols, &error);
if(ret != SQLITE_OK) {
file->error = ret;
free(error);
if(length)
*length = 0;
return NULL;
}
rows++;
assert(cols == 3);
struct rlx_project **projects = malloc(sizeof(*projects)*(rows));
assert(projects);
if(length)
*length = rows-1;
for(int i = 1; i < rows; ++i) {
projects[i-1] = malloc(sizeof(struct rlx_project));
assert(projects[i-1]);
projects[i-1]->name = rlx_strdup(table[i*cols+1]);
int ret = sscanf(table[i*cols], "%d", &projects[i-1]->id);
assert(ret == 1);
projects[i-1]->date = rlx_str_to_time(table[i*cols+2]);
}
projects[rows-1] = NULL;
sqlite3_free_table(table);
return projects;
}
static struct rlx_datapoint* rlx_get_datapoints(struct rxfile* file, int id, size_t *length)
{
char **table;
int rows;
int cols;
char *error;
char *req = rlx_alloc_printf("SELECT frequency,zreal,zimag FROM Datapoints WHERE file_id=%d", id);
int ret = sqlite3_get_table(file->db, req, &table, &rows, &cols, &error);
free(req);
++rows;
if(ret != SQLITE_OK) {
file->error = ret;
free(error);
if(length)
*length = 0;
return NULL;
}
assert(cols == 3);
if(rows < 2) {
file->error = -100;
sqlite3_free_table(table);
return NULL;
}
if(length)
*length = rows-1;
struct rlx_datapoint *out = malloc(sizeof(*out)*(rows-1));
for(int i = 1; i < rows; ++i) {
int ret = sscanf(table[i*cols], "%lf", &out[i-1].omega);
assert(ret == 1);
out[i-1].omega *= 2*M_PI;
ret = sscanf(table[i*cols+1], "%lf", &out[i-1].re);
assert(ret == 1);
ret = sscanf(table[i*cols+2], "%lf", &out[i-1].im);
assert(ret == 1);
}
sqlite3_free_table(table);
return out;
}
struct rlx_spectra* rlx_get_spectra(struct rxfile* file, const struct rlx_project* project, int id)
{
char **table;
int rows;
int cols;
char *error;
char *req = rlx_alloc_printf(
"SELECT groupname,fitted,lowfreqlimit,highfreqlimit,dateadded,datefitted FROM Files WHERE project_id=%d AND ID=%d",
project->id, id);
int ret = sqlite3_get_table(file->db, req, &table, &rows, &cols, &error);
free(req);
++rows;
if(ret != SQLITE_OK) {
file->error = ret;
free(error);
return NULL;
}
if(rows < 2) {
file->error = -100;
sqlite3_free_table(table);
return NULL;
}
assert(cols == 6);
struct rlx_spectra *out = malloc(sizeof(*out));
out->id = id;
out->circuit = rlx_strdup(table[6]);
out->fitted = table[7][0] == '1';
out->project_id = project->id;
ret = sscanf(table[8], "%lf", &out->freq_lower_limit);
assert(ret == 1);
ret = sscanf(table[9], "%lf", &out->freq_upper_limit);
assert(ret == 1);
out->date_added = rlx_str_to_time(table[10]);
out->date_fitted = rlx_str_to_time(table[11]);
out->datapoints = rlx_get_datapoints(file, id, &out->length);
sqlite3_free_table(table);
return out;
}
struct rlx_spectra** rlx_get_all_spectra(struct rxfile* file, const struct rlx_project* project)
{
size_t length;
int *ids = rlx_get_spectra_ids(file, project, &length);
if(!ids)
return NULL;
struct rlx_spectra **out = malloc(sizeof(*out)*(length+1));
for(size_t i = 0; i < length; ++i) {
out[i] = rlx_get_spectra(file, project, i);
}
out[length] = NULL;
free(ids);
return out;
}
int* rlx_get_spectra_ids(struct rxfile* file, const struct rlx_project* project, size_t* length)
{
char **table;
int rows;
int cols;
char *error;
int ret = sqlite3_get_table(file->db, "SELECT ID FROM Files;", &table, &rows, &cols, &error);
if(ret != SQLITE_OK) {
file->error = ret;
free(error);
if(length)
*length = 0;
return NULL;
}
++rows;
printf("%s: got %dx%d\n", __func__, rows, cols);
assert(cols == 1);
if(rows < 2) {
file->error = -100;
sqlite3_free_table(table);
return NULL;
}
if(length)
*length = rows-1;
int *ids = malloc(sizeof(*ids)*(rows-1));
for(int i = 1; i < rows; ++i) {
int ret = sscanf(table[i], "%d", &ids[i-1]);
assert(ret == 1);
}
sqlite3_free_table(table);
return ids;
}
struct rlx_fitparam** rlx_get_fit_parameters(struct rxfile* file, const struct rlx_project* project, int id, size_t *length)
{
(void)project;
if(length)
*length = 0;
char *req = rlx_alloc_printf("SELECT pindex,name,value,error,lowerlimit,upperlimit FROM Fitparameters WHERE file_id=%d", id);
sqlite3_stmt *ppStmt;
int ret = sqlite3_prepare_v2(file->db, req, strlen(req), &ppStmt, NULL);
free(req);
if(ret != SQLITE_OK) {
file->error = ret;
return NULL;
}
size_t outSize = 8;
size_t outIndex = 0;
struct rlx_fitparam **out = malloc(sizeof(*out)*outSize);
while((ret = sqlite3_step(ppStmt)) == SQLITE_ROW) {
assert(sqlite3_column_count(ppStmt) == 6);
struct rlx_fitparam *param = malloc(sizeof(*param));
param->p_index = sqlite3_column_int(ppStmt, 0);
param->spectra_id = id;
param->name = rlx_strdup((char*)sqlite3_column_text(ppStmt, 1));
param->value = sqlite3_column_double(ppStmt, 2);
param->error = sqlite3_column_double(ppStmt, 3);
param->lower_limit = sqlite3_column_double(ppStmt, 4);
param->upper_limit = sqlite3_column_double(ppStmt, 5);
if(outIndex == outSize) {
outSize *= 2;
assert((out = realloc(out, sizeof(*out)*outSize)));
}
out[outIndex] = param;
++outIndex;
}
if(ret != SQLITE_OK && ret != SQLITE_DONE) {
free(out);
file->error = ret;
return NULL;
}
if(outIndex == outSize) {
outSize += 1;
assert((out = realloc(out, sizeof(*out)*outSize)));
}
out[outIndex] = NULL;
if(length)
*length = outIndex;
file->error = sqlite3_finalize(ppStmt);
return out;
}
int rlx_get_errnum(const struct rxfile* file)
{
return file->error;
}
const char* rlx_get_errnum_str(int errnum)
{
if(errnum == 0)
return "Success";
if(errnum > 0)
return sqlite3_errstr(errnum);
if(errnum == -100)
return "No sutch entry";
return "Unkown error";
}
/*
* relaxisloader.h
* Copyright (C) Carl Philipp Klemm 2023 <carl@uvos.xyz>
*
* relaxisloader.h is free software: you can redistribute it and/or modify it
* under the terms of the lesser GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* relaxisloader.h is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the lesser GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdbool.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
Api for use by librelaxisloader users.
* @defgroup API User API
* This api allows you to load relaxis files and get the data therein
* @{
*/
struct rxfile;
struct rlx_project {
int id; /**< Project id*/
char* name; /**< Name of the project */
time_t date; /**< Project creation time*/
};
/**
* @brief Frees a project struct
*
* @param proj project struct to be freed, or NULL
*/
void rlx_project_free(struct rlx_project* proj);
/**
* @brief Frees an array of project structs
*
* @param proj_array array of project structs to be freed
*/
void rlx_project_free_array(struct rlx_project** proj_array);
struct rlx_datapoint {
double im; /**< imaginary part of the mesurement in Ohms*/
double re; /**< real part of the mesurement in Ohms*/
double omega; /**< freqency of the mesurement in rad/s*/
};
struct rlx_spectra {
int id; /**< Spectra id, also called "file" in relaxis*/
struct rlx_datapoint* datapoints; /**< datapoints of the spectrum*/
size_t length; /**< Amount of datapoints in the spectrum*/
char* circuit; /**< Relaxis circuit descriptian string*/
bool fitted; /**< True if circuit has been fitted to spectrum*/
int project_id; /**< Id of the project this spectrum belongs to*/
double freq_lower_limit; /**< Lower limit of freqency range of this spctrum*/
double freq_upper_limit; /**< Upper limit of freqency range of this spctrum*/
time_t date_added;
time_t date_fitted;
};
/**
* @brief Frees a spectra struct
*
* @param spectra spectra to be freed
*/
void rlx_spectra_free(struct rlx_spectra* spectra);
/**
* @brief Frees an array of spectra structs
*
* @param spectra_array array of spectra structs to be freed
*/
void rlx_spectra_free_array(struct rlx_spectra** spectra_array);
struct rlx_fitparam {
int spectra_id;
int p_index;
char* name;
double value;
double error;
double lower_limit;
double upper_limit;
};
/**
* @brief Frees a fitparam struct
*
* @param fitparam fitparam struct to be freed
*/
void rlx_fitparam_free(struct rlx_fitparam* param);
/**
* @brief Frees an array of fitparam structs
*
* @param param_array array of fitparam structs to be freed
*/
void rlx_fitparam_free_array(struct rlx_fitparam** param_array);
/**
* @brief Frees a project struct
*
* @param path the filesystem path where the file shal be opened
* @param error if an error occures and NULL is retuned, pointer to an error string is set here,
* owned by librelaxisloader, do not free, valid only untill next call to librelaxisloader
* @return a rxfile struct or NULL if opening was unsucessfull, to be closed with rlx_close_file
*/
struct rxfile* rlx_open_file(const char* path, const char** error);
void rlx_close_file(struct rxfile* file);
/**
* @brief Gets all the projects in a given RelaxIS file
*
* @param file file to load projects from
* @param length pointer to a size_t where the number of projects will be stored, or NULL
* @return A NULL terminated array of project structs will be allocated here, to be freed with rlx_project_free_array, or NULL on error
*/
struct rlx_project** rlx_get_projects(struct rxfile* file, size_t* length);
/**
* @brief Loads all spectra from file
*
* @param file file to load spectra from
* @param project project to load spectra from
* @return A NULL terminated array of spectra structs will be allocated here, to be freed with rlx_spectra_free_array, or NULL on error
*/
struct rlx_spectra** rlx_get_all_spectra(struct rxfile* file, const struct rlx_project* project);
/**
* @brief Loads a given spectra from file
*
* @param file file to load spectra from
* @param project project to load spectra from
* @param id spectra id for wich to load parameters
* @param length pointer to size_t where the number of ids will be stored or NULL
* @return A NULL terminated array of fitparam structs will be allocated here, to be freed with rlx_fitparam_free_array, or NULL on error
*/
int* rlx_get_spectra_ids(struct rxfile* file, const struct rlx_project* project, size_t* length);
/**
* @brief Loads a given spectra from file
*
* @param file file to load spectra from
* @param project project to load spectra from
* @param id spectra id to load
* @return spectra struct or NULL if unsucessful, to be freed with rlx_spectra_free
*/
struct rlx_spectra* rlx_get_spectra(struct rxfile* file, const struct rlx_project* project, int id);
/**
* @brief Loads a given spectra from file
*
* @param file file to load spectra from
* @param project project to load spectra from
* @param id spectra id for wich to load parameters
* @param length a pointer to a size_t where the number of parameters will be stored, or NULL
* @return A NULL terminated array of fitparam structs will be allocated here, to be freed with rlx_fitparam_free_array, or NULL on error
*/
struct rlx_fitparam** rlx_get_fit_parameters(struct rxfile* file, const struct rlx_project* project, int id, size_t *length);
/**
* @brief Returns the last error retuned on a file operation
*
* @return relaxiloader error number
*/
int rlx_get_errnum(const struct rxfile* file);
/**
* @brief Returns a human reable error string for a given error number
*
* @return Error string, owend by librelaxisloader do not free
*/
const char* rlx_get_errnum_str(int errnum);
/**
....
* @}
*/
#ifdef __cplusplus
}
#endif
test.eis3 0 → 100644
File added
utils.c 0 → 100644
#include "utils.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
char *rlx_strconcat(const char* a, const char* b)
{
char* full_str = malloc(strlen(a)+strlen(b));
assert(full_str);
strcpy(full_str, a);
strcat(full_str, b);
return full_str;
}
char *rlx_strdup(const char* a)
{
char *ret = malloc(strlen(a)+1);
assert(ret);
strcpy(ret, a);
return ret;
}
time_t rlx_str_to_time(const char* str)
{
struct tm tm = {};
char *tmRet = strptime(str, "%Y-%m-%d%t%H:%M:%S", &tm);
assert(tmRet);
return mktime(&tm);
}
char *rlx_alloc_printf(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
int len = vsnprintf(NULL, 0, fmt, args);
va_end(args);
char *out = malloc(len+1);
va_start(args, fmt);
vsnprintf(out, len+1, fmt, args);
va_end(args);
return out;
}
#pragma once
#include <time.h>
char *rlx_strconcat(const char* a, const char* b);
char *rlx_strdup(const char* a);
time_t rlx_str_to_time(const char* str);
char *rlx_alloc_printf(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment