<commit_before>// FbCommandFactory.cc for Fluxbox Window manager
// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
//                and Simon Bowden (rathnor at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in 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:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 AUTHORS 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 IN THE SOFTWARE.

// $Id: FbCommandFactory.cc,v 1.1 2003/06/30 14:49:23 fluxgen Exp $

#include "FbCommandFactory.hh"

#include "CurrentWindowCmd.hh"
#include "FbCommands.hh"
#include "Window.hh"
#include "WorkspaceCmd.hh"
#include "fluxbox.hh"
#include "SimpleCommand.hh"

// autoregister this module to command parser
FbCommandFactory FbCommandFactory::s_autoreg;

FbCommandFactory::FbCommandFactory() {
    // setup commands that we can handle
    const char commands[][20] = {
        "execcommand",
        "exec",
        "execute",
        "quit",
        "restart",
        "minimizewindow",
        "minimize",
        "iconfiy",
        "maximizewindow",
        "maximize",
        "maximizevertical",
        "maximizehorizontal",
        "moveright",
        "moveleft",
        "moveup",
        "movedown",
        "raise",
        "lower",
        "close",
        "shade",
        "stick",
        "sendtoworkspace",
        "killwindow",
        "nexttab",
        "prevtab",
        "detachclient",
        "nextworkspace",
        "prevworkspace",
        "nextwindow",
        "prevwindow",
        "showdesktop",
        "arrangewindows",
        ""
    };

    for (int i=0;; ++i) {
        if (strcmp(commands[i], "") == 0)
            break;
        addCommand(commands[i]);
    }

}

FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command,
                                                 const std::string &arguments) {
    using namespace FbCommands;
    //
    // WM commands
    //
    if (command == "restart")
        return new RestartFluxboxCmd(arguments);
    else if (command == "reconfigure")
        return new ReconfigureFluxboxCmd();
    else if (command == "setstyle")
        return new SetStyleCmd(arguments);
    else if (command == "saverc")
        return new SaveResources();
    else if (command == "execcommand" || command == "execute" || command == "exec")
        return new ExecuteCmd(arguments); // execute command on key screen
    else if (command == "quit")
        return new FbTk::SimpleCommand<Fluxbox>(*Fluxbox::instance(), &Fluxbox::shutdown);
    //
    // Current focused window commands
    //
    else if (command == "minimizewindow" || command == "mimimize" || command == "iconify")
        return new CurrentWindowCmd(&FluxboxWindow::iconify);
    else if (command == "maximizewindow" || command == "maximize")
        return new CurrentWindowCmd(&FluxboxWindow::maximize);
    else if (command == "maximizevertical")
        return new CurrentWindowCmd(&FluxboxWindow::maximizeVertical);
    else if (command == "maximizehorizontal")
        return new CurrentWindowCmd(&FluxboxWindow::maximizeHorizontal);
    else if (command == "moveright")
        return new MoveRightCmd(atoi(arguments.c_str()));
    else if (command == "moveleft")
        return new MoveLeftCmd(atoi(arguments.c_str()));
    else if (command == "moveup")
        return new MoveUpCmd(atoi(arguments.c_str()));
    else if (command == "movedown")
        return new MoveDownCmd(atoi(arguments.c_str()));
    else if (command == "raise")
        return new CurrentWindowCmd(&FluxboxWindow::raise);
    else if (command == "lower")
        return new CurrentWindowCmd(&FluxboxWindow::lower);
    else if (command == "close")
        return new CurrentWindowCmd(&FluxboxWindow::close);
    else if (command == "shade" || command == "shadewindow")
        return new CurrentWindowCmd(&FluxboxWindow::shade);
    else if (command == "stick" || command == "stickwindow")
        return new CurrentWindowCmd(&FluxboxWindow::stick);
    else if (command == "sendtoworkspace")
        return new SendToWorkspaceCmd(atoi(arguments.c_str()));
    else if (command == "killwindow")
        return new KillWindowCmd();
     else if (command == "nexttab")
        return new CurrentWindowCmd(&FluxboxWindow::nextClient);
    else if (command == "prevtab")
        return new CurrentWindowCmd(&FluxboxWindow::prevClient);
    else if (command == "detachclient")
        return new CurrentWindowCmd(&FluxboxWindow::detachCurrentClient);
    //
    // Workspace commands
    //
    else if (command == "nextworkspace" && arguments.size() == 0)
        return new NextWorkspaceCmd();
    else if (command == "prevworkspace" && arguments.size() == 0)
        return new PrevWorkspaceCmd();
    else if (command == "workspace") {
        int num = 0;
        if (!arguments.empty())
            num = atoi(arguments.c_str());
        return new JumpToWorkspaceCmd(num);
    } else if (command == "nextwindow")
        return new NextWindowCmd(atoi(arguments.c_str()));
    else if (command == "prevwindow")
        return new PrevWindowCmd(atoi(arguments.c_str()));
    else if (command == "arrangewindows")
        return new ArrangeWindowsCmd();
    else if (command == "showdesktop")
        return new ShowDesktopCmd();

    return 0;
}
<commit_msg>added toggledecor<commit_after>// FbCommandFactory.cc for Fluxbox Window manager
// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
//                and Simon Bowden (rathnor at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in 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:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 AUTHORS 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 IN THE SOFTWARE.

// $Id: FbCommandFactory.cc,v 1.2 2003/06/30 19:51:07 fluxgen Exp $

#include "FbCommandFactory.hh"

#include "CurrentWindowCmd.hh"
#include "FbCommands.hh"
#include "Window.hh"
#include "WorkspaceCmd.hh"
#include "fluxbox.hh"
#include "SimpleCommand.hh"

// autoregister this module to command parser
FbCommandFactory FbCommandFactory::s_autoreg;

FbCommandFactory::FbCommandFactory() {
    // setup commands that we can handle
    const char commands[][20] = {
        "execcommand",
        "exec",
        "execute",
        "quit",
        "restart",
        "minimizewindow",
        "minimize",
        "iconfiy",
        "maximizewindow",
        "maximize",
        "maximizevertical",
        "maximizehorizontal",
        "moveright",
        "moveleft",
        "moveup",
        "movedown",
        "raise",
        "lower",
        "close",
        "shade",
        "stick",
        "toggledecor",
        "sendtoworkspace",
        "killwindow",
        "nexttab",
        "prevtab",
        "detachclient",
        "nextworkspace",
        "prevworkspace",
        "nextwindow",
        "prevwindow",
        "showdesktop",
        "arrangewindows",
        ""
    };

    for (int i=0;; ++i) {
        if (strcmp(commands[i], "") == 0)
            break;
        addCommand(commands[i]);
    }

}

FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command,
                                                 const std::string &arguments) {
    using namespace FbCommands;
    //
    // WM commands
    //
    if (command == "restart")
        return new RestartFluxboxCmd(arguments);
    else if (command == "reconfigure")
        return new ReconfigureFluxboxCmd();
    else if (command == "setstyle")
        return new SetStyleCmd(arguments);
    else if (command == "saverc")
        return new SaveResources();
    else if (command == "execcommand" || command == "execute" || command == "exec")
        return new ExecuteCmd(arguments); // execute command on key screen
    else if (command == "quit")
        return new FbTk::SimpleCommand<Fluxbox>(*Fluxbox::instance(), &Fluxbox::shutdown);
    //
    // Current focused window commands
    //
    else if (command == "minimizewindow" || command == "mimimize" || command == "iconify")
        return new CurrentWindowCmd(&FluxboxWindow::iconify);
    else if (command == "maximizewindow" || command == "maximize")
        return new CurrentWindowCmd(&FluxboxWindow::maximize);
    else if (command == "maximizevertical")
        return new CurrentWindowCmd(&FluxboxWindow::maximizeVertical);
    else if (command == "maximizehorizontal")
        return new CurrentWindowCmd(&FluxboxWindow::maximizeHorizontal);
    else if (command == "moveright")
        return new MoveRightCmd(atoi(arguments.c_str()));
    else if (command == "moveleft")
        return new MoveLeftCmd(atoi(arguments.c_str()));
    else if (command == "moveup")
        return new MoveUpCmd(atoi(arguments.c_str()));
    else if (command == "movedown")
        return new MoveDownCmd(atoi(arguments.c_str()));
    else if (command == "raise")
        return new CurrentWindowCmd(&FluxboxWindow::raise);
    else if (command == "lower")
        return new CurrentWindowCmd(&FluxboxWindow::lower);
    else if (command == "close")
        return new CurrentWindowCmd(&FluxboxWindow::close);
    else if (command == "shade" || command == "shadewindow")
        return new CurrentWindowCmd(&FluxboxWindow::shade);
    else if (command == "stick" || command == "stickwindow")
        return new CurrentWindowCmd(&FluxboxWindow::stick);
    else if (command == "toggledecor")
        return new CurrentWindowCmd(&FluxboxWindow::toggleDecoration);
    else if (command == "sendtoworkspace")
        return new SendToWorkspaceCmd(atoi(arguments.c_str()));
    else if (command == "killwindow")
        return new KillWindowCmd();
     else if (command == "nexttab")
        return new CurrentWindowCmd(&FluxboxWindow::nextClient);
    else if (command == "prevtab")
        return new CurrentWindowCmd(&FluxboxWindow::prevClient);
    else if (command == "detachclient")
        return new CurrentWindowCmd(&FluxboxWindow::detachCurrentClient);
    //
    // Workspace commands
    //
    else if (command == "nextworkspace" && arguments.size() == 0)
        return new NextWorkspaceCmd();
    else if (command == "prevworkspace" && arguments.size() == 0)
        return new PrevWorkspaceCmd();
    else if (command == "workspace") {
        int num = 0;
        if (!arguments.empty())
            num = atoi(arguments.c_str());
        return new JumpToWorkspaceCmd(num);
    } else if (command == "nextwindow")
        return new NextWindowCmd(atoi(arguments.c_str()));
    else if (command == "prevwindow")
        return new PrevWindowCmd(atoi(arguments.c_str()));
    else if (command == "arrangewindows")
        return new ArrangeWindowsCmd();
    else if (command == "showdesktop")
        return new ShowDesktopCmd();

    return 0;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "FunctionChecker.hpp"

#include "ast/Program.hpp"
#include "FunctionTable.hpp"

#include "SemanticalException.hpp"
#include "ASTVisitor.hpp"
#include "VisitorUtils.hpp"

#include "mangling.hpp"

using namespace eddic;

class FunctionInserterVisitor : public boost::static_visitor<> {
    private:
        FunctionTable& functionTable;

    public:
        FunctionInserterVisitor(FunctionTable& table) : functionTable(table) {}

        AUTO_RECURSE_PROGRAM()

        void operator()(ASTFunctionDeclaration& declaration){
            auto signature = std::make_shared<FunctionSignature>();

            signature->name = declaration.Content->functionName;

            for(auto& param : declaration.Content->parameters){
                auto parameter = std::make_shared<ParameterType>();
                parameter->name = param.parameterName;
                parameter->paramType = stringToType(param.parameterType);

                signature->parameters.push_back(parameter);
            }

            declaration.Content->mangledName = signature->mangledName = mangle(declaration.Content->functionName, signature->parameters);

            //TODO Verifiy that the function has not been previously defined

            functionTable.addFunction(signature);

            //Stop recursion here
        }

        void operator()(GlobalVariableDeclaration&){
            //Stop recursion here
        }
};

class FunctionCheckerVisitor : public boost::static_visitor<> {
    private:
        FunctionTable& functionTable;

    public:
        FunctionCheckerVisitor(FunctionTable& table) : functionTable(table) {}

        AUTO_RECURSE_PROGRAM()
        AUTO_RECURSE_FUNCTION_DECLARATION()
        AUTO_RECURSE_GLOBAL_DECLARATION()
        AUTO_RECURSE_SIMPLE_LOOPS()
        AUTO_RECURSE_FOREACH()
        AUTO_RECURSE_BRANCHES()
        AUTO_RECURSE_BINARY_CONDITION()
        AUTO_RECURSE_COMPOSED_VALUES()
        AUTO_RECURSE_VARIABLE_OPERATIONS()

        void operator()(ASTFunctionCall& functionCall){
            std::string name = functionCall.Content->functionName;

            if(name == "println" || name == "print"){
                return;
            }

            std::string mangled = mangle(name, functionCall.Content->values);

            if(!functionTable.exists(mangled)){
                throw SemanticalException("The function \"" + functionCall.Content->functionName + "()\" does not exists");
            }
            //TODO
        }

        void operator()(ASTVariable&){
            //No function calls there
        }

        void operator()(ASTSwap&){
            //No function calls there
        }

        void operator()(TerminalNode&){
            //No function calls there
        }
};

void FunctionChecker::check(ASTProgram& program, FunctionTable& functionTable){
    //First phase : Collect functions
    FunctionInserterVisitor inserterVisitor(functionTable);
    inserterVisitor(program);

    //Second phase : Verify calls
    FunctionCheckerVisitor checkerVisitor(functionTable);
    checkerVisitor(program);
}
<commit_msg>Remove old TODO<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "FunctionChecker.hpp"

#include "ast/Program.hpp"
#include "FunctionTable.hpp"

#include "SemanticalException.hpp"
#include "ASTVisitor.hpp"
#include "VisitorUtils.hpp"

#include "mangling.hpp"

using namespace eddic;

class FunctionInserterVisitor : public boost::static_visitor<> {
    private:
        FunctionTable& functionTable;

    public:
        FunctionInserterVisitor(FunctionTable& table) : functionTable(table) {}

        AUTO_RECURSE_PROGRAM()

        void operator()(ASTFunctionDeclaration& declaration){
            auto signature = std::make_shared<FunctionSignature>();

            signature->name = declaration.Content->functionName;

            for(auto& param : declaration.Content->parameters){
                auto parameter = std::make_shared<ParameterType>();
                parameter->name = param.parameterName;
                parameter->paramType = stringToType(param.parameterType);

                signature->parameters.push_back(parameter);
            }

            declaration.Content->mangledName = signature->mangledName = mangle(declaration.Content->functionName, signature->parameters);

            //TODO Verifiy that the function has not been previously defined

            functionTable.addFunction(signature);

            //Stop recursion here
        }

        void operator()(GlobalVariableDeclaration&){
            //Stop recursion here
        }
};

class FunctionCheckerVisitor : public boost::static_visitor<> {
    private:
        FunctionTable& functionTable;

    public:
        FunctionCheckerVisitor(FunctionTable& table) : functionTable(table) {}

        AUTO_RECURSE_PROGRAM()
        AUTO_RECURSE_FUNCTION_DECLARATION()
        AUTO_RECURSE_GLOBAL_DECLARATION()
        AUTO_RECURSE_SIMPLE_LOOPS()
        AUTO_RECURSE_FOREACH()
        AUTO_RECURSE_BRANCHES()
        AUTO_RECURSE_BINARY_CONDITION()
        AUTO_RECURSE_COMPOSED_VALUES()
        AUTO_RECURSE_VARIABLE_OPERATIONS()

        void operator()(ASTFunctionCall& functionCall){
            std::string name = functionCall.Content->functionName;

            if(name == "println" || name == "print"){
                return;
            }

            std::string mangled = mangle(name, functionCall.Content->values);

            if(!functionTable.exists(mangled)){
                throw SemanticalException("The function \"" + functionCall.Content->functionName + "()\" does not exists");
            }
        }

        void operator()(ASTVariable&){
            //No function calls there
        }

        void operator()(ASTSwap&){
            //No function calls there
        }

        void operator()(TerminalNode&){
            //No function calls there
        }
};

void FunctionChecker::check(ASTProgram& program, FunctionTable& functionTable){
    //First phase : Collect functions
    FunctionInserterVisitor inserterVisitor(functionTable);
    inserterVisitor(program);

    //Second phase : Verify calls
    FunctionCheckerVisitor checkerVisitor(functionTable);
    checkerVisitor(program);
}
<|endoftext|>


<commit_before>#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cstdio>
#include <cstdlib>

#include <map>
#include <string>

#include <gtk/gtk.h>

#define die(msg, ...) \
{ fprintf(stderr, "gtkglswitch: fatal: " msg "\n", ##__VA_ARGS__); exit(1); }

static bool ask_user(const char procname[], bool &remember)
{
  GtkWidget *dialog = gtk_message_dialog_new (NULL,
      GTK_DIALOG_DESTROY_WITH_PARENT,
      GTK_MESSAGE_QUESTION,
      GTK_BUTTONS_OK,
      "Use OpenGL offloading for %s?", procname);
  GtkWidget *content = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog));

  GtkWidget *radioy = gtk_radio_button_new_with_label(NULL, "Yes, use the discrete GPU");
  gtk_container_add(GTK_CONTAINER(content), radioy);
  GtkWidget *radion = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radioy), "No, use integrated GPU");
  gtk_container_add(GTK_CONTAINER(content), radion);

  GtkWidget *check = gtk_check_button_new_with_label("Remember my choice");
  gtk_container_add(GTK_CONTAINER(content), check);
  gtk_widget_show_all(dialog);
  gtk_dialog_run(GTK_DIALOG (dialog));
  gboolean yes = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioy));
  remember = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check));
  gtk_widget_destroy(dialog);
  return yes;
}

static char *conffile;

static std::map<std::string, bool> read_memos()
{
  const char *configdir, *homedir;
  int r;
  if ((configdir = getenv("XDG_CONFIG_HOME")))
    r = asprintf(&conffile, "%s/libgl_switcheroo.conf", configdir);
  else if ((homedir = getenv("HOME")))
    r = asprintf(&conffile, "%s/.config/libgl_switcheroo.conf", homedir);
  else
    die("XDG_CONFIG_HOME and HOME are not set");
  if (r < 0)
    die("asprintf failed");
  FILE *f = fopen(conffile, "r");
  std::map<std::string, bool> memos;
  if (!f)
    return memos;
  char c, procname[17];
  while (fscanf(f, "%c%16[^\n]\n", &c, procname) == 2)
    memos[std::string(procname)] = c == '+';
  fclose(f);
  return memos;
}

static std::map<std::string, bool> memos(read_memos());

static bool lookup_memo(const char procname[], bool &choice)
{
  std::map<std::string, bool>::iterator i = memos.find(std::string(procname));
  if (i != memos.end())
    choice = i->second;
  return i != memos.end();
}

static void add_memo(const char procname[], bool choice)
{
  memos[std::string(procname)] = choice;
  FILE *f = fopen(conffile, "a");
  if (!f)
    die("failed to open %s for writing", conffile);
  fprintf(f, "%c%s\n", choice ? '+' : '-', procname);
  fclose(f);
}

