/* * Copyright 2007-2008 Volker Fritzsch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package motej; import java.io.IOException; import java.util.concurrent.ConcurrentLinkedQueue; import javax.bluetooth.L2CAPConnection; import javax.microedition.io.Connector; import motej.request.MoteRequest; import motej.request.PlayerLedRequest; import motej.request.RumbleRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * <p> * @author <a href="mailto:vfritzsch@users.sourceforge.net">Volker Fritzsch</a> */ class OutgoingThread extends Thread { private static final long THREAD_SLEEP = 10l; private Logger log = LoggerFactory.getLogger(OutgoingThread.class); private volatile boolean active; private L2CAPConnection outgoing; private volatile ConcurrentLinkedQueue<MoteRequest> requestQueue; private byte ledByte; private long rumbleMillis = Long.MIN_VALUE; private Mote source; protected OutgoingThread(Mote source, String btaddress) throws IOException, InterruptedException { super("out:" + btaddress); this.source = source; String l2cap = "btl2cap://" + btaddress + ":11;authenticate=false;encrypt=false;master=false"; if (log.isDebugEnabled()) { log.debug("Opening outgoing connection to " + l2cap); } outgoing = (L2CAPConnection) Connector.open(l2cap, Connector.WRITE, true); if (log.isDebugEnabled()) { log.debug("Outgoing connection is " + outgoing.toString()); } requestQueue = new ConcurrentLinkedQueue<MoteRequest>(); Thread.sleep(THREAD_SLEEP); active = true; } public void disconnect() { active = false; } public void run() { while (active || !requestQueue.isEmpty()) { try { if (rumbleMillis > 0) { rumbleMillis -= THREAD_SLEEP; } if (rumbleMillis == 0) { rumbleMillis = Long.MIN_VALUE; outgoing.send(RumbleRequest.getStopRumbleBytes(ledByte)); Thread.sleep(THREAD_SLEEP); continue; } if (!requestQueue.isEmpty()) { MoteRequest request = requestQueue.poll(); if (request instanceof PlayerLedRequest) { ledByte = ((PlayerLedRequest) request).getLedByte(); } if (request instanceof RumbleRequest) { ((RumbleRequest)request).setLedByte(ledByte); rumbleMillis = ((RumbleRequest) request).getMillis(); } if (log.isTraceEnabled()) { byte[] buf = request.getBytes(); StringBuffer sb = new StringBuffer(); log.trace("sending:"); for (int i = 0; i < buf.length; i++) { String hex = Integer.toHexString(buf[i] & 0xff); sb.append(hex.length() == 1 ? "0x0" : "0x").append(hex).append(" "); if ((i + 1) % 8 == 0) { log.trace(sb.toString()); sb.delete(0, sb.length()); } } if (sb.length() > 0) { log.trace(sb.toString()); } } outgoing.send(request.getBytes()); } Thread.sleep(THREAD_SLEEP); } catch (InterruptedException ex) { ex.printStackTrace(); } catch (IOException ex) { log.error("connection closed?", ex); active = false; source.fireMoteDisconnectedEvent(); } } try { outgoing.close(); } catch (IOException ex) { log.error(ex.getMessage(), ex); } } public void sendRequest(MoteRequest request) { requestQueue.add(request); } }