Skip to content

Instantly share code, notes, and snippets.

@mr5z
Created February 2, 2016 09:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mr5z/22290e62a2d2ddc10c5a to your computer and use it in GitHub Desktop.
Save mr5z/22290e62a2d2ddc10c5a to your computer and use it in GitHub Desktop.
command queue polling service
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