CSM R5-3
csmbase.c
Go to the documentation of this file.
1/*
2Copyright 2026 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
3<https://www.helmholtz-berlin.de>
4
5This file is part of CSM.
6
7CSM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12CSM is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with CSM. If not, see <https://www.gnu.org/licenses/>.
19*/
20
30
31/*____________________________________________________________*/
32/* general Defines */
33/*____________________________________________________________*/
34
35
36#ifndef DOXYGEN_SKIP_THIS
37
39# define _INCLUDE_POSIX_SOURCE
40
42# define USE_DBG 0
43
45# define USE_ERRLOGPRINTF 1
46
48# define USE_SEM 1
49
51# define USE_PSEM 0
52
53/* the following macros affect the debug (dbg) module: */
54
55# if USE_DBG
56
58# define DBG_ASRT_COMP 0
59
61# define DBG_MSG_COMP 0
62
64# define DBG_TRC_COMP 0
65
67# define DBG_LOCAL_COMP 1
68
70# define DBG_ASYNC_COMP 1
71
72/* the following defines are for sci-debugging, they do not influence
73 any header-files but are placed here since they are usually changed
74 together with the above macros.*/
75
77# define CSMBASE_OUT_FILE "stdout"
78
84# define CSMBASE_TRC_LEVEL 0
85
87# define CSMBASE_FLUSHMODE 1
88
89# else /* USE_DBG */
90
91# if !USE_ERRLOGPRINTF
92# define errlogPrintf printf
93# endif
94
96# define DBG_MSG_PRINTF2(f,x) errlogPrintf(f,x)
97
99# define DBG_MSG_PRINTF3(f,x,y) errlogPrintf(f,x,y)
100
102# define DBG_MSG_PRINTF4(f,x,y,z) errlogPrintf(f,x,y,z)
103
105# define DBG_MSG_PRINTF5(f,x,y,z,q) errlogPrintf(f,x,y,z,q)
106
107# endif /* USE_DBG */
108
109# if !USE_SEM
110# define SEM_TYPE int
111# define SEMTAKE(x)
112# define SEMGIVE(x)
113# define SEMDELETE(x)
114# define SEMCREATE(x) 0
115
116# else /* !USE_SEM */
117
118# if USE_PSEM
119# define SEM_TYPE psem_mutex
120# define SEMTAKE(x) psem_mutex_take(&(x))
121# define SEMGIVE(x) psem_mutex_give(&(x))
122# define SEMDELETE(x) psem_mutex_remove(&(x))
123# define SEMCREATE(x) (!psem_mutex_create(&(x)))
124# define epicsShareFunc
125# else /* USE_PSEM */
127# define SEM_TYPE epicsMutexId
129# define SEMTAKE(x) epicsMutexLock(x)
131# define SEMGIVE(x) epicsMutexUnlock(x)
133# define SEMDELETE(x) epicsMutexDestroy(x)
135# define SEMCREATE(x) (NULL==(x= epicsMutexCreate()))
136# endif /* USE_PSEM */
137
138# endif /* !USE_SEM */
139
140#endif /* DOXYGEN_SKIP_THIS */
141
143#define CSM_TRUE 1
144
146#define CSM_FALSE 0
147
148/*____________________________________________________________*/
149/* Include-Files */
150/*____________________________________________________________*/
151
152#if USE_SEM
153
154#if USE_PSEM
155#include <psem.h>
156#else
157#include <epicsMutex.h>
158#include <shareLib.h>
159#endif
160
161#endif
162
163#if USE_DBG
164#include <dbg.h>
165#endif
166
167#if USE_ERRLOGPRINTF
168#include <errlog.h> /* epics error printf */
169#endif
170
171#include <ctype.h>
172#include <stdlib.h>
173#include <stdio.h>
174#include <string.h>
175
176/* math.h for definition of NAN */
177#include <math.h>
178
179#define epicsExportSharedSymbols
180#include "csmbase.h"
181
182/*____________________________________________________________*/
183/* Defines */
184/*____________________________________________________________*/
185
186#ifndef NAN
188#define NAN (-(0.0/0.0))
189#endif
190
191/*____________________________________________________________*/
192/* Types */
193/*____________________________________________________________*/
194
195 /*................................................*/
196 /* the coordinate type (private) */
197 /*................................................*/
198
200typedef struct
201 {
202 double value;
203 int index;
204 } csm_coordinate;
205
207typedef struct
208 { csm_coordinate *coordinate;
209 int no_of_elements;
212 int a_last;
213 int b_last;
214 } csm_coordinates;
215
216 /*................................................*/
217 /* the linear function type (private) */
218 /*................................................*/
219
221typedef struct
222 { double a;
223 double b;
224 } csm_linear_function;
225
226 /*................................................*/
227 /* the 1d table type (private) */
228 /*................................................*/
229
235typedef struct
236 { csm_coordinates x;
237 csm_coordinates y;
238 double x_last;
239 double y_last;
240 csm_bool value_cached;
241 } csm_1d_functiontable;
242
243 /*................................................*/
244 /* the 2d table type (private) */
245 /*................................................*/
246
252typedef struct
253 { csm_coordinates x;
254 csm_coordinates y;
255 double *z;
256 double x_last;
257 double y_last;
258 double z_last;
259 csm_bool value_cached;
260 } csm_2d_functiontable;
261
262 /*................................................*/
263 /* the function-type (private) */
264 /*................................................*/
265
266#ifndef DOXYGEN_SKIP_THIS
268typedef enum { CSM_NOTHING,
269 CSM_LINEAR,
270 CSM_1D_TABLE,
271 CSM_2D_TABLE
272 } csm_func_type;
273#endif
274
276struct csm_Function
277 { SEM_TYPE semaphore;
278 double last_x;
279 double last_y;
280 double last_dx;
281 double last_dy;
282 double last_z;
283 csm_bool on_hold;
284 csm_func_type type;
285
286 union { csm_linear_function lf;
287 csm_1d_functiontable tf_1;
288 csm_2d_functiontable tf_2;
289 } f;
290
291 };
292
293/*____________________________________________________________*/
294/* Variables */
295/*____________________________________________________________*/
296
297 /*................................................*/
298 /* initialization (private) */
299 /*................................................*/
300
306static csm_bool initialized= CSM_FALSE;
307
308/*____________________________________________________________*/
309/* Functions */
310/*____________________________________________________________*/
311
312
313 /*----------------------------------------------------*/
314 /* debug - managment (private) */
315 /*----------------------------------------------------*/
316
317#if USE_DBG
322
323static void csm_dbg_init(void)
324 { static csm_bool csmbase_init= CSM_FALSE;
325
326 if (csmbase_init)
327 return;
328 csmbase_init= CSM_TRUE;
329 /* initialize the debug (dbg) module: use stdout for error-output */
330 DBG_SET_OUT(CSMBASE_OUT_FILE);
331 DBG_TRC_LEVEL= CSMBASE_TRC_LEVEL;
332 /* level 6: dense traces for debugging
333 level 5: enter/exit tracing
334 level 2: output less severe errors and warnings
335 level 1: output of severe errors
336 level 0: no output */
337 DBG_FLUSHMODE(CSMBASE_FLUSHMODE);
338 }
339
340#endif /* USE_DBG */
341
342 /*----------------------------------------------------*/
343 /* utilities for csm-coordinates (private) */
344 /*----------------------------------------------------*/
345
346 /* initialization */
347
355static void init_coordinates(csm_coordinates *c)
356 {
357 c->a_last=-1;
358 c->b_last=-1;
359 c->coordinate= NULL;
360 c->no_of_elements=0;
361 }
362
371static csm_bool alloc_coordinates(csm_coordinates *c, int elements)
372 { int i;
373 csm_coordinate *co;
374
375 if (c->no_of_elements==0) /* 1st time memory allocation */
376 c->coordinate= malloc(sizeof(csm_coordinate)*elements);
377 else
378 c->coordinate= realloc(c->coordinate,
379 sizeof(csm_coordinate)*elements);
380
381 if (c->coordinate==NULL) /* allocation error */
382 { DBG_MSG_PRINTF2("error in csm:alloc_coordinates line %d,\n"
383 "allocation failed!\n", __LINE__);
384 init_coordinates(c);
385 return(CSM_FALSE);
386 };
387
388 for(i=c->no_of_elements, co= (c->coordinate + c->no_of_elements);
389 i<elements;
390 i++, co++)
391 { co->value=0;
392 co->index=i;
393 };
394
395 c->no_of_elements= elements;
396 return(CSM_TRUE);
397 }
398
409static csm_bool resize_coordinates(csm_coordinates *c, int elements)
410 { if (elements==c->no_of_elements)
411 return(CSM_TRUE);
412
413 c->no_of_elements= elements;
414 if (NULL== (c->coordinate= realloc(c->coordinate,
415 sizeof(csm_coordinate)*elements)))
416 { DBG_MSG_PRINTF2("error in csm:resize_coordinates line %d,\n" \
417 "realloc failed!\n", __LINE__);
418 return(CSM_FALSE);
419 };
420 return(CSM_TRUE);
421 }
422
431static void reinit_coordinates(csm_coordinates *c)
432 { if (c->no_of_elements==0)
433 return;
434
435 free(c->coordinate);
436 init_coordinates(c);
437 }
438
448static csm_bool init_matrix(double **z, int rows, int columns)
449 { int i;
450 double *zp;
451
452 if (NULL== (zp= malloc((sizeof(double))*rows*columns)))
453 { DBG_MSG_PRINTF2("error in csm:init_matrix line %d,\n" \
454 "malloc failed!\n", __LINE__);
455 return(CSM_FALSE);
456 };
457 *z = zp;
458 for (i= rows*columns; i>0; i--, *(zp++)=0);
459 return(CSM_TRUE);
460 }
461
462 /* x-compare for qsort */
463
475static int coordinate_cmp(const void *t1, const void *t2)
476 { double x1= ((csm_coordinate *)(t1))->value;
477 double x2= ((csm_coordinate *)(t2))->value;
478
479 if (x1 < x2)
480 return(-1);
481 if (x1 > x2)
482 return( 1);
483 return(0);
484 }
485
486 /* coordinate-sort */
487
494static void coordinate_sort( csm_coordinates *coords)
495 {
496 qsort( coords->coordinate, coords->no_of_elements,
497 sizeof(csm_coordinate), coordinate_cmp);
498 }
499
515static void coordinate_update_backlinks( csm_coordinates *coords1,
516 csm_coordinates *coords2)
517 { int i,l;
518 csm_coordinate *c,*d;
519
520 l= coords1->no_of_elements;
521 for (i=0, c= coords1->coordinate, d= coords2->coordinate; i<l; i++, c++)
522 { d[c->index].index = i; };
523 }
524
525 /* lookup an index in coordinates */
526
549
550#define ret(idx_a, idx_b, ret_code) \
551 *a= idx_a;\
552 *b= idx_b;\
553 coords->a_last= idx_a;\
554 coords->b_last= idx_b;\
555 return(ret_code)
556
557static int coordinate_lookup_index(csm_coordinates *coords,double x,
558 int *a, int *b)
559 /* 2: x was found, it is returned in a
560 1: x was not found, but a and b define the closest interval around x
561 0: x was not found at it is outside the closest interval a and b
562 -1: error
563 */
564 /* the table should be x-sorted */
565 { int i, ia, ib;
566 double xt;
567 csm_coordinate *c= coords->coordinate;
568 double x_boundary;
569 int last_idx= coords->no_of_elements-1;
570 int a_last, b_last;
571 int tries;
572
573 if (coords->no_of_elements<2)
574 { if (coords->no_of_elements<1)
575 {
576 DBG_MSG_PRINTF2("error in csm:coordinate_lookup_index %d,\n" \
577 "table has less than 1 element!\n", __LINE__);
578 ret(0,0,-1);
579 };
580 coords->a_last= 0; coords->b_last= 0;
581 if (x== c[0].value)
582 {
583 ret(0,0,2);
584 }
585 else
586 {
587 ret(0,0,0);
588 }
589 };
590
591 a_last= coords->a_last;
592 b_last= coords->b_last;
593 if (a_last<0)
594 a_last= 0;
595 if (b_last<0)
596 b_last= last_idx;
597
598 for(tries=1; tries<=3; tries++)
599 {
600 switch(tries)
601 {
602 case 1:
603 break;
604 case 2:
605 b_last= a_last;
606 a_last= a_last-1;
607 break;
608 case 3:
609 b_last= a_last;
610 a_last= 0;
611 break;
612 }
613
614 x_boundary= c[a_last].value;
615 if (x>x_boundary)
616 break;
617 if (x==x_boundary)
618 {
619 ret(a_last,a_last,2);
620 }
621 if (a_last==0)
622 { /* left of area */
623 ret(0,1, 0);
624 }
625 }
626
627 for(tries=1; tries<=3; tries++)
628 {
629 switch(tries)
630 {
631 case 1:
632 break;
633 case 2:
634 a_last= b_last;
635 b_last= b_last+1;
636 break;
637 case 3:
638 a_last= b_last;
639 b_last= last_idx;
640 break;
641 }
642
643 x_boundary= c[b_last].value;
644 if (x<x_boundary)
645 break;
646 if (x==x_boundary)
647 {
648 ret(b_last,b_last,2);
649 }
650 if (b_last==last_idx)
651 { /* right of area */
652 ret(last_idx-1,last_idx, 0);
653 }
654 }
655
656 ia= a_last;
657 ib= b_last;
658 /* necessary condition here:
659 c[ia].value<= x <= c[ib].value
660 */
661 for (; (ib>ia+1); )
662 { i= (ib+ia)/2;
663 xt= c[i].value;
664 if (xt<x)
665 {
666 ia= i;
667 continue;
668 }
669 if (xt>x)
670 {
671 ib= i;
672 continue;
673 }
674 /* exact match */
675 ret(i,i,2);
676 };
677 ret(ia,ib,1);
678 }
679
680 /*----------------------------------------------------*/
681 /* utilities for csm_linear_function (private) */
682 /*----------------------------------------------------*/
683
684 /* calculation */
685
693static double linear_get_y(csm_linear_function *p, double x)
694 { return( (p->a) + (p->b)*x ); }
695
702static double linear_get_x(csm_linear_function *p, double y)
703 { return( (y - (p->a))/(p->b) ); }
704
711static double linear_delta_get_y(csm_linear_function *p, double x)
712 { return( (p->b)*x ); }
713
720static double linear_delta_get_x(csm_linear_function *p, double y)
721 { return( y/(p->b) ); }
722
723 /*----------------------------------------------------*/
724 /* utilities for csm_1d_functiontable (private) */
725 /*----------------------------------------------------*/
726
727 /* initialization */
728
736static void init_1d_functiontable(csm_1d_functiontable *ft)
737 { init_coordinates(&(ft->x));
738 init_coordinates(&(ft->y));
739 ft->value_cached= CSM_FALSE;
740 }
741
750static void reinit_1d_functiontable(csm_1d_functiontable *ft)
751 { reinit_coordinates(&(ft->x));
752 reinit_coordinates(&(ft->y));
753 ft->value_cached= CSM_FALSE;
754 }
755
756 /* lookup a value in the table */
757
772static double lookup_1d_functiontable(csm_1d_functiontable *ft, double x,
773 csm_bool invert)
774 { int res,a,b;
775 double xa,xb,ya,yb;
776 csm_coordinate c;
777 csm_coordinates *xcoords;
778 csm_coordinates *ycoords;
779
780 if (!invert)
781 {
782 if ((ft->value_cached) && (ft->x_last==x))
783 return(ft->y_last);
784 xcoords= &(ft->x);
785 ycoords= &(ft->y);
786 }
787 else
788 {
789 if ((ft->value_cached) && (ft->y_last==x))
790 return(ft->x_last);
791 xcoords= &(ft->y);
792 ycoords= &(ft->x);
793 };
794
795 res= coordinate_lookup_index(xcoords, x, &a, &b);
796
797
798 if (res==-1) /* error */
799 {
800 ft->value_cached= CSM_FALSE;
801 return(NAN);
802 }
803 if ((res== 2)||(a==b)) /* exact match or table with just a single value */
804 {
805 /* if the table has just a single value (only one [x,y] pair) we return
806 the corresponding y value. */
807 c= (xcoords->coordinate)[a];
808 ft->value_cached= CSM_TRUE;
809 if (!invert)
810 {
811 ft->x_last= x;
812 return(ft->y_last= (ycoords->coordinate)[c.index].value);
813 }
814 else
815 {
816 ft->y_last= x;
817 return(ft->x_last= (ycoords->coordinate)[c.index].value);
818 }
819 };
820
821 c= (xcoords->coordinate)[a];
822 xa= c.value;
823 ya= (ycoords->coordinate)[c.index].value;
824
825 c= (xcoords->coordinate)[b];
826 xb= c.value;
827 yb= (ycoords->coordinate)[c.index].value;
828
829 ft->value_cached= CSM_TRUE;
830
831 if (!invert)
832 {
833 ft->x_last= x;
834 /* y= ya + (x-xa)/(xb-xa)*(yb-ya) */
835 return(ft->y_last= ya + (x-xa)/(xb-xa) * (yb-ya));
836 }
837 else
838 {
839 ft->y_last= x;
840 /* y= ya + (x-xa)/(xb-xa)*(yb-ya) */
841 return(ft->x_last= ya + (x-xa)/(xb-xa) * (yb-ya));
842 }
843
844 }
845
846 /*----------------------------------------------------*/
847 /* utilities for csm_2d_functiontable (private) */
848 /*----------------------------------------------------*/
849
850 /* initialization */
851
859static void init_2d_functiontable(csm_2d_functiontable *ft)
860 { init_coordinates(&(ft->x));
861 init_coordinates(&(ft->y));
862 ft->value_cached= CSM_FALSE;
863 }
864
873static void reinit_2d_functiontable(csm_2d_functiontable *ft)
874 { reinit_coordinates(&(ft->x));
875 reinit_coordinates(&(ft->y));
876 if (ft->z!=NULL)
877 free(ft->z);
878 ft->z= NULL;
879 ft->value_cached= CSM_FALSE;
880 }
881
882 /* lookup a value in the xy-table */
883
896static double lookup_2d_functiontable(csm_2d_functiontable *ft,
897 double x, double y)
898 { int res,xia,xib,yia,yib;
899 double xa,xb,ya,yb;
900 double zaa,zab,zba,zbb;
901 double *z= ft->z;
902 int no_of_columns;
903
904 csm_coordinate cxa,cxb,cya,cyb;
905 csm_coordinates *xcoords= &(ft->x);
906 csm_coordinates *ycoords= &(ft->y);
907
908 if (ft->value_cached)
909 {
910 if ((ft->x_last==x) && (ft->y_last==y))
911 return(ft->z_last);
912 }
913
914 no_of_columns= ycoords->no_of_elements;
915
916 res= coordinate_lookup_index(xcoords, x, &xia, &xib);
917 if (res==-1) /* error */
918 {
919 ft->value_cached= CSM_FALSE;
920 return(NAN);
921 }
922
923 res= coordinate_lookup_index(ycoords, y, &yia, &yib);
924 if (res==-1) /* error */
925 {
926 ft->value_cached= CSM_FALSE;
927 return(NAN);
928 }
929
930 /* res==2 with exact match is currently not treated separately */
931
932 cxa= (xcoords->coordinate)[xia];
933 cxb= (xcoords->coordinate)[xib];
934 cya= (ycoords->coordinate)[yia];
935 cyb= (ycoords->coordinate)[yib];
936
937 xa= cxa.value; /* with exact match, xa==xb or ya==yb is possible */
938 xb= cxb.value;
939 ya= cya.value;
940 yb= cyb.value;
941
942 zaa= z[ cxa.index * no_of_columns + cya.index ];
943 zab= z[ cxa.index * no_of_columns + cyb.index ];
944 zba= z[ cxb.index * no_of_columns + cya.index ];
945 zbb= z[ cxb.index * no_of_columns + cyb.index ];
946
947#if 0
948printf("x:%f y:%f xa:%f xb:%f ya:%f yb:%f\n",x,y,xa,xb,ya,yb);
949printf("zaa:%f zab:%f zba:%f zbb:%f\n",zaa,zab,zba,zbb);
950#endif
951#if 1
952 { double alpha = (xb==xa) ? 0 : (x-xa)/(xb-xa);
953 double beta = (yb==ya) ? 0 : (y-ya)/(yb-ya);
954 if (alpha==0) /* xb==xa ? */
955 {
956 ft->value_cached= CSM_TRUE;
957 ft->x_last= x;
958 ft->y_last= y;
959 if (beta==0) /* yb==ya ? */
960 return(ft->z_last= zaa);
961 return(ft->z_last= zaa+ beta *(zab-zaa) );
962 };
963 if (beta==0) /* yb==ya ? */
964 {
965 ft->value_cached= CSM_TRUE;
966 ft->x_last= x;
967 ft->y_last= y;
968 return(ft->z_last= zaa+ alpha*(zba-zaa) );
969 }
970
971#if 0
972printf(" ret: %f\n",
973 zaa + beta*(zab-zaa)+alpha*(zba-zaa+beta*(zbb-zba-zab+zaa)));
974#endif
975 ft->value_cached= CSM_TRUE;
976 ft->x_last= x;
977 ft->y_last= y;
978 return(ft->z_last=
979 zaa + beta*(zab-zaa)+alpha*(zba-zaa+beta*(zbb-zba-zab+zaa)) );
980 };
981#endif
982
983#if 0
984 { /* alternative according to formula given by J.Bahrdt */
985 /* doesn't work when yb==ya or xb==xa */
986 double delta= (yb-ya)*(xb-xa);
987 double yb_ = yb - y;
988 double xb_ = xb - x;
989 double y_a = y - ya;
990 double x_a = x - xa;
991 return((zaa*yb_*xb_ + zab*y_a*xb_ + zba*yb_*x_a + zbb*y_a*x_a)/delta);
992#endif
993
994 }
995
996 /*----------------------------------------------------*/
997 /* generic functions (public) */
998 /*----------------------------------------------------*/
999
1000double csm_x(csm_function *func, double y)
1001 { double ret;
1002
1003 SEMTAKE(func->semaphore);
1004
1005 if (func->on_hold)
1006 { ret= func->last_x;
1007 SEMGIVE(func->semaphore);
1008 return(ret);
1009 };
1010
1011 switch (func->type)
1012 { case CSM_NOTHING:
1013 func->last_x= 0;
1014 break;
1015 case CSM_LINEAR:
1016 func->last_x= linear_get_x(&(func->f.lf), y);
1017 break;
1018 case CSM_1D_TABLE:
1019 func->last_x= lookup_1d_functiontable(&(func->f.tf_1),y,
1020 CSM_TRUE);
1021 break;
1022 default:
1023 func->last_x=0;
1024 break;
1025 };
1026 ret= func->last_x;
1027 SEMGIVE(func->semaphore);
1028 return(ret);
1029 }
1030
1031double csm_y(csm_function *func, double x)
1032 { double ret;
1033
1034 SEMTAKE(func->semaphore);
1035
1036 if (func->on_hold)
1037 { ret= func->last_y;
1038 SEMGIVE(func->semaphore);
1039 return(ret);
1040 };
1041
1042 switch (func->type)
1043 { case CSM_NOTHING:
1044 func->last_y= 0;
1045 break;
1046 case CSM_LINEAR:
1047 func->last_y= linear_get_y(&(func->f.lf), x);
1048 break;
1049 case CSM_1D_TABLE:
1050 func->last_y= lookup_1d_functiontable(&(func->f.tf_1),x,
1051 CSM_FALSE);
1052 break;
1053 default:
1054 func->last_y=0;
1055 break;
1056 };
1057 ret= func->last_y;
1058 SEMGIVE(func->semaphore);
1059 return(ret);
1060 }
1061
1062double csm_dx(csm_function *func, double y)
1063 { double ret;
1064
1065 SEMTAKE(func->semaphore);
1066
1067 if (func->on_hold)
1068 { ret= func->last_dx;
1069 SEMGIVE(func->semaphore);
1070 return(ret);
1071 };
1072
1073 if (func->type==CSM_LINEAR)
1074 func->last_dx= linear_delta_get_x(&(func->f.lf), y);
1075 else
1076 func->last_dx=0;
1077
1078 ret= func->last_dx;
1079 SEMGIVE(func->semaphore);
1080 return(ret);
1081 }
1082
1083double csm_dy(csm_function *func, double x)
1084 { double ret;
1085
1086 SEMTAKE(func->semaphore);
1087
1088 if (func->on_hold)
1089 { ret= func->last_dy;
1090 SEMGIVE(func->semaphore);
1091 return(ret);
1092 };
1093
1094 if (func->type==CSM_LINEAR)
1095 func->last_dy= linear_delta_get_y(&(func->f.lf), x);
1096 else
1097 func->last_dy=0;
1098
1099 ret= func->last_dy;
1100 SEMGIVE(func->semaphore);
1101 return(ret);
1102 }
1103
1104double csm_z(csm_function *func, double x, double y)
1105 { double ret;
1106
1107 SEMTAKE(func->semaphore);
1108
1109 if (func->on_hold)
1110 { ret= func->last_z;
1111 SEMGIVE(func->semaphore);
1112 return(ret);
1113 };
1114
1115 if (func->type==CSM_2D_TABLE)
1116 func->last_z= lookup_2d_functiontable(&(func->f.tf_2), x, y);
1117 else
1118 func->last_z=0;
1119
1120 ret= func->last_z;
1121 SEMGIVE(func->semaphore);
1122 return(ret);
1123 }
1124
1125 /*----------------------------------------------------*/
1126 /* initialization */
1127 /*----------------------------------------------------*/
1128
1129 /* initialize a csm_function object (private) */
1130
1138static void reinit_function(csm_function *func)
1139 { if (func->type==CSM_NOTHING)
1140 { return; };
1141 if (func->type==CSM_1D_TABLE)
1142 reinit_1d_functiontable( &(func->f.tf_1) );
1143 if (func->type==CSM_2D_TABLE)
1144 reinit_2d_functiontable( &(func->f.tf_2) );
1145
1146 /* @@@@ CAUTION: currently there is no locking,
1147 no test wether another process is currently
1148 accessing the structure */
1149 func->type= CSM_NOTHING;
1150 }
1151
1152 /* scan a string for a list of doubles (private) */
1153
1162static csm_bool str_empty_or_comment(char *st)
1163 { for(;*st!=0; st++)
1164 { if (isspace(*st))
1165 continue;
1166 if (*st=='#')
1167 return(CSM_TRUE);
1168 return(CSM_FALSE);
1169 };
1170 return(CSM_TRUE);
1171 }
1172
1173 /* scan a string for a list of doubles (private) */
1174
1188static int strdoublescan(char *st, double *d, int no_of_cols)
1189 /* returns the number of numbers found in the line, d may be null,
1190 in this case, the numbers are only counted,
1191 if a line contains not enough numbers, (unequal no_of_cols) the missing
1192 ones are set to 0 */
1193 /* reads over leading whitespaces */
1194 /* uses strtok ! */
1195 { int i;
1196 char *p= st; /* anything different from NULL */
1197 char buf[1024];
1198 char *str= buf;
1199 double *dptr;
1200
1201 if ((no_of_cols<=0)||(no_of_cols>1000))
1202 return(0);
1203 for( ;NULL!=strchr( " \t\r\n", *st); st++);
1204 if (*st==0)
1205 return(0);
1206 strncpy(buf, st, 1023); buf[1023]=0;
1207 if (d!=NULL)
1208 for(dptr= d, i=0; i<no_of_cols; i++, *(dptr++)=0 );
1209 for(p= str, dptr= d, i=0; i<no_of_cols; i++, dptr++)
1210 {
1211 if (NULL== (p= strtok(str," \t\r\n")))
1212 return(i);
1213 str= NULL;
1214 if (d!=NULL)
1215 { if (1!=sscanf(p,"%lf",dptr))
1216 return(0); /* a kind of fatal error */
1217 };
1218 };
1219 return(no_of_cols); /* everything that was expected was found */
1220 }
1221
1222 /* clear a function (public) */
1223
1225 { SEMTAKE(func->semaphore);
1226 func->on_hold= CSM_TRUE;
1227 SEMGIVE(func->semaphore);
1228
1229 reinit_function(func);
1230
1231 func->on_hold= CSM_FALSE;
1232 }
1233
1234 /* free all data for a function (public) */
1235
1237 { csm_clear(func);
1238 SEMDELETE(func->semaphore);
1239 free(func);
1240 }
1241
1242 /* define a function (public) */
1243
1244void csm_def_linear(csm_function *func, double a, double b)
1245 /* y= a+b*x */
1246 { SEMTAKE(func->semaphore);
1247 func->on_hold= CSM_TRUE;
1248 SEMGIVE(func->semaphore);
1249
1250 reinit_function(func);
1251
1252 func->type= CSM_LINEAR;
1253 (func->f.lf).a= a;
1254 (func->f.lf).b= b;
1255
1256 func->on_hold= CSM_FALSE;
1257 }
1258
1260 { if (func->type!=CSM_LINEAR)
1261 { DBG_MSG_PRINTF2("error in csm_def_linear_offset line %d,\n" \
1262 "not a linear function!\n", __LINE__);
1263 return(CSM_FALSE);
1264 };
1265
1266 SEMTAKE(func->semaphore);
1267 func->f.lf.a= a;
1268 SEMGIVE(func->semaphore);
1269
1270 return(CSM_TRUE);
1271 }
1272
1273csm_bool csm_fill_1d_table(double *x, double *y, int len, csm_function *func)
1274 /* fill the 1d table numbers of two arrays.
1275 * len is the number of rows in the table
1276 */
1277 {
1278 csm_1d_functiontable *ft= &(func->f.tf_1);
1279 csm_coordinate *xc, *yc;
1280 int row;
1281
1282 SEMTAKE(func->semaphore);
1283 func->on_hold= CSM_TRUE;
1284 SEMGIVE(func->semaphore);
1285
1286 reinit_function(func);
1287
1288 init_1d_functiontable(ft);
1289
1290 if (!alloc_coordinates(&(ft->x), len))
1291 {
1292 reinit_function(func);
1293 func->on_hold= CSM_FALSE;
1294 return(CSM_FALSE);
1295 };
1296
1297 if (!alloc_coordinates(&(ft->y), len))
1298 {
1299 reinit_function(func);
1300 func->on_hold= CSM_FALSE;
1301 return(CSM_FALSE);
1302 };
1303
1304 xc= (ft->x).coordinate;
1305 yc= (ft->y).coordinate;
1306
1307 for(row=0; row<len; row++, xc++, yc++, x++, y++)
1308 {
1309 xc->value= *x;
1310 yc->value= *y;
1311 xc->index= row;
1312 yc->index= row;
1313 }
1314
1315 func->type= CSM_1D_TABLE;
1316
1317 coordinate_sort(&(ft->x));
1318 coordinate_update_backlinks(&(ft->x), &(ft->y));
1319 coordinate_sort(&(ft->y));
1320 coordinate_update_backlinks(&(ft->y), &(ft->x));
1321 func->on_hold= CSM_FALSE;
1322 return(CSM_TRUE);
1323 }
1324
1326/* if len==0, the table length is determined by counting the number of lines
1327 in the file from the current position to it's end */
1328 { char line[128];
1329 long pos;
1330 long i;
1331 long errcount;
1332 csm_1d_functiontable *ft= &(func->f.tf_1);
1333 csm_coordinate *xc, *yc;
1334 int len;
1335 FILE *f;
1336 char dummy;
1337
1338 if (NULL==(f=fopen(filename,"r"))) /* vxworks doesn't accept "rt" */
1339 { DBG_MSG_PRINTF2("error in csm_read_xytable line %d,\n" \
1340 "file open error!\n", __LINE__);
1341 return(CSM_FALSE);
1342 };
1343
1344 pos= ftell(f);
1345 for(len=0; NULL!=fgets(line, 127, f); len++);
1346 if (-1==fseek(f, pos, SEEK_SET))
1347 { fclose(f);
1348 return(CSM_FALSE);
1349 };
1350
1351 SEMTAKE(func->semaphore);
1352 func->on_hold= CSM_TRUE;
1353 SEMGIVE(func->semaphore);
1354
1355 reinit_function(func);
1356
1357 init_1d_functiontable(ft);
1358
1359 if (!alloc_coordinates(&(ft->x), len))
1360 { fclose(f);
1361 reinit_function(func);
1362 func->on_hold= CSM_FALSE;
1363 return(CSM_FALSE);
1364 };
1365
1366 if (!alloc_coordinates(&(ft->y), len))
1367 { fclose(f);
1368 reinit_function(func);
1369 func->on_hold= CSM_FALSE;
1370 return(CSM_FALSE);
1371 };
1372
1373 xc= (ft->x).coordinate;
1374 yc= (ft->y).coordinate;
1375
1376 for(errcount=0, i=0;(len>0) && (NULL!=fgets(line, 127, f)); len--)
1377 { if (str_empty_or_comment(line))
1378 continue;
1379 if (2!=sscanf(line, " %lf %lf %c",
1380 &(xc->value), &(yc->value), &dummy))
1381 { DBG_MSG_PRINTF5("warning[%s:%d]: the following line of the "
1382 "data-file (%s) was not understood:\n%s\n",
1383 __FILE__,__LINE__,filename,line);
1384 if (++errcount<4)
1385 continue;
1386 fclose(f);
1387 reinit_function(func);
1388 func->on_hold= CSM_FALSE;
1389 DBG_MSG_PRINTF3("error[%s:%d]: too many errors in file\n",
1390 __FILE__,__LINE__);
1391 return(CSM_FALSE);
1392 };
1393 xc->index= i;
1394 yc->index= i;
1395 i++, xc++,yc++;
1396 };
1397 if (i<=0)
1398 { fclose(f);
1399 reinit_function(func);
1400 func->on_hold= CSM_FALSE;
1401 DBG_MSG_PRINTF3("error[%s:%d]: no data was found at all\n",
1402 __FILE__,__LINE__);
1403 return(CSM_FALSE);
1404 };
1405
1406 if (!resize_coordinates(&(ft->x), i))
1407 { fclose(f);
1408 reinit_function(func);
1409 func->on_hold= CSM_FALSE;
1410 return(CSM_FALSE);
1411 };
1412 if (!resize_coordinates(&(ft->y), i))
1413 { fclose(f);
1414 reinit_function(func);
1415 func->on_hold= CSM_FALSE;
1416 return(CSM_FALSE);
1417 };
1418 fclose(f);
1419
1420 func->type= CSM_1D_TABLE;
1421
1422 coordinate_sort(&(ft->x));
1423 coordinate_update_backlinks(&(ft->x), &(ft->y));
1424 coordinate_sort(&(ft->y));
1425 coordinate_update_backlinks(&(ft->y), &(ft->x));
1426 func->on_hold= CSM_FALSE;
1427 return(CSM_TRUE);
1428 }
1429
1431/* file format:
1432 y1 y2 y3 ..
1433x1 z11 z12 z13 ...
1434x2 z21 z22 z23 ...
1435. . . .
1436. . . .
1437. . . .
1438*/
1439 { char line[1024];
1440 long pos;
1441 long i,j,lines,errcount;
1442 double *buffer;
1443 double *zptr;
1444 csm_2d_functiontable *ft= &(func->f.tf_2);
1445 csm_coordinate *xc, *yc;
1446 FILE *f;
1447 int columns,rows;
1448
1449 if (NULL==(f=fopen(filename,"r"))) /* vxworks doesn't accept "rt" */
1450 { DBG_MSG_PRINTF2("error in csm_read_xytable line %d,\n" \
1451 "file open error!\n", __LINE__);
1452 return(CSM_FALSE);
1453 };
1454
1455 if (NULL==fgets(line, 1024, f))
1456 { fclose(f);
1457 return(CSM_FALSE);
1458 };
1459
1460 columns= strdoublescan(line, NULL, 512);
1461 if (columns<1)
1462 { fclose(f);
1463 return(CSM_FALSE);
1464 };
1465 if (NULL==(buffer= malloc(sizeof(double)*(columns+1))))
1466 { DBG_MSG_PRINTF2("MALLOC FAILED in file %s\n",__FILE__);
1467 fclose(f);
1468 return(CSM_FALSE);
1469 };
1470 if (columns!= (i= strdoublescan(line, buffer, columns)))
1471 { DBG_MSG_PRINTF3("unexpected err in line %d in file %s\n",
1472 __LINE__,__FILE__);
1473 free(buffer);
1474 fclose(f);
1475 return(CSM_FALSE);
1476 };
1477
1478 SEMTAKE(func->semaphore);
1479 func->on_hold= CSM_TRUE;
1480 SEMGIVE(func->semaphore);
1481
1482 reinit_function(func);
1483 init_2d_functiontable(ft);
1484
1485 if (!alloc_coordinates(&(ft->y), columns))
1486 { free(buffer);
1487 reinit_function(func);
1488 fclose(f);
1489 func->on_hold= CSM_FALSE;
1490 return(CSM_FALSE);
1491 };
1492
1493 yc= (ft->y).coordinate;
1494
1495 /* copy y-values into the csm_table_function - structure */
1496 { double *r= buffer;
1497 csm_coordinate *c= yc;
1498 for(i=0; i< columns; i++, c++, r++ )
1499 { c->value= *r;
1500 c->index= i;
1501 };
1502 };
1503
1504 pos= ftell(f);
1505 for(lines=0; NULL!=fgets(line, 1024, f); lines++);
1506 if (-1==fseek(f, pos, SEEK_SET))
1507 { free(buffer);
1508 reinit_function(func);
1509 fclose(f);
1510 func->on_hold= CSM_FALSE;
1511 return(CSM_FALSE);
1512 };
1513 rows= lines;
1514
1515 if (!alloc_coordinates(&(ft->x), rows))
1516 { free(buffer);
1517 reinit_function(func);
1518 fclose(f);
1519 func->on_hold= CSM_FALSE;
1520 return(CSM_FALSE);
1521 };
1522
1523 xc= (ft->x).coordinate;
1524
1525 if (!init_matrix(&(ft->z), rows, columns))
1526 { free(buffer);
1527 reinit_function(func);
1528 fclose(f);
1529 func->on_hold= CSM_FALSE;
1530 return(CSM_FALSE);
1531 };
1532
1533 zptr= ft->z;
1534
1535 for(errcount=0, i=0; (lines>0) && (NULL!=fgets(line, 1024, f)); lines--)
1536 {
1537 if (str_empty_or_comment(line))
1538 continue;
1539 if (columns+1 != strdoublescan(line, buffer, columns+1))
1540 { DBG_MSG_PRINTF5("warning[%s:%d]: the following line of the "
1541 "data-file (%s) was not understood:\n%s\n",
1542 __FILE__,__LINE__,filename,line);
1543 if (++errcount<4)
1544 continue;
1545 fclose(f);
1546 reinit_function(func);
1547 func->on_hold= CSM_FALSE;
1548 DBG_MSG_PRINTF3("error[%s:%d]: too many errors in file\n",
1549 __FILE__,__LINE__);
1550 return(CSM_FALSE);
1551 };
1552
1553 xc->value= buffer[0];
1554 xc->index= i;
1555
1556 zptr= &((ft->z)[i*columns]);
1557 for (j=0; j<columns; j++)
1558 zptr[j]= buffer[j+1];
1559
1560 i++, xc++;
1561 };
1562
1563 if (i<=0)
1564 { free(buffer);
1565 reinit_function(func);
1566 fclose(f);
1567 func->on_hold= CSM_FALSE;
1568 DBG_MSG_PRINTF3("error[%s:%d]: no data was found at all\n",
1569 __FILE__,__LINE__);
1570 return(CSM_FALSE);
1571 };
1572
1573 rows= i;
1574 if (!resize_coordinates(&(ft->x), rows))
1575 { free(buffer);
1576 reinit_function(func);
1577 fclose(f);
1578 func->on_hold= CSM_FALSE;
1579 return(CSM_FALSE);
1580 };
1581
1582 fclose(f);
1583 free(buffer);
1584
1585 func->type= CSM_2D_TABLE;
1586
1587 coordinate_sort(&(ft->x));
1588 coordinate_sort(&(ft->y));
1589 func->on_hold= CSM_FALSE;
1590 return(CSM_TRUE);
1591 }
1592
1593
1594 /* initialize the module (public) */
1595
1596void csm_init(void)
1597 {
1598 if (initialized)
1599 return;
1600 initialized= CSM_TRUE;
1601#if USE_DBG
1602 csm_dbg_init();
1603#endif
1604 }
1605
1606 /* create a new function object */
1607
1609 {
1610 csm_function *f= malloc(sizeof(csm_function));
1611
1612 if (f==NULL)
1613 return(NULL);
1614
1615 f->type= CSM_NOTHING;
1616 f->last_x = 0;
1617 f->last_y = 0;
1618 f->last_dx= 0;
1619 f->last_dy= 0;
1620 f->last_z = 0;
1621 f->on_hold= CSM_FALSE;
1622 if (SEMCREATE(f->semaphore))
1623 { free(f);
1624 return(NULL);
1625 };
1626 return((csm_function *)f);
1627 }
1628
1629 /*----------------------------------------------------*/
1630 /* debugging (public) */
1631 /*----------------------------------------------------*/
1632
1639static void csm_pr_coordinates(csm_coordinates *c)
1640 { int i;
1641 printf("no . of elements: %d\n", c->no_of_elements);
1642 if (c->a_last==-1)
1643 printf("(still in initial-state)\n");
1644 else
1645 { printf("a_last:%d b_last:%d\n",
1646 c->a_last, c->b_last);
1647 };
1648 for(i=0; i< c->no_of_elements; i++)
1649 printf(" [%03d]: %12f --> %3d\n",
1650 i,(c->coordinate)[i].value,(c->coordinate)[i].index);
1651 }
1652
1660static void csm_pr_1d_table_elm(csm_1d_functiontable *t, int index)
1661 {
1662 /* print (x,y) in the order of the x coordinates. */
1663 csm_coordinate xc= (t->x).coordinate[index];
1664 printf("x: %15f y: %15f\n",
1665 xc.value, ((t->y).coordinate)[xc.index].value);
1666 }
1667
1674static void csm_pr_linear(csm_linear_function *lf)
1675 { printf("a:%f b:%f (y=a+b*x)\n", lf->a, lf->b); }
1676
1683static void csm_pr_1d_table(csm_1d_functiontable *tf)
1684 { int i;
1685 int l= (tf->x).no_of_elements;
1686
1687 if (tf->x.a_last==-1)
1688 printf("x-coord is still in initial-state\n");
1689 else
1690 printf("x-a_last:%d x-b_last:%d\n", tf->x.a_last, tf->x.b_last);
1691 if (tf->y.a_last==-1)
1692 printf("x-coord is still in initial-state\n");
1693 else
1694 printf("y-a_last:%d y-b_last:%d\n", tf->y.a_last, tf->y.b_last);
1695 printf("number of elements: %d\n", l);
1696 for(i=0; i<l; i++)
1697 csm_pr_1d_table_elm( tf, i);
1698 }
1699
1706static void csm_pr_2d_table(csm_2d_functiontable *ft)
1707 { int i,j;
1708 int rows = ft->x.no_of_elements;
1709 int columns= ft->y.no_of_elements;
1710 double *z= ft->z;
1711 csm_coordinate *xc= ft->x.coordinate;
1712 csm_coordinate *yc= ft->y.coordinate;
1713
1714 printf("rows:%d columns:%d\n",
1715 rows, columns);
1716 printf("%18s"," ");
1717 for (j=0; j<columns; j++)
1718 printf("%15f | ", yc[j].value);
1719 printf("\n");
1720 printf("------------------");
1721 for (j=0; j<columns; j++)
1722 { printf("---------------"); };
1723 for(i=0; i<rows; i++)
1724 { printf("%15f | ", xc[i].value);
1725 for (j=0; j<columns; j++)
1726 printf("%15f | ", z[columns*i+j]);
1727 printf("\n");
1728 };
1729 }
1730
1732 { if (func->on_hold)
1733 printf("function is on hold!\n");
1734 else
1735 printf("function is operational\n");
1736
1737 printf("Last calculated values: x:%f y:%f z:%f dx:%f dy%f\n",
1738 func->last_x, func->last_y, func->last_z,
1739 func->last_dx, func->last_dy);
1740
1741 printf("function type: \n");
1742 switch( func->type)
1743 { case CSM_NOTHING:
1744 printf("CSM_NOTHING\n");
1745 break;
1746 case CSM_LINEAR:
1747 printf("CSM_LINEAR\n");
1748 csm_pr_linear(&(func->f.lf));
1749 break;
1750 case CSM_1D_TABLE:
1751 printf("CSM_1D TABLE\n");
1752 printf("normal function:\n");
1753 csm_pr_1d_table(&(func->f.tf_1));
1754 break;
1755 case CSM_2D_TABLE:
1756 printf("CSM_2D_TABLE\n");
1757 csm_pr_2d_table(&(func->f.tf_2));
1758 break;
1759 default:
1760 printf("%d (unknown)\n", func->type);
1761 break;
1762 };
1763 }
#define CSM_FALSE
for type csm_bool
Definition csmbase.c:146
#define CSM_TRUE
for type csm_bool
Definition csmbase.c:143
void csm_free(csm_function *func)
free a function-structure
Definition csmbase.c:1236
csm_bool csm_def_linear_offset(csm_function *func, double a)
re-define the offset of a linear function
Definition csmbase.c:1259
double csm_dy(csm_function *func, double x)
compute delta-y from a given delta-x
Definition csmbase.c:1083
csm_bool csm_read_2d_table(char *filename, csm_function *func)
read parameters of two-dimensional function table
Definition csmbase.c:1430
void csm_def_linear(csm_function *func, double a, double b)
define a linear function
Definition csmbase.c:1244
double csm_x(csm_function *func, double y)
compute x from a given y
Definition csmbase.c:1000
csm_function * csm_new_function(void)
create a new function object
Definition csmbase.c:1608
void csm_pr_func(csm_function *func)
dump a new function object
Definition csmbase.c:1731
void csm_clear(csm_function *func)
clear a function
Definition csmbase.c:1224
csm_bool csm_fill_1d_table(double *x, double *y, int len, csm_function *func)
fill one-dimensional function table from double arrays.
Definition csmbase.c:1273
csm_bool csm_read_1d_table(char *filename, csm_function *func)
read parameters of one-dimensional function table
Definition csmbase.c:1325
double csm_dx(csm_function *func, double y)
compute delta-x from a given delta-y
Definition csmbase.c:1062
double csm_z(csm_function *func, double x, double y)
compute z from a given x and y
Definition csmbase.c:1104
void csm_init(void)
initialize the module
Definition csmbase.c:1596
double csm_y(csm_function *func, double x)
compute y from a given x
Definition csmbase.c:1031
interface for csmbase.c
int csm_bool
the boolean data type used in this module
Definition csmbase.h:17
struct csm_Function csm_function
the abstract csm function object
Definition csmbase.h:19