<commit_before>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// 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.
//
////////////////////////////////////////////////////////////

#ifndef BASE_RESOURCE_HPP
#define BASE_RESOURCE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include <iostream>
#include <string>

namespace rm
{
    ///////////////////////////////////////////////////////////
    /// \brief An abstract resource class
    ///
    /// This abstract base class needs to be inherited by a
    /// ManagedResource class. It contains three pure virtual
    /// functions that require a specific body of code for each
    /// resource type.
    ///
    ///////////////////////////////////////////////////////////
	class BaseResource
	{
    public:
        void BaseResource();
        void ~BaseResource();

        ///////////////////////////////////////////////////////////
        /// \brief Loads the resource from the file path
        ///
        /// pure virtual function that has a specific load
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual void load() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief unloads the resource
        ///
        /// a pure virtual function that has a specific unload
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual void unload() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Reloads the resource from the file path
        ///
        /// a pure virtual function that has a specific reload
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual void reload() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the alias of type string by value
        ///
        ///////////////////////////////////////////////////////////
        std::string getAlias()const;

        ///////////////////////////////////////////////////////////
        /// \ brief
        ///
        ///////////////////////////////////////////////////////////
        std::string getResourceType()const;
        std::string getFilePath()const;
        bool isLoaded()const;
        size_t getRamUse()const;

        void setAlias();
        void setResourceType();
        void setFilePath();
        void setIsLoaded();
        void setRam();

    private:
        std::string alias, type, filePath;
        bool isLoaded;
        size_t ramUse;
	};
}

#endif //BASE_RESOURCE_HPP
<commit_msg>Finished BaseResource Header<commit_after>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// 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.
//
////////////////////////////////////////////////////////////

#ifndef BASE_RESOURCE_HPP
#define BASE_RESOURCE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include <string>

namespace rm
{
    ///////////////////////////////////////////////////////////
    /// \brief An abstract resource class
    ///
    /// This abstract base class needs to be inherited by a
    /// ManagedResource class. It contains three pure virtual
    /// functions that require a specific body of code for each
    /// resource type.
    ///
    ///////////////////////////////////////////////////////////
	class BaseResource
	{
    public:
        ////////////////////////////////////////////////////////////
        /// \brief Default Constructor
        ///
        /// Standard constructor
        ///
        ////////////////////////////////////////////////////////////
        void BaseResource();

        ////////////////////////////////////////////////////////////
        /// \brief  Destructor
        ///
        /// Standard destructor
        ///
        ////////////////////////////////////////////////////////////
        void ~BaseResource();

        ///////////////////////////////////////////////////////////
        /// \brief Loads the resource
        ///
        /// pure virtual function that has a specific load
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual void load() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief unloads the resource
        ///
        /// a pure virtual function that has a specific unload
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual void unload() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Reloads the resource
        ///
        /// a pure virtual function that has a specific reload
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual void reload() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the alias of type string by reference
        ///
        ///////////////////////////////////////////////////////////
        std::string& getAlias()const;

        ///////////////////////////////////////////////////////////
        /// \ brief Returns the resource type string by reference
        ///
        ///////////////////////////////////////////////////////////
        std::string& getResourceType()const;

        ///////////////////////////////////////////////////////////
        /// \ brief Returns the file path string by reference
        ///
        ///////////////////////////////////////////////////////////
        std::string& getFilePath()const;

        ///////////////////////////////////////////////////////////
        /// \ brief Returns true if resource is loaded
        ///
        ///////////////////////////////////////////////////////////
        bool isLoaded()const;

        ///////////////////////////////////////////////////////////
        /// \ brief Returns the RAM use by value
        ///
        ///////////////////////////////////////////////////////////
        size_t getRamUse()const;

        ///////////////////////////////////////////////////////////
        /// \ brief Sets the alias member
        ///
        ///////////////////////////////////////////////////////////
        void setAlias();

        ///////////////////////////////////////////////////////////
        /// \ brief Sets the resource type member
        ///
        ///////////////////////////////////////////////////////////
        void setResourceType();

        ///////////////////////////////////////////////////////////
        /// \ brief Sets the file path member
        ///
        ///////////////////////////////////////////////////////////
        void setFilePath();

        ///////////////////////////////////////////////////////////
        /// \ brief Sets the isLoaded member
        ///
        ///////////////////////////////////////////////////////////
        void setIsLoaded();

        ///////////////////////////////////////////////////////////
        /// \ brief Sets the ram use member
        ///
        ///////////////////////////////////////////////////////////
        void setRam();

    private:
        std::string alias, type, filePath;
        bool isLoaded;
        size_t ramUse;
	};
}

#endif //BASE_RESOURCE_HPP
<|endoftext|>


<commit_before>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>
#include <vector>
#include <map>

#include <Observation.hpp>
#include <utils.hpp>

#ifndef DEDISPERSION_HPP
#define DEDISPERSION_HPP

namespace PulsarSearch {

public DedispersionConf {
public:
  DedispersionConf();
  ~DedispersionConf();

  // Get
  inline bool getLocalMem() const;
  inline unsigned int getNrsamplesPerBlock() const;
  inline unsigned int getNrSamplesPerThread() const;
  inline unsigned int getNrDMsPerBlock() const;
  inline unsigned int getNrDMsPerThread() const;
  inline unsigned int getUnroll() const;
  // Set
  inline void setLocalMem(bool local);
  inline void setNrSamplesPerBlock(unsigned int samples);
  inline void setNrSamplesPerThread(unsigned int samples);
  inline void setNrDMsPerBlock(unsigned int dms);
  inline void setNrDMsPerThread(unsigned int dms);
  inline void setUnroll(unsigned int unroll);

private:
  bool local;
  unsigned int nrSamplesPerBlock;
  unsigned int nrSamplesPerThread;
  unsigned int nrDMsPerBlock;
  unsigned int nrDMsPerThread;
  unsigned int unroll;
};

// Sequential dedispersion
template< typename T > void dedispersion(AstroData::Observation & observation, const std::vector< T > & input, std::vector< T > & output, const std::vector< float > & shifts);
// OpenCL dedispersion algorithm
std::string * getDedispersionOpenCL(const DedispersionConf & conf, const std::string & dataType, const AstroData::Observation & observation, std::vector< float > & shifts);

} // PulsarSearch

#endif // DEDISPERSION_HPP

<commit_msg>Typo.<commit_after>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>
#include <vector>
#include <map>

#include <Observation.hpp>
#include <utils.hpp>

#ifndef DEDISPERSION_HPP
#define DEDISPERSION_HPP

namespace PulsarSearch {

class DedispersionConf {
public:
  DedispersionConf();
  ~DedispersionConf();

  // Get
  inline bool getLocalMem() const;
  inline unsigned int getNrsamplesPerBlock() const;
  inline unsigned int getNrSamplesPerThread() const;
  inline unsigned int getNrDMsPerBlock() const;
  inline unsigned int getNrDMsPerThread() const;
  inline unsigned int getUnroll() const;
  // Set
  inline void setLocalMem(bool local);
  inline void setNrSamplesPerBlock(unsigned int samples);
  inline void setNrSamplesPerThread(unsigned int samples);
  inline void setNrDMsPerBlock(unsigned int dms);
  inline void setNrDMsPerThread(unsigned int dms);
  inline void setUnroll(unsigned int unroll);

private:
  bool local;
  unsigned int nrSamplesPerBlock;
  unsigned int nrSamplesPerThread;
  unsigned int nrDMsPerBlock;
  unsigned int nrDMsPerThread;
  unsigned int unroll;
};

// Sequential dedispersion
template< typename T > void dedispersion(AstroData::Observation & observation, const std::vector< T > & input, std::vector< T > & output, const std::vector< float > & shifts);
// OpenCL dedispersion algorithm
std::string * getDedispersionOpenCL(const DedispersionConf & conf, const std::string & dataType, const AstroData::Observation & observation, std::vector< float > & shifts);

} // PulsarSearch

#endif // DEDISPERSION_HPP

<|endoftext|>


<commit_before>#pragma once

#include <bitset>
#include <iomanip>

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <iwlib.h>
#include <limits.h>
#include <linux/ethtool.h>
#include <linux/if_link.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <memory>
#include <sstream>
#include <string>
#include <string>

#ifdef inline
#undef inline
#endif

#include "common.hpp"
#include "config.hpp"
#include "utils/command.hpp"
#include "utils/file.hpp"
#include "utils/string.hpp"

LEMONBUDDY_NS

namespace net {
  DEFINE_ERROR(network_error);

  // types {{{

  struct quality_range {
    int val = 0;
    int max = 0;

    int percentage() const {
      if (max < 0)
        return 2 * (val + 100);
      return static_cast<float>(val) / max * 100.0f + 0.5f;
    }
  };

  using bytes_t = unsigned int;

  struct link_activity {
    bytes_t transmitted = 0;
    bytes_t received = 0;
    chrono::system_clock::time_point time;
  };

  struct link_status {
    string ip;
    link_activity previous;
    link_activity current;
  };

  // }}}
  // class: network {{{

  class network {
   public:
    /**
     * Construct network interface
     */
    explicit network(string interface) : m_interface(interface) {
      if (if_nametoindex(m_interface.c_str()) == 0)
        throw network_error("Invalid network interface \"" + m_interface + "\"");
      if ((m_socketfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        throw network_error("Failed to open socket");
    }

    /**
     * Destruct network interface
     */
    virtual ~network() {
      if (m_socketfd != -1)
        close(m_socketfd);
    }

    /**
     * Query device driver for information
     */
    virtual bool query() {
      struct ifaddrs* ifaddr;

      if (getifaddrs(&ifaddr) == -1)
        return false;

      for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
        if (m_interface.compare(0, m_interface.length(), ifa->ifa_name) != 0)
          continue;

        switch (ifa->ifa_addr->sa_family) {
          case AF_INET:
            char ip_buffer[NI_MAXHOST];
            getnameinfo(ifa->ifa_addr, sizeof(sockaddr_in), ip_buffer, NI_MAXHOST, nullptr, 0,
                NI_NUMERICHOST);
            m_status.ip = string{ip_buffer};
            break;

          case AF_PACKET:
            if (ifa->ifa_data == nullptr)
              continue;
            struct rtnl_link_stats* link_state =
                reinterpret_cast<decltype(link_state)>(ifa->ifa_data);
            m_status.previous = m_status.current;
            m_status.current.transmitted = link_state->tx_bytes;
            m_status.current.received = link_state->rx_bytes;
            m_status.current.time = chrono::system_clock::now();
            break;
        }
      }

      freeifaddrs(ifaddr);

      return true;
    }

    /**
     * Check current connection state
     */
    virtual bool connected() const = 0;

    /**
     * Run ping command to test internet connectivity
     */
    virtual bool ping() const {
      try {
        auto exec = "ping -c 2 -W 2 -I " + m_interface + " " + string(CONNECTION_TEST_IP);
        auto ping = command_util::make_command(exec);
        return ping && ping->exec(true) == EXIT_SUCCESS;
      } catch (const std::exception& err) {
        return false;
      }
    }

    /**
     * Get interface ip address
     */
    string ip() const {
      return m_status.ip;
    }

    /**
     * Get download speed rate
     */
    string downspeed(int minwidth = 3) const {
      float bytes_diff = m_status.current.received - m_status.previous.received;
      return format_speedrate(bytes_diff, minwidth);
    }

    /**
     * Get upload speed rate
     */
    string upspeed(int minwidth = 3) const {
      float bytes_diff = m_status.current.transmitted - m_status.previous.transmitted;
      return format_speedrate(bytes_diff, minwidth);
    }

   protected:
    /**
     * Test if the network interface is in a valid state
     */
    bool test_interface(struct ifreq& request) const {
      if ((ioctl(m_socketfd, SIOCGIFFLAGS, &request)) == -1)
        return false;
      if ((request.ifr_flags & IFF_UP) == 0)
        return false;
      if ((request.ifr_flags & IFF_RUNNING) == 0)
        return false;

      auto operstate = file_util::get_contents("/sys/class/net/" + m_interface + "/operstate");

      return operstate.compare(0, 2, "up") == 0;
    }

    /**
     * Format up- and download speed
     */
    string format_speedrate(float bytes_diff, int minwidth) const {
      const auto duration = m_status.current.time - m_status.previous.time;
      float time_diff = chrono::duration_cast<chrono::seconds>(duration).count();
      float speedrate = bytes_diff / (time_diff ? time_diff : 1);

      vector<string> suffixes{"GB", "MB"};
      string suffix{"KB"};

      while ((speedrate /= 1000) > 999) {
        suffix = suffixes.back();
        suffixes.pop_back();
      }

      return string_util::from_stream(stringstream() << std::setw(minwidth) << std::setfill(' ')
                                                     << std::setprecision(0) << std::fixed
                                                     << speedrate << " " << suffix << "/s");
    }

    int m_socketfd = 0;
    link_status m_status;
    string m_interface;
  };

