Created
February 2, 2016 09:00
-
-
Save mr5z/22290e62a2d2ddc10c5a to your computer and use it in GitHub Desktop.
command queue polling service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.kinpo.bcutility; | |
import java.util.LinkedList; | |
import java.util.concurrent.TimeUnit; | |
import com.kinpo.bcutility.settings.Settings.CommandBehavior; | |
import com.kinpo.training.lazyutils.Debug; | |
public class CommandProcessor implements Runnable { | |
private Debug mDebug = new Debug(CommandProcessor.class); | |
private static volatile CommandProcessor mInstance; | |
private ServiceBle mServiceBle; | |
private volatile LinkedList<byte[]> mCommandQueue = new LinkedList<>(); | |
private int mCommandTimedoutCount; | |
private CommandProcessor(ServiceBle serviceBle) { | |
mServiceBle = serviceBle; | |
} | |
public static CommandProcessor getInstance(ServiceBle serviceBle) { | |
/* | |
* return a double-check locking singleton instance | |
* see https://en.wikipedia.org/wiki/Double-checked_locking for reference | |
*/ | |
if ( mInstance == null ) { | |
synchronized(CommandProcessor.class) { | |
if ( mInstance == null ) { | |
mInstance = new CommandProcessor(serviceBle); | |
} | |
} | |
} | |
return mInstance; | |
} | |
@Override | |
public void run() { | |
Debug.log("CQPS has been started"); | |
while( !Thread.currentThread().isInterrupted() ) { | |
pollCommandQueue(); | |
synchronized (this) { | |
try { | |
Debug.log("Waiting for commands..."); | |
wait(); | |
Debug.log("CQPS has been notified"); | |
} | |
catch (IllegalMonitorStateException e) { | |
mDebug.logToFile("An error occurred. This is a bug and must be reported immediately: %s", e.getMessage()); | |
} | |
catch (InterruptedException e) { | |
break; | |
} | |
} | |
} | |
Debug.log("CQPS has been interrupted. Exiting..."); | |
} | |
/** | |
* Adds command to the queue to be polled later | |
* @param command the bytes to be sent in the BLE device | |
*/ | |
public void addCommand(byte[] command) { | |
mCommandQueue.add(command); | |
synchronized (this) { | |
notify(); | |
} | |
} | |
public int getCommandTimedoutCount() { | |
return mCommandTimedoutCount; | |
} | |
public void resetAnalysis() { | |
mCommandTimedoutCount = 0; | |
} | |
private void pollCommandQueue() { | |
while( !mCommandQueue.isEmpty() ) { | |
waitForPendingCommand(); | |
byte[] command = mCommandQueue.poll(); | |
boolean result = false; | |
byte type; | |
try { | |
// the command type is actually in the second index | |
// the firmware doc is wrong! | |
type = command[1]; | |
} | |
catch(Exception e) { | |
mDebug.logToFile("Cannot send the command because it is malformed. Skipping..."); | |
continue; | |
} | |
try { | |
result = mServiceBle.writeCommand(command); | |
mDebug.logToFile("Sending command of type 0x%02x %s", | |
type, (result ? "success" : "fail")); | |
} | |
catch(Exception e) { | |
mDebug.logToFile("An error occurred while sending command 0x%02x: %s", | |
type, e.getMessage()); | |
} | |
} | |
} | |
private void waitForPendingCommand() { | |
while ( mServiceBle.hasPendingCommand() ) { | |
long diff = System.nanoTime() - mServiceBle.getLastCommandIssueDate(); | |
diff = TimeUnit.MILLISECONDS.convert(diff, TimeUnit.NANOSECONDS); | |
long timeout = CommandBehavior.getCommandTimeout(mServiceBle.getApplicationContext()); | |
if ( diff > timeout ) { | |
// timeout! | |
mCommandTimedoutCount++; | |
mDebug.logToFile("Command timed out!"); | |
break; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment