]> git.sesse.net Git - vlc/blob - modules/control/motionlib.c
Simple channel mixer: move the decision logic to the Open function
[vlc] / modules / control / motionlib.c
1 /*****************************************************************************
2  * motion.c: laptop built-in motion sensors
3  *****************************************************************************
4  * Copyright (C) 2006 - 2012 the VideoLAN team
5  * $Id$
6  *
7  * Author: Sam Hocevar <sam@zoy.org>
8  *         Jérôme Decoodt <djc@videolan.org> (unimotion integration)
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <assert.h>
30 #include <math.h>
31 #include <unistd.h>
32
33 #include <vlc_common.h>
34
35 #ifdef __APPLE__
36 # include "TargetConditionals.h"
37 # if !TARGET_OS_IPHONE
38 #  define HAVE_MACOS_UNIMOTION
39 # endif
40 #endif
41
42 #ifdef HAVE_MACOS_UNIMOTION
43 # include "unimotion.h"
44 #endif
45
46 #include "motionlib.h"
47
48 struct motion_sensors_t
49 {
50     enum { HDAPS_SENSOR, AMS_SENSOR, APPLESMC_SENSOR,
51            UNIMOTION_SENSOR } sensor;
52 #ifdef HAVE_MACOS_UNIMOTION
53     enum sms_hardware unimotion_hw;
54 #endif
55     int i_calibrate;
56
57     int p_oldx[16];
58     int i;
59     int i_sum;
60 };
61
62 motion_sensors_t *motion_create( vlc_object_t *obj )
63 {
64     FILE *f;
65     int i_x = 0, i_y = 0;
66
67     motion_sensors_t *motion = malloc( sizeof( motion_sensors_t ) );
68     if( unlikely( motion == NULL ) )
69     {
70         return NULL;
71     }
72
73     if( access( "/sys/devices/platform/hdaps/position", R_OK ) == 0 
74         && ( f = fopen( "/sys/devices/platform/hdaps/calibrate", "r" ) ) )
75     {
76         /* IBM HDAPS support */
77         motion->i_calibrate = fscanf( f, "(%d,%d)", &i_x, &i_y ) == 2 ? i_x: 0;
78         fclose( f );
79         motion->sensor = HDAPS_SENSOR;
80         msg_Dbg( obj, "HDAPS motion detection correctly loaded" );
81     }
82     else if( access( "/sys/devices/ams/x", R_OK ) == 0 )
83     {
84         /* Apple Motion Sensor support */
85         motion->sensor = AMS_SENSOR;
86         msg_Dbg( obj, "AMS motion detection correctly loaded" );
87     }
88     else if( access( "/sys/devices/platform/applesmc.768/position", R_OK ) == 0 
89              && ( f = fopen( "/sys/devices/platform/applesmc.768/calibrate", "r" ) ) )
90     {
91         /* Apple SMC (newer macbooks) */
92         /* Should be factorised with HDAPS */
93         motion->i_calibrate = fscanf( f, "(%d,%d)", &i_x, &i_y ) == 2 ? i_x: 0;
94         fclose( f );
95         motion->sensor = APPLESMC_SENSOR;
96         msg_Dbg( obj, "Apple SMC motion detection correctly loaded" );
97     }
98 #ifdef HAVE_MACOS_UNIMOTION
99     else if( (motion->unimotion_hw = detect_sms()) )
100     {
101         motion->sensor = UNIMOTION_SENSOR;
102         msg_Dbg( obj, "UniMotion motion detection correctly loaded" );
103     }
104 #endif
105     else
106     {
107         /* No motion sensor support */
108         msg_Err( obj, "No motion sensor available" );
109         free( motion );
110         return NULL;
111     }
112
113     memset( motion->p_oldx, 0, sizeof( motion->p_oldx ) );
114     motion->i = 0;
115     motion->i_sum = 0;
116     return motion;
117 }
118
119 void motion_destroy( motion_sensors_t *motion )
120 {
121     free( motion );
122 }
123
124 /*****************************************************************************
125  * GetOrientation: get laptop orientation, range -1800 / +1800
126  *****************************************************************************/
127 static int GetOrientation( motion_sensors_t *motion )
128 {
129     FILE *f;
130     int i_x = 0, i_y = 0, i_z = 0;
131     int i_ret;
132
133     switch( motion->sensor )
134     {
135     case HDAPS_SENSOR:
136         f = fopen( "/sys/devices/platform/hdaps/position", "r" );
137         if( !f )
138         {
139             return 0;
140         }
141
142         i_ret = fscanf( f, "(%d,%d)", &i_x, &i_y );
143         fclose( f );
144
145         if( i_ret < 2 )
146             return 0;
147         else
148             return ( i_x - motion->i_calibrate ) * 10;
149
150     case AMS_SENSOR:
151         f = fopen( "/sys/devices/ams/x", "r" );
152         if( !f )
153         {
154             return 0;
155         }
156
157         i_ret = fscanf( f, "%d", &i_x);
158         fclose( f );
159
160         if( i_ret < 1 )
161             return 0;
162         else
163             return - i_x * 30; /* FIXME: arbitrary */
164
165     case APPLESMC_SENSOR:
166         f = fopen( "/sys/devices/platform/applesmc.768/position", "r" );
167         if( !f )
168         {
169             return 0;
170         }
171
172         i_ret = fscanf( f, "(%d,%d,%d)", &i_x, &i_y, &i_z );
173         fclose( f );
174
175         if( i_ret < 3 )
176             return 0;
177         else
178             return ( i_x - motion->i_calibrate ) * 10;
179
180 #ifdef HAVE_MACOS_UNIMOTION
181     case UNIMOTION_SENSOR:
182         if( read_sms_raw( motion->unimotion_hw, &i_x, &i_y, &i_z ) )
183         {
184             double d_norm = sqrt( i_x*i_x+i_z*i_z );
185             if( d_norm < 100 )
186                 return 0;
187             double d_x = i_x / d_norm;
188             if( i_z > 0 )
189                 return -asin(d_x)*3600/3.141;
190             else
191                 return 3600 + asin(d_x)*3600/3.141;
192         }
193         else
194             return 0;
195 #endif
196     default:
197         assert( 0 );
198     }
199 }
200
201 /*****************************************************************************
202  * motion_get_angle: get averaged laptop orientation, range -1800 / +1800
203  *****************************************************************************/
204 int motion_get_angle( motion_sensors_t *motion )
205 {
206     const int filter_length = ARRAY_SIZE( motion->p_oldx );
207     int i_x = GetOrientation( motion );
208
209     motion->i_sum += i_x - motion->p_oldx[motion->i];
210     motion->p_oldx[motion->i] = i_x;
211     motion->i = ( motion->i + 1 ) % filter_length;
212     i_x = motion->i_sum / filter_length;
213
214     return i_x;
215 }
216