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