/** * This file is part of WiiuseJ. * * WiiuseJ is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * WiiuseJ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with WiiuseJ. If not, see . */ package wiiusej; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.event.EventListenerList; import wiiusej.values.Calibration; import wiiusej.values.RawAcceleration; import wiiusej.wiiusejevents.utils.EventsGatherer; import wiiusej.wiiusejevents.utils.WiiUseApiListener; import wiiusej.wiiusejevents.wiiuseapievents.WiiUseApiEvent; /** * Class that manages the use of Wiiuse API. * * @author guiguito */ public class WiiUseApiManager extends Thread { private static WiiUseApiManager instance = new WiiUseApiManager(); private final EventListenerList listeners = new EventListenerList(); private Semaphore semaphore = new Semaphore(0); private Wiimote[] wiimotes; private WiiUseApi wiiuse = WiiUseApi.getInstance(); private int connected = -1; private AtomicBoolean running = new AtomicBoolean(false); private boolean leave = false; public static int WIIUSE_STACK_UNKNOWN = 0; public static int WIIUSE_STACK_MS = 1; public static int WIIUSE_STACK_BLUESOLEIL = 2; public static WiiUseApiManager getInstance() { return instance; } /** * Get wiimotes. Load library if necessary. Connect to wiimotes if * necessary. Start polling if necessary. Return an array with the connected * wiimotes. * * @param nb * try to connect nb wiimotes. * @param rumble * make the connected wiimotes rumble. * * @return an array with connected wiimotes or NULL. */ public static Wiimote[] getWiimotes(int nb, boolean rumble) { return getWiimotesPrivate(nb, rumble, false, WIIUSE_STACK_UNKNOWN); } /** * Get wiimotes. Load library if necessary. Connect to wiimotes if * necessary. Start polling if necessary. Return an array with the connected * wiimotes. * * @param nb * try to connect nb wiimotes. * @param rumble * make the connected wiimotes rumble.* * @param stackType * the stack type : WiiUseApiManager.WIIUSE_STACK_UNKNOWN or * WiiUseApiManager.WIIUSE_STACK_MS or * WiiUseApiManager.WIIUSE_STACK_BLUESOLEIL * * @return an array with connected wiimotes or NULL. */ public static Wiimote[] getWiimotes(int nb, boolean rumble, int stackType) { return getWiimotesPrivate(nb, rumble, true, stackType); } /** * Get wiimotes. Load library if necessary. Connect to wiimotes if * necessary. Start polling if necessary. Return an array with the connected * wiimotes. * * @param nb * try to connect nb wiimotes. * @param rumble * make the connected wiimotes rumble.* * @param forceStackType * true if we want to force the stack type. * @param stackType * the stack type : WiiUseApiManager.WIIUSE_STACK_UNKNOWN or * WiiUseApiManager.WIIUSE_STACK_MS or * WiiUseApiManager.WIIUSE_STACK_BLUESOLEIL * * @return an array with connected wiimotes or NULL. */ private synchronized static Wiimote[] getWiimotesPrivate(int nb, boolean rumble, boolean forceStackType, int stackType) { WiiUseApiManager manager = getInstance(); if (manager.leave) return null;// wiiusej definitively stopped if (manager.connected <= 0 && !manager.running.get()) { // connect wiimotes. int nbWiimotes = manager.connectWiimotes(nb, rumble, forceStackType, stackType); manager.wiimotes = new Wiimote[nbWiimotes]; for (int i = 0; i < nbWiimotes; i++) { Wiimote wim = new Wiimote(WiiUseApi.getInstance().getUnId(i), manager); manager.wiimotes[i] = wim; manager.addWiiUseApiListener(wim); } // Set leds on wiimote for (Wiimote wiimote : manager.wiimotes) { int id = wiimote.getId(); if (id % 4 == 0) { wiimote.setLeds(true, true, true, true); } else if (id % 4 == 1) { wiimote.setLeds(true, false, false, false); } else if (id % 4 == 2) { wiimote.setLeds(true, true, false, false); } else if (id % 4 == 3) { wiimote.setLeds(true, true, true, false); } } // make the connected wiimotes rumble if (rumble) { for (Wiimote wiimote : manager.wiimotes) { wiimote.activateRumble(); } try { sleep(500); } catch (InterruptedException e) { } for (Wiimote wiimote : manager.wiimotes) { wiimote.deactivateRumble(); } } } if (manager.connected == 0) {// no wiimote connected // return empty array return new Wiimote[0]; } if (!manager.isAlive())// start wiiuseJ polling manager.start(); manager.semaphore.release(1); return manager.wiimotes; } /** * Connect wiimote and get the number of wiimotes connected. Supposed to be * used once. * * @param nb * try to connect nb wiimotes * @param rumble * make the connected wiimotes rumble * @param forceStackType * true if we want to force the stack type. * @param stackType * the stack type : WiiUseApiManager.WIIUSE_STACK_UNKNOWN or * WiiUseApiManager.WIIUSE_STACK_MS or * WiiUseApiManager.WIIUSE_STACK_BLUESOLEIL * @return 0 if nothing connected or the number of wiimotes connected. */ private int connectWiimotes(int nb, boolean rumble, boolean forceStackType, int stackType) { if (connected <= 0) { int nbWiimotesFound; wiiuse.init(nb); // force bluetooth stack type ? if (forceStackType) setBlueToothstackType(stackType); nbWiimotesFound = wiiuse.find(nb, 3); connected = wiiuse.connect(nbWiimotesFound); return connected; } else {// library not loaded, no wiimotes connected return 0; } } /** * Ask the thread to close a connection. * * @param id * id of the wiimote to disconnect. */ protected void closeConnection(int id) { int index = 0; boolean found = false; while (index < wiimotes.length && !found) { if (wiimotes[index]!=null && wiimotes[index].getId() == id) {// we have a wiimote with this // id // remove the wiimote removeWiiUseApiListener(wiimotes[index]); wiimotes[index] = null; connected--; if (connected == 0) {// stop this thread if there is // no more wiimotes connected. // stop thread running.set(false); } /* Close connection in wiiuse */ wiiuse.closeConnection(index); } index++; } } /** * Get the number of wiimotes connected. * * @return the number of wiimotes connected. */ public static int getNbConnectedWiimotes() { return getInstance().connected; } /** * Stop thread and shutdown wiiuse Api. */ public static void shutdown() { WiiUseApiManager manager = getInstance(); int pastConnected = manager.connected; if (manager.connected > 0) { for (Wiimote wim : manager.wiimotes) { if (wim != null) wim.disconnect(); } } manager.running.set(false); if (pastConnected > 0) { manager.wiiuse.cleanUp(); } } /** * Stop wiiuseJ definitively for this program. It finishes Wiiusej thread * and shutdown wiiuse API. */ public static void definitiveShutdown() { getInstance().leave = true; shutdown(); } /** * Activate the rumble for the wiimote with the given id. * * @param id * id of the wiimote. */ protected void activateRumble(int id) { wiiuse.activateRumble(id); } /** * Deactivate the rumble for the wiimote with the given id. * * @param id * id of the wiimote. */ protected void deactivateRumble(int id) { wiiuse.deactivateRumble(id); } /** * Activate IR Tracking for the wiimote with the given id. * * @param id * id of the wiimote. */ protected void activateIRTRacking(int id) { wiiuse.activateIRTracking(id); } /** * Deactivate IR Tracking for the wiimote with the given id. * * @param id * id of the wiimote. */ protected void deactivateIRTRacking(int id) { wiiuse.deactivateIRTracking(id); } /** * Activate motion sensing for the wiimote with the given id. * * @param id * id of the wiimote. */ protected void activateMotionSensing(int id) { wiiuse.activateMotionSensing(id); } /** * Deactivate motion sensing for the wiimoter with the given id. * * @param id * id of the wiimote. */ protected void deactivateMotionSensing(int id) { wiiuse.deactivateMotionSensing(id); } /** * Activate smoothing the wiimotes with the given id. * * @param id * id of the wiimote. */ protected void activateSmoothing(int id) { wiiuse.activateSmoothing(id); } /** * Deactivate smoothing the wiimotes with the given id. * * @param id * id of the wiimote. */ protected void deactivateSmoothing(int id) { wiiuse.deactivateSmoothing(id); } /** * Activate continuous for the wiimotes with the given id. * * @param id * id of the wiimote. */ protected void activateContinuous(int id) { wiiuse.activateContinuous(id); } /** * Deactivate continuous for the wiimotes with the given id. * * @param id * id of the wiimote. */ protected void deactivateContinuous(int id) { wiiuse.deactivateContinuous(id); } /** * Set leds for the wiimotes with the given id. * * @param id * id of the wiimote * @param l1 * status of led1. True : ON, False : OFF. * @param l2 * status of led2. True : ON, False : OFF. * @param l3 * status of led3. True : ON, False : OFF. * @param l4 * status of led4. True : ON, False : OFF. */ protected void setLeds(int id, boolean l1, boolean l2, boolean l3, boolean l4) { wiiuse.setLeds(id, l1, l2, l3, l4); } /** * Set the orientation threshold for the given id. (minimum angle between * two events) * * @param id * id of the wiimote. * @param th * threshold in degrees. */ protected void setOrientationThreshold(int id, float th) { wiiuse.setOrientThreshold(id, th); } /** * Set the acceleration threshold for the given id. (minimum angle between * two events) * * @param id * id of the wiimote. * @param th * threshold. */ protected void setAccelerationThreshold(int id, int th) { wiiuse.setAccelThreshold(id, th); } /** * Set alpha smoothing for the given id. * * @param id * id of the wiimote. * @param th * threshold. */ protected void setAlphaSmoothing(int id, float th) { wiiuse.setAlphaSmoothing(id, th); } /** * Try to resync with the wiimote by starting a new handshake. * * @param id * id of the wiimote. */ protected void reSync(int id) { wiiuse.reSync(id); } /** * Set screen aspect ratio to 4/3 for the given id. * * @param id * id of the wiimote. */ protected void setScreenAspectRatio43(int id) { wiiuse.setScreenRatio43(id); } /** * Set screen aspect ratio to 16/9 for the given id. * * @param id * id of the wiimote. */ protected void setScreenAspectRatio169(int id) { wiiuse.setScreenRatio169(id); } /** * Set the sensor bar to be above the screen. * * @param id * id of the wiimote. */ protected void setSensorBarAboveScreen(int id) { wiiuse.setSensorBarAboveScreen(id); } /** * Set the sensor bar to be below the screen. * * @param id * id of the wiimote. */ protected void setSensorBarBelowScreen(int id) { wiiuse.setSensorBarBelowScreen(id); } /** * Set virtual resolution. It is used to automatically compute the position * of a cursor on this virtual screen using the sensor bar. These results * come in the IREvent. * * @param id * id of the wiimote. * @param x * x resolution. * @param y * y resolution. */ protected void setVirtualResolution(int id, int x, int y) { wiiuse.setVirtualScreenResolution(id, x, y); } /** * Get Status for the wiimote for the given id. * * @param id * id of the wiimote. */ protected void getStatus(int id) { wiiuse.getStatus(id); } /** * Set the normal and expansion handshake timeouts. * * @param id * the id of the wiimote concerned. * @param normalTimeout * The timeout in milliseconds for a normal read. * @param expansionTimeout * The timeout in millisecondsd to wait for an expansion * handshake. */ protected void setTimeout(int id, short normalTimeout, short expansionTimeout) { wiiuse.setTimeout(id, normalTimeout, expansionTimeout); } /** * Set the IR sensitivity. * * @param id * the id of the wiimote concerned. * @param level * 1-5, same as Wii system sensitivity setting. If the level is < * 1, then level will be set to 1. If the level is > 5, then * level will be set to 5. */ protected void setIrSensitivity(int id, int level) { wiiuse.setIrSensitivity(id, level); } /** * Set the nunchuk orientation threshold for the given id. (minimum angle * between two events) * * @param id * id of the wiimote. * @param th * threshold in degrees. */ protected void setNunchukOrientationThreshold(int id, float th) { wiiuse.setNunchukOrientationThreshold(id, th); } /** * Set the nunchuk acceleration threshold for the given id. (minimum angle * between two events) * * @param id * id of the wiimote. * @param th * threshold. */ protected void setNunchukAccelerationThreshold(int id, int th) { wiiuse.setNunchukAccelerationThreshold(id, th); } /** * Force the bluetooth stack type.(useful only for windows) * * @param type * must be WIIUSE_STACK_UNKNOWN or WIIUSE_STACK_MS or * WIIUSE_STACK_BLUESOLEIL. */ private void setBlueToothstackType(int type) { wiiuse.windowsSetBluetoothStack(type); } @Override public void run() { while (!leave) { try { semaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } if (connected > 0) { running.set(true); EventsGatherer gather = new EventsGatherer(connected); // Start polling and tell the observers when there are Wiimote // events while (running.get() && connected > 0) { /* Polling */ wiiuse.specialPoll(gather); /* deal with events gathered in Wiiuse API */ for (WiiUseApiEvent evt : gather.getEvents()) { if (evt.getWiimoteId() != -1) {// event filled // there is an event notify observers notifyWiiUseApiListener(evt); if (evt.getEventType() == WiiUseApiEvent.DISCONNECTION_EVENT) { // check if it was a disconnection // in this case disconnect the wiimote closeConnection(evt.getWiimoteId()); } } else { System.out .println("There is an event with id == -1 ??? there is a problem !!! : " + evt); } } gather.clearEvents(); } }/* else { if (connected <= 0) { System.out.println("No wiimotes connected !"); } }*/ }// end while true } /** * Add WiiUseApiListener to the listeners list. * * @param listener * a WiiUseApiListener */ protected void addWiiUseApiListener(WiiUseApiListener listener) { listeners.add(WiiUseApiListener.class, listener); } /** * Remove WiiUseApiListener from the listeners list. * * @param listener * a WiiUseApiListener */ protected void removeWiiUseApiListener(WiiUseApiListener listener) { listeners.remove(WiiUseApiListener.class, listener); } /** * Get the list of WiiUseApiListeners. * * @return the list of WiiUseApiListeners. */ protected WiiUseApiListener[] getWiiUseApiListeners() { return listeners.getListeners(WiiUseApiListener.class); } /** * Notify WiiUseApiListeners that an event occured. * * @param evt * GenericEvent occured */ private void notifyWiiUseApiListener(WiiUseApiEvent evt) { for (WiiUseApiListener listener : getWiiUseApiListeners()) { listener.onWiiUseApiEvent(evt); } } /** * Called by the garbage collector at the end. */ protected void finalize() throws Throwable { shutdown(); } }