<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "GeomHelper.h"

#include <math.h>
#include <iostream>

using namespace std;

namespace avg {

DLineSegment::DLineSegment(const DPoint& pt0, const DPoint& pt1)
    : p0(pt0),
      p1(pt1)
{
}

bool DLineSegment::isPointOver(const DPoint& pt)
{
    DPoint c = pt - p0;   // DPoint from a to Point
    DPoint v = (p1 - p0);
    double d = v.getNorm(); // Length of the line segment
    v /= d; // Unit DPoint from a to b
    double t = dotProduct(v, c);  // Intersection point Distance from a

    return (t >= 0 && t <= d);
}

// Code adapted from Antonio, Franklin, "Faster Line Segment Intersection,"
// Graphics Gems III (David Kirk, ed.), Academic Press, pp. 199-202, 1992.
bool lineSegmentsIntersect(const DLineSegment& l0, const DLineSegment& l1)
{
    double xdiff0 = l0.p1.x-l0.p0.x;
    double xdiff1 = l1.p0.x-l1.p1.x;

    double x1lo, x1hi;

    /* X bound box test*/
    if (xdiff0 < 0) {
        x1lo=l0.p1.x;
        x1hi=l0.p0.x;
    } else {
        x1hi=l0.p1.x;
        x1lo=l0.p0.x;
    }
    if (xdiff1>0) {
        if (x1hi < l1.p1.x || l1.p0.x < x1lo) {
            return false;
        }
    } else {
        if (x1hi < l1.p0.x || l1.p1.x < x1lo) {
            return false;
        }
    }

    double ydiff0 = l0.p1.y-l0.p0.y;
    double ydiff1 = l1.p0.y-l1.p1.y;

    double y1lo, y1hi;

    /* Y bound box test*/
    if (ydiff0<0) {
        y1lo=l0.p1.y;
        y1hi=l0.p0.y;
    } else {
        y1hi=l0.p1.y;
        y1lo=l0.p0.y;
    }
    if (ydiff1>0) {
        if (y1hi < l1.p1.y || l1.p0.y < y1lo) {
            return false;
        }
    } else {
        if (y1hi < l1.p0.y || l1.p1.y < y1lo) {
            return false;
        }
    }

    double Cx = l0.p0.x-l1.p0.x;
    double Cy = l0.p0.y-l1.p0.y;
    double d = ydiff1*Cx - xdiff1*Cy;                  /* alpha numerator*/
    double f = ydiff0*xdiff1 - xdiff0*ydiff1;          /* both denominator*/
    if (f>0) {                                         /* alpha tests*/
        if (d<0 || d>f) {
            return false;
        }
    } else {
        if (d>0 || d<f) {
            return false;
        }
    }

    double e = xdiff0*Cy - ydiff0*Cx;                  /* beta numerator*/
    if(f>0) {                                          /* beta tests*/
        if (e<0 || e>f) {
            return false;
        }
    } else {
        if (e>0 || e<f) {
            return false;
        }
    }

    if (f==0) {
        // Theoretically, lines could still intersect in this case, but we don't care
        // because given numerical inaccuracies, the result is random anyway :-).
        return false;
    }

//    /*compute intersection coordinates*/
//    double num = d*xdiff0;                     /* numerator */
//    offset = SAME_SIGNS(num,f) ? f/2 : -f/2;   /* round direction*/
//    *x = x1 + (num+offset) / f;                /* intersection x */
//
//    num = d*ydiff0;
//    offset = SAME_SIGNS(num,f) ? f/2 : -f/2;
//    *y = y1 + (num+offset) / f;                /* intersection y */

    return true;
}

// Standard Jordan Curve Theorem (aka ray casting, even-odd-rule, crossing number)
// point-in-polygon test.
// Precomputing a bounding box for the polygon would speed this up a lot,
// but we're not using the code in a speed-critical place so far.
bool pointInPolygon(const DPoint& pt, const vector<DPoint>& poly)
{
    if (poly.size() < 3) {
        return false;
    }
    DPoint pointOutside(0,0);
    vector<DPoint>::const_iterator it;
    for (it=poly.begin(); it != poly.end(); ++it) {
        if (pointOutside.x > it->x) {
            pointOutside = *it;
        }
    }
    pointOutside.x -= 1;

    DLineSegment line0(pointOutside, pt);
    const DPoint* pLastPt = &(*--poly.end());
    bool ptInPoly = false;
    for (it=poly.begin(); it != poly.end(); ++it) {
        DLineSegment line1(*pLastPt, *it);
        if (lineSegmentsIntersect(line0, line1)) {
            ptInPoly = !ptInPoly;
        }
        pLastPt = &(*it);
    }
    return ptInPoly;
}

DPoint getLineLineIntersection(const DPoint& p1, const DPoint& v1, const DPoint& p2,
        const DPoint& v2)
{
    double denom = v2.y*v1.x-v2.x*v1.y;
    if (fabs(denom) < 0.0000001) {
        // If the lines are parallel or coincident, we just return p2!
        return p2;
    }
    double numer = v2.x*(p1.y-p2.y) - v2.y*(p1.x-p2.x);
    double ua = numer/denom;

    return p1+ua*v1;

}

}
<commit_msg>Replaced point in polygon algorithm to fix bug (when the intersection ray passes through a vertex of the polygon, the result was random).<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "GeomHelper.h"

#include <math.h>
#include <iostream>

using namespace std;

namespace avg {

DLineSegment::DLineSegment(const DPoint& pt0, const DPoint& pt1)
    : p0(pt0),
      p1(pt1)
{
}

bool DLineSegment::isPointOver(const DPoint& pt)
{
    DPoint c = pt - p0;   // DPoint from a to Point
    DPoint v = (p1 - p0);
    double d = v.getNorm(); // Length of the line segment
    v /= d; // Unit DPoint from a to b
    double t = dotProduct(v, c);  // Intersection point Distance from a

    return (t >= 0 && t <= d);
}

// Code adapted from Antonio, Franklin, "Faster Line Segment Intersection,"
// Graphics Gems III (David Kirk, ed.), Academic Press, pp. 199-202, 1992.
bool lineSegmentsIntersect(const DLineSegment& l0, const DLineSegment& l1)
{
    double xdiff0 = l0.p1.x-l0.p0.x;
    double xdiff1 = l1.p0.x-l1.p1.x;

    double x1lo, x1hi;

    /* X bound box test*/
    if (xdiff0 < 0) {
        x1lo=l0.p1.x;
        x1hi=l0.p0.x;
    } else {
        x1hi=l0.p1.x;
        x1lo=l0.p0.x;
    }
    if (xdiff1>0) {
        if (x1hi < l1.p1.x || l1.p0.x < x1lo) {
            return false;
        }
    } else {
        if (x1hi < l1.p0.x || l1.p1.x < x1lo) {
            return false;
        }
    }

    double ydiff0 = l0.p1.y-l0.p0.y;
    double ydiff1 = l1.p0.y-l1.p1.y;

    double y1lo, y1hi;

    /* Y bound box test*/
    if (ydiff0<0) {
        y1lo=l0.p1.y;
        y1hi=l0.p0.y;
    } else {
        y1hi=l0.p1.y;
        y1lo=l0.p0.y;
    }
    if (ydiff1>0) {
        if (y1hi < l1.p1.y || l1.p0.y < y1lo) {
            return false;
        }
    } else {
        if (y1hi < l1.p0.y || l1.p1.y < y1lo) {
            return false;
        }
    }

    double Cx = l0.p0.x-l1.p0.x;
    double Cy = l0.p0.y-l1.p0.y;
    double d = ydiff1*Cx - xdiff1*Cy;                  /* alpha numerator*/
    double f = ydiff0*xdiff1 - xdiff0*ydiff1;          /* both denominator*/
    if (f>0) {                                         /* alpha tests*/
        if (d<0 || d>f) {
            return false;
        }
    } else {
        if (d>0 || d<f) {
            return false;
        }
    }

    double e = xdiff0*Cy - ydiff0*Cx;                  /* beta numerator*/
    if(f>0) {                                          /* beta tests*/
        if (e<0 || e>f) {
            return false;
        }
    } else {
        if (e>0 || e<f) {
            return false;
        }
    }

    if (f==0) {
        // Theoretically, lines could still intersect in this case, but we don't care
        // because given numerical inaccuracies, the result is random anyway :-).
        return false;
    }

//    /*compute intersection coordinates*/
//    double num = d*xdiff0;                     /* numerator */
//    offset = SAME_SIGNS(num,f) ? f/2 : -f/2;   /* round direction*/
//    *x = x1 + (num+offset) / f;                /* intersection x */
//
//    num = d*ydiff0;
//    offset = SAME_SIGNS(num,f) ? f/2 : -f/2;
//    *y = y1 + (num+offset) / f;                /* intersection y */

    return true;
}

// Original code from: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html.
// Precomputing a bounding box for the polygon would speed this up a lot,
// but it hasn't shown up on any profiles so far.
bool pointInPolygon(const DPoint& pt, const vector<DPoint>& poly)
{
    if (poly.size() < 3) {
        return false;
    }
    bool bPtInPoly = false;
    for (unsigned i = 0, j = poly.size()-1; i < poly.size(); j = i++) {
        if (((poly[i].y > pt.y) != (poly[j].y > pt.y)) &&
                (pt.x < (poly[j].x-poly[i].x)*(pt.y-poly[i].y) / (poly[j].y-poly[i].y)
                 +poly[i].x))
        {
            bPtInPoly = !bPtInPoly;
        }
    }
    return bPtInPoly;
}

DPoint getLineLineIntersection(const DPoint& p1, const DPoint& v1, const DPoint& p2,
        const DPoint& v2)
{
    double denom = v2.y*v1.x-v2.x*v1.y;
    if (fabs(denom) < 0.0000001) {
        // If the lines are parallel or coincident, we just return p2!
        return p2;
    }
    double numer = v2.x*(p1.y-p2.y) - v2.y*(p1.x-p2.x);
    double ua = numer/denom;

    return p1+ua*v1;

}

}
<|endoftext|>


