make flex stuff as reentrant as i can
[comedilib.git] / lib / calib.c
1 /*
2     lib/calib.c
3     functions for setting calibration
4
5     Copyright (C) 2003 Frank Mori Hess <fmhess@users.sourceforge.net
6
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License as published by the Free Software Foundation, version 2.1
10     of the License.
11
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.
16
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
20     USA.
21 */
22
23 #define _GNU_SOURCE
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <comedilib.h>
29 #include <libinternal.h>
30
31 static int check_cal_file( comedi_t *dev, struct calibration_file_contents *parsed_file )
32 {
33         if( strcmp( comedi_get_driver_name( dev ), parsed_file->driver_name ) )
34         {
35                 COMEDILIB_DEBUG( 3, "driver name does not match '%s' from calibration file\n",
36                         parsed_file->driver_name );
37                 return -1;
38         }
39
40         if( strcmp( comedi_get_board_name( dev ), parsed_file->board_name ) )
41         {
42                 COMEDILIB_DEBUG( 3, "board name does not match '%s' from calibration file\n",
43                         parsed_file->board_name );
44                 return -1;
45         }
46
47         return 0;
48 }
49
50 static inline int valid_channel( struct calibration_file_contents *parsed_file,
51         unsigned int cal_index, unsigned int channel )
52 {
53         int num_channels, i;
54
55         num_channels = parsed_file->calibrations[ cal_index ].num_channels;
56         if( num_channels == 0 ) return 1;
57         for( i = 0; i < num_channels; i++ )
58         {
59                 if( parsed_file->calibrations[ cal_index ].channels[ i ] == channel )
60                         return 1;
61         }
62
63         return 0;
64 }
65
66 static inline int valid_range( struct calibration_file_contents *parsed_file,
67         unsigned int cal_index, unsigned int range )
68 {
69         int num_ranges, i;
70
71         num_ranges = parsed_file->calibrations[ cal_index ].num_ranges;
72         if( num_ranges == 0 ) return 1;
73         for( i = 0; i < num_ranges; i++ )
74         {
75                 if( parsed_file->calibrations[ cal_index ].ranges[ i ] == range )
76                         return 1;
77         }
78
79         return 0;
80 }
81
82 static inline int valid_aref( struct calibration_file_contents *parsed_file,
83         unsigned int cal_index, unsigned int aref )
84 {
85         int num_arefs, i;
86
87         num_arefs = parsed_file->calibrations[ cal_index ].num_arefs;
88         if( num_arefs == 0 ) return 1;
89         for( i = 0; i < num_arefs; i++ )
90         {
91                 if( parsed_file->calibrations[ cal_index ].arefs[ i ] == aref )
92                         return 1;
93         }
94
95         return 0;
96 }
97
98 static int find_calibration( struct calibration_file_contents *parsed_file,
99         unsigned int subdev, unsigned int channel, unsigned int range, unsigned int aref )
100 {
101         int num_cals, i;
102
103         num_cals = parsed_file->num_calibrations;
104
105         for( i = 0; i < num_cals; i++ )
106         {
107                 if( parsed_file->calibrations[ i ].subdevice != subdev ) continue;
108                 if( valid_range( parsed_file, i, range ) == 0 ) continue;
109                 if( valid_channel( parsed_file, i, channel ) == 0 ) continue;
110                 if( valid_aref( parsed_file, i, aref ) == 0 ) continue;
111                 break;
112         }
113         if( i == num_cals )
114         {
115                 COMEDILIB_DEBUG( 3, "failed to find matching calibration\n" );
116                 return -1;
117         }
118
119         return i;
120 }
121
122 static int set_calibration( comedi_t *dev, struct calibration_file_contents *parsed_file,
123         unsigned int cal_index )
124 {
125         int i, retval, num_caldacs;
126
127         num_caldacs = parsed_file->calibrations[ cal_index ].num_caldacs;
128         COMEDILIB_DEBUG( 4, "num_caldacs %i\n", num_caldacs );
129
130         for( i = 0; i < num_caldacs; i++ )
131         {
132                 struct caldac_setting caldac;
133
134                 caldac = parsed_file->calibrations[ cal_index ].caldacs[ i ];
135                 COMEDILIB_DEBUG( 4, "subdev %i, ch %i, val %i\n", caldac.subdevice,
136                         caldac.channel,caldac.value);
137                 retval = comedi_data_write( dev, caldac.subdevice, caldac.channel,
138                         0, 0, caldac.value );
139                 if( retval < 0 ) return retval;
140         }
141
142         return 0;
143 }
144
145 EXPORT_SYMBOL(comedi_apply_calibration,0.7.20);
146 int comedi_apply_calibration( comedi_t *dev, unsigned int subdev, unsigned int channel,
147         unsigned int range, unsigned int aref, const char *cal_file_path )
148 {
149         struct stat file_stats;
150         char file_path[ 1024 ];
151         int retval;
152         int cal_index;
153         FILE *cal_file;
154         struct calibration_file_contents *parsed_file;
155
156         if( cal_file_path )
157         {
158                 strncpy( file_path, cal_file_path, sizeof( file_path ) );
159         }else
160         {
161                 if( fstat( comedi_fileno( dev ), &file_stats ) < 0 )
162                 {
163                         COMEDILIB_DEBUG( 3, "failed to get file stats of comedi device file\n" );
164                         return -1;
165                 }
166
167                 snprintf( file_path, sizeof( file_path ), "/etc/comedi/calibrations/%s_0x%lx",
168                         comedi_get_board_name( dev ),
169                         ( unsigned long ) file_stats.st_ino );
170         }
171
172         cal_file = fopen( file_path, "r" );
173         if( cal_file == NULL )
174         {
175                 COMEDILIB_DEBUG( 3, "failed to open file\n" );
176                 return -1;
177         }
178
179         parsed_file = parse_calibration_file( cal_file );
180         if( parsed_file == NULL )
181         {
182                 COMEDILIB_DEBUG( 3, "failed to parse calibration file\n" );
183                 return -1;
184         }
185
186         fclose( cal_file );
187
188         retval = check_cal_file( dev, parsed_file );
189         if( retval < 0 )
190         {
191                 cleanup_calibration_parse( parsed_file );
192                 return retval;
193         }
194
195         cal_index = find_calibration( parsed_file, subdev, channel, range, aref );
196         if( cal_index < 0 )
197         {
198                 cleanup_calibration_parse( parsed_file );
199                 return cal_index;
200         }
201
202         retval = set_calibration( dev, parsed_file, cal_index );
203         if( retval < 0 )
204         {
205                 cleanup_calibration_parse( parsed_file );
206                 return retval;
207         }
208
209         return 0;
210 }