  // }}}
  // class: wired_network {{{

  class wired_network : public network {
   public:
    explicit wired_network(string interface) : network(interface) {}

    /**
     * Query device driver for information
     */
    bool query() override {
      if (!network::query())
        return false;

      struct ethtool_cmd ethernet_data;
      ethernet_data.cmd = ETHTOOL_GSET;

      struct ifreq request;
      strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
      request.ifr_data = reinterpret_cast<caddr_t>(&ethernet_data);

      if (ioctl(m_socketfd, SIOCETHTOOL, &request) == -1)
        return false;

      m_linkspeed = ethernet_data.speed;

      return true;
    }

    /**
     * Check current connection state
     */
    bool connected() const override {
      struct ifreq request;
      struct ethtool_value ethernet_data;

      strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
      ethernet_data.cmd = ETHTOOL_GLINK;
      request.ifr_data = reinterpret_cast<caddr_t>(&ethernet_data);

      if (!network::test_interface(request))
        return false;

      if (ioctl(m_socketfd, SIOCETHTOOL, &request) != -1)
        return ethernet_data.data != 0;

      return false;
    }

    /**
     *
     * about the current connection
     */
    string linkspeed() const {
      return (m_linkspeed == 0 ? "???" : to_string(m_linkspeed)) + " Mbit/s";
    }

   private:
    int m_linkspeed = 0;
  };

  // }}}
  // class: wireless_network {{{

  class wireless_network : public network {
   public:
    wireless_network(string interface) : network(interface) {}

    /**
     * Query the wireless device for information
     * about the current connection
     */
    bool query() override {
      if (!network::query())
        return false;

      auto socket_fd = iw_sockets_open();

      if (socket_fd == -1)
        return false;

      struct iwreq req;

      if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWMODE, &req) == -1)
        return false;

      // Ignore interfaces in ad-hoc mode
      if (req.u.mode == IW_MODE_ADHOC)
        return false;

      query_essid(socket_fd);
      query_quality(socket_fd);

      iw_sockets_close(socket_fd);

      return true;
    }

    /**
     * Check current connection state
     */
    bool connected() const override {
      struct ifreq request;
      strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);

      if (!network::test_interface(request))
        return false;
      if (m_essid.empty())
        return false;

      return true;
    }

    /**
     * ESSID reported by last query
     */
    string essid() const {
      return m_essid;
    }

    /**
     * Signal strength percentage reported by last query
     */
    int signal() const {
      return m_signalstrength.percentage();
    }

    /**
     * Link quality percentage reported by last query
     */
    int quality() const {
      return m_linkquality.percentage();
    }

   protected:
    /**
     * Query for ESSID
     */
    void query_essid(const int& socket_fd) {
      char essid[IW_ESSID_MAX_SIZE + 1];

      struct iwreq req;
      req.u.essid.pointer = &essid;
      req.u.essid.length = sizeof(essid);
      req.u.essid.flags = 0;

      if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWESSID, &req) != -1) {
        m_essid = string{essid};
      } else {
        m_essid.clear();
      }
    }

    /**
     * Query for device driver quality values
     */
    void query_quality(const int& socket_fd) {
      iwrange range;
      iwstats stats;

      // Fill range
      if (iw_get_range_info(socket_fd, m_interface.c_str(), &range) == -1)
        return;
      // Fill stats
      if (iw_get_stats(socket_fd, m_interface.c_str(), &stats, &range, 1) == -1)
        return;

      // Check if the driver supplies the quality value
      if (stats.qual.updated & IW_QUAL_QUAL_INVALID)
        return;
      // Check if the driver supplies the quality level value
      if (stats.qual.updated & IW_QUAL_LEVEL_INVALID)
        return;

      // Check if the link quality has been uodated
      if (stats.qual.updated & IW_QUAL_QUAL_UPDATED) {
        m_linkquality.val = stats.qual.qual;
        m_linkquality.max = range.max_qual.qual;
      }

      // Check if the signal strength has been uodated
      if (stats.qual.updated & IW_QUAL_LEVEL_UPDATED) {
        m_signalstrength.val = stats.qual.level;
        m_signalstrength.max = range.max_qual.level;

        // Check if the values are defined in dBm
        if (stats.qual.level > range.max_qual.level) {
          m_signalstrength.val -= 0x100;
          m_signalstrength.max -= 0x100;
        }
      }
    }

   private:
    shared_ptr<wireless_info> m_info;
    string m_essid;
    quality_range m_signalstrength;
    quality_range m_linkquality;
  };

  // }}}

  /**
   * Test if interface with given name is a wireless device
   */
  inline bool is_wireless_interface(string ifname) {
    return file_util::exists("/sys/class/net/" + ifname + "/wireless");
  }

  using wireless_t = unique_ptr<wireless_network>;
  using wired_t = unique_ptr<wired_network>;
}

LEMONBUDDY_NS_END
<commit_msg>fix(network): Connection state<commit_after>#pragma once

#include <bitset>
#include <iomanip>

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <iwlib.h>
#include <limits.h>
#include <linux/ethtool.h>
#include <linux/if_link.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <memory>
#include <sstream>
#include <string>
#include <string>

#ifdef inline
#undef inline
#endif

#include "common.hpp"
#include "config.hpp"
#include "utils/command.hpp"
#include "utils/file.hpp"
#include "utils/string.hpp"

LEMONBUDDY_NS

namespace net {
  DEFINE_ERROR(network_error);

  // types {{{

  struct quality_range {
    int val = 0;
    int max = 0;

    int percentage() const {
      if (max < 0)
        return 2 * (val + 100);
      return static_cast<float>(val) / max * 100.0f + 0.5f;
    }
  };

  using bytes_t = unsigned int;

  struct link_activity {
    bytes_t transmitted = 0;
    bytes_t received = 0;
    chrono::system_clock::time_point time;
  };

  struct link_status {
    string ip;
    link_activity previous;
    link_activity current;
  };

  // }}}
  // class: network {{{

  class network {
   public:
    /**
     * Construct network interface
     */
    explicit network(string interface) : m_interface(interface) {
      if (if_nametoindex(m_interface.c_str()) == 0)
        throw network_error("Invalid network interface \"" + m_interface + "\"");
      if ((m_socketfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        throw network_error("Failed to open socket");
    }

    /**
     * Destruct network interface
     */
    virtual ~network() {
      if (m_socketfd != -1)
        close(m_socketfd);
    }

    /**
     * Query device driver for information
     */
    virtual bool query() {
      struct ifaddrs* ifaddr;

      if (getifaddrs(&ifaddr) == -1)
        return false;

      for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
        if (m_interface.compare(0, m_interface.length(), ifa->ifa_name) != 0)
          continue;

        switch (ifa->ifa_addr->sa_family) {
          case AF_INET:
            char ip_buffer[NI_MAXHOST];
            getnameinfo(ifa->ifa_addr, sizeof(sockaddr_in), ip_buffer, NI_MAXHOST, nullptr, 0,
                NI_NUMERICHOST);
            m_status.ip = string{ip_buffer};
            break;

          case AF_PACKET:
            if (ifa->ifa_data == nullptr)
              continue;
            struct rtnl_link_stats* link_state =
                reinterpret_cast<decltype(link_state)>(ifa->ifa_data);
            m_status.previous = m_status.current;
            m_status.current.transmitted = link_state->tx_bytes;
            m_status.current.received = link_state->rx_bytes;
            m_status.current.time = chrono::system_clock::now();
            break;
        }
      }

      freeifaddrs(ifaddr);

      return true;
    }

    /**
     * Check current connection state
     */
    virtual bool connected() const = 0;

    /**
     * Run ping command to test internet connectivity
     */
    virtual bool ping() const {
      try {
        auto exec = "ping -c 2 -W 2 -I " + m_interface + " " + string(CONNECTION_TEST_IP);
        auto ping = command_util::make_command(exec);
        return ping && ping->exec(true) == EXIT_SUCCESS;
      } catch (const std::exception& err) {
        return false;
      }
    }

    /**
     * Get interface ip address
     */
    string ip() const {
      return m_status.ip;
    }

    /**
     * Get download speed rate
     */
    string downspeed(int minwidth = 3) const {
      float bytes_diff = m_status.current.received - m_status.previous.received;
      return format_speedrate(bytes_diff, minwidth);
    }

    /**
     * Get upload speed rate
     */
    string upspeed(int minwidth = 3) const {
      float bytes_diff = m_status.current.transmitted - m_status.previous.transmitted;
      return format_speedrate(bytes_diff, minwidth);
    }

   protected:
    /**
     * Test if the network interface is in a valid state
     */
    bool test_interface() const {
      auto operstate = file_util::get_contents("/sys/class/net/" + m_interface + "/operstate");
      return operstate.compare(0, 2, "up") == 0;
    }

    /**
     * Format up- and download speed
     */
    string format_speedrate(float bytes_diff, int minwidth) const {
      const auto duration = m_status.current.time - m_status.previous.time;
      float time_diff = chrono::duration_cast<chrono::seconds>(duration).count();
      float speedrate = bytes_diff / (time_diff ? time_diff : 1);

      vector<string> suffixes{"GB", "MB"};
      string suffix{"KB"};

      while ((speedrate /= 1000) > 999) {
        suffix = suffixes.back();
        suffixes.pop_back();
      }

      return string_util::from_stream(stringstream() << std::setw(minwidth) << std::setfill(' ')
                                                     << std::setprecision(0) << std::fixed
                                                     << speedrate << " " << suffix << "/s");
    }

    int m_socketfd = 0;
    link_status m_status;
    string m_interface;
  };

  // }}}
  // class: wired_network {{{

  class wired_network : public network {
   public:
    explicit wired_network(string interface) : network(interface) {}

    /**
     * Query device driver for information
     */
    bool query() override {
      if (!network::query())
        return false;

      struct ethtool_cmd ethernet_data;
      ethernet_data.cmd = ETHTOOL_GSET;

      struct ifreq request;
      strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
      request.ifr_data = reinterpret_cast<caddr_t>(&ethernet_data);

      if (ioctl(m_socketfd, SIOCETHTOOL, &request) == -1)
        return false;

      m_linkspeed = ethernet_data.speed;

      return true;
    }

