1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is mozilla.org code.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Mozilla Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Michael Ventnor <m.ventnor@gmail.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include <unistd.h>
39 :
40 : #include "mozilla/Util.h"
41 :
42 : #include "nsDeviceMotionSystem.h"
43 : #include "nsIServiceManager.h"
44 :
45 : using namespace mozilla;
46 :
47 : typedef struct {
48 : const char* mPosition;
49 : const char* mCalibrate;
50 : nsAccelerometerSystemDriver mToken;
51 : } AccelerometerData;
52 :
53 : static const AccelerometerData gAccelerometers[] = {
54 : // MacBook
55 : {"/sys/devices/platform/applesmc.768/position",
56 : "/sys/devices/platform/applesmc.768/calibrate",
57 : eAppleSensor},
58 : // Thinkpad
59 : {"/sys/devices/platform/hdaps/position",
60 : "/sys/devices/platform/hdaps/calibrate",
61 : eIBMSensor},
62 : // Maemo Fremantle
63 : {"/sys/class/i2c-adapter/i2c-3/3-001d/coord",
64 : NULL,
65 : eMaemoSensor},
66 : // HP Pavilion dv7
67 : {"/sys/devices/platform/lis3lv02d/position",
68 : "/sys/devices/platform/lis3lv02d/calibrate",
69 : eHPdv7Sensor},
70 : };
71 :
72 0 : nsDeviceMotionSystem::nsDeviceMotionSystem() :
73 : mPositionFile(NULL),
74 : mCalibrateFile(NULL),
75 0 : mType(eNoSensor)
76 : {
77 0 : }
78 :
79 0 : nsDeviceMotionSystem::~nsDeviceMotionSystem()
80 : {
81 0 : }
82 :
83 : void
84 0 : nsDeviceMotionSystem::UpdateHandler(nsITimer *aTimer, void *aClosure)
85 : {
86 0 : nsDeviceMotionSystem *self = reinterpret_cast<nsDeviceMotionSystem *>(aClosure);
87 0 : if (!self) {
88 0 : NS_ERROR("no self");
89 0 : return;
90 : }
91 :
92 : float xf, yf, zf;
93 :
94 0 : switch (self->mType) {
95 : case eAppleSensor:
96 : {
97 : int x, y, z, calibrate_x, calibrate_y;
98 0 : fflush(self->mCalibrateFile);
99 0 : rewind(self->mCalibrateFile);
100 :
101 0 : fflush(self->mPositionFile);
102 0 : rewind(self->mPositionFile);
103 :
104 0 : if (fscanf(self->mCalibrateFile, "(%d, %d)", &calibrate_x, &calibrate_y) <= 0)
105 0 : return;
106 :
107 0 : if (fscanf(self->mPositionFile, "(%d, %d, %d)", &x, &y, &z) <= 0)
108 0 : return;
109 :
110 : // In applesmc:
111 : // - the x calibration value is negated
112 : // - a negative z actually means a correct-way-up computer
113 : // - dividing by 255 gives us the intended value of -1 to 1
114 0 : xf = ((float)(x + calibrate_x)) / 255.0;
115 0 : yf = ((float)(y - calibrate_y)) / 255.0;
116 0 : zf = ((float)z) / -255.0;
117 0 : break;
118 : }
119 : case eIBMSensor:
120 : {
121 : int x, y, calibrate_x, calibrate_y;
122 0 : fflush(self->mCalibrateFile);
123 0 : rewind(self->mCalibrateFile);
124 :
125 0 : fflush(self->mPositionFile);
126 0 : rewind(self->mPositionFile);
127 :
128 0 : if (fscanf(self->mCalibrateFile, "(%d, %d)", &calibrate_x, &calibrate_y) <= 0)
129 0 : return;
130 :
131 0 : if (fscanf(self->mPositionFile, "(%d, %d)", &x, &y) <= 0)
132 0 : return;
133 :
134 0 : xf = ((float)(x - calibrate_x)) / 180.0;
135 0 : yf = ((float)(y - calibrate_y)) / 180.0;
136 0 : zf = 1.0f;
137 0 : break;
138 : }
139 : case eMaemoSensor:
140 : {
141 : int x, y, z;
142 0 : fflush(self->mPositionFile);
143 0 : rewind(self->mPositionFile);
144 :
145 0 : if (fscanf(self->mPositionFile, "%d %d %d", &x, &y, &z) <= 0)
146 0 : return;
147 :
148 0 : xf = ((float)x) / -1000.0;
149 0 : yf = ((float)y) / -1000.0;
150 0 : zf = ((float)z) / -1000.0;
151 0 : break;
152 : }
153 : case eHPdv7Sensor:
154 : {
155 : int x, y, z, calibrate_x, calibrate_y, calibrate_z;
156 0 : fflush(self->mCalibrateFile);
157 0 : rewind(self->mCalibrateFile);
158 :
159 0 : fflush(self->mPositionFile);
160 0 : rewind(self->mPositionFile);
161 :
162 0 : if (fscanf(self->mCalibrateFile, "(%d,%d,%d)", &calibrate_x, &calibrate_y, &calibrate_z) <= 0)
163 0 : return;
164 :
165 0 : if (fscanf(self->mPositionFile, "(%d,%d,%d)", &x, &y, &z) <= 0)
166 0 : return;
167 :
168 : // Example data:
169 : //
170 : // Calibration (-4,0,51)
171 : // flat on the table (-5,-2,50)
172 : // Tilted on its left side (-60,0,-4)
173 : // Tilted on its right side (51,1,-1)
174 : // upside down (-2,3,-60)
175 : //
176 : // So assuming the calibration data shows the acceleration
177 : // (1G) measured with the notebook laying flat on the table
178 : // it would mean that our best bet, is to ignore the z-axis
179 : // calibration... We are still way off, but it's hard to
180 : // see how to get better data without doing calibration with
181 : // user intervention (like: Turn your notbook slowly around
182 : // so every edge and the top and bottom points up in turn)
183 :
184 0 : xf = ((float)(x - calibrate_x)) / 60.0;
185 0 : yf = ((float)(y - calibrate_y)) / 60.0;
186 0 : zf = ((float)(z)) / 60.0;
187 0 : break;
188 : }
189 :
190 : case eNoSensor:
191 : default:
192 0 : return;
193 : }
194 :
195 0 : self->DeviceMotionChanged(nsIDeviceMotionData::TYPE_ACCELERATION, xf, yf, zf );
196 : }
197 :
198 0 : void nsDeviceMotionSystem::Startup()
199 : {
200 : // Accelerometers in Linux are used by reading a file (yay UNIX!), which is
201 : // in a slightly different location depending on the driver.
202 0 : for (unsigned int i = 0; i < ArrayLength(gAccelerometers); i++) {
203 0 : if (!(mPositionFile = fopen(gAccelerometers[i].mPosition, "r")))
204 0 : continue;
205 :
206 0 : mType = gAccelerometers[i].mToken;
207 0 : if (gAccelerometers[i].mCalibrate) {
208 0 : mCalibrateFile = fopen(gAccelerometers[i].mCalibrate, "r");
209 0 : if (!mCalibrateFile) {
210 0 : fclose(mPositionFile);
211 0 : mPositionFile = nsnull;
212 0 : return;
213 : }
214 : }
215 :
216 0 : break;
217 : }
218 :
219 0 : if (mType == eNoSensor)
220 0 : return;
221 :
222 0 : mUpdateTimer = do_CreateInstance("@mozilla.org/timer;1");
223 0 : if (mUpdateTimer)
224 0 : mUpdateTimer->InitWithFuncCallback(UpdateHandler,
225 : this,
226 : mUpdateInterval,
227 0 : nsITimer::TYPE_REPEATING_SLACK);
228 : }
229 :
230 0 : void nsDeviceMotionSystem::Shutdown()
231 : {
232 0 : if (mPositionFile) {
233 0 : fclose(mPositionFile);
234 0 : mPositionFile = nsnull;
235 : }
236 :
237 : // Fun fact: writing to the calibrate file causes the
238 : // driver to re-calibrate the accelerometer
239 0 : if (mCalibrateFile) {
240 0 : fclose(mCalibrateFile);
241 0 : mCalibrateFile = nsnull;
242 : }
243 :
244 0 : mType = eNoSensor;
245 :
246 0 : if (mUpdateTimer) {
247 0 : mUpdateTimer->Cancel();
248 0 : mUpdateTimer = nsnull;
249 : }
250 0 : }
251 :
|