<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file is based on the SMSLib library.
//
// SMSLib Sudden Motion Sensor Access Library
// Copyright (c) 2010 Suitable Systems
// All rights reserved.
//
// Developed by: Daniel Griscom
//               Suitable Systems
//               http://www.suitable.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal with the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// - Neither the names of Suitable Systems nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
//
// For more information about SMSLib, see
//    <http://www.suitable.com/tools/smslib.html>
// or contact
//    Daniel Griscom
//    Suitable Systems
//    1 Centre Street, Suite 204
//    Wakefield, MA 01880
//    (781) 665-0053

#include "chrome/browser/device_orientation/accelerometer_mac.h"

#include <math.h>  // For isfinite.
#include <sys/sysctl.h>

#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/device_orientation/orientation.h"

namespace device_orientation {

struct AccelerometerMac::GenericMacbookSensor {
  // Name of device to be read.
  const char* service_name;

  // Number of bytes of the axis data.
  int axis_size;

  // Default calibration value for zero g.
  float zero_g;

  // Default calibration value for one g (negative when axis is inverted).
  float one_g;

  // Kernel function index.
  unsigned int function;

  // Size of the sensor record to be sent/received.
  unsigned int record_size;
};

struct AccelerometerMac::AxisData {
  // Location of the first byte representing the axis in the sensor data.
  int index;

  // Axis inversion flag. The value changes often between models.
  bool inverted;
};

// Sudden Motion Sensor descriptor.
struct AccelerometerMac::SensorDescriptor {
  // Prefix of model to be tested.
  const char* model_name;