    /**
     * Check current connection state
     */
    bool connected() const override {
      if (!network::test_interface())
        return false;

      struct ifreq request;
      struct ethtool_value ethernet_data;

      strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
      ethernet_data.cmd = ETHTOOL_GLINK;
      request.ifr_data = reinterpret_cast<caddr_t>(&ethernet_data);

      if (ioctl(m_socketfd, SIOCETHTOOL, &request) != -1)
        return ethernet_data.data != 0;

      return false;
    }

    /**
     *
     * about the current connection
     */
    string linkspeed() const {
      return (m_linkspeed == 0 ? "???" : to_string(m_linkspeed)) + " Mbit/s";
    }

   private:
    int m_linkspeed = 0;
  };

  // }}}
  // class: wireless_network {{{

  class wireless_network : public network {
   public:
    wireless_network(string interface) : network(interface) {}

    /**
     * Query the wireless device for information
     * about the current connection
     */
    bool query() override {
      if (!network::query())
        return false;

      auto socket_fd = iw_sockets_open();

      if (socket_fd == -1)
        return false;

      struct iwreq req;

      if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWMODE, &req) == -1)
        return false;

      // Ignore interfaces in ad-hoc mode
      if (req.u.mode == IW_MODE_ADHOC)
        return false;

      query_essid(socket_fd);
      query_quality(socket_fd);

      iw_sockets_close(socket_fd);

      return true;
    }

    /**
     * Check current connection state
     */
    bool connected() const override {
      if (!network::test_interface())
        return false;

      struct ifreq request;
      strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);

      if ((ioctl(m_socketfd, SIOCGIFFLAGS, &request)) == -1)
        return false;
      if (m_essid.empty())
        return false;

      return true;
    }

    /**
     * ESSID reported by last query
     */
    string essid() const {
      return m_essid;
    }

    /**
     * Signal strength percentage reported by last query
     */
    int signal() const {
      return m_signalstrength.percentage();
    }

    /**
     * Link quality percentage reported by last query
     */
    int quality() const {
      return m_linkquality.percentage();
    }

   protected:
    /**
     * Query for ESSID
     */
    void query_essid(const int& socket_fd) {
      char essid[IW_ESSID_MAX_SIZE + 1];

      struct iwreq req;
      req.u.essid.pointer = &essid;
      req.u.essid.length = sizeof(essid);
      req.u.essid.flags = 0;

      if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWESSID, &req) != -1) {
        m_essid = string{essid};
      } else {
        m_essid.clear();
      }
    }

    /**
     * Query for device driver quality values
     */
    void query_quality(const int& socket_fd) {
      iwrange range;
      iwstats stats;

      // Fill range
      if (iw_get_range_info(socket_fd, m_interface.c_str(), &range) == -1)
        return;
      // Fill stats
      if (iw_get_stats(socket_fd, m_interface.c_str(), &stats, &range, 1) == -1)
        return;

      // Check if the driver supplies the quality value
      if (stats.qual.updated & IW_QUAL_QUAL_INVALID)
        return;
      // Check if the driver supplies the quality level value
      if (stats.qual.updated & IW_QUAL_LEVEL_INVALID)
        return;

      // Check if the link quality has been uodated
      if (stats.qual.updated & IW_QUAL_QUAL_UPDATED) {
        m_linkquality.val = stats.qual.qual;
        m_linkquality.max = range.max_qual.qual;
      }

      // Check if the signal strength has been uodated
      if (stats.qual.updated & IW_QUAL_LEVEL_UPDATED) {
        m_signalstrength.val = stats.qual.level;
        m_signalstrength.max = range.max_qual.level;

        // Check if the values are defined in dBm
        if (stats.qual.level > range.max_qual.level) {
          m_signalstrength.val -= 0x100;
          m_signalstrength.max -= 0x100;
        }
      }
    }

   private:
    shared_ptr<wireless_info> m_info;
    string m_essid;
    quality_range m_signalstrength;
    quality_range m_linkquality;
  };

  // }}}

  /**
   * Test if interface with given name is a wireless device
   */
  inline bool is_wireless_interface(string ifname) {
    return file_util::exists("/sys/class/net/" + ifname + "/wireless");
  }

  using wireless_t = unique_ptr<wireless_network>;
  using wired_t = unique_ptr<wired_network>;
}

LEMONBUDDY_NS_END
<|endoftext|>


<commit_before>#include "game/states/skirmishstate.hpp"

#include <SFML/Graphics/Sprite.hpp>

#include "game/gui/victorydialog.hpp"
#include "game/states/deploystate.hpp"
#include "game/path.hpp"

#include "engine/pathfinding/astar.hpp"
#include "engine/pathfinding/path.hpp"
#include "engine/player.hpp"

#include "gui/texturemanager.hpp"
#include "gui/ng/label.hpp"
#include "gui/ng/spritewidget.hpp"
#include "gui/ng/button.hpp"
#include "gui/squaredetailwindow.hpp"
#include "gui/cursor.hpp"
#include "gui/squaremarker.hpp"

#include "eventsystem/inputevents.hpp"

namespace qrw
{

SkirmishState::SkirmishState(sf::RenderWindow* renderWindow)
	: SceneState(renderWindow, EGameStateId::EGSID_SKIRMISH_STATE),
	  _selectedUnit(nullptr),
	  m_victoryGui(new namelessgui::Gui(renderWindow))
{
    _squareDetailWindow = new SquareDetailWindow();
    _guiUptr->addWidget(_squareDetailWindow);

	path_ = new Path();
	g_scene.addGameObject(path_);

	_squareMarker = new SquareMarker();
	_squareMarker->setVisible(false);
	g_scene.addGameObject(_squareMarker);

	_playerNameText = new namelessgui::Text();
	_playerNameText->setText("Player Name");
	_playerNameText->setParentAnchor({0.5, 0});
	_playerNameText->setAnchor({0.5, 0});
	_toolBar->addWidget(_playerNameText);

	namelessgui::Button* endTurnButton = new namelessgui::Button();
	endTurnButton->setText("End Turn");
	endTurnButton->setSize({140, 30});
	endTurnButton->setParentAnchor({0.5, 1});
	endTurnButton->setAnchor({0.5, 1.0});
	endTurnButton->setRelativePosition({0.0f, -5.0f});
	endTurnButton->signalClicked.connect(std::bind(&SkirmishState::endTurn, this));
	_toolBar->addWidget(endTurnButton);

	m_victoryDialog = new VictoryDialog();
	m_victoryDialog->signalCloseClicked.connect(std::bind(&SceneState::slotBackToMainMenu, this));
	m_victoryGui->addWidget(m_victoryDialog);
	m_victoryGui->setVisible(false);
}

void SkirmishState::init(GameState *previousState)
{
    SceneState::init(previousState);

    if(previousState->getId() != EGameStateId::EGSID_DEPLOY_STATE)
        return;

    DeployState* deployState = static_cast<DeployState*>(previousState);

    _board = deployState->getBoard();
	g_scene.setBoard(_board);

	_players = deployState->getPlayers();
	_currentPlayer = 0;
	_playerNameText->setText(_players[_currentPlayer]->getName());

    // Initialize square detail window.
	const Coordinates& cursorPosition = g_scene.getSingleGameObject<Cursor>()->getBoardPosition();
	Unit* unit = _board->getUnit(cursorPosition);
	Terrain* terrain = _board->getTerrain(cursorPosition);
	_squareDetailWindow->setUnitAndTerrain(unit, terrain);
}

void SkirmishState::draw()
{
	SceneState::draw();
	m_victoryGui->render(*_renderWindow);
}

bool SkirmishState::handleEvent(const IEvent &event)
{
	SceneState::handleEvent(event);

	if(event.getName() == RightMouseButtonPressedEvent::name)
		deselectUnit();

	return false;
}

EGameStateId SkirmishState::update()
{
    if(_backToMainMenu)
        return EGameStateId::EGSID_MAIN_MENU_STATE;

    return EGameStateId::EGSID_NO_CHANGE;
}

void SkirmishState::slotCursorMoved(const Coordinates &boardPosition)
{
	if(_board->isOnBoard(boardPosition))
	{
		Unit* unitUnderCursor = _board->getUnit(boardPosition);
		Terrain* terrainUnderCursor = _board->getTerrain(boardPosition);
		_squareDetailWindow->setUnitAndTerrain(unitUnderCursor, terrainUnderCursor);

		if(_selectedUnit)
		{
			path_->setStartAndEnd(_selectedUnit->getPosition(), boardPosition);

			Cursor::Color cursorColor = Cursor::Color::ESC_DEFAULT;
			if(path_->getMovementCosts() > _selectedUnit->getCurrentMovement())
				cursorColor = Cursor::Color::ESC_WARNING;
			if(boardPosition == _squareMarker->getBoardPosition())
				cursorColor = Cursor::Color::ESC_DEFAULT;

			g_scene.getSingleGameObject<Cursor>()->setFillColor(cursorColor);
		}
	}
    else
		_squareDetailWindow->setUnitAndTerrain(nullptr, nullptr);
}

void SkirmishState::moveUnit()
{
	if(!_selectedUnit) return;

	int pathCosts = path_->getMovementCosts();

	int maxDistance = _selectedUnit->getCurrentMovement();
	if(pathCosts > maxDistance) return;

	int remainingMovement = maxDistance - pathCosts;
	_selectedUnit->setCurrentMovement(remainingMovement);
	_selectedUnit->setPosition(path_->getTarget());
}

void SkirmishState::performAttack(Unit* attackedUnit)
{
	const Coordinates& positionOfAttackedUnit = attackedUnit->getPosition();

	if(!_selectedUnit->isTargetWithinAttackRange(positionOfAttackedUnit))
		return;

	if(_selectedUnit->getCurrentMovement() == 0)
		return;
	_selectedUnit->setCurrentMovement(0);

	int inflictedDamage = _selectedUnit->getModifiedAttack() - attackedUnit->getModifiedDefense();
	inflictedDamage = inflictedDamage < 0 ? 0 : inflictedDamage;
	attackedUnit->damage(inflictedDamage);

	if(attackedUnit->getHP() == 0)
	{
		g_scene.despawn(attackedUnit);
		_selectedUnit->setPosition(positionOfAttackedUnit);
	}
	else
	{
		inflictedDamage = attackedUnit->getModifiedAttack() - _selectedUnit->getModifiedDefense();
		inflictedDamage = inflictedDamage < 0 ? 0 : inflictedDamage;
		_selectedUnit->damage(inflictedDamage);

		if(_selectedUnit->getHP() == 0)
		{
			g_scene.despawn(_selectedUnit);
			_selectedUnit = nullptr;
		}
	}

	updateSquareDetailWindow(positionOfAttackedUnit);
}

void SkirmishState::checkVictory()
{
	bool playersHaveUnits[] = {false, false};

	for(auto unitIter : _board->getUnits())
	{
		playersHaveUnits[unitIter.second->getPlayer()->getId() - 1] = true;
	}

	bool gameEnded = !playersHaveUnits[0] || !playersHaveUnits[1];
	if(gameEnded)
	{
		m_victoryDialog->setLoserName(!playersHaveUnits[0] ? _players[0]->getName() : _players[1]->getName());
		m_victoryDialog->setWinnerName(!playersHaveUnits[0] ? _players[1]->getName() : _players[0]->getName());
		m_victoryGui->setVisible(true);
		_guiUptr->setVisible(false);
	}
}

void SkirmishState::replenishTroops()
{
	Unit* unit;
	for(auto unitIter : _board->getUnits())
	{
		unit = unitIter.second;
		unit->setCurrentMovement(unit->getMovement());
	}
}

void SkirmishState::updateSquareDetailWindow(const Coordinates& position)
{
	_squareDetailWindow->setUnitAndTerrain(
				_board->getUnit(position),
				_board->getTerrain(position));
}

void SkirmishState::slotCursorLeftClicked(const Coordinates &boardPosition)
{
	Unit* unitUnderCursor = _board->getUnit(boardPosition);
	Terrain* terrainUnderCursor = _board->getTerrain(boardPosition);

	_squareDetailWindow->setUnitAndTerrain(unitUnderCursor, terrainUnderCursor);

	// Case 1: Unit is selected and instructed to move.
	if(_selectedUnit && !unitUnderCursor)
	{
		moveUnit();
		deselectUnit();
		return;
	}

	// Case 2: Unit is selected and instructed to attack enemy.
	if(_selectedUnit && unitUnderCursor && unitUnderCursor->getPlayer() != _selectedUnit->getPlayer())
	{
		performAttack(unitUnderCursor);
		deselectUnit();
		checkVictory();
		return;
	}

	// Select unit if it belongs to current player
	if(unitUnderCursor && unitUnderCursor->getPlayer() == _players[_currentPlayer])
	{
		// Select unit
		_selectedUnit = unitUnderCursor;
		_squareMarker->setBoardPosition(boardPosition);
		_squareMarker->setVisible(true);

		return;
	}

	deselectUnit();
}

void SkirmishState::endTurn()
{
	_currentPlayer = (_currentPlayer + 1) % _players.size();
	_playerNameText->setText(_players[_currentPlayer]->getName());

	deselectUnit();
	replenishTroops();
}

void SkirmishState::deselectUnit()
{
	_selectedUnit = nullptr;
	_squareMarker->setVisible(false);
	g_scene.getSingleGameObject<Cursor>()->setFillColor(Cursor::Color::ESC_DEFAULT);
	path_->reset();
}

} // namespace qrw
<commit_msg>Assertion to ensure game state order<commit_after>#include "game/states/skirmishstate.hpp"