static bool need_switch(pid_t pid)
{
  char pathbuf[32];
  snprintf(pathbuf, 32, "/proc/%d/status", pid);
  int fd = open(pathbuf, O_RDONLY);
  char namebuf[32];
  read(fd, namebuf, 32);
  close(fd);
  *strchr(namebuf, '\n') = 0;
  char *procname = namebuf + 6;
  bool switch_yes;
  if (lookup_memo(procname, switch_yes))
    return switch_yes;
  bool remember = false;
  switch_yes = ask_user(procname, remember);
  if (remember)
    add_memo(procname, switch_yes);
  return switch_yes;
}

static void gdk_input_cb(void *data, int sock, GdkInputCondition cond)
{
  int fd = accept(sock, 0, 0);
  int pid;
  recv(fd, &pid, sizeof(pid), 0);
  pid = need_switch(pid);
  send(fd, &pid, sizeof(pid), 0);
  close(fd);
}

int main(int argc, char *argv[])
{
  gtk_init(&argc, &argv);

  struct sockaddr_un addr;
  addr.sun_family = AF_UNIX;
  snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/libgl-switcheroo-%s/socket", getenv("USER"));
  unlink(addr.sun_path);
  int sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    die("failed to bind socket %s: %s", addr.sun_path, strerror(errno));
  listen(sock, 16);
  gdk_input_add(sock, GDK_INPUT_READ, gdk_input_cb, NULL);
  gtk_main();

  return 0;
}
<commit_msg>Use statement expression in 'die' macro<commit_after>#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cstdio>
#include <cstdlib>

#include <map>
#include <string>

#include <gtk/gtk.h>

#define die(msg, ...) \
({fprintf(stderr, "gtkglswitch: fatal: " msg "\n", ##__VA_ARGS__); exit(1);})

static bool ask_user(const char procname[], bool &remember)
{
  GtkWidget *dialog = gtk_message_dialog_new (NULL,
      GTK_DIALOG_DESTROY_WITH_PARENT,
      GTK_MESSAGE_QUESTION,
      GTK_BUTTONS_OK,
      "Use OpenGL offloading for %s?", procname);
  GtkWidget *content = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog));

  GtkWidget *radioy = gtk_radio_button_new_with_label(NULL, "Yes, use the discrete GPU");
  gtk_container_add(GTK_CONTAINER(content), radioy);
  GtkWidget *radion = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radioy), "No, use integrated GPU");
  gtk_container_add(GTK_CONTAINER(content), radion);

  GtkWidget *check = gtk_check_button_new_with_label("Remember my choice");
  gtk_container_add(GTK_CONTAINER(content), check);
  gtk_widget_show_all(dialog);
  gtk_dialog_run(GTK_DIALOG (dialog));
  gboolean yes = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioy));
  remember = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check));
  gtk_widget_destroy(dialog);
  return yes;
}

static char *conffile;

static std::map<std::string, bool> read_memos()
{
  const char *configdir, *homedir;
  int r;
  if ((configdir = getenv("XDG_CONFIG_HOME")))
    r = asprintf(&conffile, "%s/libgl_switcheroo.conf", configdir);
  else if ((homedir = getenv("HOME")))
    r = asprintf(&conffile, "%s/.config/libgl_switcheroo.conf", homedir);
  else
    die("XDG_CONFIG_HOME and HOME are not set");
  if (r < 0)
    die("asprintf failed");
  FILE *f = fopen(conffile, "r");
  std::map<std::string, bool> memos;
  if (!f)
    return memos;
  char c, procname[17];
  while (fscanf(f, "%c%16[^\n]\n", &c, procname) == 2)
    memos[std::string(procname)] = c == '+';
  fclose(f);
  return memos;
}

static std::map<std::string, bool> memos(read_memos());

static bool lookup_memo(const char procname[], bool &choice)
{
  std::map<std::string, bool>::iterator i = memos.find(std::string(procname));
  if (i != memos.end())
    choice = i->second;
  return i != memos.end();
}

static void add_memo(const char procname[], bool choice)
{
  memos[std::string(procname)] = choice;
  FILE *f = fopen(conffile, "a");
  if (!f)
    die("failed to open %s for writing", conffile);
  fprintf(f, "%c%s\n", choice ? '+' : '-', procname);
  fclose(f);
}

static bool need_switch(pid_t pid)
{
  char pathbuf[32];
  snprintf(pathbuf, 32, "/proc/%d/status", pid);
  int fd = open(pathbuf, O_RDONLY);
  char namebuf[32];
  read(fd, namebuf, 32);
  close(fd);
  *strchr(namebuf, '\n') = 0;
  char *procname = namebuf + 6;
  bool switch_yes;
  if (lookup_memo(procname, switch_yes))
    return switch_yes;
  bool remember = false;
  switch_yes = ask_user(procname, remember);
  if (remember)
    add_memo(procname, switch_yes);
  return switch_yes;
}

static void gdk_input_cb(void *data, int sock, GdkInputCondition cond)
{
  int fd = accept(sock, 0, 0);
  int pid;
  recv(fd, &pid, sizeof(pid), 0);
  pid = need_switch(pid);
  send(fd, &pid, sizeof(pid), 0);
  close(fd);
}

