Example #1
0
  public static void initialize(String appVersion, boolean debugLogging) {
    if (debugLogging) {
      minimumLogLevel = DEBUG;
    }

    Logger initLogger = getLogger(Logger.class);
    StringBuilder sb = new StringBuilder();
    sb.append("System information:");
    sb.append(Util.NEW_LINE_CHAR);
    sb.append(System.getProperty("os.version"));
    sb.append(", ");
    sb.append(android.os.Build.VERSION.SDK_INT);
    sb.append(", ");
    sb.append(android.os.Build.DEVICE);
    sb.append(", ");
    sb.append(android.os.Build.MODEL);
    sb.append(", ");
    sb.append(android.os.Build.PRODUCT);
    sb.append("; App version: ");
    sb.append(appVersion);

    initLogger.info(sb.toString());
  }
/** Created by matthes on 03.11.15. */
public abstract class AsyncAdapter implements OBDAdapter {

  private static Logger LOGGER = Logger.getLogger(AsyncAdapter.class);

  private static final long DEFAULT_NO_DATA_TIMEOUT = 15000; // *10 for debug
  private final char endOfLineOutput;
  private final char endOfLineInput;
  private CommandExecutor commandExecutor;
  private Subscription dataObservable;
  private AtomicBoolean quirkDisabled = new AtomicBoolean(false);

  public AsyncAdapter(char endOfLineOutput, char endOfLineInput) {
    this.endOfLineOutput = endOfLineOutput;
    this.endOfLineInput = endOfLineInput;
  }

  /**
   * use this method to disable a CommandExecutor quirk.
   *
   * @see {@link #getQuirk()}
   */
  public void disableQuirk() {
    if (!quirkDisabled.getAndSet(true) && commandExecutor != null) {
      commandExecutor.setQuirk(null);
    }
  }

  @Override
  public Observable<Boolean> initialize(InputStream is, OutputStream os) {
    this.commandExecutor =
        new CommandExecutor(
            is, os, Collections.emptySet(), this.endOfLineInput, this.endOfLineOutput);
    this.commandExecutor.setQuirk(getQuirk());

    /** */
    Observable<Boolean> observable =
        Observable.create(
            new Observable.OnSubscribe<Boolean>() {
              @Override
              public void call(final Subscriber<? super Boolean> subscriber) {
                while (!subscriber.isUnsubscribed()) {
                  /** poll the next possible command */
                  BasicCommand cmd = pollNextCommand();
                  if (cmd != null) {
                    try {
                      commandExecutor.execute(cmd);
                    } catch (IOException e) {
                      subscriber.onError(e);
                      subscriber.unsubscribe();
                    }
                  }

                  try {
                    byte[] response = commandExecutor.retrieveLatestResponse();

                    processResponse(response);

                    if (hasEstablishedConnection()) {
                      subscriber.onNext(true);
                      subscriber.onCompleted();
                    }

                  } catch (IOException e) {
                    subscriber.onError(e);
                    subscriber.unsubscribe();
                  } catch (StreamFinishedException e) {
                    subscriber.onError(e);
                    subscriber.unsubscribe();
                  } catch (InvalidCommandResponseException e) {
                    LOGGER.warn(e.getMessage(), e);
                  } catch (NoDataReceivedException e) {
                    LOGGER.warn(e.getMessage(), e);
                  } catch (UnmatchedResponseException e) {
                    LOGGER.warn(e.getMessage(), e);
                  } catch (AdapterSearchingException e) {
                    LOGGER.warn(e.getMessage(), e);
                  }
                }
              }
            });

    return observable;
  }

  protected abstract boolean hasEstablishedConnection();

  /**
   * an implementation can provide a quirk for response parsing/filtering
   *
   * @return a quirk that filters a line of raw data
   */
  protected abstract ResponseQuirkWorkaround getQuirk();

  protected Observable<DataResponse> createDataObservable() {

    Observable<DataResponse> dataObservable =
        Observable.create(
                new Observable.OnSubscribe<DataResponse>() {
                  @Override
                  public void call(Subscriber<? super DataResponse> subscriber) {

                    while (!subscriber.isUnsubscribed()) {
                      /** poll the next possible command */
                      BasicCommand cmd = pollNextCommand();
                      if (cmd != null) {
                        try {
                          commandExecutor.execute(cmd);
                        } catch (IOException e) {
                          subscriber.onError(e);
                          subscriber.unsubscribe();
                        }
                      }

                      /** read the inputstream byte by byte */
                      try {
                        byte[] bytes = commandExecutor.retrieveLatestResponse();

                        try {
                          DataResponse result = processResponse(bytes);

                          /** call our subscriber! */
                          if (result != null) {
                            subscriber.onNext(result);

                            if (LOGGER.isEnabled(Logger.DEBUG)) {
                              if (result instanceof LambdaProbeVoltageResponse) {
                                LOGGER.debug("Received lambda voltage: " + result);
                              }
                            }
                          }
                        } catch (AdapterSearchingException e) {
                          LOGGER.warn("Adapter still searching: " + e.getMessage());
                        } catch (NoDataReceivedException e) {
                          LOGGER.warn("No data received: " + e.getMessage());
                        } catch (InvalidCommandResponseException e) {
                          LOGGER.warn("InvalidCommandResponseException: " + e.getMessage());
                        } catch (UnmatchedResponseException e) {
                          LOGGER.warn("Unmatched response: " + e.getMessage());
                        }

                      } catch (IOException e) {
                        /** IOException signals broken connection, notify subscriber accordingly */
                        subscriber.onError(e);
                        return;
                      } catch (StreamFinishedException e) {
                        /** the stream has ended, notify the subscriber */
                        LOGGER.info("The stream was closed: " + e.getMessage());
                        subscriber.onCompleted();
                        return;
                      }
                    }

                    subscriber.onCompleted();
                  }
                })
            .timeout(DEFAULT_NO_DATA_TIMEOUT, TimeUnit.MILLISECONDS);

    return dataObservable;
  }

  @Override
  public Observable<DataResponse> observe() {
    return createDataObservable();
  }

  /**
   * an async adapter might want to send commands out irregularly or on startup. An implementation
   * can provided a command that should be executed using this method.
   *
   * <p>The returned command gets executed after a valid line of response has been read.
   *
   * @return the command or null if there is no pending
   */
  protected abstract BasicCommand pollNextCommand();

  /**
   * Parse a line of response
   *
   * @param bytes the bytes
   * @return a command instace
   * @throws InvalidCommandResponseException
   * @throws NoDataReceivedException
   * @throws UnmatchedResponseException
   * @throws AdapterSearchingException
   */
  protected abstract DataResponse processResponse(byte[] bytes)
      throws InvalidCommandResponseException, NoDataReceivedException, UnmatchedResponseException,
          AdapterSearchingException;
}