#include <SFML/Graphics/Sprite.hpp>

#include "game/gui/victorydialog.hpp"
#include "game/states/deploystate.hpp"
#include "game/path.hpp"

#include "engine/pathfinding/astar.hpp"
#include "engine/pathfinding/path.hpp"
#include "engine/player.hpp"

#include "gui/texturemanager.hpp"
#include "gui/ng/label.hpp"
#include "gui/ng/spritewidget.hpp"
#include "gui/ng/button.hpp"
#include "gui/squaredetailwindow.hpp"
#include "gui/cursor.hpp"
#include "gui/squaremarker.hpp"

#include "eventsystem/inputevents.hpp"

namespace qrw
{

SkirmishState::SkirmishState(sf::RenderWindow* renderWindow)
	: SceneState(renderWindow, EGameStateId::EGSID_SKIRMISH_STATE),
	  _selectedUnit(nullptr),
	  m_victoryGui(new namelessgui::Gui(renderWindow))
{
    _squareDetailWindow = new SquareDetailWindow();
    _guiUptr->addWidget(_squareDetailWindow);

	path_ = new Path();
	g_scene.addGameObject(path_);

	_squareMarker = new SquareMarker();
	_squareMarker->setVisible(false);
	g_scene.addGameObject(_squareMarker);

	_playerNameText = new namelessgui::Text();
	_playerNameText->setText("Player Name");
	_playerNameText->setParentAnchor({0.5, 0});
	_playerNameText->setAnchor({0.5, 0});
	_toolBar->addWidget(_playerNameText);

	namelessgui::Button* endTurnButton = new namelessgui::Button();
	endTurnButton->setText("End Turn");
	endTurnButton->setSize({140, 30});
	endTurnButton->setParentAnchor({0.5, 1});
	endTurnButton->setAnchor({0.5, 1.0});
	endTurnButton->setRelativePosition({0.0f, -5.0f});
	endTurnButton->signalClicked.connect(std::bind(&SkirmishState::endTurn, this));
	_toolBar->addWidget(endTurnButton);

	m_victoryDialog = new VictoryDialog();
	m_victoryDialog->signalCloseClicked.connect(std::bind(&SceneState::slotBackToMainMenu, this));
	m_victoryGui->addWidget(m_victoryDialog);
	m_victoryGui->setVisible(false);
}

void SkirmishState::init(GameState *previousState)
{
    SceneState::init(previousState);

	assert(previousState->getId() == EGameStateId::EGSID_DEPLOY_STATE);

    DeployState* deployState = static_cast<DeployState*>(previousState);

    _board = deployState->getBoard();
	g_scene.setBoard(_board);

	_players = deployState->getPlayers();
	_currentPlayer = 0;
	_playerNameText->setText(_players[_currentPlayer]->getName());

    // Initialize square detail window.
	const Coordinates& cursorPosition = g_scene.getSingleGameObject<Cursor>()->getBoardPosition();
	Unit* unit = _board->getUnit(cursorPosition);
	Terrain* terrain = _board->getTerrain(cursorPosition);
	_squareDetailWindow->setUnitAndTerrain(unit, terrain);
}

void SkirmishState::draw()
{
	SceneState::draw();
	m_victoryGui->render(*_renderWindow);
}

bool SkirmishState::handleEvent(const IEvent &event)
{
	SceneState::handleEvent(event);

	if(event.getName() == RightMouseButtonPressedEvent::name)
		deselectUnit();

	return false;
}

EGameStateId SkirmishState::update()
{
    if(_backToMainMenu)
        return EGameStateId::EGSID_MAIN_MENU_STATE;

    return EGameStateId::EGSID_NO_CHANGE;
}

void SkirmishState::slotCursorMoved(const Coordinates &boardPosition)
{
	if(_board->isOnBoard(boardPosition))
	{
		Unit* unitUnderCursor = _board->getUnit(boardPosition);
		Terrain* terrainUnderCursor = _board->getTerrain(boardPosition);
		_squareDetailWindow->setUnitAndTerrain(unitUnderCursor, terrainUnderCursor);

		if(_selectedUnit)
		{
			path_->setStartAndEnd(_selectedUnit->getPosition(), boardPosition);

			Cursor::Color cursorColor = Cursor::Color::ESC_DEFAULT;
			if(path_->getMovementCosts() > _selectedUnit->getCurrentMovement())
				cursorColor = Cursor::Color::ESC_WARNING;
			if(boardPosition == _squareMarker->getBoardPosition())
				cursorColor = Cursor::Color::ESC_DEFAULT;

			g_scene.getSingleGameObject<Cursor>()->setFillColor(cursorColor);
		}
	}
    else
		_squareDetailWindow->setUnitAndTerrain(nullptr, nullptr);
}

void SkirmishState::moveUnit()
{
	if(!_selectedUnit) return;

	int pathCosts = path_->getMovementCosts();

	int maxDistance = _selectedUnit->getCurrentMovement();
	if(pathCosts > maxDistance) return;

	int remainingMovement = maxDistance - pathCosts;
	_selectedUnit->setCurrentMovement(remainingMovement);
	_selectedUnit->setPosition(path_->getTarget());
}

void SkirmishState::performAttack(Unit* attackedUnit)
{
	const Coordinates& positionOfAttackedUnit = attackedUnit->getPosition();

	if(!_selectedUnit->isTargetWithinAttackRange(positionOfAttackedUnit))
		return;

	if(_selectedUnit->getCurrentMovement() == 0)
		return;
	_selectedUnit->setCurrentMovement(0);

	int inflictedDamage = _selectedUnit->getModifiedAttack() - attackedUnit->getModifiedDefense();
	inflictedDamage = inflictedDamage < 0 ? 0 : inflictedDamage;
	attackedUnit->damage(inflictedDamage);

	if(attackedUnit->getHP() == 0)
	{
		g_scene.despawn(attackedUnit);
		_selectedUnit->setPosition(positionOfAttackedUnit);
	}
	else
	{
		inflictedDamage = attackedUnit->getModifiedAttack() - _selectedUnit->getModifiedDefense();
		inflictedDamage = inflictedDamage < 0 ? 0 : inflictedDamage;
		_selectedUnit->damage(inflictedDamage);

		if(_selectedUnit->getHP() == 0)
		{
			g_scene.despawn(_selectedUnit);
			_selectedUnit = nullptr;
		}
	}

	updateSquareDetailWindow(positionOfAttackedUnit);
}

void SkirmishState::checkVictory()
{
	bool playersHaveUnits[] = {false, false};

	for(auto unitIter : _board->getUnits())
	{
		playersHaveUnits[unitIter.second->getPlayer()->getId() - 1] = true;
	}

	bool gameEnded = !playersHaveUnits[0] || !playersHaveUnits[1];
	if(gameEnded)
	{
		m_victoryDialog->setLoserName(!playersHaveUnits[0] ? _players[0]->getName() : _players[1]->getName());
		m_victoryDialog->setWinnerName(!playersHaveUnits[0] ? _players[1]->getName() : _players[0]->getName());
		m_victoryGui->setVisible(true);
		_guiUptr->setVisible(false);
	}
}

void SkirmishState::replenishTroops()
{
	Unit* unit;
	for(auto unitIter : _board->getUnits())
	{
		unit = unitIter.second;
		unit->setCurrentMovement(unit->getMovement());
	}
}

void SkirmishState::updateSquareDetailWindow(const Coordinates& position)
{
	_squareDetailWindow->setUnitAndTerrain(
				_board->getUnit(position),
				_board->getTerrain(position));
}

void SkirmishState::slotCursorLeftClicked(const Coordinates &boardPosition)
{
	Unit* unitUnderCursor = _board->getUnit(boardPosition);
	Terrain* terrainUnderCursor = _board->getTerrain(boardPosition);

	_squareDetailWindow->setUnitAndTerrain(unitUnderCursor, terrainUnderCursor);

	// Case 1: Unit is selected and instructed to move.
	if(_selectedUnit && !unitUnderCursor)
	{
		moveUnit();
		deselectUnit();
		return;
	}

	// Case 2: Unit is selected and instructed to attack enemy.
	if(_selectedUnit && unitUnderCursor && unitUnderCursor->getPlayer() != _selectedUnit->getPlayer())
	{
		performAttack(unitUnderCursor);
		deselectUnit();
		checkVictory();
		return;
	}

	// Select unit if it belongs to current player
	if(unitUnderCursor && unitUnderCursor->getPlayer() == _players[_currentPlayer])
	{
		// Select unit
		_selectedUnit = unitUnderCursor;
		_squareMarker->setBoardPosition(boardPosition);
		_squareMarker->setVisible(true);

		return;
	}

	deselectUnit();
}

void SkirmishState::endTurn()
{
	_currentPlayer = (_currentPlayer + 1) % _players.size();
	_playerNameText->setText(_players[_currentPlayer]->getName());

	deselectUnit();
	replenishTroops();
}

void SkirmishState::deselectUnit()
{
	_selectedUnit = nullptr;
	_squareMarker->setVisible(false);
	g_scene.getSingleGameObject<Cursor>()->setFillColor(Cursor::Color::ESC_DEFAULT);
	path_->reset();
}

} // namespace qrw
<|endoftext|>