int main(int argc, char *argv[])
{
  gtk_init(&argc, &argv);

  struct sockaddr_un addr;
  addr.sun_family = AF_UNIX;
  snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/libgl-switcheroo-%s/socket", getenv("USER"));
  unlink(addr.sun_path);
  int sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    die("failed to bind socket %s: %s", addr.sun_path, strerror(errno));
  listen(sock, 16);
  gdk_input_add(sock, GDK_INPUT_READ, gdk_input_cb, NULL);
  gtk_main();

  return 0;
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in 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:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// 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
// AUTHORS 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 IN
// THE SOFTWARE.

#include "BitFunnel/Exceptions.h"
#include "BitFunnel/Index/IRecycler.h"
#include "BitFunnel/Index/ISliceBufferAllocator.h"
#include "BitFunnel/Index/ITermTable.h"
#include "BitFunnel/Index/Row.h"
#include "BitFunnel/Index/RowIdSequence.h"
#include "BitFunnel/Index/Token.h"
#include "BitFunnel/Term.h"
#include "IRecyclable.h"
#include "LoggerInterfaces/Check.h"
#include "LoggerInterfaces/Logging.h"
#include "Recycler.h"
#include "Rounding.h"
#include "Shard.h"

namespace BitFunnel
{
    // Extracts a RowId used to mark documents as active/soft-deleted.
    static RowId RowIdForActiveDocument(ITermTable const & termTable)
    {
        RowIdSequence rows(termTable.GetDocumentActiveTerm(), termTable);

        auto it = rows.begin();
        if (it == rows.end())
        {
            RecoverableError error("RowIdForDeletedDocument: expected at least one row.");
            throw error;
        }
        const RowId rowId = *it;

        if (rowId.GetRank() != 0)
        {
            RecoverableError error("RowIdForDeletedDocument: soft deleted row must be rank 0..");
            throw error;
        }

        ++it;
        if (it != rows.end())
        {
            RecoverableError error("RowIdForDeletedDocument: expected no more than one row.");
            throw error;

        }

        return rowId;
    }

    Shard::Shard(ShardId id,
                 IRecycler& recycler,
                 ITokenManager& tokenManager,
                 ITermTable const & termTable,
                 IDocumentDataSchema const & docDataSchema,
                 ISliceBufferAllocator& sliceBufferAllocator,
                 size_t sliceBufferSize)
        : m_shardId(id),
          m_recycler(recycler),
          m_tokenManager(tokenManager),
          m_termTable(termTable),
          m_sliceBufferAllocator(sliceBufferAllocator),
          m_documentActiveRowId(RowIdForActiveDocument(termTable)),
          m_activeSlice(nullptr),
          m_sliceBuffers(new std::vector<void*>()),
          m_sliceCapacity(GetCapacityForByteSize(sliceBufferSize,
                                                 docDataSchema,
                                                 termTable)),
          m_sliceBufferSize(sliceBufferSize),
          // TODO: will need one global, not one per shard.
          m_docFrequencyTableBuilder(new DocumentFrequencyTableBuilder())
    {
        const size_t bufferSize =
            InitializeDescriptors(this,
                                  m_sliceCapacity,
                                  docDataSchema,
                                  termTable);

        LogAssertB(bufferSize <= sliceBufferSize,
                   "Shard sliceBufferSize too small.");
    }

    Shard::~Shard() {
        delete static_cast<std::vector<void*>*>(m_sliceBuffers);
    }

    DocumentHandleInternal Shard::AllocateDocument(DocId id)
    {
        std::lock_guard<std::mutex> lock(m_slicesLock);
        DocIndex index;
        if (m_activeSlice == nullptr || !m_activeSlice->TryAllocateDocument(index))
        {
            CreateNewActiveSlice();

            LogAssertB(m_activeSlice->TryAllocateDocument(index),
                       "Newly allocated slice has no space.");
        }

        return DocumentHandleInternal(m_activeSlice, index, id);
    }

    void* Shard::AllocateSliceBuffer()
    {
        return m_sliceBufferAllocator.Allocate(m_sliceBufferSize);
    }

    // Must be called with m_slicesLock held.
    void Shard::CreateNewActiveSlice()
    {
        Slice* newSlice = new Slice(*this);

        std::vector<void*>* oldSlices = m_sliceBuffers;
        std::vector<void*>* const newSlices = new std::vector<void*>(*m_sliceBuffers);
        newSlices->push_back(newSlice->GetSliceBuffer());

        m_sliceBuffers = newSlices;
        m_activeSlice = newSlice;

        // TODO: think if this can be done outside of the lock.
        std::unique_ptr<IRecyclable>
            recyclableSliceList(new DeferredSliceListDelete(nullptr,
                                                            oldSlices,
                                                            m_tokenManager));

        m_recycler.ScheduleRecyling(recyclableSliceList);
    }

    /* static */
    DocIndex Shard::GetCapacityForByteSize(size_t bufferSizeInBytes,
                                           IDocumentDataSchema const & schema,
                                           ITermTable const & termTable)
    {
        DocIndex capacity = 0;
        for (;;)
        {
            const DocIndex newSuggestedCapacity = capacity +
                Row::DocumentsInRank0Row(1, termTable.GetMaxRankUsed());
            const size_t newBufferSize =
                InitializeDescriptors(nullptr,
                                      newSuggestedCapacity,
                                      schema,
                                      termTable);
            if (newBufferSize > bufferSizeInBytes)
            {
                break;
            }

            capacity = newSuggestedCapacity;
        }

        LogAssertB(capacity > 0, "Shard with 0 capacity.");

        return capacity;
    }

    DocTableDescriptor const & Shard::GetDocTable() const
    {
        return *m_docTable;
    }

    ptrdiff_t Shard::GetRowOffset(RowId rowId) const
    {
        // LogAssertB(rowId.IsValid(), "GetRowOffset on invalid row.");

        return GetRowTable(rowId.GetRank()).GetRowOffset(rowId.GetIndex());
    }

    RowTableDescriptor const & Shard::GetRowTable(Rank rank) const
    {
        return m_rowTables.at(rank);
    }

    std::vector<void*> const & Shard::GetSliceBuffers() const
    {
        return *m_sliceBuffers;
    }

    ShardId Shard::GetId() const
    {
        return m_shardId;
    }

    DocIndex Shard::GetSliceCapacity() const
    {
        return  m_sliceCapacity;
    }

    RowId Shard::GetDocumentActiveRowId() const
    {
        return m_documentActiveRowId;
    }

    ITermTable const & Shard::GetTermTable() const
    {
        return m_termTable;
    }

    size_t Shard::GetUsedCapacityInBytes() const
    {
        // TODO: does this really need to be locked?
        std::lock_guard<std::mutex> lock(m_slicesLock);
        return m_sliceBuffers.load()->size() * m_sliceBufferSize;
    }

    /* static */
    size_t Shard::InitializeDescriptors(Shard* shard,
                                        DocIndex sliceCapacity,
                                        IDocumentDataSchema const & docDataSchema,
                                        ITermTable const & termTable)
    {
        const Rank maxRank = termTable.GetMaxRankUsed();

        size_t currentOffset = 0;

        // A pointer to a Slice object is placed at the beginning of the slice buffer.
        currentOffset += sizeof(Slice*);

        //
        // DocTable
        //
        currentOffset = RoundUp(currentOffset, DocTableDescriptor::c_docTableByteAlignment);
        if (shard != nullptr)
        {
            // The cast of currentOffset is to avoid an implicit sign conversion
            // warning. It's possible that we should just make currentOffset
            // ptrdiff_t.
            shard->m_docTable.reset(new DocTableDescriptor(sliceCapacity,
                                                           docDataSchema,
                                                           static_cast<ptrdiff_t>(currentOffset)));
        }
        currentOffset += DocTableDescriptor::GetBufferSize(sliceCapacity, docDataSchema);

        //
        // RowTables
        //
        for (Rank rank = 0; rank <= c_maxRankValue; ++rank)
        {
            currentOffset = RoundUp(currentOffset, RowTableDescriptor::c_rowTableByteAlignment);

            const RowIndex rowCount = termTable.GetTotalRowCount(rank);

            if (shard != nullptr)
            {
                shard->m_rowTables.emplace_back(
                    sliceCapacity, rowCount, rank, maxRank, currentOffset);
            }

            currentOffset += RowTableDescriptor::GetBufferSize(
                sliceCapacity, rowCount, rank, maxRank);
        }

        const size_t sliceBufferSize = static_cast<size_t>(currentOffset);

        return sliceBufferSize;
    }

    void Shard::RecycleSlice(Slice& slice)
    {
        std::vector<void*>* oldSlices = nullptr;

        {
            std::lock_guard<std::mutex> lock(m_slicesLock);

            if (!slice.IsExpired())
            {
                throw RecoverableError("Slice being recycled has not been fully expired");
            }

            std::vector<void*>* const newSlices = new std::vector<void*>();
            newSlices->reserve(m_sliceBuffers.load()->size() - 1);

            for (const auto it : *m_sliceBuffers)
            {
                if (it != slice.GetSliceBuffer())
                {
                    newSlices->push_back(it);
                }
            }

            if (m_sliceBuffers.load()->size() != newSlices->size() + 1)
            {
                throw RecoverableError("Slice buffer to be removed is not found in the active slice buffers list");
            }

            oldSlices = m_sliceBuffers.load();
            m_sliceBuffers = newSlices;

            if (m_activeSlice == &slice)
            {
                // If all of the above validations are true, then this was the
                // last Slice in the Shard.
                m_activeSlice = nullptr;
            }
        }

        // Scheduling the Slice and the old list of slice buffers can be
        // done outside of the lock.
        std::unique_ptr<IRecyclable>
            recyclableSliceList(new DeferredSliceListDelete(&slice,
                                                            oldSlices,
                                                            m_tokenManager));

        m_recycler.ScheduleRecyling(recyclableSliceList);
    }

    void Shard::ReleaseSliceBuffer(void* sliceBuffer)
    {
        m_sliceBufferAllocator.Release(sliceBuffer);
    }

    void Shard::AddPosting(Term const & term,
                           DocIndex index,
                           void* sliceBuffer)
    {
        if (m_docFrequencyTableBuilder.get() != nullptr)
        {
            std::lock_guard<std::mutex> lock(m_temporaryFrequencyTableMutex);
            m_docFrequencyTableBuilder->OnTerm(term);
        }

        RowIdSequence rows(term, m_termTable);

        for (auto const row : rows)
        {
            m_rowTables[row.GetRank()].SetBit(sliceBuffer,
                                              row.GetIndex(),
                                              index);
        }
    }

    void Shard::AssertFact(FactHandle fact, bool value, DocIndex index, void* sliceBuffer)
    {
        Term term(fact, 0u, 0u, 1u);
        RowIdSequence rows(term, m_termTable);
        auto it = rows.begin();

        if (it == rows.end())
        {
            RecoverableError error("Shard::AssertFact: expected at least one row.");
            throw error;
        }

        const RowId row = *it;

        ++it;
        if (it != rows.end())
        {
            RecoverableError error("Shard::AssertFact: expected no more than one row.");
            throw error;

        }

        RowTableDescriptor const & rowTable =
            m_rowTables[row.GetRank()];

        if (value)
        {
            rowTable.SetBit(sliceBuffer,
                            row.GetIndex(),
                            index);
        }
        else
        {
            rowTable.ClearBit(sliceBuffer,
                              row.GetIndex(),
                              index);
        }
    }

    void Shard::TemporaryRecordDocument()
    {
        m_docFrequencyTableBuilder->OnDocumentEnter();
    }

    void Shard::TemporaryWriteDocumentFrequencyTable(std::ostream& out,
                                                     ITermToText const * termToText) const
    {
        // TODO: 0.0 is the truncation frequency, which shouldn't be fixed at 0.
        m_docFrequencyTableBuilder->WriteFrequencies(out, 0.0, termToText);
    }

    void Shard::TemporaryWriteIndexedIdfTable(std::ostream& out) const
    {
        // TODO: 0.0 is the truncation frequency, which shouldn't be fixed at 0.
        m_docFrequencyTableBuilder->WriteIndexedIdfTable(out, 0.0);
    }

    void Shard::TemporaryWriteCumulativeTermCounts(std::ostream& out) const
    {
        m_docFrequencyTableBuilder->WriteCumulativeTermCounts(out);
    }

    std::vector<double> Shard::GetDensities(Rank rank) const
    {
        // Hold a token to ensure that m_sliceBuffers won't be recycled.
        auto token = m_tokenManager.RequestToken();

        // m_sliceBuffers can change at any time, but we can safely grab a copy
        // because
        //   1. m_sliceBuffers is std::atomic.
        //   2. no m_sliceBuffers value observed while holding token can be
        //      recycled.
        std::vector<void*> const & buffers = *m_sliceBuffers;

        RowTableDescriptor const & rowTable = m_rowTables[rank];
        RowTableDescriptor const & rowTable0 = m_rowTables[0];

        RowIndex active = (*RowIdSequence(m_termTable.GetDocumentActiveTerm(),
                                          m_termTable).begin()).GetIndex();

        std::vector<double> densities;
        for (RowIndex row = 0; row < rowTable.GetRowCount(); ++row)
        {
            size_t activeBitCount = 0;
            size_t setBitCount = 0;
            for (auto buffer : buffers)
            {
                for (DocIndex doc = 0; doc < GetSliceCapacity(); ++doc)
                {
                    // Only count bits for active documents.
                    if (rowTable0.GetBit(buffer, active, doc) == 1)
                    {
                        // This document is active in the index.
                        // Go ahead and include its bits in the density
                        // calculation.
                        ++activeBitCount;
                        setBitCount += rowTable.GetBit(buffer, row, doc);
                    }
                }
            }
            double density =
                (activeBitCount == 0) ?
                0.0 :
                static_cast<double>(setBitCount) / activeBitCount;

            densities.push_back(density);
        }

        return densities;
    }

    // static
    ptrdiff_t Shard::GetSlicePtrOffset()
    {
        // The slice pointer is at the beginning of the buffer.
        return static_cast<ptrdiff_t>(0ull);
    }
}
<commit_msg>Fix bug in density calculation.<commit_after>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in 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:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// 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
// AUTHORS 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 IN
// THE SOFTWARE.

#include "BitFunnel/Exceptions.h"
#include "BitFunnel/Index/IRecycler.h"
#include "BitFunnel/Index/ISliceBufferAllocator.h"
#include "BitFunnel/Index/ITermTable.h"
#include "BitFunnel/Index/Row.h"
#include "BitFunnel/Index/RowIdSequence.h"
#include "BitFunnel/Index/Token.h"
#include "BitFunnel/Term.h"
#include "IRecyclable.h"
#include "LoggerInterfaces/Check.h"
#include "LoggerInterfaces/Logging.h"
#include "Recycler.h"
#include "Rounding.h"
#include "Shard.h"

namespace BitFunnel
{
    // Extracts a RowId used to mark documents as active/soft-deleted.
    static RowId RowIdForActiveDocument(ITermTable const & termTable)
    {
        RowIdSequence rows(termTable.GetDocumentActiveTerm(), termTable);

        auto it = rows.begin();
        if (it == rows.end())
        {
            RecoverableError error("RowIdForDeletedDocument: expected at least one row.");
            throw error;
        }
        const RowId rowId = *it;

        if (rowId.GetRank() != 0)
        {
            RecoverableError error("RowIdForDeletedDocument: soft deleted row must be rank 0..");
            throw error;
        }

        ++it;
        if (it != rows.end())
        {
            RecoverableError error("RowIdForDeletedDocument: expected no more than one row.");
            throw error;

        }

        return rowId;
    }

    Shard::Shard(ShardId id,
                 IRecycler& recycler,
                 ITokenManager& tokenManager,
                 ITermTable const & termTable,
                 IDocumentDataSchema const & docDataSchema,
                 ISliceBufferAllocator& sliceBufferAllocator,
                 size_t sliceBufferSize)
        : m_shardId(id),
          m_recycler(recycler),
          m_tokenManager(tokenManager),
          m_termTable(termTable),
          m_sliceBufferAllocator(sliceBufferAllocator),
          m_documentActiveRowId(RowIdForActiveDocument(termTable)),
          m_activeSlice(nullptr),
          m_sliceBuffers(new std::vector<void*>()),
          m_sliceCapacity(GetCapacityForByteSize(sliceBufferSize,
                                                 docDataSchema,
                                                 termTable)),
          m_sliceBufferSize(sliceBufferSize),
          // TODO: will need one global, not one per shard.
          m_docFrequencyTableBuilder(new DocumentFrequencyTableBuilder())
    {
        const size_t bufferSize =
            InitializeDescriptors(this,
                                  m_sliceCapacity,
                                  docDataSchema,
                                  termTable);

        LogAssertB(bufferSize <= sliceBufferSize,
                   "Shard sliceBufferSize too small.");
    }

    Shard::~Shard() {
        delete static_cast<std::vector<void*>*>(m_sliceBuffers);
    }

    DocumentHandleInternal Shard::AllocateDocument(DocId id)
    {
        std::lock_guard<std::mutex> lock(m_slicesLock);
        DocIndex index;
        if (m_activeSlice == nullptr || !m_activeSlice->TryAllocateDocument(index))
        {
            CreateNewActiveSlice();

            LogAssertB(m_activeSlice->TryAllocateDocument(index),
                       "Newly allocated slice has no space.");
        }

        return DocumentHandleInternal(m_activeSlice, index, id);
    }

    void* Shard::AllocateSliceBuffer()
    {
        return m_sliceBufferAllocator.Allocate(m_sliceBufferSize);
    }

    // Must be called with m_slicesLock held.
    void Shard::CreateNewActiveSlice()
    {
        Slice* newSlice = new Slice(*this);

        std::vector<void*>* oldSlices = m_sliceBuffers;
        std::vector<void*>* const newSlices = new std::vector<void*>(*m_sliceBuffers);
        newSlices->push_back(newSlice->GetSliceBuffer());

        m_sliceBuffers = newSlices;
        m_activeSlice = newSlice;

        // TODO: think if this can be done outside of the lock.
        std::unique_ptr<IRecyclable>
            recyclableSliceList(new DeferredSliceListDelete(nullptr,
                                                            oldSlices,
                                                            m_tokenManager));

        m_recycler.ScheduleRecyling(recyclableSliceList);
    }

    /* static */
    DocIndex Shard::GetCapacityForByteSize(size_t bufferSizeInBytes,
                                           IDocumentDataSchema const & schema,
                                           ITermTable const & termTable)
    {
        DocIndex capacity = 0;
        for (;;)
        {
            const DocIndex newSuggestedCapacity = capacity +
                Row::DocumentsInRank0Row(1, termTable.GetMaxRankUsed());
            const size_t newBufferSize =
                InitializeDescriptors(nullptr,
                                      newSuggestedCapacity,
                                      schema,
                                      termTable);
            if (newBufferSize > bufferSizeInBytes)
            {
                break;
            }

            capacity = newSuggestedCapacity;
        }

        LogAssertB(capacity > 0, "Shard with 0 capacity.");

        return capacity;
    }

    DocTableDescriptor const & Shard::GetDocTable() const
    {
        return *m_docTable;
    }

    ptrdiff_t Shard::GetRowOffset(RowId rowId) const
    {
        // LogAssertB(rowId.IsValid(), "GetRowOffset on invalid row.");

        return GetRowTable(rowId.GetRank()).GetRowOffset(rowId.GetIndex());
    }

    RowTableDescriptor const & Shard::GetRowTable(Rank rank) const
    {
        return m_rowTables.at(rank);
    }

    std::vector<void*> const & Shard::GetSliceBuffers() const
    {
        return *m_sliceBuffers;
    }

    ShardId Shard::GetId() const
    {
        return m_shardId;
    }

    DocIndex Shard::GetSliceCapacity() const
    {
        return  m_sliceCapacity;
    }

    RowId Shard::GetDocumentActiveRowId() const
    {
        return m_documentActiveRowId;
    }

    ITermTable const & Shard::GetTermTable() const
    {
        return m_termTable;
    }

    size_t Shard::GetUsedCapacityInBytes() const
    {
        // TODO: does this really need to be locked?
        std::lock_guard<std::mutex> lock(m_slicesLock);
        return m_sliceBuffers.load()->size() * m_sliceBufferSize;
    }

    /* static */
    size_t Shard::InitializeDescriptors(Shard* shard,
                                        DocIndex sliceCapacity,
                                        IDocumentDataSchema const & docDataSchema,
                                        ITermTable const & termTable)
    {
        const Rank maxRank = termTable.GetMaxRankUsed();

        size_t currentOffset = 0;

        // A pointer to a Slice object is placed at the beginning of the slice buffer.
        currentOffset += sizeof(Slice*);

        //
        // DocTable
        //
        currentOffset = RoundUp(currentOffset, DocTableDescriptor::c_docTableByteAlignment);
        if (shard != nullptr)
        {
            // The cast of currentOffset is to avoid an implicit sign conversion
            // warning. It's possible that we should just make currentOffset
            // ptrdiff_t.
            shard->m_docTable.reset(new DocTableDescriptor(sliceCapacity,
                                                           docDataSchema,
                                                           static_cast<ptrdiff_t>(currentOffset)));
        }
        currentOffset += DocTableDescriptor::GetBufferSize(sliceCapacity, docDataSchema);

        //
        // RowTables
        //
        for (Rank rank = 0; rank <= c_maxRankValue; ++rank)
        {
            currentOffset = RoundUp(currentOffset, RowTableDescriptor::c_rowTableByteAlignment);

            const RowIndex rowCount = termTable.GetTotalRowCount(rank);

            if (shard != nullptr)
            {
                shard->m_rowTables.emplace_back(
                    sliceCapacity, rowCount, rank, maxRank, currentOffset);
            }

            currentOffset += RowTableDescriptor::GetBufferSize(
                sliceCapacity, rowCount, rank, maxRank);
        }

        const size_t sliceBufferSize = static_cast<size_t>(currentOffset);

        return sliceBufferSize;
    }

    void Shard::RecycleSlice(Slice& slice)
    {
        std::vector<void*>* oldSlices = nullptr;

        {
            std::lock_guard<std::mutex> lock(m_slicesLock);

            if (!slice.IsExpired())
            {
                throw RecoverableError("Slice being recycled has not been fully expired");
            }

            std::vector<void*>* const newSlices = new std::vector<void*>();
            newSlices->reserve(m_sliceBuffers.load()->size() - 1);

            for (const auto it : *m_sliceBuffers)
            {
                if (it != slice.GetSliceBuffer())
                {
                    newSlices->push_back(it);
                }
            }

            if (m_sliceBuffers.load()->size() != newSlices->size() + 1)
            {
                throw RecoverableError("Slice buffer to be removed is not found in the active slice buffers list");
            }

            oldSlices = m_sliceBuffers.load();
            m_sliceBuffers = newSlices;

            if (m_activeSlice == &slice)
            {
                // If all of the above validations are true, then this was the
                // last Slice in the Shard.
                m_activeSlice = nullptr;
            }
        }

        // Scheduling the Slice and the old list of slice buffers can be
        // done outside of the lock.
        std::unique_ptr<IRecyclable>
            recyclableSliceList(new DeferredSliceListDelete(&slice,
                                                            oldSlices,
                                                            m_tokenManager));

        m_recycler.ScheduleRecyling(recyclableSliceList);
    }

    void Shard::ReleaseSliceBuffer(void* sliceBuffer)
    {
        m_sliceBufferAllocator.Release(sliceBuffer);
    }

    void Shard::AddPosting(Term const & term,
                           DocIndex index,
                           void* sliceBuffer)
    {
        if (m_docFrequencyTableBuilder.get() != nullptr)
        {
            std::lock_guard<std::mutex> lock(m_temporaryFrequencyTableMutex);
            m_docFrequencyTableBuilder->OnTerm(term);
        }

        RowIdSequence rows(term, m_termTable);

        for (auto const row : rows)
        {
            m_rowTables[row.GetRank()].SetBit(sliceBuffer,
                                              row.GetIndex(),
                                              index);
        }
    }

    void Shard::AssertFact(FactHandle fact, bool value, DocIndex index, void* sliceBuffer)
    {
        Term term(fact, 0u, 0u, 1u);
        RowIdSequence rows(term, m_termTable);
        auto it = rows.begin();

        if (it == rows.end())
        {
            RecoverableError error("Shard::AssertFact: expected at least one row.");
            throw error;
        }

        const RowId row = *it;

        ++it;
        if (it != rows.end())
        {
            RecoverableError error("Shard::AssertFact: expected no more than one row.");
            throw error;

        }

        RowTableDescriptor const & rowTable =
            m_rowTables[row.GetRank()];

        if (value)
        {
            rowTable.SetBit(sliceBuffer,
                            row.GetIndex(),
                            index);
        }
        else
        {
            rowTable.ClearBit(sliceBuffer,
                              row.GetIndex(),
                              index);
        }
    }

    void Shard::TemporaryRecordDocument()
    {
        m_docFrequencyTableBuilder->OnDocumentEnter();
    }

    void Shard::TemporaryWriteDocumentFrequencyTable(std::ostream& out,
                                                     ITermToText const * termToText) const
    {
        // TODO: 0.0 is the truncation frequency, which shouldn't be fixed at 0.
        m_docFrequencyTableBuilder->WriteFrequencies(out, 0.0, termToText);
    }

    void Shard::TemporaryWriteIndexedIdfTable(std::ostream& out) const
    {
        // TODO: 0.0 is the truncation frequency, which shouldn't be fixed at 0.
        m_docFrequencyTableBuilder->WriteIndexedIdfTable(out, 0.0);
    }

    void Shard::TemporaryWriteCumulativeTermCounts(std::ostream& out) const
    {
        m_docFrequencyTableBuilder->WriteCumulativeTermCounts(out);
    }

    std::vector<double> Shard::GetDensities(Rank rank) const
    {
        // Hold a token to ensure that m_sliceBuffers won't be recycled.
        auto token = m_tokenManager.RequestToken();

        // m_sliceBuffers can change at any time, but we can safely grab a copy
        // because
        //   1. m_sliceBuffers is std::atomic.
        //   2. no m_sliceBuffers value observed while holding token can be
        //      recycled.
        std::vector<void*> const & buffers = *m_sliceBuffers;

        RowTableDescriptor const & rowTable = m_rowTables[rank];
        RowTableDescriptor const & rowTable0 = m_rowTables[0];

        RowIndex active = (*RowIdSequence(m_termTable.GetDocumentActiveTerm(),
                                          m_termTable).begin()).GetIndex();

        std::vector<double> densities;
        for (RowIndex row = 0; row < rowTable.GetRowCount(); ++row)
        {
            size_t activeBitCount = 0;
            size_t setBitCount = 0;
            for (auto buffer : buffers)
            {
                for (DocIndex doc = 0; doc < GetSliceCapacity(); ++doc)
                {
                    // Only count bits for active documents.
                    if (rowTable0.GetBit(buffer, active, doc) != 0)
                    {
                        // This document is active in the index.
                        // Go ahead and include its bits in the density
                        // calculation.
                        ++activeBitCount;
                        if (rowTable.GetBit(buffer, row, doc) != 0)
                        {
                            ++setBitCount;
                        }
                    }
                }
            }
            double density =
                (activeBitCount == 0) ?
                0.0 :
                static_cast<double>(setBitCount) / activeBitCount;

            densities.push_back(density);
        }

        return densities;
    }

    // static
    ptrdiff_t Shard::GetSlicePtrOffset()
    {
        // The slice pointer is at the beginning of the buffer.
        return static_cast<ptrdiff_t>(0ull);
    }
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// FILE:          Rapp.cpp
// PROJECT:       Micro-Manager
// SUBSYSTEM:     DeviceAdapters
//-----------------------------------------------------------------------------
// DESCRIPTION:   Rapp UGA40 adapter
// COPYRIGHT:     University of California, San Francisco, 2012
//                All rights reserved
//
// LICENSE:       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.
//
//                You should have received a copy of the GNU Lesser General Public
//                License along with the source distribution; if not, write to
//                the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
//                Boston, MA  02111-1307  USA
//
//                This file 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.
//
//                IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//                CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//
// AUTHOR:        Arthur Edelstein, 2012
//                Special thanks to Andre Ratz

#ifdef WIN32
#define snprintf _snprintf
#pragma warning(disable: 4355)
#endif

#include "Rapp.h"
#include <cstdio>
#include <string>
#include <math.h>
#include "../../MMDevice/ModuleInterface.h"
#include "../../MMDevice/DeviceUtils.h"
#include <sstream>

#include <iostream>
using namespace std;

const char* g_RappScannerName = "RappScanner";

#define ERR_PORT_CHANGE_FORBIDDEN    10004

#define GALVO_RANGE 4096

///////////////////////////////////////////////////////////////////////////////
// Exported MMDevice API
///////////////////////////////////////////////////////////////////////////////
MODULE_API void InitializeModuleData()
{
   AddAvailableDeviceName(g_RappScannerName, "RappScanner");
}

MODULE_API MM::Device* CreateDevice(const char* deviceName)
{
   if (deviceName == 0)
      return 0;

   if (strcmp(deviceName, g_RappScannerName) == 0)
   {
      RappScanner* s = new RappScanner();
      return s;
   }

   return 0;
}

MODULE_API void DeleteDevice(MM::Device* pDevice)
{
   delete pDevice;
}

MM::DeviceDetectionStatus RappScannerDetect(MM::Device& /*device*/, MM::Core& /*core*/, std::string portToCheck, double /*answerTimeoutMs*/)
{
   // all conditions must be satisfied...
   MM::DeviceDetectionStatus result = MM::Misconfigured;

   return result;
}

///////////////////////////////////////////////////////////////////////////////
// RappScanner
//
RappScanner::RappScanner() :
   initialized_(false), port_(""), calibrationMode_(0), polygonAccuracy_(10), polygonMinRectSize_(10),
   ttlTriggered_("Rising Edge"), rasterFrequency_(500), spotSize_(10), laser2_(false)
{
   InitializeDefaultErrorMessages();

   // create pre-initialization properties
   // ------------------------------------

   // Name
   CreateProperty(MM::g_Keyword_Name, g_RappScannerName, MM::String, true);

   // Description
   CreateProperty(MM::g_Keyword_Description, "Rapp UGA-40 galvo phototargeting adapter", MM::String, true);

   // Port
   CPropertyAction* pAct = new CPropertyAction (this, &RappScanner::OnPort);

   obsROE_Device* dev = new obsROE_Device();

	std::vector<std::string> s = dev->SearchDevices();
	if (s.size() <= 0)
	{
      s.push_back(std::string("Undefined"));
	}

   CreateProperty("VirtualComPort", s.at(0).c_str(), MM::String, false, pAct, true);
	for (unsigned int i = 0; i < s.size(); i++)
   {
      AddAllowedValue("VirtualComPort", s.at(i).c_str());
   }

}

RappScanner::~RappScanner()
{
   Shutdown();
}

void RappScanner::GetName(char* Name) const
{
   CDeviceUtils::CopyLimitedString(Name, g_RappScannerName);
}

MM::DeviceDetectionStatus RappScanner::DetectDevice(void)
{
   return MM::Misconfigured;
}

int RappScanner::Initialize()
{
   UGA_ = new obsROE_Device();

   UGA_->Connect(port_.c_str());
   if (UGA_->IsConnected()) {
      UGA_->UseMaxCalibration(false);
      UGA_->SetCalibrationMode(false, laser2_);
      RunDummyCalibration();
      UGA_->CenterSpot();
      currentX_ = 0;
      currentY_ = 0;
      initialized_ = true;
   } else {
      initialized_ = false;
      return DEVICE_NOT_CONNECTED;
   }

   CPropertyAction* pAct = new CPropertyAction(this, &RappScanner::OnCalibrationMode);
   CreateProperty("CalibrationMode", "0", MM::Integer, false, pAct);
   AddAllowedValue("CalibrationMode", "1");
   AddAllowedValue("CalibrationMode", "0");

   pAct = new CPropertyAction(this, &RappScanner::OnSequence);
   CreateProperty("Sequence", "", MM::String, false, pAct);

   pAct = new CPropertyAction(this, &RappScanner::OnTTLTriggered);
   CreateProperty("TTLTriggered", "Rising Edge", MM::String, false, pAct);
   AddAllowedValue("TTLTriggered", "Rising Edge");
   AddAllowedValue("TTLTriggered", "Falling Edge");

   pAct = new CPropertyAction(this, &RappScanner::OnSpotSize);
   CreateProperty("SpotSize", "0", MM::Float, false, pAct);

   pAct = new CPropertyAction(this, &RappScanner::OnRasterFrequency);
   CreateProperty("RasterFrequency_Hz", "500", MM::Integer, false, pAct);

   pAct = new CPropertyAction(this, &RappScanner::OnAccuracy);
   CreateProperty("AccuracyPercent", "10", MM::Integer, false, pAct);

   pAct = new CPropertyAction(this, &RappScanner::OnMinimumRectSize);
   CreateProperty("MinimumRectSize", "250", MM::Integer, false, pAct);

   return DEVICE_OK;
}

int RappScanner::Shutdown()
{
   int result = DEVICE_NOT_CONNECTED;
   if (initialized_)
   {
      if (UGA_->IsConnected()) {
         if (UGA_->Disconnect()) {
            initialized_ = false;
            result = DEVICE_OK;
         }
      }

   delete UGA_;
   }
   return result;
}

bool RappScanner::Busy()
{
   return false;
}

/////////////////////////////
// Galvo API
/////////////////////////////
int RappScanner::PointAndFire(double x, double y, double pulseTime_us)
{
   int result = DEVICE_OK;
   pointf xy((float) x,(float) y);
   UGA_->ClickAndFire(xy, (int) pulseTime_us, laser2_);
   return result;
}

int RappScanner::SetPosition(double x, double y)
{
   UGA_->SetDevicePosition((int) x,(int) y);
   return DEVICE_OK;
}

int RappScanner::GetPosition(double& x, double& y)
{
   pointf p = UGA_->CurrentPosition();
   x = p.x;
   y = p.y;
   return DEVICE_OK;
}

double RappScanner::GetXRange()
{
   return (double) GALVO_RANGE;
}

double RappScanner::GetYRange()
{
   return (double) GALVO_RANGE;
}

int RappScanner::AddPolygonVertex(int polygonIndex, double x, double y)
{
   if (polygons_.size() < (unsigned) (1+polygonIndex)) {
      polygons_.resize(1+polygonIndex);
   }
   polygons_.at(polygonIndex).push_back(pointf((float) x, (float) y));
   return DEVICE_OK;
}

int RappScanner::DeletePolygons()
{
   polygons_.clear();
   UGA_->DeletePolygons();
   return DEVICE_OK;
}

int RappScanner::RunSequence()
{
   tRectList rectangles;

   pointf minRectDimensions((float) polygonMinRectSize_, (float) polygonMinRectSize_);
   for (unsigned polygonIndex=0;polygonIndex<polygons_.size();++polygonIndex)
   {
      UGA_->CreateA(polygons_.at(polygonIndex), polygonAccuracy_, minRectDimensions, &rectangles, laser2_);
   }

   if (sequence_.size() > 0)
   {
      std::string sequence2 = replaceChar(sequence_, ':', ',');
      tStringList sequenceList = split(sequence2, ' ');

      if (!UGA_->StoreSequence(sequenceList))
      {
         return DEVICE_ERR;
      }
   }

   if (UGA_->RunSequence(false))
   {
      return DEVICE_OK;
   }
   else
   {
      return DEVICE_ERR;
   }
}

int RappScanner::StopSequence()
{

   if (UGA_->AbortSequence())
   {
      return DEVICE_OK;
   }
   else
   {
      return DEVICE_ERR;
   }
}

/////////////////////////////
// Property Action Handlers
/////////////////////////////

int RappScanner::OnCalibrationMode(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   int result = DEVICE_OK;
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(calibrationMode_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(calibrationMode_);
      if (UGA_->SetCalibrationMode(calibrationMode_ == 1, laser2_)) {
         result = DEVICE_OK;
      } else {
         result = DEVICE_NOT_CONNECTED;
      }
   }

   return result;
}

int RappScanner::OnPort(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(port_.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      if (initialized_)
      {
         // revert
         pProp->Set(port_.c_str());
         return ERR_PORT_CHANGE_FORBIDDEN;
      }

      pProp->Get(port_);
   }

   return DEVICE_OK;
}

int RappScanner::OnSequence(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(sequence_.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(sequence_);
   }

   return DEVICE_OK;
}

int RappScanner::OnTTLTriggered(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(ttlTriggered_.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(ttlTriggered_);
      if (0 == ttlTriggered_.compare("Rising Edge"))
      {
         UGA_->SetTriggerBehavior(RisingEdge);
      }
      else
      {
         UGA_->SetTriggerBehavior(FallingEdge);
      }
   }

   return DEVICE_OK;
}

int RappScanner::OnSpotSize(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(spotSize_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(spotSize_);
      UGA_->DefineSpotSize((float) spotSize_, laser2_);
   }

   return DEVICE_OK;
}

int RappScanner::OnRasterFrequency(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(rasterFrequency_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(rasterFrequency_);
      UGA_->SetROIFrequence(rasterFrequency_, laser2_); // [sic]
   }

   return DEVICE_OK;
}

int RappScanner::OnAccuracy(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(polygonAccuracy_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(polygonAccuracy_);
   }

   return DEVICE_OK;
}

int RappScanner::OnMinimumRectSize(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(polygonMinRectSize_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(polygonMinRectSize_);
   }

   return DEVICE_OK;
}

/////////////////////////////
// Helper Functions
/////////////////////////////

void RappScanner::RunDummyCalibration()
{
   int side = 4096;

   UGA_->SetCalibrationMode(true, laser2_);

   UGA_->SetAOIEdge(Up, 0, laser2_);
   UGA_->SetAOIEdge(Down, side-1, laser2_);
   UGA_->SetAOIEdge(Left, 0, laser2_);
   UGA_->SetAOIEdge(Right, side-1, laser2_);

   pointf p0(0, 0);
   pointf p1((float) side-1, 0);
   pointf p2(0, (float) side-1);
   pointf p3((float) side-1, (float) side-1);

   UGA_->UseMaxCalibration(false);
   UGA_->InitializeCalibration(4, laser2_);

   UGA_->CenterSpot();
   UGA_->MoveLaser(Up, side/2 - 1);
   UGA_->MoveLaser(Left, side/2 - 1);
   UGA_->SetCalibrationPoint(false, 0, p0, laser2_);
   UGA_->MoveLaser(Right, side);
   UGA_->SetCalibrationPoint(false, 1, p1, laser2_);
   UGA_->MoveLaser(Down, side);
   UGA_->SetCalibrationPoint(false, 3, p3, laser2_); //Point-ID 2->3
   UGA_->MoveLaser(Left, side);
   UGA_->SetCalibrationPoint(false, 2, p2, laser2_); //Point-ID 3->2

   UGA_->SetCalibrationMode(calibrationMode_ == 1, laser2_);
}

std::vector<std::string> & split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

std::string replaceChar(std::string str, char ch1, char ch2) {
  std::string str2(str);
  for (unsigned i = 0; i < str2.length(); ++i) {
    if (str2[i] == ch1)
      str2[i] = ch2;
  }
  return str2;
}<commit_msg>cleanup<commit_after>///////////////////////////////////////////////////////////////////////////////
// FILE:          Rapp.cpp
// PROJECT:       Micro-Manager
// SUBSYSTEM:     DeviceAdapters
//-----------------------------------------------------------------------------
// DESCRIPTION:   Rapp UGA40 adapter
// COPYRIGHT:     University of California, San Francisco, 2012
//                All rights reserved
//
// LICENSE:       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.
//
//                You should have received a copy of the GNU Lesser General Public
//                License along with the source distribution; if not, write to
//                the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
//                Boston, MA  02111-1307  USA
//
//                This file 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.
//
//                IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//                CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//
// AUTHOR:        Arthur Edelstein, 2012
//                Special thanks to Andre Ratz

#ifdef WIN32
#define snprintf _snprintf
#pragma warning(disable: 4355)
#endif

#include "Rapp.h"
#include <cstdio>
#include <string>
#include <math.h>
#include "../../MMDevice/ModuleInterface.h"
#include "../../MMDevice/DeviceUtils.h"
#include <sstream>

#include <iostream>

const char* g_RappScannerName = "RappScanner";

#define ERR_PORT_CHANGE_FORBIDDEN    10004

#define GALVO_RANGE 4096

///////////////////////////////////////////////////////////////////////////////
// Exported MMDevice API
///////////////////////////////////////////////////////////////////////////////
MODULE_API void InitializeModuleData()
{
   AddAvailableDeviceName(g_RappScannerName, "RappScanner");
}

MODULE_API MM::Device* CreateDevice(const char* deviceName)
{
   if (deviceName == 0)
      return 0;

   if (strcmp(deviceName, g_RappScannerName) == 0)
   {
      RappScanner* s = new RappScanner();
      return s;
   }

   return 0;
}

MODULE_API void DeleteDevice(MM::Device* pDevice)
{
   delete pDevice;
}

MM::DeviceDetectionStatus RappScannerDetect(MM::Device& /*device*/, MM::Core& /*core*/, std::string portToCheck, double /*answerTimeoutMs*/)
{
   // all conditions must be satisfied...
   MM::DeviceDetectionStatus result = MM::Misconfigured;

   return result;
}

///////////////////////////////////////////////////////////////////////////////
// RappScanner
//
RappScanner::RappScanner() :
   initialized_(false), port_(""), calibrationMode_(0), polygonAccuracy_(10), polygonMinRectSize_(10),
   ttlTriggered_("Rising Edge"), rasterFrequency_(500), spotSize_(10), laser2_(false)
{
   InitializeDefaultErrorMessages();

   // create pre-initialization properties
   // ------------------------------------

   // Name
   CreateProperty(MM::g_Keyword_Name, g_RappScannerName, MM::String, true);

   // Description
   CreateProperty(MM::g_Keyword_Description, "Rapp UGA-40 galvo phototargeting adapter", MM::String, true);

   // Port
   CPropertyAction* pAct = new CPropertyAction (this, &RappScanner::OnPort);

   obsROE_Device* dev = new obsROE_Device();

	std::vector<std::string> s = dev->SearchDevices();
	if (s.size() <= 0)
	{
      s.push_back(std::string("Undefined"));
	}

   // The following line crashes hardware wizard if compiled in a Debug configuration:
   CreateProperty("VirtualComPort", s.at(0).c_str(), MM::String, false, pAct, true);
	for (unsigned int i = 0; i < s.size(); i++)
   {
      AddAllowedValue("VirtualComPort", s.at(i).c_str());
   }

}

RappScanner::~RappScanner()
{
   Shutdown();
}

void RappScanner::GetName(char* Name) const
{
   CDeviceUtils::CopyLimitedString(Name, g_RappScannerName);
}

MM::DeviceDetectionStatus RappScanner::DetectDevice(void)
{
   return MM::Misconfigured;
}

int RappScanner::Initialize()
{
   UGA_ = new obsROE_Device();

   UGA_->Connect(port_.c_str());
   if (UGA_->IsConnected()) {
      UGA_->UseMaxCalibration(false);
      UGA_->SetCalibrationMode(false, laser2_);
      RunDummyCalibration();
      UGA_->CenterSpot();
      currentX_ = 0;
      currentY_ = 0;
      initialized_ = true;
   } else {
      initialized_ = false;
      return DEVICE_NOT_CONNECTED;
   }

   CPropertyAction* pAct = new CPropertyAction(this, &RappScanner::OnCalibrationMode);
   CreateProperty("CalibrationMode", "0", MM::Integer, false, pAct);
   AddAllowedValue("CalibrationMode", "1");
   AddAllowedValue("CalibrationMode", "0");

   pAct = new CPropertyAction(this, &RappScanner::OnSequence);
   CreateProperty("Sequence", "", MM::String, false, pAct);

   pAct = new CPropertyAction(this, &RappScanner::OnTTLTriggered);
   CreateProperty("TTLTriggered", "Rising Edge", MM::String, false, pAct);
   AddAllowedValue("TTLTriggered", "Rising Edge");
   AddAllowedValue("TTLTriggered", "Falling Edge");

   pAct = new CPropertyAction(this, &RappScanner::OnSpotSize);
   CreateProperty("SpotSize", "0", MM::Float, false, pAct);

   pAct = new CPropertyAction(this, &RappScanner::OnRasterFrequency);
   CreateProperty("RasterFrequency_Hz", "500", MM::Integer, false, pAct);

   pAct = new CPropertyAction(this, &RappScanner::OnAccuracy);
   CreateProperty("AccuracyPercent", "10", MM::Integer, false, pAct);

   pAct = new CPropertyAction(this, &RappScanner::OnMinimumRectSize);
   CreateProperty("MinimumRectSize", "250", MM::Integer, false, pAct);

   return DEVICE_OK;
}

int RappScanner::Shutdown()
{
   int result = DEVICE_NOT_CONNECTED;
   if (initialized_)
   {
      if (UGA_->IsConnected()) {
         if (UGA_->Disconnect()) {
            initialized_ = false;
            result = DEVICE_OK;
         }
      }

   delete UGA_;
   }
   return result;
}

bool RappScanner::Busy()
{
   return false;
}

/////////////////////////////
// Galvo API
/////////////////////////////
int RappScanner::PointAndFire(double x, double y, double pulseTime_us)
{
   int result = DEVICE_OK;
   pointf xy((float) x,(float) y);
   UGA_->ClickAndFire(xy, (int) pulseTime_us, laser2_);
   return result;
}

int RappScanner::SetPosition(double x, double y)
{
   UGA_->SetDevicePosition((int) x,(int) y);
   return DEVICE_OK;
}

int RappScanner::GetPosition(double& x, double& y)
{
   pointf p = UGA_->CurrentPosition();
   x = p.x;
   y = p.y;
   return DEVICE_OK;
}

double RappScanner::GetXRange()
{
   return (double) GALVO_RANGE;
}

double RappScanner::GetYRange()
{
   return (double) GALVO_RANGE;
}

int RappScanner::AddPolygonVertex(int polygonIndex, double x, double y)
{
   if (polygons_.size() < (unsigned) (1+polygonIndex)) {
      polygons_.resize(1+polygonIndex);
   }
   polygons_.at(polygonIndex).push_back(pointf((float) x, (float) y));
   return DEVICE_OK;
}

int RappScanner::DeletePolygons()
{
   polygons_.clear();
   UGA_->DeletePolygons();
   return DEVICE_OK;
}

int RappScanner::RunSequence()
{
   tRectList rectangles;

   pointf minRectDimensions((float) polygonMinRectSize_, (float) polygonMinRectSize_);
   for (unsigned polygonIndex=0;polygonIndex<polygons_.size();++polygonIndex)
   {
      UGA_->CreateA(polygons_.at(polygonIndex), polygonAccuracy_, minRectDimensions, &rectangles, laser2_);
   }

   if (sequence_.size() > 0)
   {
      std::string sequence2 = replaceChar(sequence_, ':', ',');
      tStringList sequenceList = split(sequence2, ' ');

      if (!UGA_->StoreSequence(sequenceList))
      {
         return DEVICE_ERR;
      }
   }

   if (UGA_->RunSequence(false))
   {
      return DEVICE_OK;
   }
   else
   {
      return DEVICE_ERR;
   }
}

int RappScanner::StopSequence()
{

   if (UGA_->AbortSequence())
   {
      return DEVICE_OK;
   }
   else
   {
      return DEVICE_ERR;
   }
}

/////////////////////////////
// Property Action Handlers
/////////////////////////////

int RappScanner::OnCalibrationMode(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   int result = DEVICE_OK;
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(calibrationMode_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(calibrationMode_);
      if (UGA_->SetCalibrationMode(calibrationMode_ == 1, laser2_)) {
         result = DEVICE_OK;
      } else {
         result = DEVICE_NOT_CONNECTED;
      }
   }

   return result;
}

int RappScanner::OnPort(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(port_.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      if (initialized_)
      {
         // revert
         pProp->Set(port_.c_str());
         return ERR_PORT_CHANGE_FORBIDDEN;
      }

      pProp->Get(port_);
   }

   return DEVICE_OK;
}

int RappScanner::OnSequence(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(sequence_.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(sequence_);
   }

   return DEVICE_OK;
}

int RappScanner::OnTTLTriggered(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(ttlTriggered_.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(ttlTriggered_);
      if (0 == ttlTriggered_.compare("Rising Edge"))
      {
         UGA_->SetTriggerBehavior(RisingEdge);
      }
      else
      {
         UGA_->SetTriggerBehavior(FallingEdge);
      }
   }

   return DEVICE_OK;
}

int RappScanner::OnSpotSize(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(spotSize_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(spotSize_);
      UGA_->DefineSpotSize((float) spotSize_, laser2_);
   }

   return DEVICE_OK;
}

int RappScanner::OnRasterFrequency(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(rasterFrequency_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(rasterFrequency_);
      UGA_->SetROIFrequence(rasterFrequency_, laser2_); // [sic]
   }

   return DEVICE_OK;
}

int RappScanner::OnAccuracy(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(polygonAccuracy_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(polygonAccuracy_);
   }

   return DEVICE_OK;
}

int RappScanner::OnMinimumRectSize(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(polygonMinRectSize_);
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(polygonMinRectSize_);
   }

   return DEVICE_OK;
}

/////////////////////////////
// Helper Functions
/////////////////////////////

void RappScanner::RunDummyCalibration()
{
   int side = 4096;

   UGA_->SetCalibrationMode(true, laser2_);

   UGA_->SetAOIEdge(Up, 0, laser2_);
   UGA_->SetAOIEdge(Down, side-1, laser2_);
   UGA_->SetAOIEdge(Left, 0, laser2_);
   UGA_->SetAOIEdge(Right, side-1, laser2_);

   pointf p0(0, 0);
   pointf p1((float) side-1, 0);
   pointf p2(0, (float) side-1);
   pointf p3((float) side-1, (float) side-1);

   UGA_->UseMaxCalibration(false);
   UGA_->InitializeCalibration(4, laser2_);

   UGA_->CenterSpot();
   UGA_->MoveLaser(Up, side/2 - 1);
   UGA_->MoveLaser(Left, side/2 - 1);
   UGA_->SetCalibrationPoint(false, 0, p0, laser2_);
   UGA_->MoveLaser(Right, side);
   UGA_->SetCalibrationPoint(false, 1, p1, laser2_);
   UGA_->MoveLaser(Down, side);
   UGA_->SetCalibrationPoint(false, 3, p3, laser2_); //Point-ID 2->3
   UGA_->MoveLaser(Left, side);
   UGA_->SetCalibrationPoint(false, 2, p2, laser2_); //Point-ID 3->2

   UGA_->SetCalibrationMode(calibrationMode_ == 1, laser2_);
}

std::vector<std::string> & split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

std::string replaceChar(std::string str, char ch1, char ch2) {
  std::string str2(str);
  for (unsigned i = 0; i < str2.length(); ++i) {
    if (str2[i] == ch1)
      str2[i] = ch2;
  }
  return str2;
}<|endoftext|>