OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/file_util.h" | |
6 #include "base/logging.h" | |
7 #include "base/memory/singleton.h" | |
8 #include "base/string_util.h" | |
9 #include "base/stringprintf.h" | |
10 #include "content/browser/sensors/provider_impl.h" | |
11 | |
12 #include <vector> | |
13 | |
14 #include <fcntl.h> | |
15 #include <unistd.h> | |
16 | |
17 // TODO: The thread safety varies from tolerable (normal operation) to | |
18 // non-existent (delete). Need to fix that. | |
19 | |
20 namespace sensors { | |
21 | |
22 class ConnectionImpl : public Connection { | |
23 public: | |
24 ConnectionImpl(ProviderImpl* provider, Listener* listener) | |
25 : provider_(provider), listener_(listener), | |
26 listener_proxy_(base::MessageLoopProxy::CreateForCurrentThread()) { | |
27 } | |
28 | |
29 virtual void Start(Channel channel, const std::string& data) { | |
30 provider_->ConnectionStarted(this, channel, data); | |
31 } | |
32 | |
33 virtual void Stop(Channel channel) { | |
34 provider_->ConnectionStopped(this, channel); | |
35 } | |
36 | |
37 virtual void Close() { | |
38 provider_->ConnectionClosed(this); | |
39 listener_ = NULL; | |
40 } | |
41 | |
42 virtual void FireSensorChanged(Channel channel, const std::string& data) { | |
43 if (!listener_proxy_->BelongsToCurrentThread()) { | |
44 listener_proxy_->PostTask(FROM_HERE, NewRunnableMethod( | |
45 this, &ConnectionImpl::FireSensorChanged, channel, data)); | |
46 return; | |
47 } | |
48 | |
49 if (listener_) | |
50 listener_->SensorChanged(channel, data); | |
51 } | |
52 | |
53 private: | |
54 ProviderImpl* provider_; | |
55 Listener* listener_; | |
56 scoped_refptr<base::MessageLoopProxy> listener_proxy_; | |
57 }; | |
58 | |
59 ProviderImpl* ProviderImpl::GetInstance() { | |
60 return Singleton<ProviderImpl>::get(); | |
61 } | |
62 | |
63 ProviderImpl::ProviderImpl() | |
64 : device_fd_(-1), | |
65 device_buf_end_(0) { | |
66 base::Thread* thread = new base::Thread("sensor provider"); | |
67 thread->Start(); | |
68 | |
69 device_proxy_ = thread->message_loop_proxy(); | |
70 | |
71 device_proxy_->PostTask(FROM_HERE, | |
72 NewRunnableMethod(this, &ProviderImpl::DeviceStart)); | |
73 } | |
74 | |
75 ProviderImpl::~ProviderImpl() { | |
76 DCHECK(device_fd_ == -1); | |
77 } | |
78 | |
79 Connection* ProviderImpl::Open(Listener* listener) { | |
80 ConnectionImpl* conn = new ConnectionImpl(this, listener); | |
81 connections_.AddObserver(conn); | |
82 return conn; | |
83 } | |
84 | |
85 void ProviderImpl::FireSensorChanged(Channel channel, const std::string& data) { | |
86 FOR_EACH_OBSERVER(ConnectionImpl, connections_, FireSensorChanged(channel, dat a)); | |
87 } | |
88 | |
89 void ProviderImpl::DeviceStart() { | |
90 DCHECK(device_proxy_->BelongsToCurrentThread()); | |
91 | |
92 static const char* kDeviceEventPath = "/dev/device0:event0"; | |
93 static const char* kEnableEventPath = | |
94 "/sys/bus/iio/devices/device0:event0/tilt_change_en"; | |
Jói
2011/06/30 19:50:50
This seems device-dependent, or at least POSIX-spe
| |
95 | |
96 int ret; | |
97 | |
98 int fd = open(kDeviceEventPath, O_RDONLY, 0); | |
99 if (fd < 0) { | |
100 LOG(ERROR) << "Failed to open accelerometer: " << strerror(errno); | |
101 LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; | |
102 return; | |
103 } | |
104 | |
105 ret = file_util::WriteFile(FilePath(kEnableEventPath), "1\n", 2); | |
106 if (ret < 0) { | |
107 LOG(ERROR) << "Failed to enable accelerometer: " << strerror(errno); | |
108 LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; | |
109 return; | |
110 } | |
111 | |
112 device_fd_ = fd; | |
113 device_proxy_->PostDelayedTask(FROM_HERE, | |
114 NewRunnableMethod(this, &ProviderImpl::DeviceRead), 1000); | |
115 } | |
116 | |
117 struct iio_event { | |
118 uint32 code; | |
119 uint32 unused; | |
120 uint64 time; | |
121 }; | |
122 | |
123 void ProviderImpl::DeviceRead() { | |
124 DCHECK(device_proxy_->BelongsToCurrentThread()); | |
125 | |
126 if (!DoDeviceRead()) { | |
127 LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; | |
128 return; | |
129 } | |
130 | |
131 device_proxy_->PostTask(FROM_HERE, | |
132 NewRunnableMethod(this, &ProviderImpl::DeviceRead)); | |
133 } | |
134 | |
135 bool ProviderImpl::DoDeviceRead() { | |
136 DCHECK(device_proxy_->BelongsToCurrentThread()); | |
137 DCHECK(device_fd_ != -1); | |
138 | |
139 ssize_t rv = read(device_fd_, device_buf_ + device_buf_end_, | |
140 sizeof(device_buf_) - device_buf_end_); | |
141 if (rv < 0) { | |
142 if (errno == EAGAIN || errno == EWOULDBLOCK) | |
143 return true; // Do not have any data to read | |
144 | |
145 LOG(ERROR) << "Failed to read accelerometer events: " << strerror(errno); | |
146 return false; | |
147 } | |
148 device_buf_end_ += rv; | |
149 | |
150 if (device_buf_end_ < kIIOMessageSize) | |
151 return true; // Do not have a complete message yet | |
152 | |
153 device_buf_end_ = 0; | |
154 | |
155 struct iio_event* event = reinterpret_cast<struct iio_event*>(device_buf_); | |
156 | |
157 // HACK: These orientations are rearranged from their definitions in the | |
158 // accelerometer driver so that the development devices report their | |
159 // orientation correctly. This will eventually be configured in the | |
160 // sensor manager, and the data received by Chrome will be correct. | |
161 ScreenOrientationChange change; | |
162 switch (event->code >> 8) { | |
163 case 0: change.upward = ScreenOrientationChange::TOP; break; | |
164 case 1: change.upward = ScreenOrientationChange::BOTTOM; break; | |
165 case 2: change.upward = ScreenOrientationChange::RIGHT; break; | |
166 case 3: change.upward = ScreenOrientationChange::LEFT; break; | |
167 case 4: change.upward = ScreenOrientationChange::FRONT; break; | |
168 case 5: change.upward = ScreenOrientationChange::BACK; break; | |
169 default: return true; // drop unknown orientation | |
170 } | |
171 | |
172 std::string data(reinterpret_cast<const char*>(&change), sizeof(change)); | |
173 FireSensorChanged(kScreenOrientationChannel, data); | |
174 return true; | |
175 } | |
176 | |
177 void ProviderImpl::DeviceStop() { | |
178 DCHECK(device_proxy_->BelongsToCurrentThread()); | |
179 | |
180 close(device_fd_); | |
181 device_fd_ = -1; | |
182 } | |
183 | |
184 void ProviderImpl::ConnectionClosed(ConnectionImpl* conn) { | |
185 connections_.RemoveObserver(conn); | |
186 } | |
187 | |
188 void ProviderImpl::ConnectionStarted(ConnectionImpl* conn, | |
189 Channel channel, const std::string& data) { | |
190 | |
191 connections_.AddObserver(conn); | |
192 } | |
193 | |
194 void ProviderImpl::ConnectionStopped(ConnectionImpl* conn, Channel channel) { | |
195 connections_.RemoveObserver(conn); | |
196 } | |
197 | |
198 } // namespace sensors | |
OLD | NEW |