doc: add missing -lm option to command line for compiling tut1
[comedilib.git] / lib / range.c
1 /*
2     lib/range.c
3     functions to manipulate physical unit conversion
4
5     COMEDILIB - Linux Control and Measurement Device Interface Library
6     Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation, version 2.1
11     of the License.
12
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Lesser General Public License for more details.
17
18     You should have received a copy of the GNU Lesser General Public
19     License along with this library; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
21     USA.
22 */
23
24 #include <stdio.h>
25
26 #define __USE_GNU
27
28 #include <math.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <sys/ioctl.h>
35 #include <errno.h>
36 #include <string.h>
37
38 #include "libinternal.h"
39
40
41 /* sometimes we can't find a definition of NAN */
42
43 #ifndef NAN
44 #define NAN \
45   (__extension__ ((union { unsigned char __c[8];                              \
46                            double __d; })                                     \
47                   { { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f } }).__d)
48 #endif
49
50
51 static enum comedi_oor_behavior comedi_oor_is_nan = COMEDI_OOR_NAN;
52
53 EXPORT_ALIAS_DEFAULT(_comedi_set_global_oor_behavior,comedi_set_global_oor_behavior,0.7.18);
54 enum comedi_oor_behavior _comedi_set_global_oor_behavior(
55         enum comedi_oor_behavior behavior)
56 {
57         int old_behavior=comedi_oor_is_nan;
58
59         comedi_oor_is_nan=behavior;
60
61         return old_behavior;
62 }
63
64
65 EXPORT_ALIAS_DEFAULT(_comedi_to_phys,comedi_to_phys,0.7.18);
66 double _comedi_to_phys(lsampl_t data,comedi_range *rng,lsampl_t maxdata)
67 {
68         double x;
69
70         if(!rng)return NAN;
71         if(!maxdata)return NAN;
72
73         if(comedi_oor_is_nan==COMEDI_OOR_NAN && (data==0 || data==maxdata))
74                 return NAN;
75
76         x=data;
77         x/=maxdata;
78         x*=(rng->max-rng->min);
79         x+=rng->min;
80
81         return x;
82 }
83
84 EXPORT_ALIAS_DEFAULT(_comedi_from_phys,comedi_from_phys,0.7.18);
85 lsampl_t _comedi_from_phys(double data,comedi_range *rng,lsampl_t maxdata)
86 {
87         double s;
88
89         if(!rng)return 0;
90         if(!maxdata)return 0;
91
92         s=(data-rng->min)/(rng->max-rng->min)*maxdata;
93         if(s<0)return 0;
94         if(s>maxdata)return maxdata;
95
96         return (lsampl_t)(floor(s+0.5));
97 }
98
99 EXPORT_ALIAS_DEFAULT(_comedi_find_range,comedi_find_range,0.7.18);
100 int _comedi_find_range(comedi_t *it,unsigned int subd,unsigned int chan,unsigned int unit,double min,double max)
101 {
102         unsigned int range_type;
103         int best;
104         comedi_range *range_ptr,*best_ptr;
105         int i;
106         
107         if(!valid_chan(it,subd,chan))return -1;
108
109         range_type=comedi_get_rangetype(it,subd,chan);
110         best=-1;
111         best_ptr=NULL;
112         for(i=0;i<RANGE_LENGTH(range_type);i++){
113                 range_ptr=comedi_get_range(it,subd,chan,i);
114                 if(range_ptr->unit==unit && range_ptr->min<=min && range_ptr->max>=max){
115                         if(best<0 || (range_ptr->max-range_ptr->min) < 
116                            (best_ptr->max-best_ptr->min)){
117                                 best=i;
118                                 best_ptr=range_ptr;
119                         }
120                 }
121         }
122         return best;
123 }
124
125 EXPORT_ALIAS_DEFAULT(_comedi_get_n_ranges,comedi_get_n_ranges,0.7.18);
126 int _comedi_get_n_ranges(comedi_t *it,unsigned int subd,unsigned int chan)
127 {
128         unsigned int range_type;
129
130         if(!valid_chan(it,subd,chan))return -1;
131
132         range_type=comedi_get_rangetype(it,subd,chan);
133         return RANGE_LENGTH(range_type);
134 }
135
136 EXPORT_ALIAS_DEFAULT(_comedi_range_is_chan_specific,comedi_range_is_chan_specific,0.7.18);
137 int _comedi_range_is_chan_specific(comedi_t *it,unsigned int subd)
138 {
139         if(!valid_subd(it,subd)) return -1;
140         return (it->subdevices[subd].subd_flags&SDF_RANGETYPE)?1:0;
141 }
142
143 EXPORT_ALIAS_DEFAULT(_comedi_sampl_to_phys,comedi_sampl_to_phys,0.7.18);
144 int _comedi_sampl_to_phys(double *dest, int dst_stride, sampl_t *src,
145         int src_stride, comedi_range *rng, lsampl_t maxdata, int n)
146 {
147         int oor = 0;
148         int i;
149         double mult;
150
151         if(!rng)return -1;
152         if(!maxdata)return -1;
153
154         mult = (rng->max-rng->min)/maxdata;
155         if(comedi_oor_is_nan==COMEDI_OOR_NAN){
156                 for(i=0;i<n;i++){
157                         if(*src==0 || *src==maxdata){
158                                 oor++;
159                                 *dest=NAN;
160                         }else{
161                                 *dest = rng->min + mult*(*src);
162                         }
163                         dest = ((void *)dest) + dst_stride;
164                         src = ((void *)src) + src_stride;
165                 }
166         }else{
167                 for(i=0;i<n;i++){
168                         if(*src==0 || *src==maxdata){
169                                 oor++;
170                         }
171                         *dest = rng->min + mult*(*src);
172                         dest = ((void *)dest) + dst_stride;
173                         src = ((void *)src) + src_stride;
174                 }
175         }
176
177         return oor;
178 }
179
180 EXPORT_ALIAS_DEFAULT(_comedi_sampl_from_phys,comedi_sampl_from_phys,0.7.18);
181 int _comedi_sampl_from_phys(sampl_t *dest,int dst_stride,double *src,
182         int src_stride, comedi_range *rng, lsampl_t maxdata, int n)
183 {
184         int oor = 0;
185         double mult;
186         int i;
187
188         if(!rng)return -1;
189         if(!maxdata)return -1;
190
191         mult = (maxdata+1)/(rng->max-rng->min);
192         for(i=0;i<n;i++){
193                 *dest=mult*(*src-rng->min);
194                 if(*src<rng->min){
195                         *dest=0;
196                         oor++;
197                 }
198                 if(*src>rng->min){
199                         *dest=maxdata;
200                         oor++;
201                 }
202                 dest = ((void *)dest) + dst_stride;
203                 src = ((void *)src) + src_stride;
204         }
205
206         return oor;
207 }
208