fixed comedi_apply_calibration so it applies all matching calibrations
[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 "libinternal.h"
29
30 static int set_calibration( comedi_t *dev, struct calibration_file_contents *parsed_file,
31         unsigned int cal_index );
32
33 static int check_cal_file( comedi_t *dev, struct calibration_file_contents *parsed_file )
34 {
35         if( strcmp( comedi_get_driver_name( dev ), parsed_file->driver_name ) )
36         {
37                 COMEDILIB_DEBUG( 3, "driver name does not match '%s' from calibration file\n",
38                         parsed_file->driver_name );
39                 return -1;
40         }
41
42         if( strcmp( comedi_get_board_name( dev ), parsed_file->board_name ) )
43         {
44                 COMEDILIB_DEBUG( 3, "board name does not match '%s' from calibration file\n",
45                         parsed_file->board_name );
46                 return -1;
47         }
48
49         return 0;
50 }
51
52 static inline int valid_channel( struct calibration_file_contents *parsed_file,
53         unsigned int cal_index, unsigned int channel )
54 {
55         int num_channels, i;
56
57         num_channels = parsed_file->calibrations[ cal_index ].num_channels;
58         if( num_channels == 0 ) return 1;
59         for( i = 0; i < num_channels; i++ )
60         {
61                 if( parsed_file->calibrations[ cal_index ].channels[ i ] == channel )
62                         return 1;
63         }
64
65         return 0;
66 }
67
68 static inline int valid_range( struct calibration_file_contents *parsed_file,
69         unsigned int cal_index, unsigned int range )
70 {
71         int num_ranges, i;
72
73         num_ranges = parsed_file->calibrations[ cal_index ].num_ranges;
74         if( num_ranges == 0 ) return 1;
75         for( i = 0; i < num_ranges; i++ )
76         {
77                 if( parsed_file->calibrations[ cal_index ].ranges[ i ] == range )
78                         return 1;
79         }
80
81         return 0;
82 }
83
84 static inline int valid_aref( struct calibration_file_contents *parsed_file,
85         unsigned int cal_index, unsigned int aref )
86 {
87         int num_arefs, i;
88
89         num_arefs = parsed_file->calibrations[ cal_index ].num_arefs;
90         if( num_arefs == 0 ) return 1;
91         for( i = 0; i < num_arefs; i++ )
92         {
93                 if( parsed_file->calibrations[ cal_index ].arefs[ i ] == aref )
94                         return 1;
95         }
96
97         return 0;
98 }
99
100 static int apply_calibration( comedi_t *dev, struct calibration_file_contents *parsed_file,
101         unsigned int subdev, unsigned int channel, unsigned int range, unsigned int aref )
102 {
103         int num_cals, i, retval;
104         int found_cal = 0;
105
106         num_cals = parsed_file->num_calibrations;
107
108         for( i = 0; i < num_cals; i++ )
109         {
110                 if( parsed_file->calibrations[ i ].subdevice != subdev ) continue;
111                 if( valid_range( parsed_file, i, range ) == 0 ) continue;
112                 if( valid_channel( parsed_file, i, channel ) == 0 ) continue;
113                 if( valid_aref( parsed_file, i, aref ) == 0 ) continue;
114
115                 retval = set_calibration( dev, parsed_file, i );
116                 if( retval < 0 ) return retval;
117                 found_cal = 1;
118         }
119         if( found_cal == 0 )
120         {
121                 COMEDILIB_DEBUG( 3, "failed to find matching calibration\n" );
122                 return -1;
123         }
124
125         return 0;
126 }
127
128 static int set_calibration( comedi_t *dev, struct calibration_file_contents *parsed_file,
129         unsigned int cal_index )
130 {
131         int i, retval, num_caldacs;
132
133         num_caldacs = parsed_file->calibrations[ cal_index ].num_caldacs;
134         COMEDILIB_DEBUG( 4, "num_caldacs %i\n", num_caldacs );
135
136         for( i = 0; i < num_caldacs; i++ )
137         {
138                 struct caldac_setting caldac;
139
140                 caldac = parsed_file->calibrations[ cal_index ].caldacs[ i ];
141                 COMEDILIB_DEBUG( 4, "subdev %i, ch %i, val %i\n", caldac.subdevice,
142                         caldac.channel,caldac.value);
143                 retval = comedi_data_write( dev, caldac.subdevice, caldac.channel,
144                         0, 0, caldac.value );
145                 if( retval < 0 ) return retval;
146         }
147
148         return 0;
149 }
150
151 EXPORT_SYMBOL(comedi_apply_calibration,0.7.20);
152 int comedi_apply_calibration( comedi_t *dev, unsigned int subdev, unsigned int channel,
153         unsigned int range, unsigned int aref, const char *cal_file_path )
154 {
155         struct stat file_stats;
156         char file_path[ 1024 ];
157         int retval;
158         FILE *cal_file;
159         struct calibration_file_contents *parsed_file;
160
161         if( cal_file_path )
162         {
163                 strncpy( file_path, cal_file_path, sizeof( file_path ) );
164         }else
165         {
166                 if( fstat( comedi_fileno( dev ), &file_stats ) < 0 )
167                 {
168                         COMEDILIB_DEBUG( 3, "failed to get file stats of comedi device file\n" );
169                         return -1;
170                 }
171
172                 snprintf( file_path, sizeof( file_path ), "/etc/comedi/calibrations/%s_0x%lx",
173                         comedi_get_board_name( dev ),
174                         ( unsigned long ) file_stats.st_ino );
175         }
176
177         cal_file = fopen( file_path, "r" );
178         if( cal_file == NULL )
179         {
180                 COMEDILIB_DEBUG( 3, "failed to open file\n" );
181                 return -1;
182         }
183
184         parsed_file = parse_calibration_file( cal_file );
185         if( parsed_file == NULL )
186         {
187                 COMEDILIB_DEBUG( 3, "failed to parse calibration file\n" );
188                 return -1;
189         }
190
191         fclose( cal_file );
192
193         retval = check_cal_file( dev, parsed_file );
194         if( retval < 0 )
195         {
196                 cleanup_calibration_parse( parsed_file );
197                 return retval;
198         }
199
200         retval = apply_calibration( dev, parsed_file, subdev, channel, range, aref );
201         if( retval < 0 ) return retval;
202
203         cleanup_calibration_parse( parsed_file );
204
205         return 0;
206 }