FileCache: use the cache even when the system clock is wrong
[xcsoar.git] / android / src / IOIOHelper.java
bloba0d9f73b4ab525e7e5ab28bd1512761e70d0d12f
1 /*
2 Copyright_License {
4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 package org.xcsoar;
26 import java.util.Collection;
27 import java.util.LinkedList;
28 import java.util.Iterator;
29 import android.util.Log;
30 import ioio.lib.api.IOIO;
31 import ioio.lib.api.IOIOFactory;
32 import ioio.lib.api.exception.ConnectionLostException;
33 import ioio.lib.api.exception.IncompatibilityException;
35 /**
36 * A utility class which wraps the Java API into an easier API for the
37 * C++ code.
39 final class IOIOHelper extends Thread implements IOIOConnectionHolder {
40 private static final String TAG = "XCSoar";
42 private boolean shutdownFlag;
44 private IOIO ioio_;
46 /**
47 * The IOIO connection that is currently being established. It may
48 * be used by the client thread to cancel the connection.
50 private IOIO connecting;
52 /**
53 * The list of listeners that believe there is no IOIO connection.
55 private Collection<IOIOConnectionListener> closedListeners =
56 new LinkedList<IOIOConnectionListener>();
58 /**
59 * The list of listeners that believe a IOIO connection is
60 * established.
62 private Collection<IOIOConnectionListener> openListeners =
63 new LinkedList<IOIOConnectionListener>();
65 public IOIOHelper() {
66 super("IOIO");
68 start();
71 private synchronized boolean isOpen() {
72 return ioio_ != null;
75 /**
76 * Is the IOIO connection currently in use? If not, it may be
77 * closed eventually.
79 private synchronized boolean isInUse() {
80 return !openListeners.isEmpty() || !closedListeners.isEmpty();
83 public void shutdown() {
84 synchronized(this) {
85 shutdownFlag = true;
87 IOIO ioio = connecting;
88 if (ioio != null)
89 ioio.disconnect();
92 interrupt();
94 try {
95 join();
96 } catch (InterruptedException e) {
100 private static void openListener(IOIOConnectionListener listener, IOIO ioio)
101 throws ConnectionLostException {
102 /* clear this thread's "interrupted" flag, to avoid interrupting
103 the listener */
104 interrupted();
106 try {
107 try {
108 listener.onIOIOConnect(ioio);
109 } catch (InterruptedException e) {
110 /* got an interrupt from another thread; try again */
111 listener.onIOIOConnect(ioio);
113 } catch (InterruptedException e) {
114 Log.e(TAG, "Failed to open IOIO device " + listener, e);
115 } catch (RuntimeException e) {
116 Log.e(TAG, "Failed to open IOIO device " + listener, e);
120 private synchronized void openAllListeners(IOIO ioio)
121 throws ConnectionLostException {
122 for (Iterator<IOIOConnectionListener> i = closedListeners.iterator(); i.hasNext();) {
123 IOIOConnectionListener listener = i.next();
125 openListener(listener, ioio);
127 i.remove();
128 openListeners.add(listener);
132 private synchronized void closeAllListeners() {
133 for (Iterator<IOIOConnectionListener> i = openListeners.iterator(); i.hasNext();) {
134 IOIOConnectionListener listener = i.next();
135 listener.onIOIODisconnect();
137 i.remove();
138 closedListeners.add(listener);
143 * Called by the connection thread to open a connection.
145 private void synchronousOpen() {
146 Log.d(TAG, "open IOIO");
148 IOIO ioio;
150 synchronized(this) {
151 if (shutdownFlag || interrupted())
152 return;
154 connecting = ioio = IOIOFactory.create();
157 try {
158 ioio.waitForConnect();
159 if (ioio.getState() == IOIO.State.CONNECTED) {
160 Log.d(TAG, "IOIO connection established");
162 Log.i(TAG, "IOIO hardware version " +
163 ioio.getImplVersion(IOIO.VersionType.HARDWARE_VER));
164 Log.i(TAG, "IOIO bootloader version " +
165 ioio.getImplVersion(IOIO.VersionType.BOOTLOADER_VER));
166 Log.i(TAG, "IOIO firmware version " +
167 ioio.getImplVersion(IOIO.VersionType.APP_FIRMWARE_VER));
168 Log.i(TAG, "IOIOLib version " +
169 ioio.getImplVersion(IOIO.VersionType.IOIOLIB_VER));
171 ioio.softReset();
173 synchronized(this) {
174 openAllListeners(ioio);
175 ioio_ = ioio;
177 } else {
178 Log.w(TAG, "IOIO connection failed");
179 ioio.disconnect();
181 } catch (ConnectionLostException e) {
182 Log.w(TAG, "IOIO connection lost");
183 ioio.disconnect();
184 } catch (IncompatibilityException e) {
185 Log.e(TAG, "IOIO incompatible", e);
186 ioio.disconnect();
187 } finally {
188 synchronized(this) {
189 connecting = null;
194 private synchronized IOIO steal() {
195 IOIO ioio = this.ioio_;
196 this.ioio_ = null;
197 return ioio;
201 * Called by the connection thread to close the connection.
203 private void synchronousClose() {
204 IOIO ioio = steal();
205 if (ioio == null)
206 return;
208 closeAllListeners();
209 ioio.disconnect();
212 private synchronized boolean handleNewListeners() {
213 if (ioio_ == null || closedListeners.isEmpty())
214 return false;
216 /* another thread has registered new listeners; notify them
217 that a IOIO connection exists */
219 try {
220 openAllListeners(ioio_);
221 } catch (ConnectionLostException e) {
222 Log.w(TAG, "IOIO connection lost");
225 return true;
228 private void idle() {
229 if (interrupted())
230 return;
232 try {
233 if (ioio_ != null) {
234 /* there is a connection: wait for connection error or
235 until Thread.interrupt() gets called */
236 ioio_.waitForDisconnect();
237 Log.w(TAG, "IOIO connection lost");
238 } else {
239 /* there is no connection: wait until Thread.interrupt()
240 gets called */
241 synchronized(this) {
242 /* we're not actually waiting for an Object.notify() call,
243 this is just a dummy call to make this thread idle and
244 interruptible */
245 wait();
248 } catch (InterruptedException e) {
253 * The connection thread.
255 public void run() {
256 while (true) {
257 if (ioio_ != null && (ioio_.getState() != IOIO.State.CONNECTED ||
258 !isInUse()))
259 synchronousClose();
260 else if (ioio_ == null && isInUse() && !shutdownFlag)
261 synchronousOpen();
263 if (shutdownFlag) {
264 synchronousClose();
265 return;
268 if (handleNewListeners())
269 continue;
271 idle();
275 @Override public synchronized void addListener(IOIOConnectionListener l) {
276 closedListeners.add(l);
278 /* ask the thread to initiate a connection or to invoke
279 onIOIOConnect() if the connection is already established */
280 if (connecting == null)
281 interrupt();
284 @Override public synchronized void removeListener(IOIOConnectionListener l) {
285 if (openListeners.remove(l))
286 /* this listener thinks the IOIO connection is established;
287 invoke the onIOIODisconnect() method */
288 l.onIOIODisconnect();
289 else
290 /* no method call necessary */
291 closedListeners.remove(l);
293 if (!isInUse()) {
294 if (isOpen())
295 /* ask the thread to auto-close the connection */
296 interrupt();
298 if (connecting != null)
299 /* cancel the current connect attempt after the last listener
300 got removed */
301 connecting.disconnect();
305 @Override
306 public synchronized void cycleListener(IOIOConnectionListener l) {
307 if (!isOpen())
308 return;
310 if (openListeners.remove(l)) {
311 l.onIOIODisconnect();
312 closedListeners.add(l);
313 } else if (!closedListeners.contains(l))
314 return;
316 /* ask the thread to reopen the listener */
317 interrupt();
321 * @ID: ID of UArt to open (0, 1, 2, 3)
322 * @return: ID of opened UArt or -1 if fail
324 public AndroidPort openUart(int ID, int baud) {
325 return new GlueIOIOPort(this, ID, baud);