<commit_before>
namespace cusim
{
	namespace detail
	{
		template< typename tCount > __device__ inline
		tCount warp_prefix( unsigned aWTID, tCount aValue )
		{
			/* The PTX version results in much tighter code than the C version.
			 * The C version produces four instructions per step (a ISETP,
			 * IADD, SHFL and SEL); the inline PTX version gets it down to two
			 * (SHFL + predicated IADD).
			 *
			 * Incidentally, the PTX code is shown as an example for the shfl
			 * instruction in the PTX ISA document. See
			 * http://docs.nvidia.com/cuda/parallel-thread-execution/index.html
			 */
#			if 0
			auto x0 = __shfl_up( aValue, 1 );
			aValue += (aWTID >= 1) ? x0 : 0;

			auto x1 = __shfl_up( aValue, 2 );
			aValue += (aWTID >= 2) ? x1 : 0;

			auto x2 = __shfl_up( aValue, 4 );
			aValue += (aWTID >= 4) ? x2 : 0;

			auto x3 = __shfl_up( aValue, 8 );
			aValue += (aWTID >= 8) ? x3 : 0;

			auto x4 = __shfl_up( aValue, 16 );
			aValue += (aWTID >= 16) ? x4 : 0;
#			else
			__asm__ volatile( "{\n\t"
				".reg .u32 t0;\n\t"
				".reg .pred valid;\n\t"

				"shfl.up.b32 t0|valid, %0, 1, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"shfl.up.b32 t0|valid, %0, 2, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"shfl.up.b32 t0|valid, %0, 4, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"shfl.up.b32 t0|valid, %0, 8, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"shfl.up.b32 t0|valid, %0, 16, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"}\n\t"
				: "+r"(aValue)
			);
#			endif

			return aValue;
		}

		template< typename tReal > __device__ inline
		tReal reduce0( tReal aValue )
		{
			aValue += __shfl_down( aValue, 16 );
			aValue += __shfl_down( aValue, 8 );
			aValue += __shfl_down( aValue, 4 );
			aValue += __shfl_down( aValue, 2 );
			aValue += __shfl_down( aValue, 1 );
			return aValue;
		}
	}

	template< typename tReal, typename tCount > __global__
	void /*__launch_bounds__(1024,1)*/ K_distance( tReal* aDistance, unsigned aN, unsigned aM, tCount* aCur, tCount const* aRef )
	{
		__shared__ tReal totals[32]; //XXX-FIXME: number of warps in block.

		auto const warp = threadIdx.y;
		auto const wtid = threadIdx.x;

		auto const n32 = (aN+32-1)/32*32;
		auto const m32 = (aM+32-1)/32*32;

		// init
		if( 0 == warp )
		{
			totals[wtid] = tReal(0);
		}

		__syncthreads();

		// column-wise prefix sums
		for( auto row = warp; row < aN; row += blockDim.y )
		{
			tCount base = 0;
			for( auto col = wtid; col < m32; col += 32 )
			{
				tCount const val = col < aM
					? aCur[row*aM+col]
					: 0
				;

				tCount const sum = base + detail::warp_prefix( wtid, val );

				if( col < aM )
					aCur[row*aM+col] = sum;

				base = __shfl( sum, 31 );
			}
		}

		__syncthreads();

		// row-wise prefix sums, and accumulate the squared difference to the reference
		tReal acc = tReal(0);
		for( auto col = warp; col < aM; col += blockDim.y )
		{
			tCount base = 0;
			tReal a2 = tReal(0);
			for( auto row = wtid; row < n32; row += 32 )
			{
				tCount const val = row < aN
					? aCur[row*aM+col]
					: 0
				;

				tCount const sum = base + detail::warp_prefix( wtid, val );
				base = __shfl( sum, 31 );

				if( row < aN )
				{
					tCount const ref = aRef[row*aM+col];
					tReal const dd = tReal(sum) - ref;
					a2 += dd*dd;
				}
			}

			acc += a2;
		}

		// reduce the per-thread sums in each warp
		tReal const wsum = detail::reduce0( acc );
		if( 0 == wtid )
			totals[warp] = wsum;

		__syncthreads();

		// have one warp reduce the per-warp sums to the final sum
		if( 0 == warp )
		{
			tReal const tsum = wtid < 32 //XXX
				? totals[wtid]
				: 0
			;

			tReal const fin = detail::reduce0( tsum );

			if( 0 == wtid )
				*aDistance = fin;
		}

		// zero out the histogram for the next invocation
		for( auto row = warp; row < aN; row += blockDim.y )
		{
			for( auto col = wtid; col < m32; col += 32 )
			{
				aCur[row*aM+col] = 0;
			}
		}
	}
}
<commit_msg>Fixed: GPU write out of bounds<commit_after>
namespace cusim
{
	namespace detail
	{
		template< typename tCount > __device__ inline
		tCount warp_prefix( unsigned aWTID, tCount aValue )
		{
			/* The PTX version results in much tighter code than the C version.
			 * The C version produces four instructions per step (a ISETP,
			 * IADD, SHFL and SEL); the inline PTX version gets it down to two
			 * (SHFL + predicated IADD).
			 *
			 * Incidentally, the PTX code is shown as an example for the shfl
			 * instruction in the PTX ISA document. See
			 * http://docs.nvidia.com/cuda/parallel-thread-execution/index.html
			 */
#			if 0
			auto x0 = __shfl_up( aValue, 1 );
			aValue += (aWTID >= 1) ? x0 : 0;

			auto x1 = __shfl_up( aValue, 2 );
			aValue += (aWTID >= 2) ? x1 : 0;

			auto x2 = __shfl_up( aValue, 4 );
			aValue += (aWTID >= 4) ? x2 : 0;

			auto x3 = __shfl_up( aValue, 8 );
			aValue += (aWTID >= 8) ? x3 : 0;

			auto x4 = __shfl_up( aValue, 16 );
			aValue += (aWTID >= 16) ? x4 : 0;
#			else
			__asm__ volatile( "{\n\t"
				".reg .u32 t0;\n\t"
				".reg .pred valid;\n\t"

				"shfl.up.b32 t0|valid, %0, 1, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"shfl.up.b32 t0|valid, %0, 2, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"shfl.up.b32 t0|valid, %0, 4, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"shfl.up.b32 t0|valid, %0, 8, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"shfl.up.b32 t0|valid, %0, 16, 0;\n\t"
				"@valid add.s32 %0, t0, %0;\n\t"

				"}\n\t"
				: "+r"(aValue)
			);
#			endif

			return aValue;
		}

		template< typename tReal > __device__ inline
		tReal reduce0( tReal aValue )
		{
			aValue += __shfl_down( aValue, 16 );
			aValue += __shfl_down( aValue, 8 );
			aValue += __shfl_down( aValue, 4 );
			aValue += __shfl_down( aValue, 2 );
			aValue += __shfl_down( aValue, 1 );
			return aValue;
		}
	}

	template< typename tReal, typename tCount > __global__
	void /*__launch_bounds__(1024,1)*/ K_distance( tReal* aDistance, unsigned aN, unsigned aM, tCount* aCur, tCount const* aRef )
	{
		__shared__ tReal totals[32]; //XXX-FIXME: number of warps in block.

		auto const warp = threadIdx.y;
		auto const wtid = threadIdx.x;

		auto const n32 = (aN+32-1)/32*32;
		auto const m32 = (aM+32-1)/32*32;

		// init
		if( 0 == warp )
		{
			totals[wtid] = tReal(0);
		}

		__syncthreads();

		// column-wise prefix sums
		for( auto row = warp; row < aN; row += blockDim.y )
		{
			tCount base = 0;
			for( auto col = wtid; col < m32; col += 32 )
			{
				tCount const val = col < aM
					? aCur[row*aM+col]
					: 0
				;

				tCount const sum = base + detail::warp_prefix( wtid, val );

				if( col < aM )
					aCur[row*aM+col] = sum;

				base = __shfl( sum, 31 );
			}
		}

		__syncthreads();

		// row-wise prefix sums, and accumulate the squared difference to the reference
		tReal acc = tReal(0);
		for( auto col = warp; col < aM; col += blockDim.y )
		{
			tCount base = 0;
			tReal a2 = tReal(0);
			for( auto row = wtid; row < n32; row += 32 )
			{
				tCount const val = row < aN
					? aCur[row*aM+col]
					: 0
				;

				tCount const sum = base + detail::warp_prefix( wtid, val );
				base = __shfl( sum, 31 );

				if( row < aN )
				{
					tCount const ref = aRef[row*aM+col];
					tReal const dd = tReal(sum) - ref;
					a2 += dd*dd;
				}
			}

			acc += a2;
		}

		// reduce the per-thread sums in each warp
		tReal const wsum = detail::reduce0( acc );
		if( 0 == wtid )
			totals[warp] = wsum;

		__syncthreads();

		// have one warp reduce the per-warp sums to the final sum
		if( 0 == warp )
		{
			tReal const tsum = wtid < 32 //XXX
				? totals[wtid]
				: 0
			;

			tReal const fin = detail::reduce0( tsum );

			if( 0 == wtid )
				*aDistance = fin;
		}

		// zero out the histogram for the next invocation
		for( auto row = warp; row < aN; row += blockDim.y )
		{
			for( auto col = wtid; col < aM; col += 32 )
			{
				aCur[row*aM+col] = 0;
			}
		}
	}
}
<|endoftext|>


<commit_before>/**
 * @file   rotations.hpp
 * @author Paul Furgale <paul.furgale@utoronto.ca>
 * @date   Mon Nov 22 21:45:54 2010
 *
 * @brief
 *
 *
 */

#define SM_2_PI 		0.6366197723675814 // 2/pi
#define SM_PI 		3.141592653589793  // pi
#define SM_PI_2 		1.5707963267948966 // pi/2
#define SM_PI_4 		0.7853981633974483 // pi/4
#define SM_2PI 		6.283185307179586  // 2*pi
#define SM_DEG2RAD	0.017453292519943  // pi/180
#define SM_RAD2DEG	57.295779513082323 // 180/pi

#define SM_1_PI_F 	0.3183098861837907f
#define SM_2_PI_F 	0.6366197723675814f
#define SM_PI_F 		3.141592653589793f
#define SM_PI_2_F 	1.5707963267948966f
#define SM_PI_4_F		0.7853981633974483f
#define SM_2PI_F 		6.283185307179586f
#define SM_DEG2RAD_F	0.017453292519943f
#define SM_RAD2DEG_F	57.295779513082323f

#include <Eigen/Core>

namespace sm { namespace kinematics {

  // Principle axis rotations.
  Eigen::Matrix3d Rx(double radians);
  Eigen::Matrix3d Ry(double radians);
  Eigen::Matrix3d Rz(double radians);

  Eigen::Matrix3d rph2R(double x, double y, double z);
  Eigen::Matrix3d rph2R(Eigen::Vector3d const & x);
  Eigen::Vector3d R2rph(Eigen::Matrix3d const & C);

  // The C rotations are more standard. They go the other way
  Eigen::Matrix3d Cx(double radians);
  Eigen::Matrix3d Cy(double radians);
  Eigen::Matrix3d Cz(double radians);

  Eigen::Matrix3d rph2C(double x, double y, double z);
  Eigen::Matrix3d rph2C(Eigen::Vector3d const & x);
  Eigen::Vector3d C2rph(Eigen::Matrix3d const & C);

  // Small angle approximation.
  Eigen::Matrix3d crossMx(double x, double y, double z);
  Eigen::Matrix3d crossMx(Eigen::Vector3d const & x);

  // Axis Angle rotation.
  Eigen::Matrix3d axisAngle2R(double a, double ax, double ay, double az);
  Eigen::Matrix3d axisAngle2R(double x, double y, double z);
  Eigen::Matrix3d axisAngle2R(Eigen::Vector3d const & x);
  Eigen::Vector3d R2AxisAngle(Eigen::Matrix3d const & C);

  // Utility functions
  // Moves a value in radians to within -pi, pi
  double angleMod(double radians);
  double deg2rad(double degrees);
  double rad2deg(double radians);

}} // namespace sm::kinematics
<commit_msg>added missing include guard in rotations.hpp<commit_after>/**
 * @file   rotations.hpp
 * @author Paul Furgale <paul.furgale@utoronto.ca>
 * @date   Mon Nov 22 21:45:54 2010
 *
 * @brief
 *
 *
 */