<commit_before>/*
 * SessionProjects.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <session/projects/SessionProjects.hpp>

#include <core/FilePath.hpp>
#include <core/Settings.hpp>
#include <core/Exec.hpp>
#include <core/FileSerializer.hpp>
#include <core/system/System.hpp>
#include <core/r_util/RProjectFile.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/SessionUserSettings.hpp>

#include <r/session/RSessionUtils.hpp>

#include "SessionProjectsInternal.hpp"

using namespace core;

namespace session {
namespace projects {

namespace {

ProjectContext s_projectContext;

void onSuspend(Settings*)
{
   // on suspend write out current project path as the one to use
   // on resume. we read this back in initalize (rather than in
   // the onResume handler) becuase we need it very early in the
   // processes lifetime and onResume happens too late
   s_projectContext.setNextSessionProject(
                              s_projectContext.file().absolutePath());
}

void onResume(const Settings&) {}

Error createProject(const json::JsonRpcRequest& request,
                    json::JsonRpcResponse* pResponse)
{
   // read params
   std::string projectFile;
   Error error = json::readParam(request.params, 0, &projectFile);
   if (error)
      return error;
   FilePath projectFilePath = module_context::resolveAliasedPath(projectFile);

   // ensure that the parent directory exists
   error = projectFilePath.parent().ensureDirectory();
   if (error)
      return error;

   // create the project file
   return r_util::writeProjectFile(projectFilePath,
                                   ProjectContext::defaultConfig());
}

json::Object projectConfigJson(const r_util::RProjectConfig& config)
{
   json::Object configJson;
   configJson["version"] = config.version;
   configJson["restore_workspace"] = config.restoreWorkspace;
   configJson["save_workspace"] = config.saveWorkspace;
   configJson["always_save_history"] = config.alwaysSaveHistory;
   configJson["enable_code_indexing"] = config.enableCodeIndexing;
   configJson["use_spaces_for_tab"] = config.useSpacesForTab;
   configJson["num_spaces_for_tab"] = config.numSpacesForTab;
   configJson["default_encoding"] = config.encoding;
   configJson["default_sweave_engine"] = config.defaultSweaveEngine;
   configJson["default_latex_program"] = config.defaultLatexProgram;
   configJson["root_document"] = config.rootDocument;
   configJson["build_type"] = config.buildType;
   configJson["package_path"] = config.packagePath;
   configJson["package_install_args"] = config.packageInstallArgs;
   configJson["package_build_args"] = config.packageBuildArgs;
   configJson["package_check_args"] = config.packageCheckArgs;
   configJson["package_roxygenize"] = config.packageRoxygenize;
   configJson["makefile_path"] = config.makefilePath;
   configJson["custom_script_path"] = config.customScriptPath;
   return configJson;
}

json::Object projectBuildOptionsJson()
{
   RProjectBuildOptions buildOptions;
   Error error = s_projectContext.readBuildOptions(&buildOptions);
   if (error)
      LOG_ERROR(error);
   json::Object buildOptionsJson;
   buildOptionsJson["makefile_args"] = buildOptions.makefileArgs;
   buildOptionsJson["cleanup_after_check"] = buildOptions.cleanupAfterCheck;

   json::Object autoRoxJson;
   autoRoxJson["run_on_check"] = buildOptions.autoRoxygenizeForCheck;
   autoRoxJson["run_on_package_builds"] =
                              buildOptions.autoRoxygenizeForBuildPackage;
   autoRoxJson["run_on_build_and_reload"] =
                              buildOptions.autoRoxygenizeForBuildAndReload;
   buildOptionsJson["auto_roxygenize_options"] = autoRoxJson;
   return buildOptionsJson;
}

json::Object projectVcsOptionsJson()
{
   RProjectVcsOptions vcsOptions;
   Error error = s_projectContext.readVcsOptions(&vcsOptions);
   if (error)
      LOG_ERROR(error);
   json::Object vcsOptionsJson;
   vcsOptionsJson["active_vcs_override"] = vcsOptions.vcsOverride;
   return vcsOptionsJson;
}

json::Object projectVcsContextJson()
{
   module_context::VcsContext vcsContext = module_context::vcsContext(
                                             s_projectContext.directory());

   json::Object contextJson;
   contextJson["detected_vcs"] = vcsContext.detectedVcs;
   json::Array applicableJson;
   BOOST_FOREACH(const std::string& vcs, vcsContext.applicableVcs)
   {
      applicableJson.push_back(vcs);
   }
   contextJson["applicable_vcs"] = applicableJson;

   contextJson["svn_repository_root"] = vcsContext.svnRepositoryRoot;
   contextJson["git_remote_origin_url"] = vcsContext.gitRemoteOriginUrl;

   return contextJson;
}

json::Object projectBuildContextJson()
{
   json::Object contextJson;
   contextJson["roxygen2_installed"] =
                        module_context::isPackageInstalled("roxygen2");
   contextJson["devtools_installed"] =
                           module_context::isPackageInstalled("devtools");
   return contextJson;
}

Error readProjectOptions(const json::JsonRpcRequest& request,
                        json::JsonRpcResponse* pResponse)
{
   // get project config json
   json::Object configJson = projectConfigJson(s_projectContext.config());

   // create project options json
   json::Object optionsJson;
   optionsJson["config"] = configJson;
   optionsJson["vcs_options"] = projectVcsOptionsJson();
   optionsJson["vcs_context"] = projectVcsContextJson();
   optionsJson["build_options"] = projectBuildOptionsJson();
   optionsJson["build_context"] = projectBuildContextJson();

   pResponse->setResult(optionsJson);
   return Success();
}

void setProjectConfig(const r_util::RProjectConfig& config)
{
   // set it
   s_projectContext.setConfig(config);

   // sync underlying R setting
   module_context::syncRSaveAction();
}

Error rProjectBuildOptionsFromJson(const json::Object& optionsJson,
                                   RProjectBuildOptions* pOptions)
{
   json::Object autoRoxJson;
   Error error = json::readObject(
       optionsJson,
       "makefile_args", &(pOptions->makefileArgs),
       "cleanup_after_check",&(pOptions->cleanupAfterCheck),
       "auto_roxygenize_options", &autoRoxJson);
   if (error)
      return error;

   return json::readObject(
       autoRoxJson,
       "run_on_check", &(pOptions->autoRoxygenizeForCheck),
       "run_on_package_builds", &(pOptions->autoRoxygenizeForBuildPackage),
       "run_on_build_and_reload", &(pOptions->autoRoxygenizeForBuildAndReload));
}

Error rProjectVcsOptionsFromJson(const json::Object& optionsJson,
                                 RProjectVcsOptions* pOptions)
{
   return json::readObject(
         optionsJson,
         "active_vcs_override", &(pOptions->vcsOverride));
}

Error writeProjectOptions(const json::JsonRpcRequest& request,
                         json::JsonRpcResponse* pResponse)
{
   // get the project config, vcs options, and build options
   json::Object configJson, vcsOptionsJson, buildOptionsJson;
   Error error = json::readObjectParam(request.params, 0,
                                       "config", &configJson,
                                       "vcs_options", &vcsOptionsJson,
                                       "build_options", &buildOptionsJson);
   if (error)
      return error;

   // read the config
   r_util::RProjectConfig config;
   error = json::readObject(
                    configJson,
                    "version", &(config.version),
                    "restore_workspace", &(config.restoreWorkspace),
                    "save_workspace", &(config.saveWorkspace),
                    "always_save_history", &(config.alwaysSaveHistory),
                    "enable_code_indexing", &(config.enableCodeIndexing),
                    "use_spaces_for_tab", &(config.useSpacesForTab),
                    "num_spaces_for_tab", &(config.numSpacesForTab),
                    "default_encoding", &(config.encoding),
                    "default_sweave_engine", &(config.defaultSweaveEngine),
                    "default_latex_program", &(config.defaultLatexProgram),
                    "root_document", &(config.rootDocument));
   if (error)
      return error;

   error = json::readObject(
                    configJson,
                    "build_type", &(config.buildType),
                    "package_path", &(config.packagePath),
                    "package_install_args", &(config.packageInstallArgs),
                    "package_build_args", &(config.packageBuildArgs),
                    "package_check_args", &(config.packageCheckArgs),
                    "package_roxygenize", &(config.packageRoxygenize),
                    "makefile_path", &(config.makefilePath),
                    "custom_script_path", &(config.customScriptPath));
   if (error)
      return error;

   // read the vcs options
   RProjectVcsOptions vcsOptions;
   error = rProjectVcsOptionsFromJson(vcsOptionsJson, &vcsOptions);
   if (error)
      return error;

   // read the buld options
   RProjectBuildOptions buildOptions;
   error = rProjectBuildOptionsFromJson(buildOptionsJson, &buildOptions);
   if (error)
      return error;

   // write the config
   error = r_util::writeProjectFile(s_projectContext.file(), config);
   if (error)
      return error;

   // set the config
   setProjectConfig(config);

   // write the vcs options
   error = s_projectContext.writeVcsOptions(vcsOptions);
   if (error)
      LOG_ERROR(error);

   // write the build options
   error = s_projectContext.writeBuildOptions(buildOptions);
   if (error)
      LOG_ERROR(error);

   return Success();
}

Error writeProjectVcsOptions(const json::JsonRpcRequest& request,
                             json::JsonRpcResponse* pResponse)
{
   // read the vcs options
   json::Object vcsOptionsJson;
   Error error = json::readParam(request.params, 0, &vcsOptionsJson);
   if (error)
      return error;
   RProjectVcsOptions vcsOptions;
   error = rProjectVcsOptionsFromJson(vcsOptionsJson, &vcsOptions);
   if (error)
      return error;

   // write the vcs options
   error = s_projectContext.writeVcsOptions(vcsOptions);
   if (error)
      LOG_ERROR(error);

   return Success();
}

void onShutdown(bool terminatedNormally)
{
   if (terminatedNormally)
      s_projectContext.setLastProjectPath(s_projectContext.file());
}

void syncProjectFileChanges()
{
   // read project file config
   bool providedDefaults;
   std::string userErrMsg;
   r_util::RProjectConfig config;
   Error error = r_util::readProjectFile(s_projectContext.file(),
                                         ProjectContext::defaultConfig(),
                                         &config,
                                         &providedDefaults,
                                         &userErrMsg);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // set config
   setProjectConfig(config);

   // fire event to client
   json::Object dataJson;
   dataJson["type"] = "project";
   dataJson["prefs"] = s_projectContext.uiPrefs();
   ClientEvent event(client_events::kUiPrefsChanged, dataJson);
   module_context::enqueClientEvent(event);
}

void onFilesChanged(const std::vector<core::system::FileChangeEvent>& events)
{
   BOOST_FOREACH(const core::system::FileChangeEvent& event, events)
   {
      // if the project file changed then sync its changes
      if (event.fileInfo().absolutePath() ==
          s_projectContext.file().absolutePath())
      {
         syncProjectFileChanges();
         break;
      }
   }
}

void onMonitoringDisabled()
{
   // NOTE: if monitoring is disabled then we can't sync changes to the
   // project file -- we could poll for this however since it is only
   // a conveninece to have these synced we don't do this
}

}  // anonymous namespace

void startup()
{
   // register suspend handler
   using namespace module_context;
   addSuspendHandler(SuspendHandler(onSuspend, onResume));

   // determine project file path
   FilePath projectFilePath;

   // see if there is a project path hard-wired for the next session
   // (this would be used for a switch to project or for the resuming of
   // a suspended session)
   std::string nextSessionProject = s_projectContext.nextSessionProject();
   FilePath lastProjectPath = s_projectContext.lastProjectPath();

   // check for next session project path (see above for comment)
   if (!nextSessionProject.empty())
   {
      // reset next session project path so its a one shot deal
      s_projectContext.setNextSessionProject("");

      // clear any initial context settings which may be leftover
      // by a re-instatiation of rsession by desktop
      session::options().clearInitialContextSettings();

      // check for special "none" value (used for close project)
      if (nextSessionProject == "none")
      {
         projectFilePath = FilePath();
      }
      else
      {
         projectFilePath = module_context::resolveAliasedPath(
                                                   nextSessionProject);
      }
   }

   // check for envrionment variable (file association)
   else if (!session::options().initialProjectPath().empty())
   {
      projectFilePath = session::options().initialProjectPath();
   }

   // check for other working dir override (implies a launch of a file
   // but not of a project). this code path is here to prevent
   // the next code path from executing
   else if (!session::options().initialWorkingDirOverride().empty())
   {
      projectFilePath = FilePath();
   }

   // check for restore last project
   else if (userSettings().alwaysRestoreLastProject() &&
            !lastProjectPath.empty())
   {

      // get last project path
      projectFilePath = lastProjectPath;

      // reset it to empty so that we only attempt to load the "lastProject"
      // a single time (this will be reset to the path below after we
      // clear the s_projectContext.initialize)
      s_projectContext.setLastProjectPath(FilePath());
   }

   // else no active project for this session
   else
   {
      projectFilePath = FilePath();
   }

   // if we have a project file path then try to initialize the
   // project context (show a warning to the user if we can't)
   if (!projectFilePath.empty())
   {
      std::string userErrMsg;
      Error error = s_projectContext.startup(projectFilePath, &userErrMsg);
      if (error)
      {
         // log the error
         error.addProperty("project-file", projectFilePath.absolutePath());
         error.addProperty("user-msg", userErrMsg);
         LOG_ERROR(error);

         // enque the error
         json::Object openProjError;
         openProjError["project"] = module_context::createAliasedPath(
                                                            projectFilePath);
         openProjError["message"] = userErrMsg;
         ClientEvent event(client_events::kOpenProjectError, openProjError);
         module_context::enqueClientEvent(event);
      }
   }
}

Error initialize()
{
   // call project-context initialize
   Error error = s_projectContext.initialize();
   if (error)
      return error;

   // subscribe to file_monitor for project file changes
   projects::FileMonitorCallbacks cb;
   cb.onFilesChanged = onFilesChanged;
   cb.onMonitoringDisabled = onMonitoringDisabled;
   s_projectContext.subscribeToFileMonitor("", cb);

   // subscribe to shutdown for setting lastProjectPath
   module_context::events().onShutdown.connect(onShutdown);

   using boost::bind;
   using namespace module_context;
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "create_project", createProject))
      (bind(registerRpcMethod, "read_project_options", readProjectOptions))
      (bind(registerRpcMethod, "write_project_options", writeProjectOptions))
      (bind(registerRpcMethod, "write_project_vcs_options", writeProjectVcsOptions))
   ;
   return initBlock.execute();
}

ProjectContext& projectContext()
{
   return s_projectContext;
}

} // namespace projects
} // namesapce session

<commit_msg>don't create project file if it already exists (e.g. when it was retreived from version control)<commit_after>/*
 * SessionProjects.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <session/projects/SessionProjects.hpp>

#include <core/FilePath.hpp>
#include <core/Settings.hpp>
#include <core/Exec.hpp>
#include <core/FileSerializer.hpp>
#include <core/system/System.hpp>
#include <core/r_util/RProjectFile.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/SessionUserSettings.hpp>

#include <r/session/RSessionUtils.hpp>

#include "SessionProjectsInternal.hpp"

using namespace core;

namespace session {
namespace projects {

namespace {

ProjectContext s_projectContext;

void onSuspend(Settings*)
{
   // on suspend write out current project path as the one to use
   // on resume. we read this back in initalize (rather than in
   // the onResume handler) becuase we need it very early in the
   // processes lifetime and onResume happens too late
   s_projectContext.setNextSessionProject(
                              s_projectContext.file().absolutePath());
}

void onResume(const Settings&) {}

Error createProject(const json::JsonRpcRequest& request,
                    json::JsonRpcResponse* pResponse)
{
   // read params
   std::string projectFile;
   Error error = json::readParam(request.params, 0, &projectFile);
   if (error)
      return error;
   FilePath projectFilePath = module_context::resolveAliasedPath(projectFile);

   // ensure that the parent directory exists
   error = projectFilePath.parent().ensureDirectory();
   if (error)
      return error;

   // create the project file
   if (!projectFilePath.exists())
   {
      return r_util::writeProjectFile(projectFilePath,
                                      ProjectContext::defaultConfig());
   }
   else
   {
      return Success();
   }
}

json::Object projectConfigJson(const r_util::RProjectConfig& config)
{
   json::Object configJson;
   configJson["version"] = config.version;
   configJson["restore_workspace"] = config.restoreWorkspace;
   configJson["save_workspace"] = config.saveWorkspace;
   configJson["always_save_history"] = config.alwaysSaveHistory;
   configJson["enable_code_indexing"] = config.enableCodeIndexing;
   configJson["use_spaces_for_tab"] = config.useSpacesForTab;
   configJson["num_spaces_for_tab"] = config.numSpacesForTab;
   configJson["default_encoding"] = config.encoding;
   configJson["default_sweave_engine"] = config.defaultSweaveEngine;
   configJson["default_latex_program"] = config.defaultLatexProgram;
   configJson["root_document"] = config.rootDocument;
   configJson["build_type"] = config.buildType;
   configJson["package_path"] = config.packagePath;
   configJson["package_install_args"] = config.packageInstallArgs;
   configJson["package_build_args"] = config.packageBuildArgs;
   configJson["package_check_args"] = config.packageCheckArgs;
   configJson["package_roxygenize"] = config.packageRoxygenize;
   configJson["makefile_path"] = config.makefilePath;
   configJson["custom_script_path"] = config.customScriptPath;
   return configJson;
}

json::Object projectBuildOptionsJson()
{
   RProjectBuildOptions buildOptions;
   Error error = s_projectContext.readBuildOptions(&buildOptions);
   if (error)
      LOG_ERROR(error);
   json::Object buildOptionsJson;
   buildOptionsJson["makefile_args"] = buildOptions.makefileArgs;
   buildOptionsJson["cleanup_after_check"] = buildOptions.cleanupAfterCheck;

   json::Object autoRoxJson;
   autoRoxJson["run_on_check"] = buildOptions.autoRoxygenizeForCheck;
   autoRoxJson["run_on_package_builds"] =
                              buildOptions.autoRoxygenizeForBuildPackage;
   autoRoxJson["run_on_build_and_reload"] =
                              buildOptions.autoRoxygenizeForBuildAndReload;
   buildOptionsJson["auto_roxygenize_options"] = autoRoxJson;
   return buildOptionsJson;
}

json::Object projectVcsOptionsJson()
{
   RProjectVcsOptions vcsOptions;
   Error error = s_projectContext.readVcsOptions(&vcsOptions);
   if (error)
      LOG_ERROR(error);
   json::Object vcsOptionsJson;
   vcsOptionsJson["active_vcs_override"] = vcsOptions.vcsOverride;
   return vcsOptionsJson;
}

json::Object projectVcsContextJson()
{
   module_context::VcsContext vcsContext = module_context::vcsContext(
                                             s_projectContext.directory());

   json::Object contextJson;
   contextJson["detected_vcs"] = vcsContext.detectedVcs;
   json::Array applicableJson;
   BOOST_FOREACH(const std::string& vcs, vcsContext.applicableVcs)
   {
      applicableJson.push_back(vcs);
   }
   contextJson["applicable_vcs"] = applicableJson;

   contextJson["svn_repository_root"] = vcsContext.svnRepositoryRoot;
   contextJson["git_remote_origin_url"] = vcsContext.gitRemoteOriginUrl;

   return contextJson;
}

json::Object projectBuildContextJson()
{
   json::Object contextJson;
   contextJson["roxygen2_installed"] =
                        module_context::isPackageInstalled("roxygen2");
   contextJson["devtools_installed"] =
                           module_context::isPackageInstalled("devtools");
   return contextJson;
}

Error readProjectOptions(const json::JsonRpcRequest& request,
                        json::JsonRpcResponse* pResponse)
{
   // get project config json
   json::Object configJson = projectConfigJson(s_projectContext.config());

   // create project options json
   json::Object optionsJson;
   optionsJson["config"] = configJson;
   optionsJson["vcs_options"] = projectVcsOptionsJson();
   optionsJson["vcs_context"] = projectVcsContextJson();
   optionsJson["build_options"] = projectBuildOptionsJson();
   optionsJson["build_context"] = projectBuildContextJson();

   pResponse->setResult(optionsJson);
   return Success();
}

void setProjectConfig(const r_util::RProjectConfig& config)
{
   // set it
   s_projectContext.setConfig(config);

   // sync underlying R setting
   module_context::syncRSaveAction();
}

Error rProjectBuildOptionsFromJson(const json::Object& optionsJson,
                                   RProjectBuildOptions* pOptions)
{
   json::Object autoRoxJson;
   Error error = json::readObject(
       optionsJson,
       "makefile_args", &(pOptions->makefileArgs),
       "cleanup_after_check",&(pOptions->cleanupAfterCheck),
       "auto_roxygenize_options", &autoRoxJson);
   if (error)
      return error;

   return json::readObject(
       autoRoxJson,
       "run_on_check", &(pOptions->autoRoxygenizeForCheck),
       "run_on_package_builds", &(pOptions->autoRoxygenizeForBuildPackage),
       "run_on_build_and_reload", &(pOptions->autoRoxygenizeForBuildAndReload));
}

Error rProjectVcsOptionsFromJson(const json::Object& optionsJson,
                                 RProjectVcsOptions* pOptions)
{
   return json::readObject(
         optionsJson,
         "active_vcs_override", &(pOptions->vcsOverride));
}

Error writeProjectOptions(const json::JsonRpcRequest& request,
                         json::JsonRpcResponse* pResponse)
{
   // get the project config, vcs options, and build options
   json::Object configJson, vcsOptionsJson, buildOptionsJson;
   Error error = json::readObjectParam(request.params, 0,
                                       "config", &configJson,
                                       "vcs_options", &vcsOptionsJson,
                                       "build_options", &buildOptionsJson);
   if (error)
      return error;

   // read the config
   r_util::RProjectConfig config;
   error = json::readObject(
                    configJson,
                    "version", &(config.version),
                    "restore_workspace", &(config.restoreWorkspace),
                    "save_workspace", &(config.saveWorkspace),
                    "always_save_history", &(config.alwaysSaveHistory),
                    "enable_code_indexing", &(config.enableCodeIndexing),
                    "use_spaces_for_tab", &(config.useSpacesForTab),
                    "num_spaces_for_tab", &(config.numSpacesForTab),
                    "default_encoding", &(config.encoding),
                    "default_sweave_engine", &(config.defaultSweaveEngine),
                    "default_latex_program", &(config.defaultLatexProgram),
                    "root_document", &(config.rootDocument));
   if (error)
      return error;

   error = json::readObject(
                    configJson,
                    "build_type", &(config.buildType),
                    "package_path", &(config.packagePath),
                    "package_install_args", &(config.packageInstallArgs),
                    "package_build_args", &(config.packageBuildArgs),
                    "package_check_args", &(config.packageCheckArgs),
                    "package_roxygenize", &(config.packageRoxygenize),
                    "makefile_path", &(config.makefilePath),
                    "custom_script_path", &(config.customScriptPath));
   if (error)
      return error;

   // read the vcs options
   RProjectVcsOptions vcsOptions;
   error = rProjectVcsOptionsFromJson(vcsOptionsJson, &vcsOptions);
   if (error)
      return error;

   // read the buld options
   RProjectBuildOptions buildOptions;
   error = rProjectBuildOptionsFromJson(buildOptionsJson, &buildOptions);
   if (error)
      return error;

   // write the config
   error = r_util::writeProjectFile(s_projectContext.file(), config);
   if (error)
      return error;

   // set the config
   setProjectConfig(config);

   // write the vcs options
   error = s_projectContext.writeVcsOptions(vcsOptions);
   if (error)
      LOG_ERROR(error);

   // write the build options
   error = s_projectContext.writeBuildOptions(buildOptions);
   if (error)
      LOG_ERROR(error);

   return Success();
}

Error writeProjectVcsOptions(const json::JsonRpcRequest& request,
                             json::JsonRpcResponse* pResponse)
{
   // read the vcs options
   json::Object vcsOptionsJson;
   Error error = json::readParam(request.params, 0, &vcsOptionsJson);
   if (error)
      return error;
   RProjectVcsOptions vcsOptions;
   error = rProjectVcsOptionsFromJson(vcsOptionsJson, &vcsOptions);
   if (error)
      return error;

   // write the vcs options
   error = s_projectContext.writeVcsOptions(vcsOptions);
   if (error)
      LOG_ERROR(error);

   return Success();
}

void onShutdown(bool terminatedNormally)
{
   if (terminatedNormally)
      s_projectContext.setLastProjectPath(s_projectContext.file());
}

void syncProjectFileChanges()
{
   // read project file config
   bool providedDefaults;
   std::string userErrMsg;
   r_util::RProjectConfig config;
   Error error = r_util::readProjectFile(s_projectContext.file(),
                                         ProjectContext::defaultConfig(),
                                         &config,
                                         &providedDefaults,
                                         &userErrMsg);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // set config
   setProjectConfig(config);

   // fire event to client
   json::Object dataJson;
   dataJson["type"] = "project";
   dataJson["prefs"] = s_projectContext.uiPrefs();
   ClientEvent event(client_events::kUiPrefsChanged, dataJson);
   module_context::enqueClientEvent(event);
}

void onFilesChanged(const std::vector<core::system::FileChangeEvent>& events)
{
   BOOST_FOREACH(const core::system::FileChangeEvent& event, events)
   {
      // if the project file changed then sync its changes
      if (event.fileInfo().absolutePath() ==
          s_projectContext.file().absolutePath())
      {
         syncProjectFileChanges();
         break;
      }
   }
}

void onMonitoringDisabled()
{
   // NOTE: if monitoring is disabled then we can't sync changes to the
   // project file -- we could poll for this however since it is only
   // a conveninece to have these synced we don't do this
}

}  // anonymous namespace

void startup()
{
   // register suspend handler
   using namespace module_context;
   addSuspendHandler(SuspendHandler(onSuspend, onResume));

   // determine project file path
   FilePath projectFilePath;

   // see if there is a project path hard-wired for the next session
   // (this would be used for a switch to project or for the resuming of
   // a suspended session)
   std::string nextSessionProject = s_projectContext.nextSessionProject();
   FilePath lastProjectPath = s_projectContext.lastProjectPath();

   // check for next session project path (see above for comment)
   if (!nextSessionProject.empty())
   {
      // reset next session project path so its a one shot deal
      s_projectContext.setNextSessionProject("");

      // clear any initial context settings which may be leftover
      // by a re-instatiation of rsession by desktop
      session::options().clearInitialContextSettings();

      // check for special "none" value (used for close project)
      if (nextSessionProject == "none")
      {
         projectFilePath = FilePath();
      }
      else
      {
         projectFilePath = module_context::resolveAliasedPath(
                                                   nextSessionProject);
      }
   }

   // check for envrionment variable (file association)
   else if (!session::options().initialProjectPath().empty())
   {
      projectFilePath = session::options().initialProjectPath();
   }

   // check for other working dir override (implies a launch of a file
   // but not of a project). this code path is here to prevent
   // the next code path from executing
   else if (!session::options().initialWorkingDirOverride().empty())
   {
      projectFilePath = FilePath();
   }

   // check for restore last project
   else if (userSettings().alwaysRestoreLastProject() &&
            !lastProjectPath.empty())
   {

      // get last project path
      projectFilePath = lastProjectPath;

      // reset it to empty so that we only attempt to load the "lastProject"
      // a single time (this will be reset to the path below after we
      // clear the s_projectContext.initialize)
      s_projectContext.setLastProjectPath(FilePath());
   }

   // else no active project for this session
   else
   {
      projectFilePath = FilePath();
   }

   // if we have a project file path then try to initialize the
   // project context (show a warning to the user if we can't)
   if (!projectFilePath.empty())
   {
      std::string userErrMsg;
      Error error = s_projectContext.startup(projectFilePath, &userErrMsg);
      if (error)
      {
         // log the error
         error.addProperty("project-file", projectFilePath.absolutePath());
         error.addProperty("user-msg", userErrMsg);
         LOG_ERROR(error);

         // enque the error
         json::Object openProjError;
         openProjError["project"] = module_context::createAliasedPath(
                                                            projectFilePath);
         openProjError["message"] = userErrMsg;
         ClientEvent event(client_events::kOpenProjectError, openProjError);
         module_context::enqueClientEvent(event);
      }
   }
}

Error initialize()
{
   // call project-context initialize
   Error error = s_projectContext.initialize();
   if (error)
      return error;

   // subscribe to file_monitor for project file changes
   projects::FileMonitorCallbacks cb;
   cb.onFilesChanged = onFilesChanged;
   cb.onMonitoringDisabled = onMonitoringDisabled;
   s_projectContext.subscribeToFileMonitor("", cb);

   // subscribe to shutdown for setting lastProjectPath
   module_context::events().onShutdown.connect(onShutdown);

   using boost::bind;
   using namespace module_context;
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "create_project", createProject))
      (bind(registerRpcMethod, "read_project_options", readProjectOptions))
      (bind(registerRpcMethod, "write_project_options", writeProjectOptions))
      (bind(registerRpcMethod, "write_project_vcs_options", writeProjectVcsOptions))
   ;
   return initBlock.execute();
}

ProjectContext& projectContext()
{
   return s_projectContext;
}

} // namespace projects
} // namesapce session

<|endoftext|>


<commit_before>// Copyright (c) 2009-2018 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

// Maintainer: joaander

/*! \file CellListGPU.cc
    \brief Defines CellListGPU
*/

