fix default calibration file path for boards with '/' in name
[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, const comedi_calibration_t *parsed_file,
31         unsigned int cal_index );
32
33 static int check_cal_file( comedi_t *dev, const comedi_calibration_t *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( const comedi_calibration_t *parsed_file,
53         unsigned int cal_index, unsigned int channel )
54 {
55         int num_channels, i;
56
57         num_channels = parsed_file->settings[ cal_index ].num_channels;
58         if( num_channels == 0 ) return 1;
59         for( i = 0; i < num_channels; i++ )
60         {
61                 if( parsed_file->settings[ cal_index ].channels[ i ] == channel )
62                         return 1;
63         }
64
65         return 0;
66 }
67
68 static inline int valid_range( const comedi_calibration_t *parsed_file,
69         unsigned int cal_index, unsigned int range )
70 {
71         int num_ranges, i;
72
73         num_ranges = parsed_file->settings[ cal_index ].num_ranges;
74         if( num_ranges == 0 ) return 1;
75         for( i = 0; i < num_ranges; i++ )
76         {
77                 if( parsed_file->settings[ cal_index ].ranges[ i ] == range )
78                         return 1;
79         }
80
81         return 0;
82 }
83
84 static inline int valid_aref( const comedi_calibration_t *parsed_file,
85         unsigned int cal_index, unsigned int aref )
86 {
87         int num_arefs, i;
88
89         num_arefs = parsed_file->settings[ cal_index ].num_arefs;
90         if( num_arefs == 0 ) return 1;
91         for( i = 0; i < num_arefs; i++ )
92         {
93                 if( parsed_file->settings[ cal_index ].arefs[ i ] == aref )
94                         return 1;
95         }
96
97         return 0;
98 }
99
100 static int apply_calibration( comedi_t *dev, const comedi_calibration_t *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_settings;
107
108         for( i = 0; i < num_cals; i++ )
109         {
110                 if( parsed_file->settings[ 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, const comedi_calibration_t *parsed_file,
129         unsigned int cal_index )
130 {
131         int i, retval, num_caldacs;
132
133         num_caldacs = parsed_file->settings[ 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                 comedi_caldac_t caldac;
139
140                 caldac = parsed_file->settings[ 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_ALIAS_DEFAULT(_comedi_apply_parsed_calibration,comedi_apply_parsed_calibration,0.7.20);
152 int _comedi_apply_parsed_calibration( comedi_t *dev, unsigned int subdev, unsigned int channel,
153         unsigned int range, unsigned int aref, const comedi_calibration_t *calibration )
154 {
155         int retval;
156
157         retval = check_cal_file( dev, calibration );
158         if( retval < 0 ) return retval;
159
160         retval = apply_calibration( dev, calibration, subdev, channel, range, aref );
161         return retval;
162 }
163
164 /* munge characters in board name that will cause problems with file paths */
165 static void fixup_board_name( char *name )
166 {
167         while( ( name = strchr( name, '/' ) ) )
168                 if( name ) *name = '-';
169 }
170
171 EXPORT_ALIAS_DEFAULT(_comedi_get_default_calibration_path,comedi_get_default_calibration_path,0.7.20);
172 char* _comedi_get_default_calibration_path( comedi_t *dev )
173 {
174         struct stat file_stats;
175         char *file_path;
176         char *board_name, *temp;
177         char *driver_name;
178
179         if( fstat( comedi_fileno( dev ), &file_stats ) < 0 )
180         {
181                 COMEDILIB_DEBUG( 3, "failed to get file stats of comedi device file\n" );
182                 return NULL;
183         }
184
185         driver_name = comedi_get_driver_name( dev );
186         if( driver_name == NULL )
187         {
188                 return NULL;
189         }
190         temp = comedi_get_board_name( dev );
191         if( temp == NULL )
192         {
193                 return NULL;
194         }
195         board_name = strdup( temp );
196
197         fixup_board_name( board_name );
198         asprintf( &file_path, "/etc/comedi/calibrations/%s_%s_comedi%li",
199                 driver_name, board_name, ( unsigned long ) minor( file_stats.st_rdev ) );
200
201         free( board_name );
202         return file_path;
203 }
204
205 EXPORT_ALIAS_DEFAULT(_comedi_apply_calibration,comedi_apply_calibration,0.7.20);
206 int _comedi_apply_calibration( comedi_t *dev, unsigned int subdev, unsigned int channel,
207         unsigned int range, unsigned int aref, const char *cal_file_path )
208 {
209         char file_path[ 1024 ];
210         int retval;
211         comedi_calibration_t *parsed_file;
212
213         if( cal_file_path )
214         {
215                 strncpy( file_path, cal_file_path, sizeof( file_path ) );
216         }else
217         {
218                 char *temp;
219
220                 temp = comedi_get_default_calibration_path( dev );
221                 if( temp == NULL ) return -1;
222                 strncpy( file_path, temp, sizeof( file_path ) );
223                 free( temp );
224         }
225
226         parsed_file = comedi_parse_calibration_file( file_path );
227         if( parsed_file == NULL )
228         {
229                 COMEDILIB_DEBUG( 3, "failed to parse calibration file\n" );
230                 return -1;
231         }
232
233         retval = comedi_apply_parsed_calibration( dev, subdev, channel, range, aref, parsed_file );
234
235         comedi_cleanup_calibration( parsed_file );
236
237         return retval;
238 }