#ifndef SM_ROTATIONS_HPP
#define SM_ROTATIONS_HPP

#define SM_2_PI 		0.6366197723675814 // 2/pi
#define SM_PI 		3.141592653589793  // pi
#define SM_PI_2 		1.5707963267948966 // pi/2
#define SM_PI_4 		0.7853981633974483 // pi/4
#define SM_2PI 		6.283185307179586  // 2*pi
#define SM_DEG2RAD	0.017453292519943  // pi/180
#define SM_RAD2DEG	57.295779513082323 // 180/pi

#define SM_1_PI_F 	0.3183098861837907f
#define SM_2_PI_F 	0.6366197723675814f
#define SM_PI_F 		3.141592653589793f
#define SM_PI_2_F 	1.5707963267948966f
#define SM_PI_4_F		0.7853981633974483f
#define SM_2PI_F 		6.283185307179586f
#define SM_DEG2RAD_F	0.017453292519943f
#define SM_RAD2DEG_F	57.295779513082323f

#include <Eigen/Core>

namespace sm { namespace kinematics {

  // Principle axis rotations.
  Eigen::Matrix3d Rx(double radians);
  Eigen::Matrix3d Ry(double radians);
  Eigen::Matrix3d Rz(double radians);

  Eigen::Matrix3d rph2R(double x, double y, double z);
  Eigen::Matrix3d rph2R(Eigen::Vector3d const & x);
  Eigen::Vector3d R2rph(Eigen::Matrix3d const & C);

  // The C rotations are more standard. They go the other way
  Eigen::Matrix3d Cx(double radians);
  Eigen::Matrix3d Cy(double radians);
  Eigen::Matrix3d Cz(double radians);

  Eigen::Matrix3d rph2C(double x, double y, double z);
  Eigen::Matrix3d rph2C(Eigen::Vector3d const & x);
  Eigen::Vector3d C2rph(Eigen::Matrix3d const & C);

  // Small angle approximation.
  Eigen::Matrix3d crossMx(double x, double y, double z);
  Eigen::Matrix3d crossMx(Eigen::Vector3d const & x);

  // Axis Angle rotation.
  Eigen::Matrix3d axisAngle2R(double a, double ax, double ay, double az);
  Eigen::Matrix3d axisAngle2R(double x, double y, double z);
  Eigen::Matrix3d axisAngle2R(Eigen::Vector3d const & x);
  Eigen::Vector3d R2AxisAngle(Eigen::Matrix3d const & C);

  // Utility functions
  // Moves a value in radians to within -pi, pi
  double angleMod(double radians);
  double deg2rad(double degrees);
  double rad2deg(double radians);

}} // namespace sm::kinematics

#endif // ndef SM_ROTATIONS_HPP
<|endoftext|>


<commit_before>/*
 * AnalyticPassPlanner.cpp
 *
 *  Created on: Dec 9, 2009
 *      Author: Philip Rogers
 */

#include <AnalyticPassPlanner.hpp>
#include <motion/planning/rrt.hpp>
#include <framework/Path.hpp>
#include <PassState.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

using namespace Geometry2d;
using namespace Gameplay;
using namespace std;

#define TIME_TO_AIM_APPROX 0.3 // seconds it takes for the robot to pivot for an aim. Due to aiming time in kick behavior, even if we knew rot accel, this is an approximation.
#define BALL_KICK_AVG_VEL 1.0 // average speed of ball during a kick ((kick vel + end vel) / 2) very conservative due to inaccurate kick speeds and varying dynamics

void AnalyticPassPlanner::generateAllConfigs(const Point &ballPos, set<Robot *> &robots, PassConfigVector &passConfigResult){
	Geometry2d::Point goalBallPos = Geometry2d::Point(0.0, Constants::Field::Length);

	Planning::Path path;
	ObstacleGroup og;
	float pathDist, pathTime;

	// for times and distances, use a conservative estimate of 45deg. travel
	Robot* rTmp = *(robots.begin());
	float maxVel = rTmp->packet()->config.motion.deg45.velocity;
	float timeStopToMaxVel = maxVel/ rTmp->packet()->config.motion.deg45.acceleration;
	float timeMaxVelToStop = maxVel / rTmp->packet()->config.motion.deg45.deceleration;
	float distStopToMaxVel = 0.5 * maxVel * timeStopToMaxVel;
	float distMaxVelToStop = 0.5 * maxVel * timeMaxVelToStop;

	BOOST_FOREACH(Robot *r1, robots){
		if(!r1->visible()){continue;} // don't use invisible robots

		BOOST_FOREACH(Robot *r2, robots){
			if(!r2->visible()){continue;} // don't use invisible robots
			if(r2->id()==r1->id()){continue;} // don't pass to self
			PassConfig* passConfig = new PassConfig();

			// setup calculations
			Point passVec = (r2->pos() - ballPos).normalized();
			float passAngle = passVec.angle();
			Point goalVec = (goalBallPos - r2->pos()).normalized();
			float goalAngle = goalVec.angle();

			// add initial state with no robots having the ball
			passConfig->addPassState(
					PassState(r1, r2, r1->pos(), r2->pos(), r1->angle(), r2->angle(),
							ballPos, PassState::INTERMEDIATE, 0));

			// add state with robot1 at a position to pass to robot2
			Point state2Robot1Pos = ballPos - passVec * (float)(Constants::Robot::Radius + Constants::Ball::Radius);
			float state2Robot1Rot = passAngle;

			// calculate time
			og = r1->obstacles();
			Point r1pos = r1->pos();
			float r1angle = r1->angle();
			Point r1vel = r1->vel();
			Motion::RRT::Planner planner;
			Motion::Dynamics dynamics;
			dynamics.setConfig(_gameplay->state()->self[r1->id()].config.motion);
			planner.setDynamics(&dynamics);
			planner.run(r1pos,r1angle,r1vel,ballPos,&og,path);

			pathDist = path.length(0);

			if(pathDist < distStopToMaxVel + distMaxVelToStop){
				pathTime = (pathDist/(distStopToMaxVel + distMaxVelToStop))*(timeStopToMaxVel + timeMaxVelToStop);
			}else{
				pathTime = timeStopToMaxVel + timeMaxVelToStop + (pathDist - (distStopToMaxVel + distMaxVelToStop))/maxVel;
			}
			double state2Time = pathTime + TIME_TO_AIM_APPROX;
			//double state2Time = r1->pos().distTo(state2Robot1Pos) / APPROXROBOTVELTRANS;
			passConfig->addPassState(
					PassState(r1, r2, state2Robot1Pos, r2->pos(), state2Robot1Rot, r2->angle(),
							ballPos, PassState::KICKPASS, state2Time));
			// add state with robot2 receiving ball
			Point state3BallPos = r2->pos();
			Point state3Robot2Pos = state3BallPos + passVec * (float)(Constants::Robot::Radius + Constants::Ball::Radius);
			float state3Robot2Rot = (passVec * -1.0f).angle();
			double state3Time = state2Time + r2->pos().distTo(state3Robot2Pos) / BALL_KICK_AVG_VEL;
			passConfig->addPassState(
					PassState(r1, r2, state2Robot1Pos, state3Robot2Pos, state2Robot1Rot, state3Robot2Rot,
							state3BallPos, PassState::RECEIVEPASS, state3Time));

			// add state with robot2 kicking a goal
			Point state4Robot2Pos = state3BallPos - goalVec * (float)(Constants::Robot::Radius + Constants::Ball::Radius);
			float state4Robot2Rot = goalAngle;
			double state4Time = state3Time + state3Robot2Pos.distTo(state4Robot2Pos) / TIME_TO_AIM_APPROX;
			//double state4Time = state3Time + state3Robot2Pos.distTo(state4Robot2Pos) / APPROXROBOTVELTRANS;
			passConfig->addPassState(
					PassState(r1, r2, state2Robot1Pos, state4Robot2Pos, state2Robot1Rot, state4Robot2Rot,
							state3BallPos, PassState::KICKGOAL, state4Time));

			// add state with ball in goal
			double state5Time = state4Time + state3BallPos.distTo(goalBallPos) / BALL_KICK_AVG_VEL;
			//double state5Time = state4Time + state3BallPos.distTo(goalBallPos) / APPROXBALLVEL;
			passConfig->addPassState(
					PassState(r1, r2, state2Robot1Pos, state4Robot2Pos, state2Robot1Rot, state4Robot2Rot,
							goalBallPos, PassState::INTERMEDIATE, state5Time));

			passConfigResult.push_back(passConfig);
		}
	}
}

void AnalyticPassPlanner::evaluateConfigs(set<Robot *> &robots, Robot** opponents, PassConfigVector &passConfigs){
	Geometry2d::Point goalBallPos = Geometry2d::Point(0.0, Constants::Field::Length);
	//
	// Weight configs
	//
	PassState prevState;

	// locate opponent's goalie by finding closest opponent to goal
	Robot *oppGoalie = opponents[0];
	float bestDist = oppGoalie->pos().distTo(goalBallPos), thisDist;
	for (int i=0; i<Constants::Robots_Per_Team; ++i){
		Robot *opponentR = opponents[i];
		thisDist = opponentR->pos().distTo(goalBallPos);
		if(thisDist < bestDist){
			oppGoalie = opponentR;
			bestDist = thisDist;
		}
	}

	Planning::Path path;Motion::RRT::Planner planner;
	ObstacleGroup og;
	float pathDist, pathTime;

	Robot* rTmp = *(robots.begin());
	float maxVel = rTmp->packet()->config.motion.deg45.velocity;
	float timeStopToMaxVel = maxVel/ rTmp->packet()->config.motion.deg45.acceleration;
	float timeMaxVelToStop = maxVel / rTmp->packet()->config.motion.deg45.deceleration;
	float distStopToMaxVel = 0.5 * maxVel * timeStopToMaxVel;
	float distMaxVelToStop = 0.5 * maxVel * timeMaxVelToStop;

	for(int i=0; i<(int)passConfigs.size(); i++){
		int numInteractions = 0;

		// calculate the total number of opponents that can touch the ball at each intermediate
		// ballPos (where the ball will be waiting for the robot to pivot and pass)
		for(int j=0; j<passConfigs[i].length(); j++){
			PassState thisState = passConfigs[i].getPassState(j);
			for (int i=0; i<Constants::Robots_Per_Team; ++i){
				Robot *opponentR = opponents[i];
				if(opponentR->id() == oppGoalie->id()){continue;} // do not consider opponent's goalie
				og = opponentR->obstacles();
				Motion::RRT::Planner planner;
				planner.run(opponentR->pos(),opponentR->angle(),opponentR->vel(),thisState.ballPos,&og,path);
				pathDist = path.length(0);
				if(pathDist < distStopToMaxVel + distMaxVelToStop){
					pathTime = (pathDist/(distStopToMaxVel + distMaxVelToStop))*(timeStopToMaxVel + timeMaxVelToStop);
				}else{
					pathTime = timeStopToMaxVel + timeMaxVelToStop + (pathDist - (distStopToMaxVel + distMaxVelToStop))/maxVel;
				}
				if(pathTime < thisState.timestamp){
					numInteractions++;
				}
			}
			if(thisState.stateType == PassState::KICKGOAL){
				break; // do not include the last state with ball in goal.
			}
		}

		// calculate the total number of opponents that currently intersect
		// the ball's path at this instant.
		for(int j=0; j<passConfigs[i].length(); j++){
			PassState thisState = passConfigs[i].getPassState(j);
			Line ballPath(thisState.ballPos,prevState.ballPos);
			for (int i=0; i<Constants::Robots_Per_Team; ++i){
				Robot *opponentR = opponents[i];
				if(opponentR->id() == oppGoalie->id()){continue;} // do not consider opponent's goalie
				// use 1.5*Radius to give "wiggle room"
				if(ballPath.distTo(opponentR->pos()) < (float)(Constants::Robot::Radius + 1.5*Constants::Ball::Radius)){
					numInteractions++;
				}
			}
			prevState = thisState;
		}

		passConfigs[i].setWeight(numInteractions);
	}

	passConfigs.sort();
}
<commit_msg>Changed analytic planner to use new state setup<commit_after>/*
 * AnalyticPassPlanner.cpp
 *
 *  Created on: Dec 9, 2009
 *      Author: Philip Rogers
 */

