OpenHPS/openhps-sphero

View on GitHub
lib/web/src/toys/r2d2.ts

Summary

Maintainability
B
4 hrs
Test Coverage
import { IToyAdvertisement, Stance } from './types';
import { RollableToy } from './rollable-toy';
import { IQueuePayload } from './core';

export class R2D2 extends RollableToy {
  public static advertisement: IToyAdvertisement = {
    name: 'R2-D2',
    prefix: 'D2-',
    class: R2D2
  };

  protected maxVoltage: number = 3.65;
  protected minVoltage: number = 3.4;

  public wake(): Promise<IQueuePayload> {
    return this.queueCommand(this.commands.power.wake());
  }
  public sleep(): Promise<IQueuePayload> {
    return this.queueCommand(this.commands.power.sleep());
  }
  public playAudioFile(idx: number): Promise<IQueuePayload> {
    return this.queueCommand(this.commands.userIo.playAudioFile(idx));
  }

  public turnDome(angle: number): Promise<IQueuePayload> {
    const res = this.calculateDomeAngle(angle);
    return this.queueCommand(this.commands.userIo.turnDome(res));
  }

  public setStance(stance: Stance): Promise<IQueuePayload> {
    return this.queueCommand(this.commands.userIo.setStance(stance));
  }

  public playAnimation(animation: number): Promise<IQueuePayload> {
    return this.queueCommand(this.commands.userIo.playAnimation(animation));
  }

  // TODO: Refractor this and simplify
  // utility calculation for dome rotation
  private calculateDomeAngle(angle: number) {
    const result = new Uint8Array(2);
    switch (angle) {
      case -1:
        result[0] = 0xbf;
        result[1] = 0x80;
        return result;
      case 0:
        result[0] = 0x00;
        result[1] = 0x00;
        return result;
      case 1:
        result[0] = 0x3f;
        result[1] = 0x80;
        return result;
    }
    let uAngle: number = Math.abs(angle);
    const hob = R2D2.hobIndex(uAngle);
    const unshift = Math.min(8 - hob, 6);
    const shift = 6 - unshift;

    // tslint:disable-next-line:no-bitwise
    uAngle = uAngle << unshift;
    if (angle < 0) {
      // tslint:disable-next-line:no-bitwise
      uAngle = 0x8000 | uAngle;
    }

    // tslint:disable-next-line:no-bitwise
    uAngle = 0x4000 | uAngle;

    // tslint:disable-next-line:no-bitwise
    const flagA = (0x04 & shift) >> 2;

    // tslint:disable-next-line:no-bitwise
    const flagB = (0x02 & shift) >> 1;

    // tslint:disable-next-line:no-bitwise
    const flagC = 0x01 & shift;
    if (flagA === 1) {
      // tslint:disable-next-line:no-bitwise
      uAngle |= 1 << 9;
    } else {
      // tslint:disable-next-line:no-bitwise
      uAngle &= uAngle ^ (1 << 9);
    }

    if (flagB === 1) {
      // tslint:disable-next-line:no-bitwise
      uAngle |= 1 << 8;
    } else {
      // tslint:disable-next-line:no-bitwise
      uAngle &= uAngle ^ (1 << 8);
    }

    if (flagC === 1) {
      // tslint:disable-next-line:no-bitwise
      uAngle |= 1 << 7;
    } else {
      // tslint:disable-next-line:no-bitwise
      uAngle &= uAngle ^ (1 << 7);
    }

    // tslint:disable-next-line:no-bitwise
    result[0] = 0x00ff & uAngle;

    // tslint:disable-next-line:no-bitwise
    result[1] = (0xff00 & uAngle) >> 8;

    return result;
  }

  private static hobIndex(val: number) {
    const values = new Uint16Array(2);
    values[1] = 0;
    values[0] = val;
    while (values[0] > 0) {
      // tslint:disable-next-line
      values[0] = values[0] >> 1;
      values[1] = values[1] + 1;
    }
    return values[1];
  }
}