#include "CellListGPU.h"
#include "CellListGPU.cuh"

namespace py = pybind11;

using namespace std;

/*! \param sysdef system to compute the cell list of
*/
CellListGPU::CellListGPU(std::shared_ptr<SystemDefinition> sysdef)
    : CellList(sysdef)
    {
    if (!m_exec_conf->isCUDAEnabled())
        {
        m_exec_conf->msg->error() << "Creating a CellListGPU with no GPU in the execution configuration" << endl;
        throw std::runtime_error("Error initializing CellListGPU");
        }

    m_tuner.reset(new Autotuner(32, 1024, 32, 5, 100000, "cell_list", this->m_exec_conf));
    m_tuner_combine.reset(new Autotuner(32, 1024, 32, 5, 100000, "cell_list_combine", this->m_exec_conf));

    }

void CellListGPU::computeCellList()
    {
    if (m_prof)
        m_prof->push(m_exec_conf, "compute");

    // acquire the particle data
    ArrayHandle<Scalar4> d_pos(m_pdata->getPositions(), access_location::device, access_mode::read);
    ArrayHandle<Scalar4> d_orientation(m_pdata->getOrientationArray(), access_location::device, access_mode::read);
    ArrayHandle<Scalar> d_charge(m_pdata->getCharges(), access_location::device, access_mode::read);
    ArrayHandle<Scalar> d_diameter(m_pdata->getDiameters(), access_location::device, access_mode::read);
    ArrayHandle<unsigned int> d_body(m_pdata->getBodies(), access_location::device, access_mode::read);

    BoxDim box = m_pdata->getBox();

    // access the cell list data arrays
    ArrayHandle<unsigned int> d_cell_size(m_cell_size, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_xyzf(m_xyzf, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_tdb(m_tdb, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_cell_orientation(m_orientation, access_location::device, access_mode::overwrite);
    ArrayHandle<unsigned int> d_cell_idx(m_idx, access_location::device, access_mode::overwrite);

    // access the per-GPU cell list arrays (only needed with ngpu>1)
    ArrayHandle<unsigned int> d_cell_size_scratch(m_cell_size_scratch, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_xyzf_scratch(m_xyzf_scratch, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_tdb_scratch(m_tdb_scratch, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_cell_orientation_scratch(m_orientation_scratch, access_location::device, access_mode::overwrite);
    ArrayHandle<unsigned int> d_cell_idx_scratch(m_idx_scratch, access_location::device, access_mode::overwrite);

    // error conditions
    ArrayHandle<uint3> d_conditions(m_conditions, access_location::device, access_mode::overwrite);

    unsigned int ngpu = m_exec_conf->getNumActiveGPUs();

    // reset cell list contents
    cudaMemsetAsync(d_cell_size.data, 0, sizeof(unsigned int)*m_cell_indexer.getNumElements(),0);
    if (m_exec_conf->isCUDAErrorCheckingEnabled())
        CHECK_CUDA_ERROR();

    if (ngpu > 1)
        {
        // reset temporary arrays
        cudaMemsetAsync(d_cell_size_scratch.data, 0, sizeof(unsigned int)*m_cell_size_scratch.getNumElements(),0);
        if (m_exec_conf->isCUDAErrorCheckingEnabled())
            CHECK_CUDA_ERROR();
        }

    m_exec_conf->beginMultiGPU();

    // autotune block sizes
    m_tuner->begin();

    // compute cell list, and write to temporary arrays with multi-GPU
    gpu_compute_cell_list(ngpu == 1 ? d_cell_size.data : d_cell_size_scratch.data,
                          ngpu == 1 ? d_xyzf.data : d_xyzf_scratch.data,
                          ngpu == 1 ? d_tdb.data : d_tdb_scratch.data,
                          ngpu == 1 ? d_cell_orientation.data : d_cell_orientation_scratch.data,
                          ngpu == 1 ? d_cell_idx.data : d_cell_idx_scratch.data,
                          d_conditions.data,
                          d_pos.data,
                          d_orientation.data,
                          d_charge.data,
                          d_diameter.data,
                          d_body.data,
                          m_pdata->getN(),
                          m_pdata->getNGhosts(),
                          m_Nmax,
                          m_flag_charge,
                          m_flag_type,
                          box,
                          m_cell_indexer,
                          m_cell_list_indexer,
                          getGhostWidth(),
                          m_tuner->getParam(),
                          m_pdata->getGPUPartition());
    if(m_exec_conf->isCUDAErrorCheckingEnabled())
        CHECK_CUDA_ERROR();
    m_tuner->end();

    m_exec_conf->endMultiGPU();

    if (ngpu > 1)
        {
        // have to wait for all GPUs to sync up, to have cell sizes available
        m_exec_conf->beginMultiGPU();

        // autotune block sizes
        m_tuner_combine->begin();

        gpu_combine_cell_lists(d_cell_size_scratch.data,
                               d_cell_size.data,
                               d_cell_idx_scratch.data,
                               d_cell_idx.data,
                               d_xyzf_scratch.data,
                               d_xyzf.data,
                               d_tdb_scratch.data,
                               d_tdb.data,
                               d_cell_orientation_scratch.data,
                               d_cell_orientation.data,
                               m_cell_list_indexer,
                               ngpu,
                               m_tuner_combine->getParam(),
                               m_Nmax,
                               d_conditions.data,
                               m_pdata->getGPUPartition());
        m_tuner_combine->end();

        m_exec_conf->endMultiGPU();
        }

    if (m_sort_cell_list)
        {
        ScopedAllocation<uint2> d_sort_idx(m_exec_conf->getCachedAllocator(), m_cell_list_indexer.getNumElements());
        ScopedAllocation<unsigned int> d_sort_permutation(m_exec_conf->getCachedAllocator(), m_cell_list_indexer.getNumElements());
        ScopedAllocation<unsigned int> d_cell_idx_new(m_exec_conf->getCachedAllocator(), m_idx.getNumElements());
        ScopedAllocation<Scalar4> d_xyzf_new(m_exec_conf->getCachedAllocator(), m_xyzf.getNumElements());
        ScopedAllocation<Scalar4> d_cell_orientation_new(m_exec_conf->getCachedAllocator(), m_orientation.getNumElements());
        ScopedAllocation<Scalar4> d_tdb_new(m_exec_conf->getCachedAllocator(), m_tdb.getNumElements());

        gpu_sort_cell_list(d_cell_size.data,
                           d_xyzf.data,
                           d_xyzf_new.data,
                           d_tdb.data,
                           d_tdb_new.data,
                           d_cell_orientation.data,
                           d_cell_orientation_new.data,
                           d_cell_idx.data,
                           d_cell_idx_new.data,
                           d_sort_idx.data,
                           d_sort_permutation.data,
                           m_cell_indexer,
                           m_cell_list_indexer);

        if(m_exec_conf->isCUDAErrorCheckingEnabled())
            CHECK_CUDA_ERROR();
        }

    if (m_prof)
        m_prof->pop(m_exec_conf);
    }

void CellListGPU::initializeMemory()
    {
    // call base class method
    CellList::initializeMemory();

    // only need to keep separate cell lists with more than one GPU
    unsigned int ngpu = m_exec_conf->getNumActiveGPUs();
    if (ngpu < 2)
        return;

    m_exec_conf->msg->notice(10) << "CellListGPU initialize multiGPU memory" << endl;
    if (m_prof)
        m_prof->push("init");

    if (m_compute_adj_list && m_exec_conf->allConcurrentManagedAccess())
        {
        cudaMemAdvise(m_cell_adj.get(), m_cell_adj.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetReadMostly, 0);
        CHECK_CUDA_ERROR();
        }

    // allocate memory
    GlobalArray<unsigned int> cell_size_scratch(m_cell_indexer.getNumElements()*ngpu, m_exec_conf);
    m_cell_size_scratch.swap(cell_size_scratch);
    TAG_ALLOCATION(m_cell_size_scratch);

    if (m_compute_xyzf)
        {
        GlobalArray<Scalar4> xyzf_scratch(m_cell_list_indexer.getNumElements()*ngpu, m_exec_conf);
        m_xyzf_scratch.swap(xyzf_scratch);
        TAG_ALLOCATION(m_xyzf_scratch);
        }
    else
        {
        GlobalArray<Scalar4> xyzf_scratch;
        m_xyzf_scratch.swap(xyzf_scratch);
        }

    if (m_compute_tdb)
        {
        GlobalArray<Scalar4> tdb_scratch(m_cell_list_indexer.getNumElements()*ngpu, m_exec_conf);
        m_tdb_scratch.swap(tdb_scratch);
        TAG_ALLOCATION(m_tdb_scratch);
        }
    else
        {
        // array is no longer needed, discard it
        GlobalArray<Scalar4> tdb_scratch;
        m_tdb_scratch.swap(tdb_scratch);
        }

    if (m_compute_orientation)
        {
        GlobalArray<Scalar4> orientation_scratch(m_cell_list_indexer.getNumElements()*ngpu, m_exec_conf);
        m_orientation_scratch.swap(orientation_scratch);
        TAG_ALLOCATION(m_orientation_scratch);
        }
    else
        {
        // array is no longer needed, discard it
        GlobalArray<Scalar4> orientation_scratch;
        m_orientation_scratch.swap(orientation_scratch);
        }

    if (m_compute_idx || m_sort_cell_list)
        {
        GlobalArray<unsigned int> idx_scratch(m_cell_list_indexer.getNumElements()*ngpu, m_exec_conf);
        m_idx_scratch.swap(idx_scratch);
        TAG_ALLOCATION(m_idx_scratch);
        }
    else
        {
        // array is no longer needed, discard it
        GlobalArray<unsigned int> idx_scratch;
        m_idx_scratch.swap(idx_scratch);
        }

    if (! m_exec_conf->allConcurrentManagedAccess())
        return;

    // map cell list arrays into memory of all active GPUs
    auto& gpu_map = m_exec_conf->getGPUIds();

    for (unsigned int idev = 0; idev < m_exec_conf->getNumActiveGPUs(); ++idev)
        {
        cudaMemAdvise(m_cell_size.get(), m_cell_size.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetAccessedBy, gpu_map[idev]);

        if (! m_idx.isNull())
            cudaMemAdvise(m_idx.get(), m_idx.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetAccessedBy, gpu_map[idev]);

        if (! m_xyzf.isNull())
            cudaMemAdvise(m_xyzf.get(), m_xyzf.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetAccessedBy, gpu_map[idev]);

        if (! m_tdb.isNull())
            cudaMemAdvise(m_tdb.get(), m_tdb.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetAccessedBy, gpu_map[idev]);

        if (! m_orientation.isNull())
            cudaMemAdvise(m_orientation.get(), m_orientation.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetAccessedBy, gpu_map[idev]);
        }

    for (unsigned int idev = 0; idev < m_exec_conf->getNumActiveGPUs(); ++idev)
        {
        cudaMemAdvise(m_cell_size_scratch.get()+idev*m_cell_indexer.getNumElements(),
            m_cell_indexer.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        if (! m_idx_scratch.isNull())
            cudaMemAdvise(m_idx_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
                m_cell_list_indexer.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        if (! m_xyzf_scratch.isNull())
            cudaMemAdvise(m_xyzf_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
                m_cell_list_indexer.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        if (! m_tdb_scratch.isNull())
            cudaMemAdvise(m_tdb_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
            m_cell_list_indexer.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        if (! m_orientation.isNull())
            cudaMemAdvise(m_orientation_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
            m_cell_list_indexer.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        // prefetch to preferred location
        cudaMemPrefetchAsync(m_cell_size_scratch.get()+idev*m_cell_indexer.getNumElements(),
            m_cell_indexer.getNumElements()*sizeof(unsigned int), gpu_map[idev]);

        if (! m_idx.isNull())
            cudaMemPrefetchAsync(m_idx_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
                m_cell_list_indexer.getNumElements()*sizeof(unsigned int), gpu_map[idev]);

        if (! m_xyzf_scratch.isNull())
            cudaMemPrefetchAsync(m_xyzf_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
                m_cell_list_indexer.getNumElements()*sizeof(Scalar4), gpu_map[idev]);

        if (! m_tdb_scratch.isNull())
            cudaMemPrefetchAsync(m_tdb_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
            m_cell_list_indexer.getNumElements()*sizeof(Scalar4), gpu_map[idev]);

        if (! m_orientation_scratch.isNull())
            cudaMemPrefetchAsync(m_orientation_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
            m_cell_list_indexer.getNumElements()*sizeof(Scalar4), gpu_map[idev]);
        }
    CHECK_CUDA_ERROR();

    if (m_prof)
        m_prof->pop();
    }

void export_CellListGPU(py::module& m)
    {
    py::class_<CellListGPU, std::shared_ptr<CellListGPU> >(m,"CellListGPU",py::base<CellList>())
    .def(py::init< std::shared_ptr<SystemDefinition> >())
        ;
    }
<commit_msg>remove some memory hints<commit_after>// Copyright (c) 2009-2018 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

// Maintainer: joaander

/*! \file CellListGPU.cc
    \brief Defines CellListGPU
*/

#include "CellListGPU.h"
#include "CellListGPU.cuh"

namespace py = pybind11;

using namespace std;

/*! \param sysdef system to compute the cell list of
*/
CellListGPU::CellListGPU(std::shared_ptr<SystemDefinition> sysdef)
    : CellList(sysdef)
    {
    if (!m_exec_conf->isCUDAEnabled())
        {
        m_exec_conf->msg->error() << "Creating a CellListGPU with no GPU in the execution configuration" << endl;
        throw std::runtime_error("Error initializing CellListGPU");
        }

    m_tuner.reset(new Autotuner(32, 1024, 32, 5, 100000, "cell_list", this->m_exec_conf));
    m_tuner_combine.reset(new Autotuner(32, 1024, 32, 5, 100000, "cell_list_combine", this->m_exec_conf));

    }

void CellListGPU::computeCellList()
    {
    if (m_prof)
        m_prof->push(m_exec_conf, "compute");

    // acquire the particle data
    ArrayHandle<Scalar4> d_pos(m_pdata->getPositions(), access_location::device, access_mode::read);
    ArrayHandle<Scalar4> d_orientation(m_pdata->getOrientationArray(), access_location::device, access_mode::read);
    ArrayHandle<Scalar> d_charge(m_pdata->getCharges(), access_location::device, access_mode::read);
    ArrayHandle<Scalar> d_diameter(m_pdata->getDiameters(), access_location::device, access_mode::read);
    ArrayHandle<unsigned int> d_body(m_pdata->getBodies(), access_location::device, access_mode::read);

    BoxDim box = m_pdata->getBox();

    // access the cell list data arrays
    ArrayHandle<unsigned int> d_cell_size(m_cell_size, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_xyzf(m_xyzf, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_tdb(m_tdb, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_cell_orientation(m_orientation, access_location::device, access_mode::overwrite);
    ArrayHandle<unsigned int> d_cell_idx(m_idx, access_location::device, access_mode::overwrite);

    // access the per-GPU cell list arrays (only needed with ngpu>1)
    ArrayHandle<unsigned int> d_cell_size_scratch(m_cell_size_scratch, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_xyzf_scratch(m_xyzf_scratch, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_tdb_scratch(m_tdb_scratch, access_location::device, access_mode::overwrite);
    ArrayHandle<Scalar4> d_cell_orientation_scratch(m_orientation_scratch, access_location::device, access_mode::overwrite);
    ArrayHandle<unsigned int> d_cell_idx_scratch(m_idx_scratch, access_location::device, access_mode::overwrite);

    // error conditions
    ArrayHandle<uint3> d_conditions(m_conditions, access_location::device, access_mode::overwrite);

    unsigned int ngpu = m_exec_conf->getNumActiveGPUs();

    // reset cell list contents
    cudaMemsetAsync(d_cell_size.data, 0, sizeof(unsigned int)*m_cell_indexer.getNumElements(),0);
    if (m_exec_conf->isCUDAErrorCheckingEnabled())
        CHECK_CUDA_ERROR();

    if (ngpu > 1)
        {
        // reset temporary arrays
        cudaMemsetAsync(d_cell_size_scratch.data, 0, sizeof(unsigned int)*m_cell_size_scratch.getNumElements(),0);
        if (m_exec_conf->isCUDAErrorCheckingEnabled())
            CHECK_CUDA_ERROR();
        }

    m_exec_conf->beginMultiGPU();

    // autotune block sizes
    m_tuner->begin();

    // compute cell list, and write to temporary arrays with multi-GPU
    gpu_compute_cell_list(ngpu == 1 ? d_cell_size.data : d_cell_size_scratch.data,
                          ngpu == 1 ? d_xyzf.data : d_xyzf_scratch.data,
                          ngpu == 1 ? d_tdb.data : d_tdb_scratch.data,
                          ngpu == 1 ? d_cell_orientation.data : d_cell_orientation_scratch.data,
                          ngpu == 1 ? d_cell_idx.data : d_cell_idx_scratch.data,
                          d_conditions.data,
                          d_pos.data,
                          d_orientation.data,
                          d_charge.data,
                          d_diameter.data,
                          d_body.data,
                          m_pdata->getN(),
                          m_pdata->getNGhosts(),
                          m_Nmax,
                          m_flag_charge,
                          m_flag_type,
                          box,
                          m_cell_indexer,
                          m_cell_list_indexer,
                          getGhostWidth(),
                          m_tuner->getParam(),
                          m_pdata->getGPUPartition());
    if(m_exec_conf->isCUDAErrorCheckingEnabled())
        CHECK_CUDA_ERROR();
    m_tuner->end();

    m_exec_conf->endMultiGPU();

    if (ngpu > 1)
        {
        // have to wait for all GPUs to sync up, to have cell sizes available
        m_exec_conf->beginMultiGPU();

        // autotune block sizes
        m_tuner_combine->begin();

        gpu_combine_cell_lists(d_cell_size_scratch.data,
                               d_cell_size.data,
                               d_cell_idx_scratch.data,
                               d_cell_idx.data,
                               d_xyzf_scratch.data,
                               d_xyzf.data,
                               d_tdb_scratch.data,
                               d_tdb.data,
                               d_cell_orientation_scratch.data,
                               d_cell_orientation.data,
                               m_cell_list_indexer,
                               ngpu,
                               m_tuner_combine->getParam(),
                               m_Nmax,
                               d_conditions.data,
                               m_pdata->getGPUPartition());
        m_tuner_combine->end();

        m_exec_conf->endMultiGPU();
        }

    if (m_sort_cell_list)
        {
        ScopedAllocation<uint2> d_sort_idx(m_exec_conf->getCachedAllocator(), m_cell_list_indexer.getNumElements());
        ScopedAllocation<unsigned int> d_sort_permutation(m_exec_conf->getCachedAllocator(), m_cell_list_indexer.getNumElements());
        ScopedAllocation<unsigned int> d_cell_idx_new(m_exec_conf->getCachedAllocator(), m_idx.getNumElements());
        ScopedAllocation<Scalar4> d_xyzf_new(m_exec_conf->getCachedAllocator(), m_xyzf.getNumElements());
        ScopedAllocation<Scalar4> d_cell_orientation_new(m_exec_conf->getCachedAllocator(), m_orientation.getNumElements());
        ScopedAllocation<Scalar4> d_tdb_new(m_exec_conf->getCachedAllocator(), m_tdb.getNumElements());

        gpu_sort_cell_list(d_cell_size.data,
                           d_xyzf.data,
                           d_xyzf_new.data,
                           d_tdb.data,
                           d_tdb_new.data,
                           d_cell_orientation.data,
                           d_cell_orientation_new.data,
                           d_cell_idx.data,
                           d_cell_idx_new.data,
                           d_sort_idx.data,
                           d_sort_permutation.data,
                           m_cell_indexer,
                           m_cell_list_indexer);

        if(m_exec_conf->isCUDAErrorCheckingEnabled())
            CHECK_CUDA_ERROR();
        }

    if (m_prof)
        m_prof->pop(m_exec_conf);
    }

void CellListGPU::initializeMemory()
    {
    // call base class method
    CellList::initializeMemory();

    // only need to keep separate cell lists with more than one GPU
    unsigned int ngpu = m_exec_conf->getNumActiveGPUs();
    if (ngpu < 2)
        return;

    m_exec_conf->msg->notice(10) << "CellListGPU initialize multiGPU memory" << endl;
    if (m_prof)
        m_prof->push("init");

    if (m_compute_adj_list && m_exec_conf->allConcurrentManagedAccess())
        {
        cudaMemAdvise(m_cell_adj.get(), m_cell_adj.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetReadMostly, 0);
        CHECK_CUDA_ERROR();
        }

    // allocate memory
    GlobalArray<unsigned int> cell_size_scratch(m_cell_indexer.getNumElements()*ngpu, m_exec_conf);
    m_cell_size_scratch.swap(cell_size_scratch);
    TAG_ALLOCATION(m_cell_size_scratch);

    if (m_compute_xyzf)
        {
        GlobalArray<Scalar4> xyzf_scratch(m_cell_list_indexer.getNumElements()*ngpu, m_exec_conf);
        m_xyzf_scratch.swap(xyzf_scratch);
        TAG_ALLOCATION(m_xyzf_scratch);
        }
    else
        {
        GlobalArray<Scalar4> xyzf_scratch;
        m_xyzf_scratch.swap(xyzf_scratch);
        }

    if (m_compute_tdb)
        {
        GlobalArray<Scalar4> tdb_scratch(m_cell_list_indexer.getNumElements()*ngpu, m_exec_conf);
        m_tdb_scratch.swap(tdb_scratch);
        TAG_ALLOCATION(m_tdb_scratch);
        }
    else
        {
        // array is no longer needed, discard it
        GlobalArray<Scalar4> tdb_scratch;
        m_tdb_scratch.swap(tdb_scratch);
        }

    if (m_compute_orientation)
        {
        GlobalArray<Scalar4> orientation_scratch(m_cell_list_indexer.getNumElements()*ngpu, m_exec_conf);
        m_orientation_scratch.swap(orientation_scratch);
        TAG_ALLOCATION(m_orientation_scratch);
        }
    else
        {
        // array is no longer needed, discard it
        GlobalArray<Scalar4> orientation_scratch;
        m_orientation_scratch.swap(orientation_scratch);
        }

    if (m_compute_idx || m_sort_cell_list)
        {
        GlobalArray<unsigned int> idx_scratch(m_cell_list_indexer.getNumElements()*ngpu, m_exec_conf);
        m_idx_scratch.swap(idx_scratch);
        TAG_ALLOCATION(m_idx_scratch);
        }
    else
        {
        // array is no longer needed, discard it
        GlobalArray<unsigned int> idx_scratch;
        m_idx_scratch.swap(idx_scratch);
        }

    if (! m_exec_conf->allConcurrentManagedAccess())
        return;

    // map cell list arrays into memory of all active GPUs
    auto& gpu_map = m_exec_conf->getGPUIds();

    for (unsigned int idev = 0; idev < m_exec_conf->getNumActiveGPUs(); ++idev)
        {
        cudaMemAdvise(m_cell_size.get(), m_cell_size.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetAccessedBy, gpu_map[idev]);
        }

    for (unsigned int idev = 0; idev < m_exec_conf->getNumActiveGPUs(); ++idev)
        {
        cudaMemAdvise(m_cell_size_scratch.get()+idev*m_cell_indexer.getNumElements(),
            m_cell_indexer.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        if (! m_idx_scratch.isNull())
            cudaMemAdvise(m_idx_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
                m_cell_list_indexer.getNumElements()*sizeof(unsigned int), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        if (! m_xyzf_scratch.isNull())
            cudaMemAdvise(m_xyzf_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
                m_cell_list_indexer.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        if (! m_tdb_scratch.isNull())
            cudaMemAdvise(m_tdb_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
            m_cell_list_indexer.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        if (! m_orientation.isNull())
            cudaMemAdvise(m_orientation_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
            m_cell_list_indexer.getNumElements()*sizeof(Scalar4), cudaMemAdviseSetPreferredLocation, gpu_map[idev]);

        // prefetch to preferred location
        cudaMemPrefetchAsync(m_cell_size_scratch.get()+idev*m_cell_indexer.getNumElements(),
            m_cell_indexer.getNumElements()*sizeof(unsigned int), gpu_map[idev]);

        if (! m_idx.isNull())
            cudaMemPrefetchAsync(m_idx_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
                m_cell_list_indexer.getNumElements()*sizeof(unsigned int), gpu_map[idev]);

        if (! m_xyzf_scratch.isNull())
            cudaMemPrefetchAsync(m_xyzf_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
                m_cell_list_indexer.getNumElements()*sizeof(Scalar4), gpu_map[idev]);

        if (! m_tdb_scratch.isNull())
            cudaMemPrefetchAsync(m_tdb_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
            m_cell_list_indexer.getNumElements()*sizeof(Scalar4), gpu_map[idev]);

        if (! m_orientation_scratch.isNull())
            cudaMemPrefetchAsync(m_orientation_scratch.get()+idev*m_cell_list_indexer.getNumElements(),
            m_cell_list_indexer.getNumElements()*sizeof(Scalar4), gpu_map[idev]);
        }
    CHECK_CUDA_ERROR();

    if (m_prof)
        m_prof->pop();
    }

void export_CellListGPU(py::module& m)
    {
    py::class_<CellListGPU, std::shared_ptr<CellListGPU> >(m,"CellListGPU",py::base<CellList>())
    .def(py::init< std::shared_ptr<SystemDefinition> >())
        ;
    }
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file lis2mdl.cpp
 *
 * Driver for the LIS2MDL magnetometer connected via I2C or SPI.
 *
 * Based on the LIS2MDL driver.
 */

#include <px4_platform_common/time.h>
#include "lis2mdl.h"

LIS2MDL::LIS2MDL(device::Device *interface, enum Rotation rotation, I2CSPIBusOption bus_option, int bus) :
	I2CSPIDriver(MODULE_NAME, px4::device_bus_to_wq(interface->get_device_id()), bus_option, bus),
	_px4_mag(interface->get_device_id(), interface->external() ? ORB_PRIO_VERY_HIGH : ORB_PRIO_DEFAULT, rotation),
	_interface(interface),
	_comms_errors(perf_alloc(PC_COUNT, MODULE_NAME": comms_errors")),
	_conf_errors(perf_alloc(PC_COUNT, MODULE_NAME": conf_errors")),
	_range_errors(perf_alloc(PC_COUNT, MODULE_NAME": range_errors")),
	_sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": read")),
	_measure_interval(0)
{
	_px4_mag.set_external(_interface->external());
	_px4_mag.set_scale(0.0015f); /* 49.152f / (2^15) */
}

LIS2MDL::~LIS2MDL()
{
	// free perf counters
	perf_free(_sample_perf);
	perf_free(_comms_errors);
	perf_free(_range_errors);
	perf_free(_conf_errors);

	delete _interface;
}

int
LIS2MDL::measure()
{
	struct {
		uint8_t status;
		uint8_t x[2];
		uint8_t y[2];
		uint8_t z[2];
	}       lis_report;

	struct {
		int16_t x;
		int16_t y;
		int16_t z;
		int16_t t;
	} report;

	uint8_t buf_rx[2] = {};

	_px4_mag.set_error_count(perf_event_count(_comms_errors));

	perf_begin(_sample_perf);

	const hrt_abstime timestamp_sample = hrt_absolute_time();
	int ret = _interface->read(ADDR_STATUS_REG, (uint8_t *)&lis_report, sizeof(lis_report));

	/**
	 * Silicon Bug: the X axis will be read instead of the temperature registers if you do a sequential read through XYZ.
	 * The temperature registers must be addressed directly.
	 */
	ret = _interface->read(ADDR_OUT_T_L, (uint8_t *)&buf_rx, sizeof(buf_rx));

	if (ret != OK) {
		perf_end(_sample_perf);
		perf_count(_comms_errors);
		PX4_WARN("Register read error.");
		return ret;
	}

	perf_end(_sample_perf);

	if ((lis_report.status & (1 << 3)) == 0) { // check data ready
		return 0;
	}

	report.x = (int16_t)((lis_report.x[1] << 8) | lis_report.x[0]);
	report.y = (int16_t)((lis_report.y[1] << 8) | lis_report.y[0]);
	report.z = (int16_t)((lis_report.z[1] << 8) | lis_report.z[0]);

	report.t = (int16_t)((buf_rx[1] << 8) | buf_rx[0]);

	float temperature = report.t;
	_px4_mag.set_temperature(25.0f + (temperature / 8.0f));

	/* swap x and y axis */
	_px4_mag.update(timestamp_sample, report.y, report.x, report.z);

	return PX4_OK;
}

void
LIS2MDL::RunImpl()
{
	/* _measure_interval == 0  is used as _task_should_exit */
	if (_measure_interval == 0) {
		return;
	}

	if (measure() != OK) {
		PX4_DEBUG("measure error");
	}

	/* schedule a fresh cycle call when the measurement is done */
	ScheduleDelayed(LIS2MDL_CONVERSION_INTERVAL);
}

int
LIS2MDL::init()
{

	int ret = write_reg(ADDR_CFG_REG_A, CFG_REG_A_ODR | CFG_REG_A_MD | CFG_REG_A_TEMP_COMP_EN);
	ret = write_reg(ADDR_CFG_REG_B, 0);
	ret = write_reg(ADDR_CFG_REG_C, CFG_REG_C_BDU);

	_measure_interval = LIS2MDL_CONVERSION_INTERVAL;
	start();

	return ret;
}

void
LIS2MDL::print_status()
{
	I2CSPIDriverBase::print_status();
	perf_print_counter(_sample_perf);
	perf_print_counter(_comms_errors);
	PX4_INFO("poll interval:  %u", _measure_interval);
	_px4_mag.print_status();
}

void
LIS2MDL::start()
{
	/* schedule a cycle to start things */
	ScheduleNow();
}

int
LIS2MDL::read_reg(uint8_t reg, uint8_t &val)
{
	uint8_t buf = val;
	int ret = _interface->read(reg, &buf, 1);
	val = buf;
	return ret;
}

int
LIS2MDL::write_reg(uint8_t reg, uint8_t val)
{
	uint8_t buf = val;
	return _interface->write(reg, &buf, 1);
}
<commit_msg>lis2mdl: remove read error message<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file lis2mdl.cpp
 *
 * Driver for the LIS2MDL magnetometer connected via I2C or SPI.
 *
 * Based on the LIS2MDL driver.
 */

#include <px4_platform_common/time.h>
#include "lis2mdl.h"

LIS2MDL::LIS2MDL(device::Device *interface, enum Rotation rotation, I2CSPIBusOption bus_option, int bus) :
	I2CSPIDriver(MODULE_NAME, px4::device_bus_to_wq(interface->get_device_id()), bus_option, bus),
	_px4_mag(interface->get_device_id(), interface->external() ? ORB_PRIO_VERY_HIGH : ORB_PRIO_DEFAULT, rotation),
	_interface(interface),
	_comms_errors(perf_alloc(PC_COUNT, MODULE_NAME": comms_errors")),
	_conf_errors(perf_alloc(PC_COUNT, MODULE_NAME": conf_errors")),
	_range_errors(perf_alloc(PC_COUNT, MODULE_NAME": range_errors")),
	_sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": read")),
	_measure_interval(0)
{
	_px4_mag.set_external(_interface->external());
	_px4_mag.set_scale(0.0015f); /* 49.152f / (2^15) */
}

LIS2MDL::~LIS2MDL()
{
	// free perf counters
	perf_free(_sample_perf);
	perf_free(_comms_errors);
	perf_free(_range_errors);
	perf_free(_conf_errors);

	delete _interface;
}

int
LIS2MDL::measure()
{
	struct {
		uint8_t status;
		uint8_t x[2];
		uint8_t y[2];
		uint8_t z[2];
	}       lis_report;

	struct {
		int16_t x;
		int16_t y;
		int16_t z;
		int16_t t;
	} report;

	uint8_t buf_rx[2] = {};

	_px4_mag.set_error_count(perf_event_count(_comms_errors));

	perf_begin(_sample_perf);

	const hrt_abstime timestamp_sample = hrt_absolute_time();
	int ret = _interface->read(ADDR_STATUS_REG, (uint8_t *)&lis_report, sizeof(lis_report));

	/**
	 * Silicon Bug: the X axis will be read instead of the temperature registers if you do a sequential read through XYZ.
	 * The temperature registers must be addressed directly.
	 */
	ret = _interface->read(ADDR_OUT_T_L, (uint8_t *)&buf_rx, sizeof(buf_rx));

	if (ret != OK) {
		perf_end(_sample_perf);
		perf_count(_comms_errors);
		return ret;
	}

	perf_end(_sample_perf);

	if ((lis_report.status & (1 << 3)) == 0) { // check data ready
		return 0;
	}

	report.x = (int16_t)((lis_report.x[1] << 8) | lis_report.x[0]);
	report.y = (int16_t)((lis_report.y[1] << 8) | lis_report.y[0]);
	report.z = (int16_t)((lis_report.z[1] << 8) | lis_report.z[0]);

	report.t = (int16_t)((buf_rx[1] << 8) | buf_rx[0]);

	float temperature = report.t;
	_px4_mag.set_temperature(25.0f + (temperature / 8.0f));

	/* swap x and y axis */
	_px4_mag.update(timestamp_sample, report.y, report.x, report.z);

	return PX4_OK;
}

void
LIS2MDL::RunImpl()
{
	/* _measure_interval == 0  is used as _task_should_exit */
	if (_measure_interval == 0) {
		return;
	}

	if (measure() != OK) {
		PX4_DEBUG("measure error");
	}

	/* schedule a fresh cycle call when the measurement is done */
	ScheduleDelayed(LIS2MDL_CONVERSION_INTERVAL);
}

int
LIS2MDL::init()
{

	int ret = write_reg(ADDR_CFG_REG_A, CFG_REG_A_ODR | CFG_REG_A_MD | CFG_REG_A_TEMP_COMP_EN);
	ret = write_reg(ADDR_CFG_REG_B, 0);
	ret = write_reg(ADDR_CFG_REG_C, CFG_REG_C_BDU);

	_measure_interval = LIS2MDL_CONVERSION_INTERVAL;
	start();

	return ret;
}

void
LIS2MDL::print_status()
{
	I2CSPIDriverBase::print_status();
	perf_print_counter(_sample_perf);
	perf_print_counter(_comms_errors);
	PX4_INFO("poll interval:  %u", _measure_interval);
	_px4_mag.print_status();
}

void
LIS2MDL::start()
{
	/* schedule a cycle to start things */
	ScheduleNow();
}

int
LIS2MDL::read_reg(uint8_t reg, uint8_t &val)
{
	uint8_t buf = val;
	int ret = _interface->read(reg, &buf, 1);
	val = buf;
	return ret;
}

int
LIS2MDL::write_reg(uint8_t reg, uint8_t val)
{
	uint8_t buf = val;
	return _interface->write(reg, &buf, 1);
}
<|endoftext|>