  // Axis-specific data (x,y,z order).
  AxisData axis[3];
};

// Typical sensor parameters in MacBook models.
const AccelerometerMac::GenericMacbookSensor
  AccelerometerMac::kGenericSensor = {
  "SMCMotionSensor", 2,
  0, 251,
  5, 40
};

// Supported sensor descriptors. Add entries here to enhance compatibility.
// All non-tested entries from SMSLib have been removed.
const AccelerometerMac::SensorDescriptor
    AccelerometerMac::kSupportedSensors[] = {
  // Tested by S.Selz. (via avi) on a 13" MacBook.
  { "MacBook2,1",    { { 0, true  }, { 2, false }, { 4, true  } } },

  // Tested by avi on a 13" MacBook.
  { "MacBook7,1",    { { 0, true  }, { 2, true  }, { 4, false } } },

  // Tested by sfiera, pjw on a 13" MacBook Air.
  { "MacBookAir2,1", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Note: MacBookAir3,1 (11" MacBook Air) and MacBookAir3,2 (13" MacBook Air)
  // have no accelerometer sensors.

  // Not tested; data acquired by avi from L.V. from a 17" MacBook Pro.
  { "MacBookPro2,1", { { 0, true  }, { 2, false }, { 4, true  } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  { "MacBookPro2,2", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  // TODO(avi): this model name was also used for the 17" version; verify that
  // these parameters are also valid for that model.
  { "MacBookPro3,1", { { 0, false }, { 2, true  }, { 4, true  } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  // TODO(avi): this model name was also used for the 17" version; verify that
  // these parameters are also valid for that model.
  { "MacBookPro4,1", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  { "MacBookPro5,1", { { 0, false }, { 2, false }, { 4, false } } },

  // Tested by S.Selz. (via avi) on a 15" MacBook Pro.
  { "MacBookPro5,2", { { 0, false }, { 2, false }, { 4, false } } },

  // Tested by dmaclach on a 15" MacBook Pro.
  { "MacBookPro5,3", { { 2, false }, { 0, false }, { 4, true  } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  { "MacBookPro5,4", { { 0, false }, { 2, false }, { 4, false } } },

  // Tested by leandrogracia on a 13" MacBook Pro.
  { "MacBookPro5,5", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Tested by khom, leadpipe on a 17" MacBook Pro.
  { "MacBookPro6,1", { { 0, false }, { 2, false }, { 4, false } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  { "MacBookPro6,2", { { 0, true  }, { 2, false }, { 4, true  } } },

  // Tested by leandrogracia on a 13" MacBook Pro.
  { "MacBookPro7,1", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Generic MacBook accelerometer sensor data, used for for both future models
  // and past models for which there has been no testing. Note that this generic
  // configuration may well have problems with inverted axes.
  // TODO(avi): Find these past models and test on them; test on future models.
  //  MacBook1,1
  //  MacBook3,1
  //  MacBook4,1
  //  MacBook5,1
  //  MacBook5,2
  //  MacBook6,1
  //  MacBookAir1,1
  //  MacBookPro1,1
  //  MacBookPro1,2
  //  MacBookPro5,2
  { "", { { 0, true  }, { 2, true  }, { 4, false } } }
};

// Create a AccelerometerMac object and return NULL if no valid sensor found.
DataFetcher* AccelerometerMac::Create() {
  scoped_ptr<AccelerometerMac> accelerometer(new AccelerometerMac);
  return accelerometer->Init() ? accelerometer.release() : NULL;
}

AccelerometerMac::~AccelerometerMac() {
  IOServiceClose(io_connection_);
}

AccelerometerMac::AccelerometerMac()
    : sensor_(NULL),
      io_connection_(0) {
}

//  Retrieve per-axis accelerometer values.
//
//  Axes and angles are defined according to the W3C DeviceOrientation Draft.
//  See here: http://dev.w3.org/geo/api/spec-source-orientation.html
//
//  Note: only beta and gamma angles are provided. Alpha is set to zero.
//
//  Returns false in case of error or non-properly initialized object.
//
bool AccelerometerMac::GetOrientation(Orientation* orientation) {
  DCHECK(sensor_);

  // Reset output record memory buffer.
  std::fill(output_record_.begin(), output_record_.end(), 0x00);

  // Read record data from memory.
  const size_t kInputSize = kGenericSensor.record_size;
  size_t output_size = kGenericSensor.record_size;

  if (IOConnectCallStructMethod(io_connection_, kGenericSensor.function,
      static_cast<const char *>(&input_record_[0]), kInputSize,
      &output_record_[0], &output_size) != KERN_SUCCESS) {
    return false;
  }

  // Calculate per-axis calibrated values.
  float axis_value[3];

  for (int i = 0; i < 3; ++i) {
    int sensor_value = 0;
    int size  = kGenericSensor.axis_size;
    int index = sensor_->axis[i].index;

    // Important Note: little endian is assumed as this code is mac-only
    //                 and PowerPC is currently not supported.
    memcpy(&sensor_value, &output_record_[index], size);

    sensor_value = ExtendSign(sensor_value, size);

    // Correct value using the current calibration.
    axis_value[i] = static_cast<float>(sensor_value - kGenericSensor.zero_g) /
                    kGenericSensor.one_g;

    // Make sure we reject any NaN or infinite values.
    if (!isfinite(axis_value[i]))
      return false;

    // Clamp value to the [-1, 1] range.
    if (axis_value[i] < -1.0)
      axis_value[i] = -1.0;
    else if (axis_value[i] > 1.0)
      axis_value[i] = 1.0;

    // Apply axis inversion.
    if (sensor_->axis[i].inverted)
      axis_value[i] = -axis_value[i];
  }

  // Transform the accelerometer values to W3C draft angles.
  //
  // Accelerometer values are just dot products of the sensor axes
  // by the gravity vector 'g' with the result for the z axis inverted.
  //
  // To understand this transformation calculate the 3rd row of the z-x-y
  // Euler angles rotation matrix (because of the 'g' vector, only 3rd row
  // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz.
  // Then, assume alpha = 0 and you get this:
  //
  // x_acc = sin(gamma)
  // y_acc = - cos(gamma) * sin(beta)
  // z_acc = cos(beta) * cos(gamma)
  //
  // After that the rest is just a bit of trigonometry.
  //
  // Also note that alpha can't be provided but it's assumed to be always zero.
  // This is necessary in order to provide enough information to solve
  // the equations.
  //
  const double kRad2deg = 180.0 / M_PI;

  orientation->alpha_ = 0.0;
  orientation->beta_  = kRad2deg * atan2(-axis_value[1], axis_value[2]);
  orientation->gamma_ = kRad2deg * asin(axis_value[0]);

  // Make sure that the interval boundaries comply with the specification.
  if (orientation->beta_ >= 180.0)
    orientation->beta_  -= 360.0;
  if (orientation->gamma_ >= 90.0)
    orientation->gamma_ -= 180.0;

  DCHECK_GE(orientation->beta_, -180.0);
  DCHECK_LT(orientation->beta_,  180.0);
  DCHECK_GE(orientation->gamma_, -90.0);
  DCHECK_LT(orientation->gamma_,  90.0);

  orientation->can_provide_alpha_ = false;
  orientation->can_provide_beta_  = true;
  orientation->can_provide_gamma_ = true;

  return true;
}

// Probe the local hardware looking for a supported sensor device
// and initialize an I/O connection to it.
bool AccelerometerMac::Init() {
  // Allocate local variables for model name string (size from SMSLib).
  static const int kNameSize = 32;
  char local_model[kNameSize];

  // Request model name to the kernel.
  size_t name_size = kNameSize;
  int params[2] = { CTL_HW, HW_MODEL };
  if (sysctl(params, 2, local_model, &name_size, NULL, 0) != 0)
    return NULL;

  const SensorDescriptor* sensor_candidate = NULL;

  // Look for the current model in the supported sensor list.
  io_object_t device = 0;
  const int kNumSensors = arraysize(kSupportedSensors);

  for (int i = 0; i < kNumSensors; ++i) {
    // Check if the supported sensor model name is a prefix
    // of the local hardware model (empty names are accepted).
    const char* p1 = kSupportedSensors[i].model_name;
    for (const char* p2 = local_model; *p1 != '\0' && *p1 == *p2; ++p1, ++p2)
      continue;
    if (*p1 != '\0')
      continue;

    // Local hardware found in the supported sensor list.
    sensor_candidate = &kSupportedSensors[i];

    // Get a dictionary of the services matching to the one in the sensor.
    CFMutableDictionaryRef dict =
        IOServiceMatching(kGenericSensor.service_name);
    if (dict == NULL)
      continue;

    // Get an iterator for the matching services.
    io_iterator_t device_iterator;
    if (IOServiceGetMatchingServices(kIOMasterPortDefault, dict,
        &device_iterator) != KERN_SUCCESS) {
      continue;
    }

    // Get the first device in the list.
    if ((device = IOIteratorNext(device_iterator)) == 0)
      continue;

    // Try to open device.
    kern_return_t result;
    result = IOServiceOpen(device, mach_task_self(), 0, &io_connection_);
    IOObjectRelease(device);
    if (result != KERN_SUCCESS || io_connection_ == 0)
      return false;

    // Local sensor service confirmed by IOKit.
    sensor_ = sensor_candidate;
    break;
  }

  if (sensor_ == NULL)
    return false;

  // Allocate and initialize input/output records.
  input_record_.resize(kGenericSensor.record_size, 0x01);
  output_record_.resize(kGenericSensor.record_size, 0x00);

  // Try to retrieve the current orientation.
  Orientation test_orientation;
  return GetOrientation(&test_orientation);
}

// Extend the sign of an integer of less than 32 bits to a 32-bit integer.
int AccelerometerMac::ExtendSign(int value, size_t size) {
  switch (size) {
  case 1:
    if (value & 0x00000080)
      return value | 0xffffff00;
    break;

  case 2:
    if (value & 0x00008000)
      return value | 0xffff0000;
    break;

  case 3:
    if (value & 0x00800000)
      return value | 0xff000000;
    break;

  default:
    LOG(FATAL) << "Invalid integer size for sign extension: " << size;
  }

  return value;
}

}  // namespace device_orientation
<commit_msg>Accelerometer: Fix IOKit iterator leak, note that a configuration is verified.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file is based on the SMSLib library.
//
// SMSLib Sudden Motion Sensor Access Library
// Copyright (c) 2010 Suitable Systems
// All rights reserved.
//
// Developed by: Daniel Griscom
//               Suitable Systems
//               http://www.suitable.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal with the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// - Neither the names of Suitable Systems nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
//
// For more information about SMSLib, see
//    <http://www.suitable.com/tools/smslib.html>
// or contact
//    Daniel Griscom
//    Suitable Systems
//    1 Centre Street, Suite 204
//    Wakefield, MA 01880
//    (781) 665-0053

#include "chrome/browser/device_orientation/accelerometer_mac.h"

#include <math.h>  // For isfinite.
#include <sys/sysctl.h>

#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/device_orientation/orientation.h"

namespace device_orientation {

struct AccelerometerMac::GenericMacbookSensor {
  // Name of device to be read.
  const char* service_name;

  // Number of bytes of the axis data.
  int axis_size;

  // Default calibration value for zero g.
  float zero_g;

  // Default calibration value for one g (negative when axis is inverted).
  float one_g;

  // Kernel function index.
  unsigned int function;

  // Size of the sensor record to be sent/received.
  unsigned int record_size;
};

struct AccelerometerMac::AxisData {
  // Location of the first byte representing the axis in the sensor data.
  int index;

  // Axis inversion flag. The value changes often between models.
  bool inverted;
};

// Sudden Motion Sensor descriptor.
struct AccelerometerMac::SensorDescriptor {
  // Prefix of model to be tested.
  const char* model_name;

  // Axis-specific data (x,y,z order).
  AxisData axis[3];
};

// Typical sensor parameters in MacBook models.
const AccelerometerMac::GenericMacbookSensor
  AccelerometerMac::kGenericSensor = {
  "SMCMotionSensor", 2,
  0, 251,
  5, 40
};

// Supported sensor descriptors. Add entries here to enhance compatibility.
// All non-tested entries from SMSLib have been removed.
const AccelerometerMac::SensorDescriptor
    AccelerometerMac::kSupportedSensors[] = {
  // Tested by S.Selz. (via avi) on a 13" MacBook.
  { "MacBook2,1",    { { 0, true  }, { 2, false }, { 4, true  } } },

  // Tested by avi on a 13" MacBook.
  { "MacBook7,1",    { { 0, true  }, { 2, true  }, { 4, false } } },

  // Tested by sfiera, pjw on a 13" MacBook Air.
  { "MacBookAir2,1", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Note: MacBookAir3,1 (11" MacBook Air) and MacBookAir3,2 (13" MacBook Air)
  // have no accelerometer sensors.

  // Tested by L.V. (via avi) on a 17" MacBook Pro.
  { "MacBookPro2,1", { { 0, true  }, { 2, false }, { 4, true  } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  { "MacBookPro2,2", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  // TODO(avi): this model name was also used for the 17" version; verify that
  // these parameters are also valid for that model.
  { "MacBookPro3,1", { { 0, false }, { 2, true  }, { 4, true  } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  // TODO(avi): this model name was also used for the 17" version; verify that
  // these parameters are also valid for that model.
  { "MacBookPro4,1", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  { "MacBookPro5,1", { { 0, false }, { 2, false }, { 4, false } } },

  // Tested by S.Selz. (via avi) on a 15" MacBook Pro.
  { "MacBookPro5,2", { { 0, false }, { 2, false }, { 4, false } } },

  // Tested by dmaclach on a 15" MacBook Pro.
  { "MacBookPro5,3", { { 2, false }, { 0, false }, { 4, true  } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  { "MacBookPro5,4", { { 0, false }, { 2, false }, { 4, false } } },

  // Tested by leandrogracia on a 13" MacBook Pro.
  { "MacBookPro5,5", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Tested by khom, leadpipe on a 17" MacBook Pro.
  { "MacBookPro6,1", { { 0, false }, { 2, false }, { 4, false } } },

  // Tested by leandrogracia on a 15" MacBook Pro.
  { "MacBookPro6,2", { { 0, true  }, { 2, false }, { 4, true  } } },

  // Tested by leandrogracia on a 13" MacBook Pro.
  { "MacBookPro7,1", { { 0, true  }, { 2, true  }, { 4, false } } },

  // Generic MacBook accelerometer sensor data, used for for both future models
  // and past models for which there has been no testing. Note that this generic
  // configuration may well have problems with inverted axes.
  // TODO(avi): Find these past models and test on them; test on future models.
  //  MacBook1,1
  //  MacBook3,1
  //  MacBook4,1
  //  MacBook5,1
  //  MacBook5,2
  //  MacBook6,1
  //  MacBookAir1,1
  //  MacBookPro1,1
  //  MacBookPro1,2
  //  MacBookPro5,2
  { "", { { 0, true  }, { 2, true  }, { 4, false } } }
};

// Create a AccelerometerMac object and return NULL if no valid sensor found.
DataFetcher* AccelerometerMac::Create() {
  scoped_ptr<AccelerometerMac> accelerometer(new AccelerometerMac);
  return accelerometer->Init() ? accelerometer.release() : NULL;
}

AccelerometerMac::~AccelerometerMac() {
  IOServiceClose(io_connection_);
}

AccelerometerMac::AccelerometerMac()
    : sensor_(NULL),
      io_connection_(0) {
}

//  Retrieve per-axis accelerometer values.
//
//  Axes and angles are defined according to the W3C DeviceOrientation Draft.
//  See here: http://dev.w3.org/geo/api/spec-source-orientation.html
//
//  Note: only beta and gamma angles are provided. Alpha is set to zero.
//
//  Returns false in case of error or non-properly initialized object.
//
bool AccelerometerMac::GetOrientation(Orientation* orientation) {
  DCHECK(sensor_);

  // Reset output record memory buffer.
  std::fill(output_record_.begin(), output_record_.end(), 0x00);

  // Read record data from memory.
  const size_t kInputSize = kGenericSensor.record_size;
  size_t output_size = kGenericSensor.record_size;

  if (IOConnectCallStructMethod(io_connection_, kGenericSensor.function,
      static_cast<const char *>(&input_record_[0]), kInputSize,
      &output_record_[0], &output_size) != KERN_SUCCESS) {
    return false;
  }

  // Calculate per-axis calibrated values.
  float axis_value[3];

  for (int i = 0; i < 3; ++i) {
    int sensor_value = 0;
    int size  = kGenericSensor.axis_size;
    int index = sensor_->axis[i].index;

    // Important Note: little endian is assumed as this code is mac-only
    //                 and PowerPC is currently not supported.
    memcpy(&sensor_value, &output_record_[index], size);

    sensor_value = ExtendSign(sensor_value, size);

    // Correct value using the current calibration.
    axis_value[i] = static_cast<float>(sensor_value - kGenericSensor.zero_g) /
                    kGenericSensor.one_g;

    // Make sure we reject any NaN or infinite values.
    if (!isfinite(axis_value[i]))
      return false;

    // Clamp value to the [-1, 1] range.
    if (axis_value[i] < -1.0)
      axis_value[i] = -1.0;
    else if (axis_value[i] > 1.0)
      axis_value[i] = 1.0;

    // Apply axis inversion.
    if (sensor_->axis[i].inverted)
      axis_value[i] = -axis_value[i];
  }

  // Transform the accelerometer values to W3C draft angles.
  //
  // Accelerometer values are just dot products of the sensor axes
  // by the gravity vector 'g' with the result for the z axis inverted.
  //
  // To understand this transformation calculate the 3rd row of the z-x-y
  // Euler angles rotation matrix (because of the 'g' vector, only 3rd row
  // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz.
  // Then, assume alpha = 0 and you get this:
  //
  // x_acc = sin(gamma)
  // y_acc = - cos(gamma) * sin(beta)
  // z_acc = cos(beta) * cos(gamma)
  //
  // After that the rest is just a bit of trigonometry.
  //
  // Also note that alpha can't be provided but it's assumed to be always zero.
  // This is necessary in order to provide enough information to solve
  // the equations.
  //
  const double kRad2deg = 180.0 / M_PI;

  orientation->alpha_ = 0.0;
  orientation->beta_  = kRad2deg * atan2(-axis_value[1], axis_value[2]);
  orientation->gamma_ = kRad2deg * asin(axis_value[0]);

  // Make sure that the interval boundaries comply with the specification.
  if (orientation->beta_ >= 180.0)
    orientation->beta_  -= 360.0;
  if (orientation->gamma_ >= 90.0)
    orientation->gamma_ -= 180.0;

  DCHECK_GE(orientation->beta_, -180.0);
  DCHECK_LT(orientation->beta_,  180.0);
  DCHECK_GE(orientation->gamma_, -90.0);
  DCHECK_LT(orientation->gamma_,  90.0);

  orientation->can_provide_alpha_ = false;
  orientation->can_provide_beta_  = true;
  orientation->can_provide_gamma_ = true;

  return true;
}

// Probe the local hardware looking for a supported sensor device
// and initialize an I/O connection to it.
bool AccelerometerMac::Init() {
  // Allocate local variables for model name string (size from SMSLib).
  static const int kNameSize = 32;
  char local_model[kNameSize];

  // Request model name to the kernel.
  size_t name_size = kNameSize;
  int params[2] = { CTL_HW, HW_MODEL };
  if (sysctl(params, 2, local_model, &name_size, NULL, 0) != 0)
    return NULL;

  const SensorDescriptor* sensor_candidate = NULL;

  // Look for the current model in the supported sensor list.
  const int kNumSensors = arraysize(kSupportedSensors);

  for (int i = 0; i < kNumSensors; ++i) {
    // Check if the supported sensor model name is a prefix
    // of the local hardware model (empty names are accepted).
    const char* p1 = kSupportedSensors[i].model_name;
    for (const char* p2 = local_model; *p1 != '\0' && *p1 == *p2; ++p1, ++p2)
      continue;
    if (*p1 != '\0')
      continue;

    // Local hardware found in the supported sensor list.
    sensor_candidate = &kSupportedSensors[i];

    // Get a dictionary of the services matching to the one in the sensor.
    CFMutableDictionaryRef dict =
        IOServiceMatching(kGenericSensor.service_name);
    if (dict == NULL)
      continue;

    // Get an iterator for the matching services.
    io_iterator_t device_iterator;
    if (IOServiceGetMatchingServices(kIOMasterPortDefault, dict,
        &device_iterator) != KERN_SUCCESS) {
      continue;
    }

    // Get the first device in the list.
    io_object_t device = IOIteratorNext(device_iterator);
    IOObjectRelease(device_iterator);
    if (device == 0)
      continue;

    // Try to open device.
    kern_return_t result;
    result = IOServiceOpen(device, mach_task_self(), 0, &io_connection_);
    IOObjectRelease(device);
    if (result != KERN_SUCCESS || io_connection_ == 0)
      return false;

    // Local sensor service confirmed by IOKit.
    sensor_ = sensor_candidate;
    break;
  }

  if (sensor_ == NULL)
    return false;

  // Allocate and initialize input/output records.
  input_record_.resize(kGenericSensor.record_size, 0x01);
  output_record_.resize(kGenericSensor.record_size, 0x00);

  // Try to retrieve the current orientation.
  Orientation test_orientation;
  return GetOrientation(&test_orientation);
}

// Extend the sign of an integer of less than 32 bits to a 32-bit integer.
int AccelerometerMac::ExtendSign(int value, size_t size) {
  switch (size) {
  case 1:
    if (value & 0x00000080)
      return value | 0xffffff00;
    break;

  case 2:
    if (value & 0x00008000)
      return value | 0xffff0000;
    break;

  case 3:
    if (value & 0x00800000)
      return value | 0xff000000;
    break;

  default:
    LOG(FATAL) << "Invalid integer size for sign extension: " << size;
  }

  return value;
}

}  // namespace device_orientation
<|endoftext|>


<commit_before>#include "vtkCellDistanceSelector.h"

#include <vtkCell.h>
#include <vtkCellData.h>
#include <vtkIdList.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>
#include <vtkDataSet.h>
#include <vtkUnstructuredGrid.h>
#include <vtkStructuredGrid.h>
#include <vtkPolyData.h>
#include <vtkCellLinks.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkCompositeDataSet.h>
#include <vtkCompositeDataIterator.h>
#include <vtkSelection.h>
#include <vtkSelectionNode.h>
#include <vtkIdTypeArray.h>
#include <vtkSmartPointer.h>

#include <map>
#include <vector>

vtkStandardNewMacro(vtkCellDistanceSelector);

// ----------------------------------------------------------------------
vtkCellDistanceSelector::vtkCellDistanceSelector()
{
  this->Distance = 1;
  this->IncludeSeed = 1;
  this->AddIntermediate = 1;
  this->SetNumberOfInputPorts( 2 );
}

// ----------------------------------------------------------------------
vtkCellDistanceSelector::~vtkCellDistanceSelector()
{
}

// ----------------------------------------------------------------------
void vtkCellDistanceSelector::SetDataObjectConnection ( vtkAlgorithmOutput* in )
{
  this->SetInputConnection( 1, in );
}

// ----------------------------------------------------------------------
void vtkCellDistanceSelector::PrintSelf( ostream& os, vtkIndent indent )
{
  this->Superclass::PrintSelf( os, indent );
}

// ----------------------------------------------------------------------
int vtkCellDistanceSelector::FillInputPortInformation( int port, vtkInformation* info )
{
  switch ( port )
    {
    case 0:
      info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkSelection" );
      break;
    case 1:
      info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkCompositeDataSet" );
      break;
    }
  return 1;
}

// ----------------------------------------------------------------------
void vtkCellDistanceSelector::AddSelectionNode( vtkSelection* output,
                                                vtkSmartPointer<vtkDataArray> outIndices,
                                                int composite_index, int d )
{
  vtkSmartPointer<vtkSelectionNode> outSelNode = vtkSmartPointer<vtkSelectionNode>::New();
  outSelNode->SetContentType( vtkSelectionNode::INDICES );
  outSelNode->SetFieldType( vtkSelectionNode::CELL );
  outSelNode->GetProperties()->Set( vtkSelectionNode::COMPOSITE_INDEX(), composite_index );
  // NB: Use HIERARCHICAL_LEVEL key to store distance to original cells
  outSelNode->GetProperties()->Set( vtkSelectionNode::HIERARCHICAL_LEVEL(), d );
  outSelNode->SetSelectionList( outIndices );
  output->AddNode( outSelNode );
}

// ----------------------------------------------------------------------
int vtkCellDistanceSelector::RequestData( vtkInformation* vtkNotUsed( request ),
                                          vtkInformationVector** inputVector,
                                          vtkInformationVector* outputVector )
{
  vtkInformation* inSelectionInfo = inputVector[0]->GetInformationObject( 0 );
  vtkInformation* inDataObjectInfo = inputVector[1]->GetInformationObject( 0 );

  vtkInformation* outInfo = outputVector->GetInformationObject( 0 );

  vtkSelection* inputSelection =
    vtkSelection::SafeDownCast( inSelectionInfo->Get( vtkDataObject::DATA_OBJECT() ) );

  vtkCompositeDataSet* compositeInput =
    vtkCompositeDataSet::SafeDownCast( inDataObjectInfo->Get(vtkDataObject::DATA_OBJECT() ) );

  vtkSelection* output =
    vtkSelection::SafeDownCast(outInfo->Get( vtkDataObject::DATA_OBJECT() ) );

  if ( ! compositeInput )
    {
    vtkErrorMacro(<<"Missing input data object");
    return 0;
    }

  if ( ! inputSelection )
    {
    vtkErrorMacro(<<"Missing input selection");
    return 0;
    }

  std::map<int,std::vector<vtkSelectionNode*> > partSelections;
  int nSelNodes = inputSelection->GetNumberOfNodes();
  for ( int i = 0; i < nSelNodes; ++ i )
    {
    vtkSelectionNode* sn = inputSelection->GetNode( i );
    int composite_index = sn->GetProperties()->Get(vtkSelectionNode::COMPOSITE_INDEX() ) ;
    partSelections[composite_index].push_back( sn );
    }

  vtkCompositeDataIterator* inputIterator = compositeInput->NewIterator();
  inputIterator->SkipEmptyNodesOn();
  inputIterator->InitTraversal();
  inputIterator->GoToFirstItem();
  while ( ! inputIterator->IsDoneWithTraversal() )
    {
    vtkDataSet * input = vtkDataSet::SafeDownCast( inputIterator->GetCurrentDataObject() );
     // NB: composite indices start at 1
    int composite_index = inputIterator->GetCurrentFlatIndex();
    inputIterator->GoToNextItem();

    std::vector<vtkSelectionNode*>::iterator selNodeIt = partSelections[composite_index].begin();
    while ( selNodeIt != partSelections[composite_index].end() )
      {
      vtkSelectionNode* selectionNode = *selNodeIt;
      ++ selNodeIt;

      vtkDataArray* selectionList = vtkDataArray::SafeDownCast( selectionNode->GetSelectionList() );
      vtkIdType numSeeds = selectionList->GetNumberOfTuples();
      if ( numSeeds > 0
           && selectionNode->GetContentType() == vtkSelectionNode::INDICES
           && selectionNode->GetFieldType() == vtkSelectionNode::CELL
           && input->GetNumberOfCells() > 0 )
        {
        vtkIdType numCells = input->GetNumberOfCells();

        vtkUnstructuredGrid* ug_input = vtkUnstructuredGrid::SafeDownCast( input );
        vtkStructuredGrid* sg_input = vtkStructuredGrid::SafeDownCast( input );
        vtkPolyData* pd_input = vtkPolyData::SafeDownCast( input);

        vtkCellLinks * links = 0;
        if (ug_input != 0)
          {
          if ( ! ug_input->GetCellLinks() )
            {
            ug_input->BuildLinks();
            }
          links = ug_input->GetCellLinks();
          }

        std::vector<int> flags( numCells, 0 );

        vtkSmartPointer<vtkIdTypeArray> outIndices = vtkSmartPointer<vtkIdTypeArray>::New();
        outIndices->SetNumberOfTuples( numSeeds );

        int seedCount = 0;
        for ( int i = 0; i < numSeeds; ++ i )
          {
          vtkIdType cellIndex = static_cast<vtkIdType> ( selectionList->GetTuple1( i ) );
          if( cellIndex>=0 && cellIndex<numCells )
            {
            flags[cellIndex] = true;
            outIndices->SetTuple1( seedCount++, cellIndex );
            }
          else
            {
            vtkWarningMacro(<<"Cell index out of bounds in selection ("<<cellIndex<<"/"<<numCells<<")\n");
            }
          }
        outIndices->SetNumberOfTuples( seedCount );

        vtkSmartPointer<vtkIdTypeArray> finalIndices = vtkSmartPointer<vtkIdTypeArray>::New();
        vtkSmartPointer<vtkIntArray> cellDistance = vtkSmartPointer<vtkIntArray>::New();
        cellDistance->SetName("Cell Distance");

        // Iterate over increasing topological distance until desired distance is met
        for ( int d = 0; d < this->Distance; ++ d )
          {
          vtkSmartPointer<vtkIdTypeArray> nextIndices = vtkSmartPointer<vtkIdTypeArray>::New();

          if ( ug_input )
            {
            int nIndices = outIndices->GetNumberOfTuples();
            for ( int i = 0; i < nIndices; ++ i )
              {
              vtkIdType cellIndex = static_cast<vtkIdType>( outIndices->GetTuple1( i ) );
              vtkIdType * points;
              vtkIdType n;
              ug_input->GetCellPoints(cellIndex, n, points);
              for ( int k = 0; k < n; ++ k )
                {
                vtkIdType pid = points[k];
                int np = links->GetNcells( pid );
                vtkIdType* cells = links->GetCells( pid );
                for ( int j = 0; j < np; ++ j )
                  {
                  vtkIdType cid = cells[j];
                  if( cid >= 0 && cid < numCells )
                    {
                    if ( ! flags[cid] )
                      {
                      flags[cid] = true;
                      nextIndices->InsertNextValue( cid );
                      }
                    }
                  else
                    {
                    vtkWarningMacro(<<"Selection's cell index out of bounds ("<<cid<<"/"<<numCells<<")\n");
                    }
                  }
                }
              }
            } // if ( ug_input )
          else if ( pd_input )
            {
            pd_input->BuildLinks();
            int nIndices = outIndices->GetNumberOfTuples();
            for ( int i = 0; i < nIndices; ++ i )
              {
              vtkIdType cellIndex = static_cast<vtkIdType>( outIndices->GetTuple1( i) );
              vtkIdType* points;
              vtkIdType n;
              pd_input->GetCellPoints(cellIndex, n, points);
              for ( int k = 0; k < n; ++ k )
                {
                vtkIdType pid = points[k];
                short unsigned int np;
                vtkIdType* cells;
                pd_input->GetPointCells(pid, np, cells);
                for ( int j = 0; j < np; j++)
                  {
                  vtkIdType cid = cells[j];
                  if( cid>=0 && cid<numCells )
                    {
                    if (!flags[cid])
                      {
                      flags[cid] = true;
                      nextIndices->InsertNextValue(cid);
                      }
                    }
                  else
                    {
                    vtkWarningMacro(<<"Selection's cell index out of bounds ("<<cid<<"/"<<numCells<<")\n");
                    }
                  }
                }
              }
            } // else if ( ug_input )
          else if (sg_input != 0)
            {
            int dim[3];
            sg_input->GetDimensions(dim);
            dim[0]--;
            dim[1]--;
            dim[2]--;

            int nIndices = outIndices->GetNumberOfTuples();
            for ( int i = 0; i < nIndices; ++ i )
              {
              vtkIdType cellIndex = static_cast<vtkIdType>( outIndices->GetTuple1( i ) );
              vtkIdType cellId = cellIndex;
              vtkIdType ijk[3];
              for ( int c = 0; c < 3; c++)
                {
                if (dim[c] <= 1)
                  {
                  ijk[c] = 0;
                  }
                else
                  {
                  ijk[c] = cellId % dim[c];
                  cellId /= dim[c];
                  }
                }
              for ( int k = -1; k <= 1; k++)
                {
                for ( int j = -1; j <= 1; j++)
                  {
                  for ( int l = -1; l <= 1; ++ l )
                    {
                    int I = ijk[0] + l, J = ijk[1] + j, K = ijk[2] + k;
                    if ( i >= 0 && I < dim[0] && J >= 0 && J
                        < dim[1] && K >= 0 && K < dim[2])
                      {
                      cellId = I + J * dim[0] + K * dim[0] * dim[1];
                      if( cellId >= 0 && cellId < numCells )
                        {
                        if ( ! flags[cellId] )
                          {
                          flags[cellId] = true;
                          nextIndices->InsertNextValue( cellId );
                          }
                        }
                      else
                        {
                        vtkWarningMacro(<<"Selection's cell index out of bounds ("<<cellId<<"/"<<numCells<<")\n");
                        }
                      }
                    } // l
                  } // j
                } // k
              }
            } // else if ( sg_input )
          else
            {
            vtkErrorMacro(<<"Unsupported data type : "<<input->GetClassName()<<"\n");
            }

          if( ( ! d && this->IncludeSeed ) || ( d > 0 && this->AddIntermediate ) )
            {
            int ni = outIndices->GetNumberOfTuples();
            for( int i = 0; i < ni; ++ i )
              {
              cellDistance->InsertNextTuple1( d );
              finalIndices->InsertNextTuple1( outIndices->GetTuple1( i ) );
              }
            }

          outIndices = nextIndices;
          } // for ( int d = 0; d < this->Distance; ++ d )

        if( ( ! this->Distance && this->IncludeSeed ) || ( this->Distance > 0 && this->AddIntermediate ) )
          {
          int ni = outIndices->GetNumberOfTuples();
          for( int i=0;i<ni;++ i )
            {
            cellDistance->InsertNextTuple1( this->Distance );
            finalIndices->InsertNextTuple1( outIndices->GetTuple1( i ) );
            }
          }

        if( finalIndices->GetNumberOfTuples() > 0 )
          {
          vtkSmartPointer<vtkSelectionNode> outSelNode = vtkSmartPointer<vtkSelectionNode>::New();
          outSelNode->SetContentType( vtkSelectionNode::INDICES );
          outSelNode->SetFieldType( vtkSelectionNode::CELL );
          outSelNode->GetProperties()->Set( vtkSelectionNode::COMPOSITE_INDEX(), composite_index );
          outSelNode->SetSelectionList( finalIndices );
          outSelNode->GetSelectionData()->AddArray( cellDistance );
          output->AddNode( outSelNode );
          }
        } // if numSeeds > 0 etc.
      } // while selNodeIt
    } // while inputIterator

  return 1;
}
<commit_msg>Fixed a leak (composite iterator deletion)<commit_after>#include "vtkCellDistanceSelector.h"

#include <vtkCell.h>
#include <vtkCellData.h>
#include <vtkIdList.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>
#include <vtkDataSet.h>
#include <vtkUnstructuredGrid.h>
#include <vtkStructuredGrid.h>
#include <vtkPolyData.h>
#include <vtkCellLinks.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkCompositeDataSet.h>
#include <vtkCompositeDataIterator.h>
#include <vtkSelection.h>
#include <vtkSelectionNode.h>
#include <vtkIdTypeArray.h>
#include <vtkSmartPointer.h>

#include <map>
#include <vector>

vtkStandardNewMacro(vtkCellDistanceSelector);

// ----------------------------------------------------------------------
vtkCellDistanceSelector::vtkCellDistanceSelector()
{
  this->Distance = 1;
  this->IncludeSeed = 1;
  this->AddIntermediate = 1;
  this->SetNumberOfInputPorts( 2 );
}

// ----------------------------------------------------------------------
vtkCellDistanceSelector::~vtkCellDistanceSelector()
{
}

// ----------------------------------------------------------------------
void vtkCellDistanceSelector::SetDataObjectConnection ( vtkAlgorithmOutput* in )
{
  this->SetInputConnection( 1, in );
}

// ----------------------------------------------------------------------
void vtkCellDistanceSelector::PrintSelf( ostream& os, vtkIndent indent )
{
  this->Superclass::PrintSelf( os, indent );
}

// ----------------------------------------------------------------------
int vtkCellDistanceSelector::FillInputPortInformation( int port, vtkInformation* info )
{
  switch ( port )
    {
    case 0:
      info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkSelection" );
      break;
    case 1:
      info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkCompositeDataSet" );
      break;
    }
  return 1;
}

// ----------------------------------------------------------------------
void vtkCellDistanceSelector::AddSelectionNode( vtkSelection* output,
                                                vtkSmartPointer<vtkDataArray> outIndices,
                                                int composite_index, int d )
{
  vtkSmartPointer<vtkSelectionNode> outSelNode = vtkSmartPointer<vtkSelectionNode>::New();
  outSelNode->SetContentType( vtkSelectionNode::INDICES );
  outSelNode->SetFieldType( vtkSelectionNode::CELL );
  outSelNode->GetProperties()->Set( vtkSelectionNode::COMPOSITE_INDEX(), composite_index );
  // NB: Use HIERARCHICAL_LEVEL key to store distance to original cells
  outSelNode->GetProperties()->Set( vtkSelectionNode::HIERARCHICAL_LEVEL(), d );
  outSelNode->SetSelectionList( outIndices );
  output->AddNode( outSelNode );
}

// ----------------------------------------------------------------------
int vtkCellDistanceSelector::RequestData( vtkInformation* vtkNotUsed( request ),
                                          vtkInformationVector** inputVector,
                                          vtkInformationVector* outputVector )
{
  vtkInformation* inSelectionInfo = inputVector[0]->GetInformationObject( 0 );
  vtkInformation* inDataObjectInfo = inputVector[1]->GetInformationObject( 0 );

  vtkInformation* outInfo = outputVector->GetInformationObject( 0 );

  vtkSelection* inputSelection =
    vtkSelection::SafeDownCast( inSelectionInfo->Get( vtkDataObject::DATA_OBJECT() ) );

  vtkCompositeDataSet* compositeInput =
    vtkCompositeDataSet::SafeDownCast( inDataObjectInfo->Get(vtkDataObject::DATA_OBJECT() ) );

  vtkSelection* output =
    vtkSelection::SafeDownCast(outInfo->Get( vtkDataObject::DATA_OBJECT() ) );

  if ( ! compositeInput )
    {
    vtkErrorMacro(<<"Missing input data object");
    return 0;
    }

  if ( ! inputSelection )
    {
    vtkErrorMacro(<<"Missing input selection");
    return 0;
    }

  std::map<int,std::vector<vtkSelectionNode*> > partSelections;
  int nSelNodes = inputSelection->GetNumberOfNodes();
  for ( int i = 0; i < nSelNodes; ++ i )
    {
    vtkSelectionNode* sn = inputSelection->GetNode( i );
    int composite_index = sn->GetProperties()->Get(vtkSelectionNode::COMPOSITE_INDEX() ) ;
    partSelections[composite_index].push_back( sn );
    }

  vtkCompositeDataIterator* inputIterator = compositeInput->NewIterator();
  inputIterator->SkipEmptyNodesOn();
  inputIterator->InitTraversal();
  inputIterator->GoToFirstItem();
  while ( ! inputIterator->IsDoneWithTraversal() )
    {
    vtkDataSet * input = vtkDataSet::SafeDownCast( inputIterator->GetCurrentDataObject() );
     // NB: composite indices start at 1
    int composite_index = inputIterator->GetCurrentFlatIndex();
    inputIterator->GoToNextItem();

    std::vector<vtkSelectionNode*>::iterator selNodeIt = partSelections[composite_index].begin();
    while ( selNodeIt != partSelections[composite_index].end() )
      {
      vtkSelectionNode* selectionNode = *selNodeIt;
      ++ selNodeIt;

      vtkDataArray* selectionList = vtkDataArray::SafeDownCast( selectionNode->GetSelectionList() );
      vtkIdType numSeeds = selectionList->GetNumberOfTuples();
      if ( numSeeds > 0
           && selectionNode->GetContentType() == vtkSelectionNode::INDICES
           && selectionNode->GetFieldType() == vtkSelectionNode::CELL
           && input->GetNumberOfCells() > 0 )
        {
        vtkIdType numCells = input->GetNumberOfCells();

        vtkUnstructuredGrid* ug_input = vtkUnstructuredGrid::SafeDownCast( input );
        vtkStructuredGrid* sg_input = vtkStructuredGrid::SafeDownCast( input );
        vtkPolyData* pd_input = vtkPolyData::SafeDownCast( input);

        vtkCellLinks * links = 0;
        if (ug_input != 0)
          {
          if ( ! ug_input->GetCellLinks() )
            {
            ug_input->BuildLinks();
            }
          links = ug_input->GetCellLinks();
          }

        std::vector<int> flags( numCells, 0 );

        vtkSmartPointer<vtkIdTypeArray> outIndices = vtkSmartPointer<vtkIdTypeArray>::New();
        outIndices->SetNumberOfTuples( numSeeds );

        int seedCount = 0;
        for ( int i = 0; i < numSeeds; ++ i )
          {
          vtkIdType cellIndex = static_cast<vtkIdType> ( selectionList->GetTuple1( i ) );
          if( cellIndex>=0 && cellIndex<numCells )
            {
            flags[cellIndex] = true;
            outIndices->SetTuple1( seedCount++, cellIndex );
            }
          else
            {
            vtkWarningMacro(<<"Cell index out of bounds in selection ("<<cellIndex<<"/"<<numCells<<")\n");
            }
          }
        outIndices->SetNumberOfTuples( seedCount );

        vtkSmartPointer<vtkIdTypeArray> finalIndices = vtkSmartPointer<vtkIdTypeArray>::New();
        vtkSmartPointer<vtkIntArray> cellDistance = vtkSmartPointer<vtkIntArray>::New();
        cellDistance->SetName("Cell Distance");

        // Iterate over increasing topological distance until desired distance is met
        for ( int d = 0; d < this->Distance; ++ d )
          {
          vtkSmartPointer<vtkIdTypeArray> nextIndices = vtkSmartPointer<vtkIdTypeArray>::New();

          if ( ug_input )
            {
            int nIndices = outIndices->GetNumberOfTuples();
            for ( int i = 0; i < nIndices; ++ i )
              {
              vtkIdType cellIndex = static_cast<vtkIdType>( outIndices->GetTuple1( i ) );
              vtkIdType * points;
              vtkIdType n;
              ug_input->GetCellPoints(cellIndex, n, points);
              for ( int k = 0; k < n; ++ k )
                {
                vtkIdType pid = points[k];
                int np = links->GetNcells( pid );
                vtkIdType* cells = links->GetCells( pid );
                for ( int j = 0; j < np; ++ j )
                  {
                  vtkIdType cid = cells[j];
                  if( cid >= 0 && cid < numCells )
                    {
                    if ( ! flags[cid] )
                      {
                      flags[cid] = true;
                      nextIndices->InsertNextValue( cid );
                      }
                    }
                  else
                    {
                    vtkWarningMacro(<<"Selection's cell index out of bounds ("<<cid<<"/"<<numCells<<")\n");
                    }
                  }
                }
              }
            } // if ( ug_input )
          else if ( pd_input )
            {
            pd_input->BuildLinks();
            int nIndices = outIndices->GetNumberOfTuples();
            for ( int i = 0; i < nIndices; ++ i )
              {
              vtkIdType cellIndex = static_cast<vtkIdType>( outIndices->GetTuple1( i) );
              vtkIdType* points;
              vtkIdType n;
              pd_input->GetCellPoints(cellIndex, n, points);
              for ( int k = 0; k < n; ++ k )
                {
                vtkIdType pid = points[k];
                short unsigned int np;
                vtkIdType* cells;
                pd_input->GetPointCells(pid, np, cells);
                for ( int j = 0; j < np; j++)
                  {
                  vtkIdType cid = cells[j];
                  if( cid>=0 && cid<numCells )
                    {
                    if (!flags[cid])
                      {
                      flags[cid] = true;
                      nextIndices->InsertNextValue(cid);
                      }
                    }
                  else
                    {
                    vtkWarningMacro(<<"Selection's cell index out of bounds ("<<cid<<"/"<<numCells<<")\n");
                    }
                  }
                }
              }
            } // else if ( ug_input )
          else if (sg_input != 0)
            {
            int dim[3];
            sg_input->GetDimensions(dim);
            dim[0]--;
            dim[1]--;
            dim[2]--;

            int nIndices = outIndices->GetNumberOfTuples();
            for ( int i = 0; i < nIndices; ++ i )
              {
              vtkIdType cellIndex = static_cast<vtkIdType>( outIndices->GetTuple1( i ) );
              vtkIdType cellId = cellIndex;
              vtkIdType ijk[3];
              for ( int c = 0; c < 3; c++)
                {
                if (dim[c] <= 1)
                  {
                  ijk[c] = 0;
                  }
                else
                  {
                  ijk[c] = cellId % dim[c];
                  cellId /= dim[c];
                  }
                }
              for ( int k = -1; k <= 1; k++)
                {
                for ( int j = -1; j <= 1; j++)
                  {
                  for ( int l = -1; l <= 1; ++ l )
                    {
                    int I = ijk[0] + l, J = ijk[1] + j, K = ijk[2] + k;
                    if ( i >= 0 && I < dim[0] && J >= 0 && J
                        < dim[1] && K >= 0 && K < dim[2])
                      {
                      cellId = I + J * dim[0] + K * dim[0] * dim[1];
                      if( cellId >= 0 && cellId < numCells )
                        {
                        if ( ! flags[cellId] )
                          {
                          flags[cellId] = true;
                          nextIndices->InsertNextValue( cellId );
                          }
                        }
                      else
                        {
                        vtkWarningMacro(<<"Selection's cell index out of bounds ("<<cellId<<"/"<<numCells<<")\n");
                        }
                      }
                    } // l
                  } // j
                } // k
              }
            } // else if ( sg_input )
          else
            {
            vtkErrorMacro(<<"Unsupported data type : "<<input->GetClassName()<<"\n");
            }

          if( ( ! d && this->IncludeSeed ) || ( d > 0 && this->AddIntermediate ) )
            {
            int ni = outIndices->GetNumberOfTuples();
            for( int i = 0; i < ni; ++ i )
              {
              cellDistance->InsertNextTuple1( d );
              finalIndices->InsertNextTuple1( outIndices->GetTuple1( i ) );
              }
            }

          outIndices = nextIndices;
          } // for ( int d = 0; d < this->Distance; ++ d )

        if( ( ! this->Distance && this->IncludeSeed ) || ( this->Distance > 0 && this->AddIntermediate ) )
          {
          int ni = outIndices->GetNumberOfTuples();
          for( int i=0;i<ni;++ i )
            {
            cellDistance->InsertNextTuple1( this->Distance );
            finalIndices->InsertNextTuple1( outIndices->GetTuple1( i ) );
            }
          }

        if( finalIndices->GetNumberOfTuples() > 0 )
          {
          vtkSmartPointer<vtkSelectionNode> outSelNode = vtkSmartPointer<vtkSelectionNode>::New();
          outSelNode->SetContentType( vtkSelectionNode::INDICES );
          outSelNode->SetFieldType( vtkSelectionNode::CELL );
          outSelNode->GetProperties()->Set( vtkSelectionNode::COMPOSITE_INDEX(), composite_index );
          outSelNode->SetSelectionList( finalIndices );
          outSelNode->GetSelectionData()->AddArray( cellDistance );
          output->AddNode( outSelNode );
          }
        } // if numSeeds > 0 etc.
      } // while selNodeIt
    } // while inputIterator

  // Clean up
  inputIterator->Delete();

  return 1;
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
#include "ExperimentalD3D12.hpp"
#include "Application/iWindowedApplication.hpp"
#include "Application/WindowFlags.hpp"
#include "Application/WindowDesc.hpp"
#include "Graphics/ImageFlags.hpp"
#include "Logging/Logging.hpp"
#include "Math/Constants.hpp"
#include "Graphics/ImageDesc.hpp"
#include "Graphics/Format.hpp"

using namespace Cpf;

#define WINDOW_TITLE "Hello Triangle: " CPF_STRINGIZE(GFX_ADAPTER)

bool ExperimentalD3D12::_CreateWindow()
{
	//////////////////////////////////////////////////////////////////////////
	// Create the window.
	mpApplication->GetEmitter()->On<iApplication::OnQuit>([]() {
		CPF_LOG(Experimental, Info) << "**** Quit requested.";
		return true;
	});

	// Create the window.
	Math::Vector2i mWindowSize(1200, 800);
	WindowDesc windowDesc;
	windowDesc.mpTitle = WINDOW_TITLE;
	windowDesc.mX = 0; // iWindow::Centered();
	windowDesc.mY = 0; // iWindow::Centered();
	windowDesc.mWidth = mWindowSize.x;
	windowDesc.mHeight = mWindowSize.y;
	windowDesc.mFlags = WindowFlags::eResizable | WindowFlags::eShown;
	mpApplication->Create(&windowDesc, mpWindow.AsTypePP());

	if (mpWindow)
	{
		mpWindow->GetEmitter()->On<iWindow::OnResize>(Bind(&ExperimentalD3D12::_Resize, this, Placeholders::_1, Placeholders::_2));
		return true;
	}
	return false;
}

void ExperimentalD3D12::_Resize(int32_t x, int32_t y)
{
	if (mpSwapChain)
	{
		mFOV = Math::kDegToRad * 33.0f;
		float halfFov = tan(mFOV / 2.0f);
		mViewportSize = halfFov;

		mpSwapChain->Resize(x, y);

		// Recreate the depth buffers.
		// TODO: There should only be a single depth buffer.
		mpDepthBuffer.Assign(nullptr);
		mpDepthBufferView.Assign(nullptr);
		Graphics::ImageDesc depthBufferDesc
		{
			x, y,
			1,
			1,
			Graphics::Format::eD32f,
			{ 1, 0 },
			Graphics::ImageFlags::eAllowDepthStencil
		};
		mpDevice->CreateImage2D(&depthBufferDesc, nullptr, mpDepthBuffer.AsTypePP());
		mpDevice->CreateDepthStencilView(mpDepthBuffer, nullptr, mpDepthBufferView.AsTypePP());
	}
}
<commit_msg>Changed testing window size.<commit_after>//////////////////////////////////////////////////////////////////////////
#include "ExperimentalD3D12.hpp"
#include "Application/iWindowedApplication.hpp"
#include "Application/WindowFlags.hpp"
#include "Application/WindowDesc.hpp"
#include "Graphics/ImageFlags.hpp"
#include "Logging/Logging.hpp"
#include "Math/Constants.hpp"
#include "Graphics/ImageDesc.hpp"
#include "Graphics/Format.hpp"

using namespace Cpf;

#define WINDOW_TITLE "Hello Triangle: " CPF_STRINGIZE(GFX_ADAPTER)

bool ExperimentalD3D12::_CreateWindow()
{
	//////////////////////////////////////////////////////////////////////////
	// Create the window.
	mpApplication->GetEmitter()->On<iApplication::OnQuit>([]() {
		CPF_LOG(Experimental, Info) << "**** Quit requested.";
		return true;
	});

	// Create the window.
	Math::Vector2i mWindowSize(1200, 800);
	WindowDesc windowDesc;
	windowDesc.mpTitle = WINDOW_TITLE;
	windowDesc.mX = iWindow::Centered();
	windowDesc.mY = iWindow::Centered();
	windowDesc.mWidth = mWindowSize.x;
	windowDesc.mHeight = mWindowSize.y;
	windowDesc.mFlags = WindowFlags::eResizable | WindowFlags::eShown;
	mpApplication->Create(&windowDesc, mpWindow.AsTypePP());

	if (mpWindow)
	{
		mpWindow->GetEmitter()->On<iWindow::OnResize>(Bind(&ExperimentalD3D12::_Resize, this, Placeholders::_1, Placeholders::_2));
		return true;
	}
	return false;
}

void ExperimentalD3D12::_Resize(int32_t x, int32_t y)
{
	if (mpSwapChain)
	{
		mFOV = Math::kDegToRad * 33.0f;
		float halfFov = tan(mFOV / 2.0f);
		mViewportSize = halfFov;

		mpSwapChain->Resize(x, y);

		// Recreate the depth buffers.
		// TODO: There should only be a single depth buffer.
		mpDepthBuffer.Assign(nullptr);
		mpDepthBufferView.Assign(nullptr);
		Graphics::ImageDesc depthBufferDesc
		{
			x, y,
			1,
			1,
			Graphics::Format::eD32f,
			{ 1, 0 },
			Graphics::ImageFlags::eAllowDepthStencil
		};
		mpDevice->CreateImage2D(&depthBufferDesc, nullptr, mpDepthBuffer.AsTypePP());
		mpDevice->CreateDepthStencilView(mpDepthBuffer, nullptr, mpDepthBufferView.AsTypePP());
	}
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/explorer/procedures/hwp/memory/exp_getidec.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file exp_getidec.C
/// @brief Contains function to lookup Chip ID and EC values of Explorer Chip
///
/// *HWP HWP Owner: Christian Geddes <crgeddes@us.ibm.com>
/// *HWP HWP Backup: <none>
/// *HWP Team: Hostboot
/// *HWP Level: 2
/// *HWP Consumed by: Hostboot / Cronus

#include <fapi2.H>
#include <exp_getidec.H>
#include <lib/shared/exp_consts.H>
#include <chips/ocmb/explorer/common/include/explorer_scom_addresses.H>
#include <chips/ocmb/explorer/common/include/explorer_scom_addresses_fixes.H>
#include <chips/ocmb/explorer/common/include/explorer_scom_addresses_fld.H>
#include <chips/ocmb/explorer/common/include/explorer_scom_addresses_fld_fixes.H>
#include <generic/memory/mss_git_data_helper.H>

extern "C"
{

    ///
    /// @brief Lookup the Chip ID and EC level values for this explorer chip
    /// @param[in]   i_target Explorer OCMB chip
    /// @param[out]  o_chipId Explorer Chip ID
    /// @param[out]  o_chipEc Explorer Chip EC
    /// @return fapi2:ReturnCode FAPI2_RC_SUCCESS if success, else error code.
    ///
    fapi2::ReturnCode exp_getidec(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
                                  uint16_t& o_chipId,
                                  uint8_t& o_chipEc)
    {
        mss::display_git_commit_info("exp_getidec");
        uint8_t l_majorEc  = 0;
        uint8_t l_minorEc  = 0;
        uint8_t l_location = 0;
        uint8_t l_chipBaseId = 0;
        fapi2::buffer<uint64_t> l_reg_buffer;

        FAPI_TRY(fapi2::getScom( i_target,
                                 static_cast<uint64_t>(mss::exp::idec_consts::EXPLR_CHIP_INFO_REG),
                                 l_reg_buffer ),
                 "exp_getidec: could not read explorer chip_info register register 0x%08x",
                 mss::exp::idec_consts::EXPLR_CHIP_INFO_REG);

        l_reg_buffer.extractToRight<mss::exp::idec_consts::MAJOR_EC_BIT_START,
                                    mss::exp::idec_consts::MAJOR_EC_BIT_LENGTH>(l_majorEc);
        l_reg_buffer.extractToRight<mss::exp::idec_consts::LOCATION_BIT_START,
                                    mss::exp::idec_consts::LOCATION_BIT_LENGTH>(l_location);
        l_reg_buffer.extractToRight<mss::exp::idec_consts::CHIPID_BIT_START,
                                    mss::exp::idec_consts::CHIPID_BIT_LENGTH>(l_chipBaseId);

        // Due to design errors we must read the minor ec (2nd nibble) from a different register
        FAPI_TRY(fapi2::getScom( i_target, static_cast<uint64_t>(EXPLR_EFUSE_IMAGE_OUT_3), l_reg_buffer ),
                 "exp_getidec: could not read explorer efuse_out3 register 0x%08x", EXPLR_EFUSE_IMAGE_OUT_3);

        l_reg_buffer.extractToRight<EXPLR_EFUSE_IMAGE_OUT_3_ENTERPRISE_MODE_EC_MINOR,
                                    EXPLR_EFUSE_IMAGE_OUT_3_ENTERPRISE_MODE_EC_MINOR_LEN>(l_minorEc);

        // Major EC 0:3
        // Minor EC 4:7
        o_chipEc = (l_majorEc << 4) | l_minorEc;

        // Location  0:3
        // Empty     4:7
        // ChipId    8:15
        o_chipId = (l_location << 12) | l_chipBaseId;

        FAPI_DBG("EC found 0x%.02x   chipId found 0x%.04x", o_chipEc, o_chipId);

    fapi_try_exit:
        return fapi2::current_err;
    }

} // extern "C"
<commit_msg>cleaned up paths<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/explorer/procedures/hwp/memory/exp_getidec.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file exp_getidec.C
/// @brief Contains function to lookup Chip ID and EC values of Explorer Chip
///
/// *HWP HWP Owner: Christian Geddes <crgeddes@us.ibm.com>
/// *HWP HWP Backup: <none>
/// *HWP Team: Hostboot
/// *HWP Level: 2
/// *HWP Consumed by: Hostboot / Cronus

#include <fapi2.H>
#include <exp_getidec.H>
#include <lib/shared/exp_consts.H>
#include <explorer_scom_addresses.H>
#include <explorer_scom_addresses_fixes.H>
#include <explorer_scom_addresses_fld.H>
#include <explorer_scom_addresses_fld_fixes.H>
#include <generic/memory/mss_git_data_helper.H>

extern "C"
{

    ///
    /// @brief Lookup the Chip ID and EC level values for this explorer chip
    /// @param[in]   i_target Explorer OCMB chip
    /// @param[out]  o_chipId Explorer Chip ID
    /// @param[out]  o_chipEc Explorer Chip EC
    /// @return fapi2:ReturnCode FAPI2_RC_SUCCESS if success, else error code.
    ///
    fapi2::ReturnCode exp_getidec(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
                                  uint16_t& o_chipId,
                                  uint8_t& o_chipEc)
    {
        mss::display_git_commit_info("exp_getidec");
        uint8_t l_majorEc  = 0;
        uint8_t l_minorEc  = 0;
        uint8_t l_location = 0;
        uint8_t l_chipBaseId = 0;
        fapi2::buffer<uint64_t> l_reg_buffer;

        FAPI_TRY(fapi2::getScom( i_target,
                                 static_cast<uint64_t>(mss::exp::idec_consts::EXPLR_CHIP_INFO_REG),
                                 l_reg_buffer ),
                 "exp_getidec: could not read explorer chip_info register register 0x%08x",
                 mss::exp::idec_consts::EXPLR_CHIP_INFO_REG);

        l_reg_buffer.extractToRight<mss::exp::idec_consts::MAJOR_EC_BIT_START,
                                    mss::exp::idec_consts::MAJOR_EC_BIT_LENGTH>(l_majorEc);
        l_reg_buffer.extractToRight<mss::exp::idec_consts::LOCATION_BIT_START,
                                    mss::exp::idec_consts::LOCATION_BIT_LENGTH>(l_location);
        l_reg_buffer.extractToRight<mss::exp::idec_consts::CHIPID_BIT_START,
                                    mss::exp::idec_consts::CHIPID_BIT_LENGTH>(l_chipBaseId);

        // Due to design errors we must read the minor ec (2nd nibble) from a different register
        FAPI_TRY(fapi2::getScom( i_target, static_cast<uint64_t>(EXPLR_EFUSE_IMAGE_OUT_3), l_reg_buffer ),
                 "exp_getidec: could not read explorer efuse_out3 register 0x%08x", EXPLR_EFUSE_IMAGE_OUT_3);

        l_reg_buffer.extractToRight<EXPLR_EFUSE_IMAGE_OUT_3_ENTERPRISE_MODE_EC_MINOR,
                                    EXPLR_EFUSE_IMAGE_OUT_3_ENTERPRISE_MODE_EC_MINOR_LEN>(l_minorEc);

        // Major EC 0:3
        // Minor EC 4:7
        o_chipEc = (l_majorEc << 4) | l_minorEc;

        // Location  0:3
        // Empty     4:7
        // ChipId    8:15
        o_chipId = (l_location << 12) | l_chipBaseId;

        FAPI_DBG("EC found 0x%.02x   chipId found 0x%.04x", o_chipEc, o_chipId);

    fapi_try_exit:
        return fapi2::current_err;
    }

} // extern "C"
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_cpu_special_wakeup_core.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
///  @file          :    p9_cpu_special_wakeup_core.C
///  @brief         :    HWP to perform special wakeup of a core

// *HWP HW Owner    :    Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner    :    Prem S Jha <premjha2@in.ibm.com>
// *HWP Team        :    PM
// *HWP Level       :    3
// *HWP Consumed by :    OCC:FSP:HOST:CRO

// -----------------------------------------------------------------------------
// Includes
// -----------------------------------------------------------------------------
#include <p9_cpu_special_wakeup.H>
#include <p9_cpu_special_wakeup_lib.H>
#include <p9_ppe_defs.H>
#include <p9_ppe_utils.H>

fapi2::ReturnCode collectCoreTimeoutFailInfo( const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
        ProcessingValues_t i_processing_info );

/// ----------------------------------------------------------------------------
///
/// @brief      Sets a normal core chiplet into special wakeup state.
/// @param[in]  i_target     core target
/// @param[in]  i_operation  Special Wakeup Operation i.e. assert or deassert
/// @param[in]  i_entity     entity to be considered for special wakeup.
/// @return     fapi2 return code.
///
fapi2::ReturnCode p9_cpu_special_wakeup_core(
    const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
    const p9specialWakeup::PROC_SPCWKUP_OPS i_operation,
    const p9specialWakeup::PROC_SPCWKUP_ENTITY i_entity )
{
    FAPI_INF(">> p9_cpu_special_wakeup_core");
    fapi2::ReturnCode l_rc;
    uint8_t l_spWakeUpInProg = 0;
    ProcessingValues_t l_processing_info;
    auto l_eqTarget = i_target.getParent<fapi2::TARGET_TYPE_EQ>();

    FAPI_ATTR_GET( fapi2::ATTR_CORE_INSIDE_SPECIAL_WAKEUP,
                   i_target,
                   l_spWakeUpInProg );

    // A special wakeup is already in progress. In all likelyhood, a special
    // wakeup has timed out and we are in FFDC collection path. During this
    // FFDC collection, we SCOMed a register which itself needs a special
    // wakeup.

    if( l_spWakeUpInProg )
    {
        FAPI_INF("exiting core recurssion");
        return fapi2::FAPI2_RC_SUCCESS;
    }

    p9specialWakeup::blockWakeupRecurssion( l_eqTarget, p9specialWakeup::BLOCK );

    l_rc = _special_wakeup<fapi2::TARGET_TYPE_CORE> (
               i_target,
               i_operation,
               i_entity,
               l_processing_info );

    if( l_rc == (uint32_t)fapi2::RC_INTERNAL_SPCWKUP_TIMEOUT )
    {
        collectCoreTimeoutFailInfo( i_target, l_processing_info );
    }

    p9specialWakeup::blockWakeupRecurssion( l_eqTarget, p9specialWakeup::UNBLOCK );

    FAPI_INF("<< p9_cpu_special_wakeup_core" );
    return fapi2::current_err;
}

// -----------------------------------------------------------------------------

///
/// @brief      Collect FFDC for EQ Special Wakeup timeout
/// @param[in]  i_target     core target
/// @param[in]  i_operation  info pertaining to special wakeup
/// @return     fapi2 return code.
///
fapi2::ReturnCode collectCoreTimeoutFailInfo( const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
        ProcessingValues_t i_processing_info )
{
    FAPI_INF(">> collectCoreTimeoutFailInfo" );
    fapi2::buffer<uint64_t> l_CPMMR;
    fapi2::buffer<uint64_t> l_GPMMR;
    fapi2::buffer<uint64_t> l_spWakeupRegVal;
    fapi2::buffer<uint64_t> l_histRegVal;

    fapi2::getScom( i_target, C_CPPM_CPMMR, l_CPMMR );
    fapi2::getScom( i_target, C_PPM_GPMMR_SCOM, l_GPMMR );
    fapi2::getScom( i_target, i_processing_info.spwkup_address[0], l_spWakeupRegVal );
    fapi2::getScom( i_target, i_processing_info.history_address[0], l_histRegVal );
    fapi2::Target < fapi2::TARGET_TYPE_EX> parentExTgt = i_target.getParent <fapi2::TARGET_TYPE_EX>();
    uint8_t l_exPos = 0;
    FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, parentExTgt, l_exPos );

    std::vector<uint64_t> l_cmeBaseAddress;
    std::vector<uint64_t> l_sgpeBaseAddress;
    l_sgpeBaseAddress.push_back( SGPE_BASE_ADDRESS );
    l_cmeBaseAddress.push_back( getCmeBaseAddress( l_exPos ) );

    FAPI_ASSERT( false ,
                 fapi2::SPCWKUP_CORE_TIMEOUT().
                 set_POLLCOUNT( i_processing_info.poll_count ).
                 set_SP_WKUP_REG_VALUE( l_spWakeupRegVal ).
                 set_HISTORY_VALUE( l_histRegVal ).
                 set_ENTITY( i_processing_info.entity ).
                 set_CPMMR( l_CPMMR ).
                 set_GPMMR( l_GPMMR ).
                 set_EQ_TARGET( i_target.getParent <fapi2::TARGET_TYPE_EQ>() ).
                 set_EX_TARGET( parentExTgt ).
                 set_CORE_TARGET( i_target ).
                 set_PROC_CHIP_TARGET( i_processing_info.procTgt ).
                 set_CME_BASE_ADDRESS( l_cmeBaseAddress ).
                 set_SGPE_BASE_ADDRESS( l_sgpeBaseAddress ).
                 set_CME_STATE_MODE( XIRS ).
                 set_SGPE_STATE_MODE( XIRS ),
                 "Timed Out In Setting Core Special Wakeup");
fapi_try_exit:
    FAPI_INF("<< collectCoreTimeoutFailInfo" );
    return fapi2::current_err;
}
// -----------------------------------------------------------------------------
/// @param[in]  i_chipletTarget     core target
/// @param[in]  i_processing_info   struct storing processing info
/// @param[in]  i_msgId             Id pertaining to debug message string.
/// @return     fapi2 return code.
fapi2::ReturnCode spwkup_deassert(  const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_chipletTarget,
                                    const ProcessingValues_t i_processing_info,
                                    p9specialWakeup::SpecialWakeUpMsg i_msgId )
{
    FAPI_INF("> spwkup_deassert Core" );

    uint64_t l_address = i_processing_info.spwkup_address[0];
    FAPI_TRY(_spwkup_deassert(i_chipletTarget, l_address, i_msgId));

fapi_try_exit:
    FAPI_INF("< spwkup_deassert Core" );
    return fapi2::current_err;
}

// -----------------------------------------------------------------------------
///
/// @brief Set addresses for a core target type
/// @param[in]  i_target         core target
/// @param[in]  i_structure      struct storing processing info
/// @param[in]  i_entity         entity to be considered for special wakeup.
/// @return fapi2 return code.
///
template<>
fapi2::ReturnCode set_addresses(const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_target,
                                ProcessingValues_t& i_structure,
                                const uint32_t i_entity )
{
    FAPI_INF(">> set_addresses for Core");

    uint8_t l_core_num = 0;

    FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, i_target, l_core_num),
             "fapiGetAttribute of ATTR_CHIP_UNIT_POS");

    FAPI_DBG("Core %d being procesed.", l_core_num);

    i_structure.spwkup_address[0]  = SPCWKUP_ADDR[i_entity][p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.history_address[0] = SPCWKUP_HIST_ADDR[i_entity][p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.netctrl_address[0] = SPCWKUP_NETCTRL0_ADDR[p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.gpmmr_address[0] = SPCWKUP_GPMMR_ADDR[p9specialWakeup::SPW_CORE]
                                   + 0x01000000 * l_core_num;
    i_structure.num_addresses = 1;

    FAPI_DBG("i_structure.spwkup_address[%d]  = 0x%08llX \n "
             "i_structure.history_address[%d] = 0x%08llX \n "
             "i_structure.netctrl_address[%d] = 0x%08llX \n "
             "i_structure.gpmmr_addresss[%d]  = 0x%08llX \n " ,
             0, i_structure.spwkup_address[0],
             0, i_structure.history_address[0],
             0, i_structure.netctrl_address[0],
             0, i_structure.gpmmr_address[0]);

fapi_try_exit:
    FAPI_INF("<< set_addresses for Core");
    return fapi2::current_err;
}
<commit_msg>PM: Use auto-special wake-up to cover PM complex reset window<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_cpu_special_wakeup_core.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
///  @file          :    p9_cpu_special_wakeup_core.C
///  @brief         :    HWP to perform special wakeup of a core

// *HWP HW Owner    :    Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner    :    Prem S Jha <premjha2@in.ibm.com>
// *HWP Team        :    PM
// *HWP Level       :    3
// *HWP Consumed by :    OCC:FSP:HOST:CRO

// -----------------------------------------------------------------------------
// Includes
// -----------------------------------------------------------------------------
#include <p9_cpu_special_wakeup.H>
#include <p9_cpu_special_wakeup_lib.H>
#include <p9_ppe_defs.H>
#include <p9_ppe_utils.H>
#include <p9n2_quad_scom_addresses.H>
#include <p9n2_quad_scom_addresses_fld.H>

fapi2::ReturnCode collectCoreTimeoutFailInfo( const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
        ProcessingValues_t i_processing_info );

/// ----------------------------------------------------------------------------
///
/// @brief      Sets a normal core chiplet into special wakeup state.
/// @param[in]  i_target     core target
/// @param[in]  i_operation  Special Wakeup Operation i.e. assert or deassert
/// @param[in]  i_entity     entity to be considered for special wakeup.
/// @return     fapi2 return code.
///
fapi2::ReturnCode p9_cpu_special_wakeup_core(
    const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
    const p9specialWakeup::PROC_SPCWKUP_OPS i_operation,
    const p9specialWakeup::PROC_SPCWKUP_ENTITY i_entity )
{
    FAPI_INF(">> p9_cpu_special_wakeup_core");
    fapi2::ReturnCode l_rc;
    fapi2::buffer<uint64_t> l_cpmmrRegVal;
    fapi2::buffer<uint64_t> l_lmcrRegVal;
    uint8_t l_spWakeUpInProg    =   0;
    uint8_t l_corePos           =   0;
    uint8_t l_autoSplWkUpBitPos =   12; //EQ_CME_SCOM_LMCR_C0_AUTO_SPECIAL_WAKEUP_DISABLE
    uint8_t l_lmcr_fail_state = 0;

    ProcessingValues_t l_processing_info;
    auto l_eqTarget = i_target.getParent<fapi2::TARGET_TYPE_EQ>();
    auto l_exTarget = i_target.getParent<fapi2::TARGET_TYPE_EX>();

    FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS,
                   i_target,
                   l_corePos );

    l_autoSplWkUpBitPos  =  l_autoSplWkUpBitPos + ( l_corePos & 0x01) ;

    FAPI_ATTR_GET( fapi2::ATTR_CORE_INSIDE_SPECIAL_WAKEUP,
                   i_target,
                   l_spWakeUpInProg );

    // A special wakeup is already in progress. In all likelyhood, a special
    // wakeup has timed out and we are in FFDC collection path. During this
    // FFDC collection, we SCOMed a register which itself needs a special
    // wakeup.

    if( l_spWakeUpInProg )
    {
        FAPI_INF("exiting core recurssion");
        return fapi2::FAPI2_RC_SUCCESS;
    }

    p9specialWakeup::blockWakeupRecurssion( l_eqTarget, p9specialWakeup::BLOCK );

    //Not using FAPI TRY to avoid chances of  RC corruption
    l_rc = getScom( i_target,   P9N2_C_CPPM_CPMMR_SCOM, l_cpmmrRegVal );

    if( l_rc )
    {
        FAPI_ERR("Failed to SCOM CPMMR Reg, Core Pos %d", l_corePos );
        return l_rc;
    }

    l_rc = getScom( l_exTarget, EX_CME_SCOM_LMCR_SCOM,  l_lmcrRegVal );

    if( (l_rc) && (l_rc != (uint32_t)PIB_CHIPLET_OFFLINE_ERR ))
    {
        FAPI_ERR("Failed to SCOM LMCR Reg, EX Pos %d", (l_corePos >> 1 ) );
        return l_rc;
    }
    else if ((l_rc) && (l_rc == (uint32_t)PIB_CHIPLET_OFFLINE_ERR ))
    {
        l_rc = fapi2::FAPI2_RC_SUCCESS;
        l_lmcr_fail_state = 1;
    }

    if( !l_lmcrRegVal.getBit( l_autoSplWkUpBitPos ) &&
        !l_lmcr_fail_state)
    {
        if( l_cpmmrRegVal.getBit( P9N2_EX_CPPM_CPMMR_WKUP_NOTIFY_SELECT ) )
        {
            //If auto special wakeup is enabled and Special wakeup signal is not
            //getting routed towards CME, let us route it towards CME so that
            //CME HW asserts DONE bit without CME Firmware's intervention.
            FAPI_DBG("Enabling Auto Special Wakeup For Core %d", l_corePos );

            l_cpmmrRegVal.clearBit( P9N2_EX_CPPM_CPMMR_WKUP_NOTIFY_SELECT );
            putScom( i_target, P9N2_C_CPPM_CPMMR_SCOM, l_cpmmrRegVal );
        }
    }

    l_rc = _special_wakeup<fapi2::TARGET_TYPE_CORE> (
               i_target,
               i_operation,
               i_entity,
               l_processing_info );

    if( l_rc == (uint32_t)fapi2::RC_INTERNAL_SPCWKUP_TIMEOUT )
    {
        collectCoreTimeoutFailInfo( i_target, l_processing_info );
    }

    p9specialWakeup::blockWakeupRecurssion( l_eqTarget, p9specialWakeup::UNBLOCK );

    FAPI_INF("<< p9_cpu_special_wakeup_core" );
    return fapi2::current_err;
}

// -----------------------------------------------------------------------------

///
/// @brief      Collect FFDC for EQ Special Wakeup timeout
/// @param[in]  i_target     core target
/// @param[in]  i_operation  info pertaining to special wakeup
/// @return     fapi2 return code.
///
fapi2::ReturnCode collectCoreTimeoutFailInfo( const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
        ProcessingValues_t i_processing_info )
{
    FAPI_INF(">> collectCoreTimeoutFailInfo" );
    fapi2::buffer<uint64_t> l_CPMMR;
    fapi2::buffer<uint64_t> l_GPMMR;
    fapi2::buffer<uint64_t> l_spWakeupRegVal;
    fapi2::buffer<uint64_t> l_histRegVal;

    fapi2::getScom( i_target, C_CPPM_CPMMR, l_CPMMR );
    fapi2::getScom( i_target, C_PPM_GPMMR_SCOM, l_GPMMR );
    fapi2::getScom( i_target, i_processing_info.spwkup_address[0], l_spWakeupRegVal );
    fapi2::getScom( i_target, i_processing_info.history_address[0], l_histRegVal );
    fapi2::Target < fapi2::TARGET_TYPE_EX> parentExTgt = i_target.getParent <fapi2::TARGET_TYPE_EX>();
    uint8_t l_exPos = 0;
    FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, parentExTgt, l_exPos );

    std::vector<uint64_t> l_cmeBaseAddress;
    std::vector<uint64_t> l_sgpeBaseAddress;
    l_sgpeBaseAddress.push_back( SGPE_BASE_ADDRESS );
    l_cmeBaseAddress.push_back( getCmeBaseAddress( l_exPos ) );

    FAPI_ASSERT( false ,
                 fapi2::SPCWKUP_CORE_TIMEOUT().
                 set_POLLCOUNT( i_processing_info.poll_count ).
                 set_SP_WKUP_REG_VALUE( l_spWakeupRegVal ).
                 set_HISTORY_VALUE( l_histRegVal ).
                 set_ENTITY( i_processing_info.entity ).
                 set_CPMMR( l_CPMMR ).
                 set_GPMMR( l_GPMMR ).
                 set_EQ_TARGET( i_target.getParent <fapi2::TARGET_TYPE_EQ>() ).
                 set_EX_TARGET( parentExTgt ).
                 set_CORE_TARGET( i_target ).
                 set_PROC_CHIP_TARGET( i_processing_info.procTgt ).
                 set_CME_BASE_ADDRESS( l_cmeBaseAddress ).
                 set_SGPE_BASE_ADDRESS( l_sgpeBaseAddress ).
                 set_CME_STATE_MODE( XIRS ).
                 set_SGPE_STATE_MODE( XIRS ),
                 "Timed Out In Setting Core Special Wakeup");
fapi_try_exit:
    FAPI_INF("<< collectCoreTimeoutFailInfo" );
    return fapi2::current_err;
}
// -----------------------------------------------------------------------------
/// @param[in]  i_chipletTarget     core target
/// @param[in]  i_processing_info   struct storing processing info
/// @param[in]  i_msgId             Id pertaining to debug message string.
/// @return     fapi2 return code.
fapi2::ReturnCode spwkup_deassert(  const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_chipletTarget,
                                    const ProcessingValues_t i_processing_info,
                                    p9specialWakeup::SpecialWakeUpMsg i_msgId )
{
    FAPI_INF("> spwkup_deassert Core" );

    uint64_t l_address = i_processing_info.spwkup_address[0];
    FAPI_TRY(_spwkup_deassert(i_chipletTarget, l_address, i_msgId));

fapi_try_exit:
    FAPI_INF("< spwkup_deassert Core" );
    return fapi2::current_err;
}

// -----------------------------------------------------------------------------
///
/// @brief Set addresses for a core target type
/// @param[in]  i_target         core target
/// @param[in]  i_structure      struct storing processing info
/// @param[in]  i_entity         entity to be considered for special wakeup.
/// @return fapi2 return code.
///
template<>
fapi2::ReturnCode set_addresses(const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_target,
                                ProcessingValues_t& i_structure,
                                const uint32_t i_entity )
{
    FAPI_INF(">> set_addresses for Core");

    uint8_t l_core_num = 0;

    FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, i_target, l_core_num),
             "fapiGetAttribute of ATTR_CHIP_UNIT_POS");

    FAPI_DBG("Core %d being procesed.", l_core_num);

    i_structure.spwkup_address[0]  = SPCWKUP_ADDR[i_entity][p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.history_address[0] = SPCWKUP_HIST_ADDR[i_entity][p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.netctrl_address[0] = SPCWKUP_NETCTRL0_ADDR[p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.gpmmr_address[0] = SPCWKUP_GPMMR_ADDR[p9specialWakeup::SPW_CORE]
                                   + 0x01000000 * l_core_num;
    i_structure.num_addresses = 1;

    FAPI_DBG("i_structure.spwkup_address[%d]  = 0x%08llX \n "
             "i_structure.history_address[%d] = 0x%08llX \n "
             "i_structure.netctrl_address[%d] = 0x%08llX \n "
             "i_structure.gpmmr_addresss[%d]  = 0x%08llX \n " ,
             0, i_structure.spwkup_address[0],
             0, i_structure.history_address[0],
             0, i_structure.netctrl_address[0],
             0, i_structure.gpmmr_address[0]);

fapi_try_exit:
    FAPI_INF("<< set_addresses for Core");
    return fapi2::current_err;
}
<|endoftext|>