#include <AnalyticPassPlanner.hpp>
#include <motion/planning/rrt.hpp>
#include <framework/Path.hpp>
#include <PassState.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

using namespace Geometry2d;
using namespace Gameplay;
using namespace std;

#define TIME_TO_AIM_APPROX 0.3 // seconds it takes for the robot to pivot for an aim. Due to aiming time in kick behavior, even if we knew rot accel, this is an approximation.
#define BALL_KICK_AVG_VEL 1.0 // average speed of ball during a kick ((kick vel + end vel) / 2) very conservative due to inaccurate kick speeds and varying dynamics

void AnalyticPassPlanner::generateAllConfigs(const Point &ballPos, set<Robot *> &robots, PassConfigVector &passConfigResult){
	Geometry2d::Point goalBallPos = Geometry2d::Point(0.0, Constants::Field::Length);

	Planning::Path path;
	ObstacleGroup og;
	float pathDist, pathTime;

	// for times and distances, use a conservative estimate of 45deg. travel
	Robot* rTmp = *(robots.begin());
	float maxVel = rTmp->packet()->config.motion.deg45.velocity;
	float timeStopToMaxVel = maxVel/ rTmp->packet()->config.motion.deg45.acceleration;
	float timeMaxVelToStop = maxVel / rTmp->packet()->config.motion.deg45.deceleration;
	float distStopToMaxVel = 0.5 * maxVel * timeStopToMaxVel;
	float distMaxVelToStop = 0.5 * maxVel * timeMaxVelToStop;

	BOOST_FOREACH(Robot *r1, robots){
		if(!r1->visible()){continue;} // don't use invisible robots

		BOOST_FOREACH(Robot *r2, robots){
			if(!r2->visible()){continue;} // don't use invisible robots
			if(r2->id()==r1->id()){continue;} // don't pass to self
			PassConfig* passConfig = new PassConfig();

			// setup calculations
			Point passVec = (r2->pos() - ballPos).normalized();
			float passAngle = passVec.angle();
			Point goalVec = (goalBallPos - r2->pos()).normalized();
			float goalAngle = goalVec.angle();

			// add initial state with no robots having the ball
			passConfig->addPassState(
					PassState(r1, r2, r1->pos(), r2->pos(), r1->angle(), r2->angle(),
							ballPos, PassState::INITIAL, 0));

			// add state with robot1 at a position to pass to robot2
			Point state2Robot1Pos = ballPos - passVec * (float)(Constants::Robot::Radius + Constants::Ball::Radius);
			float state2Robot1Rot = passAngle;
			Point state2Robot2Pos = r2->pos();
			float state2Robot2Rot = (passVec * -1.0f).angle();

			// calculate time
			og = r1->obstacles();
			Point r1pos = r1->pos();
			float r1angle = r1->angle();
			Point r1vel = r1->vel();
			Motion::RRT::Planner planner;
			Motion::Dynamics dynamics;
			dynamics.setConfig(_gameplay->state()->self[r1->id()].config.motion);
			planner.setDynamics(&dynamics);
			planner.run(r1pos,r1angle,r1vel,ballPos,&og,path);

			pathDist = path.length(0);

			if(pathDist < distStopToMaxVel + distMaxVelToStop){
				pathTime = (pathDist/(distStopToMaxVel + distMaxVelToStop))*(timeStopToMaxVel + timeMaxVelToStop);
			}else{
				pathTime = timeStopToMaxVel + timeMaxVelToStop + (pathDist - (distStopToMaxVel + distMaxVelToStop))/maxVel;
			}
			double state2Time = pathTime + TIME_TO_AIM_APPROX;
			//double state2Time = r1->pos().distTo(state2Robot1Pos) / APPROXROBOTVELTRANS;
			passConfig->addPassState(
					PassState(r1, r2, state2Robot1Pos, state2Robot2Pos, state2Robot1Rot, state2Robot2Rot,
							ballPos, PassState::KICKPASS, state2Time));
			// add state with robot2 receiving ball
			Point state3BallPos = state2Robot2Pos;
			Point state3Robot2Pos = state3BallPos + passVec * (float)(Constants::Robot::Radius + Constants::Ball::Radius);
			float state3Robot2Rot = (passVec * -1.0f).angle();
			double state3Time = state2Time + r2->pos().distTo(state3Robot2Pos) / BALL_KICK_AVG_VEL;
			passConfig->addPassState(
					PassState(r1, r2, state2Robot1Pos, state3Robot2Pos, state2Robot1Rot, state3Robot2Rot,
							state3BallPos, PassState::RECEIVEPASS, state3Time));

			// add state with robot2 kicking a goal
			Point state4Robot2Pos = state3BallPos - goalVec * (float)(Constants::Robot::Radius + Constants::Ball::Radius);
			float state4Robot2Rot = goalAngle;
			double state4Time = state3Time + state3Robot2Pos.distTo(state4Robot2Pos) / TIME_TO_AIM_APPROX;
			//double state4Time = state3Time + state3Robot2Pos.distTo(state4Robot2Pos) / APPROXROBOTVELTRANS;
			passConfig->addPassState(
					PassState(r1, r2, state2Robot1Pos, state4Robot2Pos, state2Robot1Rot, state4Robot2Rot,
							state3BallPos, PassState::KICKGOAL, state4Time));

			// add state with ball in goal
			double state5Time = state4Time + state3BallPos.distTo(goalBallPos) / BALL_KICK_AVG_VEL;
			//double state5Time = state4Time + state3BallPos.distTo(goalBallPos) / APPROXBALLVEL;
			passConfig->addPassState(
					PassState(r1, r2, state2Robot1Pos, state4Robot2Pos, state2Robot1Rot, state4Robot2Rot,
							goalBallPos, PassState::GOAL, state5Time));

			passConfigResult.push_back(passConfig);
		}
	}
}

void AnalyticPassPlanner::evaluateConfigs(set<Robot *> &robots, Robot** opponents, PassConfigVector &passConfigs){
	Geometry2d::Point goalBallPos = Geometry2d::Point(0.0, Constants::Field::Length);
	//
	// Weight configs
	//
	PassState prevState;

	// locate opponent's goalie by finding closest opponent to goal
	Robot *oppGoalie = opponents[0];
	float bestDist = oppGoalie->pos().distTo(goalBallPos), thisDist;
	for (int i=0; i<Constants::Robots_Per_Team; ++i){
		Robot *opponentR = opponents[i];
		thisDist = opponentR->pos().distTo(goalBallPos);
		if(thisDist < bestDist){
			oppGoalie = opponentR;
			bestDist = thisDist;
		}
	}

	Planning::Path path;Motion::RRT::Planner planner;
	ObstacleGroup og;
	float pathDist, pathTime;

	Robot* rTmp = *(robots.begin());
	float maxVel = rTmp->packet()->config.motion.deg45.velocity;
	float timeStopToMaxVel = maxVel/ rTmp->packet()->config.motion.deg45.acceleration;
	float timeMaxVelToStop = maxVel / rTmp->packet()->config.motion.deg45.deceleration;
	float distStopToMaxVel = 0.5 * maxVel * timeStopToMaxVel;
	float distMaxVelToStop = 0.5 * maxVel * timeMaxVelToStop;

	for(int i=0; i<(int)passConfigs.size(); i++){
		int numInteractions = 0;

		// calculate the total number of opponents that can touch the ball at each intermediate
		// ballPos (where the ball will be waiting for the robot to pivot and pass)
		for(int j=0; j<passConfigs[i].length(); j++){
			PassState thisState = passConfigs[i].getPassState(j);
			for (int i=0; i<Constants::Robots_Per_Team; ++i){
				Robot *opponentR = opponents[i];
				if(opponentR->id() == oppGoalie->id()){continue;} // do not consider opponent's goalie
				og = opponentR->obstacles();
				Motion::RRT::Planner planner;
				planner.run(opponentR->pos(),opponentR->angle(),opponentR->vel(),thisState.ballPos,&og,path);
				pathDist = path.length(0);
				if(pathDist < distStopToMaxVel + distMaxVelToStop){
					pathTime = (pathDist/(distStopToMaxVel + distMaxVelToStop))*(timeStopToMaxVel + timeMaxVelToStop);
				}else{
					pathTime = timeStopToMaxVel + timeMaxVelToStop + (pathDist - (distStopToMaxVel + distMaxVelToStop))/maxVel;
				}
				if(pathTime < thisState.timestamp){
					numInteractions++;
				}
			}
			if(thisState.stateType == PassState::KICKGOAL){
				break; // do not include the last state with ball in goal.
			}
		}

		// calculate the total number of opponents that currently intersect
		// the ball's path at this instant.
		for(int j=0; j<passConfigs[i].length(); j++){
			PassState thisState = passConfigs[i].getPassState(j);
			Line ballPath(thisState.ballPos,prevState.ballPos);
			for (int i=0; i<Constants::Robots_Per_Team; ++i){
				Robot *opponentR = opponents[i];
				if(opponentR->id() == oppGoalie->id()){continue;} // do not consider opponent's goalie
				// use 1.5*Radius to give "wiggle room"
				if(ballPath.distTo(opponentR->pos()) < (float)(Constants::Robot::Radius + 1.5*Constants::Ball::Radius)){
					numInteractions++;
				}
			}
			prevState = thisState;
		}

		passConfigs[i].setWeight(numInteractions);
	}

	passConfigs.sort();
}
<|endoftext|>


<commit_before>#include <climits>
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <set>

#include <wibble/commandline/parser.h>

#include <elevator/elevator.h>
#include <elevator/scheduler.h>
#include <elevator/udptools.h>
#include <elevator/udpqueue.h>
#include <elevator/sessionmanager.h>

namespace elevator {

using namespace wibble;
using namespace wibble::commandline;
using namespace udp;

struct Main {

    const Address commSend{ IPv4Address::any, Port{ 64123 } };
    const Address commRcv{ IPv4Address::any, Port{ 64125 } };
    const Address commBroadcast{ IPv4Address::broadcast, Port{ 64125 } };

    const Port stateChangePort{ 64016 };
    const Port commandPort{ 64017 };

    StandardParser opts;
    OptionGroup *execution;
    IntOption *optNodes;
    BoolOption *avoidRecovery;
    const int peerMsg = 1000;
    std::set< IPv4Address > peerAddresses;
    int id = INT_MIN;
    int nodes = 1;

