void PMU::procDirectDebugInstruction(StringBuilder *input) {
  const char* str = (char *) input->position(0);
  char c    = *str;
  int temp_int = 0;

  if (input->count() > 1) {
    // If there is a second token, we proceed on good-faith that it's an int.
    temp_int = input->position_as_int(1);
  }
  else if (strlen(str) > 1) {
    // We allow a short-hand for the sake of short commands that involve a single int.
    temp_int = atoi(str + 1);
  }

  switch (c) {
    case 'f':
    case 'F':
      cpu_scale(*(str) == 'f' ? 0 : 1);
      break;

    case 'w':
      // Find the current wattage draw.
      break;

    case 'p':
    case 'P':
      // Start or stop the periodic sensor read.
      if (temp_int) {
        _periodic_pmu_read.alterSchedulePeriod(temp_int * 10);
        local_log.concatf("_periodic_pmu_read set to %d ms period.\n", (temp_int * 10));
      }
      _periodic_pmu_read.enableSchedule(*(str) == 'P');
      local_log.concatf("%s _periodic_pmu_read.\n", (*(str) == 'p' ? "Stopping" : "Starting"));
      break;

    case 'e':
      // Read the present battery voltage.
      break;

    case 'm':   // Set the system-wide power mode.
      if (255 != temp_int) {
        ManuvrMsg* event = Kernel::returnEvent(MANUVR_MSG_SYS_POWER_MODE);
        event->addArg((uint8_t) temp_int);
        EventReceiver::raiseEvent(event);
        local_log.concatf("Power mode is now %d.\n", temp_int);
      }
      else {
      }
      break;

    default:
      EventReceiver::procDirectDebugInstruction(input);
      break;
  }

  flushLocalLog();
}
void LegendManager::procDirectDebugInstruction(StringBuilder *input) {
  char* str = input->position(0);

  uint8_t temp_byte = 0;
  if (*(str) != 0) {
    temp_byte = atoi((char*) str+1);
  }

  StringBuilder parse_mule;

  switch (*(str)) {
    case 'v':
      parse_mule.concat(str);
      local_log.concatf("parse_mule split (%s) into %d positions.\n", str, parse_mule.split(","));
      parse_mule.drop_position(0);
      if (temp_byte < 17) {
        if (parse_mule.count() > 0) {
          int temp_int = parse_mule.position_as_int(0);
          iius[temp_byte].setVerbosity(temp_int);
        }
        local_log.concatf("Verbosity on IIU %d is %d.\n", temp_byte, iius[temp_byte].getVerbosity());
      }
      break;

    case 'i':
      if (1 == temp_byte) {
        local_log.concatf("The IIU preallocated measurements are stored at %p.\n", (uintptr_t) __prealloc);
      }
      else if (2 == temp_byte) {
        if (operating_legend) {
          operating_legend->printDebug(&local_log);
        }
      }
      else {
        int8_t old_verbosity = getVerbosity();
        if (temp_byte && (temp_byte < 7)) setVerbosity(temp_byte);
        printDebug(&local_log);
        if (temp_byte && (temp_byte < 7)) setVerbosity(old_verbosity);
      }
      break;

    case '-':
      if (operating_legend) {
        operating_legend->copy_frame();
        local_log.concat("Frame copied.\n");
        operating_legend->printDataset(&local_log);
      }
      break;
    case '+':
      if (temp_byte < 17) {
        iius[temp_byte].dumpPointers(&local_log);
      }
      break;


    // IMU DEBUG //////////////////////////////////////////////////////////////////
    case 'c':
      if (temp_byte < 17) {
        iius[temp_byte].printDebug(&local_log);
      }
      break;

    // IMU STATE CONTROL //////////////////////////////////////////////////////////
    case 'g':
      if (255 == temp_byte) {
        local_log.concat("Syncing all IIUs...\n");
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].sync();
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].sync();
        local_log.concatf("Syncing IIU %d.\n", temp_byte);
      }
      break;

    case 's':
      parse_mule.concat(str);
      parse_mule.split(",");
      parse_mule.drop_position(0);
      if (parse_mule.count() > 0) {
        int temp_int = parse_mule.position_as_int(0);

        if (255 == temp_byte) {
          for (uint8_t i = 0; i < 17; i++) {
            iius[i].setOperatingState(temp_int);
          }
        }
        else if (temp_byte < 17) {
          local_log.concatf("Setting the state of IMU %d to %d\n", temp_byte, temp_int);
          iius[temp_byte].setOperatingState(temp_int);
        }

      }
      break;

    case 'k':
      if ((temp_byte < 6) && (temp_byte >= 0)) {
        ManuvrMsg *event = Kernel::returnEvent(DIGITABULUM_MSG_IMU_INIT);
        event->addArg((uint8_t) temp_byte);  // Set the desired init stage.
        event->priority(0);
        raiseEvent(event);
        local_log.concatf("Broadcasting IMU_INIT for stage %u...\n", temp_byte);
      }
      else {
        local_log.concatf("Illegal INIT stage: %u\n", temp_byte);
      }
      break;

    case 'r':
      if (255 == temp_byte) {
        local_log.concat("Reseting all IIUs...\n");
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].reset();
        }
      }
      else if (temp_byte < 17) {
        local_log.concatf("Resetting IIU %d.\n", temp_byte);
        iius[temp_byte].reset();
      }
      break;


    case 'T':
    case 't':
      if (temp_byte < 17) {
        ManuvrMsg *event = Kernel::returnEvent((*(str) == 'T') ? DIGITABULUM_MSG_IMU_DOUBLE_TAP : DIGITABULUM_MSG_IMU_TAP);
        event->setOriginator((EventReceiver*) this);
        event->addArg((uint8_t) temp_byte);
        Kernel::staticRaiseEvent(event);
        local_log.concatf("Sent %stap event for IMU %d.\n", ((*(str) == 'T') ? "double ":""), temp_byte);
      }
      break;

    case 'q':
      if (temp_byte < 17) {
        ManuvrMsg *event = Kernel::returnEvent(DIGITABULUM_MSG_IMU_QUAT_CRUNCH);
        event->specific_target = (EventReceiver*) this;
        event->addArg((uint8_t) temp_byte);
        Kernel::staticRaiseEvent(event);
        local_log.concatf("Running quat on IIU %d.\n", temp_byte);
      }
      break;



    // IMU DATA ///////////////////////////////////////////////////////////////////
    case 'j':
      switch (*(str+1)) {
        case '0':
          reflection_acc.x = -1;
          reflection_acc.y = 1;
          reflection_acc.z = -1;
          reflection_gyr.set(-1, 1, -1);
          reflection_mag.x = 1;
          reflection_mag.y = 1;
          reflection_mag.z = -1;
          break;
        case 'm':
          if (*(str+2) == 'x')      reflection_mag.x *= -1;
          else if (*(str+2) == 'y') reflection_mag.y *= -1;
          else if (*(str+2) == 'z') reflection_mag.z *= -1;
          break;

        case 'a':
          if (*(str+2) == 'x')      reflection_acc.x *= -1;
          else if (*(str+2) == 'y') reflection_acc.y *= -1;
          else if (*(str+2) == 'z') reflection_acc.z *= -1;
          break;

        case 'g':
          if (*(str+2) == 'x')      reflection_gyr.x *= -1;
          else if (*(str+2) == 'y') reflection_gyr.y *= -1;
          else if (*(str+2) == 'z') reflection_gyr.z *= -1;
          break;
      }
      local_log.concatf("Reflection vectors\n\tMag (%d, %d, %d)\n\tAcc (%d, %d, %d)\n\tGyr (%d, %d, %d)\n", reflection_mag.x, reflection_mag.y, reflection_mag.z, reflection_acc.x, reflection_acc.y, reflection_acc.z, reflection_gyr.x, reflection_gyr.y, reflection_gyr.z);
      break;

    case '[':
    case ']':
      if (255 == temp_byte) {
        local_log.concatf("%sabling spherical abberation correction on all IIUs.\n", ((*(str) == ']') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].correctSphericalAbberation((*(str) == ']'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].correctSphericalAbberation((*(str) == ']'));
        local_log.concatf("%sabling spherical abberation correction on IIU %d.\n", ((*(str) == ']') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'u':
    case 'U':
      if (255 == temp_byte) {
        local_log.concatf("%sabling (clean-mag-is-zero) on all IIUs.\n", ((*(str) == 'U') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].cleanMagZero((*(str) == 'U'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].cleanMagZero((*(str) == 'U'));
        local_log.concatf("%sabling (clean-mag-is-zero) on IIU %d.\n", ((*(str) == 'U') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'w':
    case 'W':
      if (255 == temp_byte) {
        local_log.concatf("%sabling mag data scrutiny on all IIUs.\n", ((*(str) == 'Z') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].dropObviousBadMag((*(str) == 'Z'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].dropObviousBadMag((*(str) == 'Z'));
        local_log.concatf("%sabling mag data scrutiny on IIU %d.\n", ((*(str) == 'Z') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'z':
    case 'Z':
      if (255 == temp_byte) {
        local_log.concatf("%sabling autoscale on all IIUs.\n", ((*(str) == 'Z') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].enableAutoscale((*(str) == 'Z'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].enableAutoscale((*(str) == 'Z'));
        local_log.concatf("%sabling autoscale on IIU %d.\n", ((*(str) == 'Z') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'n':
    case 'N':
      if (255 == temp_byte) {
        local_log.concatf("%sabling range-binding on all IIUs.\n", ((*(str) == 'N') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].rangeBind((*(str) == 'N'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].rangeBind((*(str) == 'N'));
        local_log.concatf("%sabling range-binding on IIU %d.\n", ((*(str) == 'N') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'h':
    case 'H':
      if (255 == temp_byte) {
        local_log.concatf("%sabling quats on all IIUs.\n", ((*(str) == 'H') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].processQuats((*(str) == 'H'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].processQuats((*(str) == 'H'));
        local_log.concatf("%sabling quats on IIU %d.\n", ((*(str) == 'H') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'x':
    case 'X':
      if (255 == temp_byte) {
        local_log.concatf("%sabling gyro error compensation on all IIUs.\n", ((*(str) == 'X') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].nullGyroError((*(str) == 'X'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].nullGyroError((*(str) == 'X'));
        local_log.concatf("%sabling gyro error compensation on IIU %d.\n", ((*(str) == 'X') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'm':
    case 'M':
      if (255 == temp_byte) {
        local_log.concatf("%sabling gravity nullification on all IIUs.\n", ((*(str) == 'M') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].nullifyGravity((*(str) == 'M'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].nullifyGravity((*(str) == 'M'));
        local_log.concatf("%sabling gravity nullification on IIU %d.\n", ((*(str) == 'M') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'y':
    case 'Y':
      if (255 == temp_byte) {
        local_log.concatf("%sabling bearing nullification on all IIUs.\n", ((*(str) == 'Y') ? "En":"Dis"));
        for (uint8_t i = 0; i < 17; i++) {
          iius[i].nullifyBearing((*(str) == 'Y'));
        }
      }
      else if (temp_byte < 17) {
        iius[temp_byte].nullifyBearing((*(str) == 'Y'));
        local_log.concatf("%sabling bearing nullification on IIU %d.\n", ((*(str) == 'Y') ? "En":"Dis"), temp_byte);
      }
      break;

    case 'Q':
      local_log.concatf("Madgwick iterations to %d on all IIUs.\n", temp_byte);
      for (uint8_t i = 0; i < 17; i++) {
        iius[i].madgwickIterations(temp_byte);
      }
      break;



    case ',':
      IIU::max_quats_per_event = temp_byte;
      local_log.concatf("IIU class now runs a maximum of %u quats per event.\n", IIU::max_quats_per_event);
      break;

    case 'b':
      for (uint8_t i = 0; i < 17; i++) {
        iius[i].beta = (float)temp_byte * 0.1;
      }
      local_log.concatf("Beta value is now %f.\n", (double) (temp_byte * 0.1f));
      break;

    case 'L':
      for (uint8_t i = 0; i < 17; i++) {
        iius[i].setSampleRateProfile(temp_byte);
      }
      local_log.concatf("Moving to sample rate profile %d.\n", temp_byte);
      break;

    case 'o':
      for (uint8_t i = 0; i < 17; i++) {
        iius[i].setGyroBaseFiler(temp_byte);
      }
      local_log.concatf("Setting GYR base filter to %d.\n", temp_byte);
      break;

    case 'O':
      for (uint8_t i = 0; i < 17; i++) {
        iius[i].setAccelBaseFiler(temp_byte);
      }
      local_log.concatf("Setting ACC base filter to %d.\n", temp_byte);
      break;

    case 'a':
      if (255 == temp_byte) {
        refreshIMU();
      }
      else if (17 > temp_byte) {
        refreshIMU(temp_byte);
      }
      break;

    case 'd':
      switch (temp_byte) {
        case 255:
          event_legend_frame_ready.fireNow();  // Fire a single frame transmission.
          local_log.concat("We are manually firing the IMU frame broadcasts schedule.\n");
          break;
        case 254:
          event_legend_frame_ready.enableSchedule(true);  // Enable the periodic read.
          local_log.concat("Enabled frame broadcasts.\n");
          break;
        #if defined(__MANUVR_DEBUG)
          case 253:
            event_legend_frame_ready.printDebug(&local_log);
            break;
        #endif
        case 252:
          send_map_event();
          local_log.concat("We are manually firing the IMU frame broadcasts schedule.\n");
          break;
        default:
          if (temp_byte) {
            event_legend_frame_ready.alterSchedulePeriod(temp_byte*10);
            local_log.concatf("Set periodic frame broadcast to once every %dms.\n", temp_byte*10);
          }
          else {
            event_legend_frame_ready.enableSchedule(false);  // Disable the periodic read.
            local_log.concat("Disabled frame broadcasts.\n");
          }
          break;
      }
      break;

    case 'f':
      switch (temp_byte) {
        case 255:
          event_iiu_read.fireNow();
          local_log.concat("We are manually firing the IMU read schedule.\n");
          break;
        case 254:
          event_iiu_read.enableSchedule(true);
          local_log.concat("Enabled periodic readback.\n");
          break;
        default:
          if (temp_byte) {
            event_iiu_read.alterSchedulePeriod(temp_byte*10);
            local_log.concatf("Set periodic read schedule to once every %dms.\n", temp_byte*10);
          }
          else {
            event_iiu_read.enableSchedule(false);  // Disable the periodic read.
            local_log.concat("Disabled periodic readback.\n");
          }
          break;
      }
      break;

    case 'p':
      {
        parse_mule.concat(str);
        parse_mule.split(",");
        parse_mule.drop_position(0);
        uint8_t start = (temp_byte < 17) ? temp_byte   : 0;
        uint8_t stop  = (temp_byte < 17) ? temp_byte+1 : 17;
        int temp_int  = (parse_mule.count() > 0) ? parse_mule.position_as_int(0) : 255;
        for (uint8_t i = start; i < stop; i++) {
          if (255 != temp_int) {  // The user wants to make a change..
            iius[i].enableProfiling(temp_int ? true:false);
          }
          local_log.concatf("Profiling IIU %d: %sabled.\n", i, (iius[i].enableProfiling() ? "en":"dis"));
        }
      }
      break;

    case 'e':
      if (temp_byte < 17) {
        iius[temp_byte].dumpPreformedElements(&local_log);
      }
      break;


    default:
      EventReceiver::procDirectDebugInstruction(input);
      break;
  }

  flushLocalLog();
}
int8_t LegendManager::notify(ManuvrMsg* active_event) {
  int8_t return_value = 0;
  uint8_t temp_uint_8 = 0;

  /* Some class-specific set of conditionals below this line. */
  switch (active_event->eventCode()) {
    case DIGITABULUM_MSG_IMU_READ:
      iius[last_imu_read].readSensor();
      return_value++;
      break;


    case MANUVR_MSG_SESS_ESTABLISHED:
      event_legend_frame_ready.delaySchedule(1100);     // Enable the periodic frame broadcast.
      {
        ManuvrMsg *event = Kernel::returnEvent(DIGITABULUM_MSG_IMU_INIT);
        event->addArg((uint8_t) 4);  // Set the desired init stage.
        event->priority(0);
        raiseEvent(event);
      }
      event_iiu_read.delaySchedule(1000);  // Enable the periodic read after letting the dust settle.
      return_value++;
      break;

    case MANUVR_MSG_SESS_HANGUP:
      event_legend_frame_ready.enableSchedule(false);
      for (uint8_t i = 0; i < LEGEND_DATASET_IIU_COUNT; i++) {
        ManuvrMsg *event = Kernel::returnEvent(DIGITABULUM_MSG_IMU_INIT);
        event->addArg((uint8_t) 4);  // Set the desired init stage.
        event->priority(0);
        raiseEvent(event);
      }
      event_iiu_read.enableSchedule(false);    // Disable the periodic read.
      return_value++;
      break;

    case DIGITABULUM_MSG_IMU_INIT:
      /* This is a request (probably from elsewhere in this class) to move one-or-more
           IMUs into the given INIT stage. The argument forms are...
           None        A request to move all IMUs into the minimum meaningful INIT stage (INIT-1).
           uint8       A request to move all IMUs into the given INIT stage.
       */
      if (0 == active_event->argCount()) {
        if (last_imu_read > 16) {
          if (getVerbosity() > 1) local_log.concat("MSG_IMU_INIT: last_imu_read > 16.\n");
        }
        else {
          iius[last_imu_read].init();
          return_value++;
        }
      }
      else if (0 == active_event->getArgAs(&temp_uint_8)) {
        // If the arg was present, we interpret this as a specified INIT stage...
        if (temp_uint_8 > 16) {
          if (getVerbosity() > 1) local_log.concat("MSG_IMU_INIT had an IMU idx > 16.\n");
        }
        else {
          iius[last_imu_read].state_pass_through(temp_uint_8);
          return_value++;
        }
      }
      break;

    case DIGITABULUM_MSG_IMU_MAP_STATE:
      //if (0 == active_event->argCount()) {
        // No args means a request. Send it.
      //  send_map_event();
      //  return_value++;
      //}
      break;


    case DIGITABULUM_MSG_CPLD_RESET_COMPLETE:
      if (getVerbosity() > 3) local_log.concatf("Initializing IMUs...\n");
      // Range-bind everything....
      for (uint8_t i = 0; i < 17; i++) iius[i].rangeBind(true);

      // Fire the event to put the IMUs into INIT-1.
      //raiseEvent(Kernel::returnEvent(DIGITABULUM_MSG_IMU_INIT));
      return_value++;
      break;

    case DIGITABULUM_MSG_IMU_TAP:
      if (0 == active_event->argCount()) {
        // Somthing wants the thresholds for all configured taps.
      }
      else {
        // Otherwise, it means we've emitted the event. No need to respond.
      }
      break;

    case DIGITABULUM_MSG_IMU_QUAT_CRUNCH:
      if (0 == active_event->getArgAs(&temp_uint_8)) {
        if (temp_uint_8 > 16) {
          if (getVerbosity() > 1) local_log.concat("QUAT_CRUNCH had an IMU idx > 16.\n");
        }
        else {
          iius[temp_uint_8].MadgwickQuaternionUpdate();
        }
        return_value++;
      }
      else {
        if (getVerbosity() > 2) local_log.concatf("QUAT_CRUNCH handler (IIU %u) got a bad return from an Arg..\n", temp_uint_8);
      }
      break;

    default:
      return_value += EventReceiver::notify(active_event);
      break;
  }

  flushLocalLog();
  return return_value;
}
Example #4
0
void MGC3130::dispatchGestureEvents() {
  ManuvrMsg* event = nullptr;

  if (isPositionDirty()) {
    // We don't want to spam the Kernel. We need to rate-limit.
    if ((millis() - MGC3130_MINIMUM_NUANCE_PERIOD) > last_nuance_sent) {
      if (!position_asserted()) {
        // If we haven't asserted the position gesture yet, do so now.
        event = Kernel::returnEvent(MANUVR_MSG_GESTURE_RECOGNIZED);
        event->addArg((uint32_t) 1);
        raiseEvent(event);
        position_asserted(true);
      }
      last_nuance_sent = millis();
      event = Kernel::returnEvent(MANUVR_MSG_GESTURE_NUANCE);
      event->addArg((uint32_t) 1);
      event->addArg((uint16_t) _pos_x);
      event->addArg((uint16_t) _pos_y);
      event->addArg((uint16_t) _pos_z);
      raiseEvent(event);
      _pos_x = -1;
      _pos_y = -1;
      _pos_z = -1;
    }
  }
  else if (position_asserted()) {
    // We need to disassert the position gesture.
    event = Kernel::returnEvent(MANUVR_MSG_GESTURE_DISASSERT);
    event->addArg((uint32_t) 1);
    raiseEvent(event);
    position_asserted(false);
    _pos_x = -1;
    _pos_y = -1;
    _pos_z = -1;
  }

  if (0 < wheel_position) {
    // We don't want to spam the Kernel. We need to rate-limit.
    if ((millis() - MGC3130_MINIMUM_NUANCE_PERIOD) > last_nuance_sent) {
      if (!airwheel_asserted()) {
        // If we haven't asserted the airwheel gesture yet, do so now.
        event = Kernel::returnEvent(MANUVR_MSG_GESTURE_RECOGNIZED);
        event->addArg((uint32_t) 2);
        raiseEvent(event);
        airwheel_asserted(true);
      }
      last_nuance_sent = millis();
      event = Kernel::returnEvent(MANUVR_MSG_GESTURE_NUANCE);
      event->addArg((uint32_t) 2);
      event->addArg((int32_t) wheel_position);
      raiseEvent(event);
      wheel_position = 0;
    }
  }
  else if (airwheel_asserted()) {
    // We need to disassert the airwheel gesture.
    event = Kernel::returnEvent(MANUVR_MSG_GESTURE_DISASSERT);
    event->addArg((uint32_t) 2);
    raiseEvent(event);
    airwheel_asserted(false);
    wheel_position = 0;
  }

  if (0 < last_tap) {
    event = Kernel::returnEvent(MANUVR_MSG_GESTURE_ONE_SHOT);
    event->addArg(getTouchTapString(last_tap));
    raiseEvent(event);
    last_tap = 0;
  }
  if (0 < last_double_tap) {
    event = Kernel::returnEvent(MANUVR_MSG_GESTURE_ONE_SHOT);
    event->addArg(getTouchTapString(last_double_tap));
    raiseEvent(event);
    last_double_tap = 0;
  }
  if (0 < last_swipe) {
    event = Kernel::returnEvent(MANUVR_MSG_GESTURE_ONE_SHOT);
    event->addArg(getTouchTapString(last_swipe));
    raiseEvent(event);
    last_swipe = 0;
  }
  if (isTouchDirty()) {
    event = Kernel::returnEvent(MANUVR_MSG_GESTURE_ONE_SHOT);
    event->addArg(getTouchTapString(last_touch));
    raiseEvent(event);
    last_touch_noted = last_touch;
  }
  if (special) {
    // TODO: Not sure how to deal with this yet...
    #ifdef MANUVR_DEBUG
    if (getVerbosity() > 3) {
      local_log.concatf("MGC3130 special code 0x08\n", special);
      Kernel::log(&local_log);
    }
    #endif
    special = 0;
  }
  if (last_event) {
    // TODO: Not sure how to deal with this yet...
    #ifdef MANUVR_DEBUG
    if (getVerbosity() > 3) {
      local_log.concatf("MGC3130 last_event 0x08\n", last_event);
      Kernel::log(&local_log);
    }
    #endif
    last_event = 0;
  }
}