    Main( int argc, const char **argv ) : opts( "elevator", "0.1" ) {
        // setup options
        execution = opts.createGroup( "Execution options" );
        optNodes = execution->add< IntOption >(
                "nodes", 'n', "nodes", "",
                "specifies number of elevator nodes to expect" );

        avoidRecovery = execution->add< BoolOption >(
                "avoid recovery", 0, "avoid-recovery", "",
                "avoid auto-recovery when program is killed (do not fork)" );

        opts.usage = "";
        opts.description = "Elevator control software as a project for the "
                           "TTK4145 Real-Time Programming at NTNU. Controls "
                           "multiple elevator connected with local network.\n"
                           "(c) 2014, Vladimír Štill and Sameh Khalil\n"
                           "https://github.com/vlstill/ttk4145/tree/master/project";

        opts.add( execution );

        // parse options
        try {
            opts.parse( argc, argv );
        } catch ( exception::BadOption &ex ) {
            std::cerr << "FATAL: " << ex.fullInfo() << std::endl;
            exit( 1 );
        }
        if ( opts.help->boolValue() || opts.version->boolValue() )
            exit( 0 );
    }

    void main() {

        if ( avoidRecovery->boolValue() ) {
            runElevator();
        } else {
            assert_unimplemented();
        }
    }

    void runElevator() {
        int id;
        GlobalState global;
        SessionManager sessman{ global };
        if ( optNodes->boolValue() && optNodes->intValue() > 1 ) {
            nodes = optNodes->intValue();
            sessman.connect( nodes );
            id = sessman.id();
        } else {
            id = 0;
        }

        std::cout << "starting elevator, id " << id << " of " << nodes << " elevators" << std::endl;
        HeartBeatManager heartbeatManager;

        ConcurrentQueue< Command > commandsToLocalElevator;
        ConcurrentQueue< Command > commandsToOthers;
        ConcurrentQueue< StateChange > stateChangesIn;
        ConcurrentQueue< StateChange > stateChangesOut;

        std::unique_ptr< QueueReceiver< Command > > commandsToLocalElevatorReceiver;
        std::unique_ptr< QueueReceiver< StateChange > > stateChangesInReceiver;
        std::unique_ptr< QueueSender< StateChange > > stateChangesOutSender;
        std::unique_ptr< QueueSender< Command > > commandsToOthersReceiver;

        if ( nodes > 1 ) {
            commandsToOthersReceiver.reset( new QueueSender< Command >{
                    commSend,
                    Address{ IPv4Address::broadcast, commandPort },
                    commandsToOthers
                } );

            commandsToLocalElevatorReceiver.reset( new QueueReceiver< Command >{
                    Address{ IPv4Address::any, commandPort },
                    commandsToLocalElevator,
                    [id]( const Command &comm ) { return comm.targetElevatorId == id; }
                } );

            stateChangesInReceiver.reset( new QueueReceiver< StateChange >{
                    Address{ IPv4Address::any, stateChangePort },
                    stateChangesIn,
                    [id]( const StateChange &chan ) { return chan.state.id != id; }
                } );

            stateChangesOutSender.reset( new QueueSender< StateChange >{
                    commSend,
                    Address{ IPv4Address::broadcast, stateChangePort },
                    stateChangesOut
                } );
        }

        /* about heartbeat lengths:
         * - elevator loop is polling and never sleeping, therefore its scheduling
         *   is quite relieable and it can have short heartbeat,
         *   furthermore we need to make sure we will detect any floor change,
         *   therefore heartbeat it must respond faster then is time to cross sensor
         *   (approx 400ms), also note that even with heartbeat of 10ms the elevator
         *   seems to be running reliably
         * - scheduler again has quite tight demand, as it should be able to handle
         *   all state changes from elevator, but we have to be more carefull here
         *   as it is sleeping sometimes
         */
        Elevator elevator{ id, heartbeatManager.getNew( 500 /* ms */ ),
            commandsToLocalElevator, stateChangesIn };
        Scheduler scheduler{ id, heartbeatManager.getNew( 1000 /* ms */ ),
            elevator.info(),
            stateChangesIn, stateChangesOut, commandsToOthers, commandsToLocalElevator };

        if ( nodes > 1 ) {
            commandsToLocalElevatorReceiver->run();
            stateChangesInReceiver->run();
            commandsToOthersReceiver->run();
            stateChangesOutSender->run();
        }
        elevator.run();
        scheduler.run();

        // wait for 2 seconds so that everything has chance to start
        // it something fails to start in this time heartbeat will
        // fail and process will be terminated
        std::this_thread::sleep_for( std::chrono::seconds( 2 ) );
        // heartbeat failure will throw an exception which will terminate
        // process (as it is not catched)
        heartbeatManager.runInThisThread();
    }
};

}

int main( int args, const char **argv ) {
    elevator::Main m( args, argv );
    m.main();
}
<commit_msg>main: Use automatic recovery in case of receiving signal.<commit_after>#include <climits>
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <set>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <wibble/commandline/parser.h>
#include <string.h>
#include <elevator/driver.h>
#include <elevator/test.h>
#include <elevator/elevator.h>
#include <elevator/scheduler.h>
#include <elevator/udptools.h>
#include <elevator/udpqueue.h>
#include <elevator/sessionmanager.h>

void handler( int sig, siginfo_t *info, void * ) {
    elevator::Driver driver;
    driver.stopElevator();
    std::cerr << "elevator stopped" << std::endl;
    if ( sig != SIGCHLD ) {
        exit( sig );
    } else {
        int pid = info->si_pid;
        waitpid( pid, nullptr, WNOHANG );
    }
}

namespace elevator {

using namespace wibble;
using namespace wibble::commandline;
using namespace udp;

struct Main {

    const Address commSend{ IPv4Address::any, Port{ 64123 } };
    const Address commRcv{ IPv4Address::any, Port{ 64125 } };
    const Address commBroadcast{ IPv4Address::broadcast, Port{ 64125 } };

    const Port stateChangePort{ 64016 };
    const Port commandPort{ 64017 };

    StandardParser opts;
    OptionGroup *execution;
    IntOption *optNodes;
    BoolOption *avoidRecovery;
    const int peerMsg = 1000;
    std::set< IPv4Address > peerAddresses;
    int id = INT_MIN;
    int nodes = 1;

    Main( int argc, const char **argv ) : opts( "elevator", "0.1" ) {
        // setup options
        execution = opts.createGroup( "Execution options" );
        optNodes = execution->add< IntOption >(
                "nodes", 'n', "nodes", "",
                "specifies number of elevator nodes to expect" );

        avoidRecovery = execution->add< BoolOption >(
                "avoid recovery", 0, "avoid-recovery", "",
                "avoid auto-recovery when program is killed (do not fork)" );

        opts.usage = "";
        opts.description = "Elevator control software as a project for the "
                           "TTK4145 Real-Time Programming at NTNU. Controls "
                           "multiple elevator connected with local network.\n"
                           "(c) 2014, Vladimír Štill and Sameh Khalil\n"
                           "https://github.com/vlstill/ttk4145/tree/master/project";

        opts.add( execution );

        // parse options
        try {
            opts.parse( argc, argv );
        } catch ( exception::BadOption &ex ) {
            std::cerr << "FATAL: " << ex.fullInfo() << std::endl;
            exit( 1 );
        }
        if ( opts.help->boolValue() || opts.version->boolValue() )
            exit( 0 );
    }

    void setupChild() {
        struct sigaction act;
        memset( &act, 0, sizeof( struct sigaction ) );
        act.sa_handler = SIG_DFL;
        sigaction( SIGCHLD, &act, nullptr );
        sigaction( SIGINT, &act, nullptr );

        runElevator();
    }

    void watchChild( int childPid ) {
        while ( true ) {
            pause(); // wait for signal
            initRecovery();
        }
    }

    void setupSignals() {
        struct sigaction act;
        memset( &act, 0, sizeof( struct sigaction ) );
        act.sa_sigaction = handler;
        act.sa_flags = SA_SIGINFO;
        sigaction( SIGCHLD, &act, nullptr ); // child died
        sigaction( SIGINT, &act, nullptr ); // ctrl+c
    }

    void initRecovery() {
        setupSignals();
        int pid = fork();
        if ( pid == 0 ) { // child
            setupChild();
        } else if ( pid > 0 ) { // parent
            watchChild( pid );
        } else {
            std::cerr << "Fatal error: fork failed" << std::endl;
            exit( 1 );
        }
    }

    void main() {

        if ( avoidRecovery->boolValue() ) {
            runElevator();
        } else {
            initRecovery();
        }
    }

    void runElevator() {
        int id;
        GlobalState global;
        SessionManager sessman{ global };
        if ( optNodes->boolValue() && optNodes->intValue() > 1 ) {
            nodes = optNodes->intValue();
            sessman.connect( nodes );
            id = sessman.id();
        } else {
            id = 0;
        }

        std::cout << "starting elevator, id " << id << " of " << nodes << " elevators" << std::endl;
        HeartBeatManager heartbeatManager;

        ConcurrentQueue< Command > commandsToLocalElevator;
        ConcurrentQueue< Command > commandsToOthers;
        ConcurrentQueue< StateChange > stateChangesIn;
        ConcurrentQueue< StateChange > stateChangesOut;

        std::unique_ptr< QueueReceiver< Command > > commandsToLocalElevatorReceiver;
        std::unique_ptr< QueueReceiver< StateChange > > stateChangesInReceiver;
        std::unique_ptr< QueueSender< StateChange > > stateChangesOutSender;
        std::unique_ptr< QueueSender< Command > > commandsToOthersReceiver;

        if ( nodes > 1 ) {
            commandsToOthersReceiver.reset( new QueueSender< Command >{
                    commSend,
                    Address{ IPv4Address::broadcast, commandPort },
                    commandsToOthers
                } );

            commandsToLocalElevatorReceiver.reset( new QueueReceiver< Command >{
                    Address{ IPv4Address::any, commandPort },
                    commandsToLocalElevator,
                    [id]( const Command &comm ) { return comm.targetElevatorId == id; }
                } );

            stateChangesInReceiver.reset( new QueueReceiver< StateChange >{
                    Address{ IPv4Address::any, stateChangePort },
                    stateChangesIn,
                    [id]( const StateChange &chan ) { return chan.state.id != id; }
                } );

            stateChangesOutSender.reset( new QueueSender< StateChange >{
                    commSend,
                    Address{ IPv4Address::broadcast, stateChangePort },
                    stateChangesOut
                } );
        }

        /* about heartbeat lengths:
         * - elevator loop is polling and never sleeping, therefore its scheduling
         *   is quite relieable and it can have short heartbeat,
         *   furthermore we need to make sure we will detect any floor change,
         *   therefore heartbeat it must respond faster then is time to cross sensor
         *   (approx 400ms), also note that even with heartbeat of 10ms the elevator
         *   seems to be running reliably
         * - scheduler again has quite tight demand, as it should be able to handle
         *   all state changes from elevator, but we have to be more carefull here
         *   as it is sleeping sometimes
         */
        Elevator elevator{ id, heartbeatManager.getNew( 500 /* ms */ ),
            commandsToLocalElevator, stateChangesIn };
        Scheduler scheduler{ id, heartbeatManager.getNew( 1000 /* ms */ ),
            elevator.info(),
            stateChangesIn, stateChangesOut, commandsToOthers, commandsToLocalElevator };

        if ( nodes > 1 ) {
            commandsToLocalElevatorReceiver->run();
            stateChangesInReceiver->run();
            commandsToOthersReceiver->run();
            stateChangesOutSender->run();
        }
        elevator.run();
        scheduler.run();

        // wait for 2 seconds so that everything has chance to start
        // it something fails to start in this time heartbeat will
        // fail and process will be terminated
        std::this_thread::sleep_for( std::chrono::seconds( 2 ) );
        // heartbeat failure will throw an exception which will terminate
        // process (as it is not catched)
        heartbeatManager.runInThisThread();
    }
};

}

int main( int args, const char **argv ) {
    elevator::Main m( args, argv );
    m.main();
}
<|endoftext|>