<commit_before>#include "stdafx.h"
#include "Version.h"
#include "D435iCamera.h"
#include "Visualizer.h"

#include <librealsense2/rs.hpp>
#include <librealsense2/rsutil.h>
#include <librealsense2/hpp/rs_pipeline.hpp>

/** RealSense SDK2 Cross-Platform Depth Camera Backend **/
namespace ark {
    D435iCamera::D435iCamera():
        last_ts_g(0), kill(false) {
        //Setup camera
        //TODO: Make read from config file
        rs2::context ctx;
        device = ctx.query_devices().front();
        width = 640;
        height = 480;
        //Setup configuration
        config.enable_stream(RS2_STREAM_DEPTH,-1,width, height,RS2_FORMAT_Z16,30);
        config.enable_stream(RS2_STREAM_INFRARED, 1, width, height, RS2_FORMAT_Y8, 30);
        config.enable_stream(RS2_STREAM_INFRARED, 2, width, height, RS2_FORMAT_Y8, 30);
        config.enable_stream(RS2_STREAM_COLOR, -1, width, height, RS2_FORMAT_RGB8, 30);
        motion_config.enable_stream(RS2_STREAM_ACCEL, RS2_FORMAT_MOTION_XYZ32F,250);
        motion_config.enable_stream(RS2_STREAM_GYRO, RS2_FORMAT_MOTION_XYZ32F,200);
        imu_rate=200; //setting imu_rate to be the gyro rate since we are using the gyro timestamps
        //Need to get the depth sensor specifically as it is the one that controls the sync funciton
        depth_sensor = new rs2::depth_sensor(device.first<rs2::depth_sensor>());

        scale = depth_sensor->get_option(RS2_OPTION_DEPTH_UNITS);
        rs2::sensor color_sensor = device.query_sensors()[1];

        color_sensor.set_option(RS2_OPTION_ENABLE_AUTO_EXPOSURE,false);

    }

    D435iCamera::~D435iCamera() {
        try {
            kill=true;
            imuReaderThread_.join();
            pipe->stop();
            if(depth_sensor){
                delete depth_sensor;
                depth_sensor=nullptr;
            }
        }
        catch (...) {}
    }

    void D435iCamera::start(){
        //enable sync
        //depth_sensor->set_option(RS2_OPTION_INTER_CAM_SYNC_MODE,1);
        //depth_sensor->set_option(RS2_OPTION_EMITTER_ENABLED, 1.f);
        //start streaming
        pipe = std::make_shared<rs2::pipeline>();
        rs2::pipeline_profile selection = pipe->start(config);
        //get the depth intrinsics (needed for projection to 3d)
        auto depthStream = selection.get_stream(RS2_STREAM_DEPTH)
                             .as<rs2::video_stream_profile>();
        depthIntrinsics = depthStream.get_intrinsics();
        auto dev = selection.get_device();
        auto sensors = dev.query_sensors();

        #ifdef RS2_OPTION_GLOBAL_TIME_ENABLED
        for (auto sensor: sensors) {
            sensor.set_option(RS2_OPTION_GLOBAL_TIME_ENABLED, false);
        }
        #endif

        motion_pipe = std::make_shared<rs2::pipeline>();
        rs2::pipeline_profile selection_motion = motion_pipe->start(motion_config);
        auto dev_motion = selection_motion.get_device();
        auto sensors_motion = dev_motion.query_sensors();

        #ifdef RS2_OPTION_GLOBAL_TIME_ENABLED
        for (auto sensor: sensors_motion) {
            sensor.set_option(RS2_OPTION_GLOBAL_TIME_ENABLED, false);
        }
        #endif

        imuReaderThread_ = std::thread(&D435iCamera::imuReader, this);
    }

    void D435iCamera::imuReader(){
        while(!kill){
            auto frames = motion_pipe->wait_for_frames();
            auto fa = frames.first(RS2_STREAM_ACCEL, RS2_FORMAT_MOTION_XYZ32F)
                .as<rs2::motion_frame>();
            auto fg = frames.first(RS2_STREAM_GYRO, RS2_FORMAT_MOTION_XYZ32F)
                .as<rs2::motion_frame>();

            double ts_g = fg.get_timestamp();
            if(ts_g != last_ts_g){
                last_ts_g=ts_g;
                // std::cout << "GYRO: " << ts_g / 1e2 << std::endl;
                // Get gyro measures
                rs2_vector gyro_data = fg.get_motion_data();

                // Get the timestamp of the current frame
                double ts_a = fa.get_timestamp();
                //std::cout << "ACCEL: " << ts_a  <<  std::endl;
                // Get accelerometer measures
                rs2_vector accel_data = fa.get_motion_data();

                ImuPair imu_out { double(ts_g)*1e6, //convert to nanoseconds, for some reason gyro timestamp is in centiseconds
                    Eigen::Vector3d(gyro_data.x,gyro_data.y,gyro_data.z),
                    Eigen::Vector3d(accel_data.x,accel_data.y,accel_data.z)};
                imu_queue_.enqueue(imu_out);
            }

        }

    }

    bool D435iCamera::getImuToTime(double timestamp, std::vector<ImuPair>& data_out){
        ImuPair imu_data;
        imu_data.timestamp=0;
        while((imu_data.timestamp+1e9/imu_rate)<timestamp){
            if(imu_queue_.try_dequeue(&imu_data)){
                data_out.push_back(imu_data);
            }
        }
        return true;

    };

    const std::string D435iCamera::getModelName() const {
        return "RealSense";
    }

    cv::Size D435iCamera::getImageSize() const
    {
        return cv::Size(width,height);
    }

    void D435iCamera::update(MultiCameraFrame & frame) {

        try {
            // Ensure the frame has space for all images
            frame.images_.resize(5);

            // Get frames from camera
            auto frames = pipe->wait_for_frames();
            auto infrared = frames.get_infrared_frame(1);
            auto infrared2 = frames.get_infrared_frame(2);
            auto depth = frames.get_depth_frame();
            auto color = frames.get_color_frame();

            // Store ID for later
            frame.frameId_ = depth.get_frame_number();
            if(depth.supports_frame_metadata(RS2_FRAME_METADATA_SENSOR_TIMESTAMP)){
                frame.timestamp_= depth.get_frame_metadata(RS2_FRAME_METADATA_SENSOR_TIMESTAMP)*1e3;
                //std::cout << "Image: " << std::fixed << frame.timestamp_/1e3 << std::endl;

            }else{
                std::cout << "No Metadata" << std::endl;
            }

            // Convert infrared frame to opencv
            if (frame.images_[0].empty()) frame.images_[0] = cv::Mat(cv::Size(width,height), CV_8UC1);
            std::memcpy( frame.images_[0].data, infrared.get_data(),width * height);

            if (frame.images_[1].empty()) frame.images_[1] = cv::Mat(cv::Size(width,height), CV_8UC1);
            std::memcpy( frame.images_[1].data, infrared2.get_data(),width * height);

            if (frame.images_[2].empty()) frame.images_[2] = cv::Mat(cv::Size(width,height), CV_32FC3);
            project(depth, frame.images_[2]);
            frame.images_[2] = frame.images_[2]*scale; //depth is in mm by default

            if (frame.images_[3].empty()) frame.images_[3] = cv::Mat(cv::Size(width,height), CV_8UC3);
            std::memcpy( frame.images_[3].data, color.get_data(),3 * width * height);

            if (frame.images_[4].empty()) frame.images_[4] = cv::Mat(cv::Size(width,height), CV_16UC1);
            // 16 bits = 2 bytes
            std::memcpy(frame.images_[4].data, depth.get_data(),width * height * 2);

        } catch (std::runtime_error e) {
            // Try reconnecting
            badInputFlag = true;
            pipe->stop();
            printf("Couldn't connect to camera, retrying in 0.5s...\n");
            boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
            //query_intrinsics();
            pipe->start(config);
            badInputFlag = false;
            return;
        }
    }

    // project depth map to xyz coordinates directly (faster and minimizes distortion, but will not be aligned to RGB/IR)
    void D435iCamera::project(const rs2::frame & depth_frame, cv::Mat & xyz_map) {
        const uint16_t * depth_data = (const uint16_t *)depth_frame.get_data();

        rs2_intrinsics * dIntrin = &depthIntrinsics;

        const uint16_t * srcPtr;
        cv::Vec3f * destPtr;
        float srcPixel[2], destXYZ[3];

        for (int r = 0; r < height; ++r)
        {
            srcPtr = depth_data + r * dIntrin->width;
            destPtr = xyz_map.ptr<Vec3f>(r);
            srcPixel[1] = r;

            for (int c = 0; c < width; ++c)
            {
                if (srcPtr[c] == 0) {
                    memset(&destPtr[c], 0, 3 * sizeof(float));
                    continue;
                }
                srcPixel[0] = c;
                rs2_deproject_pixel_to_point(destXYZ, dIntrin, srcPixel, srcPtr[c]);
                memcpy(&destPtr[c], destXYZ, 3 * sizeof(float));
            }
        }
    }

    const rs2_intrinsics &D435iCamera::getDepthIntrinsics() {
        return depthIntrinsics;
    }

    double D435iCamera::getDepthScale() {
        return scale;
    }
}
<commit_msg>fixed bug with new start<commit_after>#include "stdafx.h"
#include "Version.h"
#include "D435iCamera.h"
#include "Visualizer.h"

#include <librealsense2/rs.h>
#include <librealsense2/rs.hpp>
#include <librealsense2/rsutil.h>
#include <librealsense2/hpp/rs_pipeline.hpp>

/** RealSense SDK2 Cross-Platform Depth Camera Backend **/
namespace ark {
    D435iCamera::D435iCamera():
        last_ts_g(0), kill(false) {
        //Setup camera
        //TODO: Make read from config file
        rs2::context ctx;
        device = ctx.query_devices().front();
        width = 640;
        height = 480;
        //Setup configuration
        config.enable_stream(RS2_STREAM_DEPTH,-1,width, height,RS2_FORMAT_Z16,30);
        config.enable_stream(RS2_STREAM_INFRARED, 1, width, height, RS2_FORMAT_Y8, 30);
        config.enable_stream(RS2_STREAM_INFRARED, 2, width, height, RS2_FORMAT_Y8, 30);
        config.enable_stream(RS2_STREAM_COLOR, -1, width, height, RS2_FORMAT_RGB8, 30);
        motion_config.enable_stream(RS2_STREAM_ACCEL, RS2_FORMAT_MOTION_XYZ32F,250);
        motion_config.enable_stream(RS2_STREAM_GYRO, RS2_FORMAT_MOTION_XYZ32F,200);
        imu_rate=200; //setting imu_rate to be the gyro rate since we are using the gyro timestamps
        //Need to get the depth sensor specifically as it is the one that controls the sync funciton
        depth_sensor = new rs2::depth_sensor(device.first<rs2::depth_sensor>());

        scale = depth_sensor->get_option(RS2_OPTION_DEPTH_UNITS);
        rs2::sensor color_sensor = device.query_sensors()[1];

        color_sensor.set_option(RS2_OPTION_ENABLE_AUTO_EXPOSURE,false);

    }

    D435iCamera::~D435iCamera() {
        try {
            kill=true;
            imuReaderThread_.join();
            pipe->stop();
            if(depth_sensor){
                delete depth_sensor;
                depth_sensor=nullptr;
            }
        }
        catch (...) {}
    }

    void D435iCamera::start(){
        //enable sync
        //depth_sensor->set_option(RS2_OPTION_INTER_CAM_SYNC_MODE,1);
        //depth_sensor->set_option(RS2_OPTION_EMITTER_ENABLED, 1.f);
        //start streaming
        pipe = std::make_shared<rs2::pipeline>();
        rs2::pipeline_profile selection = pipe->start(config);
        //get the depth intrinsics (needed for projection to 3d)
        auto depthStream = selection.get_stream(RS2_STREAM_DEPTH)
                             .as<rs2::video_stream_profile>();
        depthIntrinsics = depthStream.get_intrinsics();

        if (RS2_API_MAJOR_VERSION > 2 || RS2_API_MAJOR_VERSION == 2 && RS2_API_MINOR_VERSION >= 22) {
            auto dev = selection.get_device();
            auto sensors = dev.query_sensors();
            for (auto sensor: sensors) {
                sensor.set_option(RS2_OPTION_GLOBAL_TIME_ENABLED, false);
            }

            motion_pipe = std::make_shared<rs2::pipeline>();
            rs2::pipeline_profile selection_motion = motion_pipe->start(motion_config);
            auto dev_motion = selection_motion.get_device();
            auto sensors_motion = dev_motion.query_sensors();

            for (auto sensor: sensors_motion) {
                sensor.set_option(RS2_OPTION_GLOBAL_TIME_ENABLED, false);
            }
        }

        imuReaderThread_ = std::thread(&D435iCamera::imuReader, this);
    }

    void D435iCamera::imuReader(){
        while(!kill){
            auto frames = motion_pipe->wait_for_frames();
            auto fa = frames.first(RS2_STREAM_ACCEL, RS2_FORMAT_MOTION_XYZ32F)
                .as<rs2::motion_frame>();
            auto fg = frames.first(RS2_STREAM_GYRO, RS2_FORMAT_MOTION_XYZ32F)
                .as<rs2::motion_frame>();

            double ts_g = fg.get_timestamp();
            if(ts_g != last_ts_g){
                last_ts_g=ts_g;
                // std::cout << "GYRO: " << ts_g / 1e2 << std::endl;
                // Get gyro measures
                rs2_vector gyro_data = fg.get_motion_data();

                // Get the timestamp of the current frame
                double ts_a = fa.get_timestamp();
                //std::cout << "ACCEL: " << ts_a  <<  std::endl;
                // Get accelerometer measures
                rs2_vector accel_data = fa.get_motion_data();

                ImuPair imu_out { double(ts_g)*1e6, //convert to nanoseconds, for some reason gyro timestamp is in centiseconds
                    Eigen::Vector3d(gyro_data.x,gyro_data.y,gyro_data.z),
                    Eigen::Vector3d(accel_data.x,accel_data.y,accel_data.z)};
                imu_queue_.enqueue(imu_out);
            }

        }

    }

    bool D435iCamera::getImuToTime(double timestamp, std::vector<ImuPair>& data_out){
        ImuPair imu_data;
        imu_data.timestamp=0;
        while((imu_data.timestamp+1e9/imu_rate)<timestamp){
            if(imu_queue_.try_dequeue(&imu_data)){
                data_out.push_back(imu_data);
            }
        }
        return true;

    };

    const std::string D435iCamera::getModelName() const {
        return "RealSense";
    }

    cv::Size D435iCamera::getImageSize() const
    {
        return cv::Size(width,height);
    }

    void D435iCamera::update(MultiCameraFrame & frame) {

        try {
            // Ensure the frame has space for all images
            frame.images_.resize(5);

            // Get frames from camera
            auto frames = pipe->wait_for_frames();
            auto infrared = frames.get_infrared_frame(1);
            auto infrared2 = frames.get_infrared_frame(2);
            auto depth = frames.get_depth_frame();
            auto color = frames.get_color_frame();

            // Store ID for later
            frame.frameId_ = depth.get_frame_number();
            if(depth.supports_frame_metadata(RS2_FRAME_METADATA_SENSOR_TIMESTAMP)){
                frame.timestamp_= depth.get_frame_metadata(RS2_FRAME_METADATA_SENSOR_TIMESTAMP)*1e3;
                //std::cout << "Image: " << std::fixed << frame.timestamp_/1e3 << std::endl;

            }else{
                std::cout << "No Metadata" << std::endl;
            }

            // Convert infrared frame to opencv
            if (frame.images_[0].empty()) frame.images_[0] = cv::Mat(cv::Size(width,height), CV_8UC1);
            std::memcpy( frame.images_[0].data, infrared.get_data(),width * height);

            if (frame.images_[1].empty()) frame.images_[1] = cv::Mat(cv::Size(width,height), CV_8UC1);
            std::memcpy( frame.images_[1].data, infrared2.get_data(),width * height);

            if (frame.images_[2].empty()) frame.images_[2] = cv::Mat(cv::Size(width,height), CV_32FC3);
            project(depth, frame.images_[2]);
            frame.images_[2] = frame.images_[2]*scale; //depth is in mm by default

            if (frame.images_[3].empty()) frame.images_[3] = cv::Mat(cv::Size(width,height), CV_8UC3);
            std::memcpy( frame.images_[3].data, color.get_data(),3 * width * height);

            if (frame.images_[4].empty()) frame.images_[4] = cv::Mat(cv::Size(width,height), CV_16UC1);
            // 16 bits = 2 bytes
            std::memcpy(frame.images_[4].data, depth.get_data(),width * height * 2);

        } catch (std::runtime_error e) {
            // Try reconnecting
            badInputFlag = true;
            pipe->stop();
            printf("Couldn't connect to camera, retrying in 0.5s...\n");
            boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
            //query_intrinsics();
            pipe->start(config);
            badInputFlag = false;
            return;
        }
    }

    // project depth map to xyz coordinates directly (faster and minimizes distortion, but will not be aligned to RGB/IR)
    void D435iCamera::project(const rs2::frame & depth_frame, cv::Mat & xyz_map) {
        const uint16_t * depth_data = (const uint16_t *)depth_frame.get_data();

        rs2_intrinsics * dIntrin = &depthIntrinsics;

        const uint16_t * srcPtr;
        cv::Vec3f * destPtr;
        float srcPixel[2], destXYZ[3];

        for (int r = 0; r < height; ++r)
        {
            srcPtr = depth_data + r * dIntrin->width;
            destPtr = xyz_map.ptr<Vec3f>(r);
            srcPixel[1] = r;

            for (int c = 0; c < width; ++c)
            {
                if (srcPtr[c] == 0) {
                    memset(&destPtr[c], 0, 3 * sizeof(float));
                    continue;
                }
                srcPixel[0] = c;
                rs2_deproject_pixel_to_point(destXYZ, dIntrin, srcPixel, srcPtr[c]);
                memcpy(&destPtr[c], destXYZ, 3 * sizeof(float));
            }
        }
    }

    const rs2_intrinsics &D435iCamera::getDepthIntrinsics() {
        return depthIntrinsics;
    }

    double D435iCamera::getDepthScale() {
        return scale;
    }
}
<|endoftext|>


<commit_before>//sys_init_policy.hpp    chromatic universe 2017-2020  william k. johnson

#include <memory>
#include <string>

//contrib
#include "ace/Log_Msg.h"
#include "ace/Trace.h"

//cci
#include <cci_time_utils.h>
#include <cci_daemonize.h>

using namespace cpp_real_stream;

namespace cci_policy
{

        //
	//system init policies
	//
	template<typename T>
	class runtime_sys_init
	{

		public :

			//ctor
			runtime_sys_init( T meta ) : m_tutils( std::make_unique<time_utils>() ) ,
						     m_meta( meta )
			{}

		private :

			//attributes
			std::unique_ptr<std::string> 	m_runtime_data;
			std::unique_ptr<cpp_real_stream::time_utils> 	m_tutils;
			T 				m_meta;

		protected :

			//dtor
			~runtime_sys_init()
			{}

		public :

			//accessors-inspctiors
			std::string runtime_data() const noexcept { return *m_runtime_data.get(); }
			cpp_real_stream::time_utils_ptr _t() { return m_tutils.get(); }
			//mutators
			void runtime_data( std::unique_ptr<std::string>& data )
			{ m_runtime_data = std::move( data ); }

			//services
			void configure_init ( T meta )
			{

				cci_daemonize::daemon_proc dp = cci_daemonize::daemon_proc::dp_fork_background_proc;

				ACE_TRACE ("runtime_sys_init::configure_init");

				while( dp != cci_daemonize::daemon_proc::dp_error )
				{
					switch( dp  )
					{

					    case cci_daemonize::daemon_proc::dp_fork_background_proc :
					    {

                            //become background process
                            switch( fork() )
                            {
                                case -1 :
                                dp = cci_daemonize::daemon_proc::dp_error;
                                break;
                                case  0 :
                                dp = cci_daemonize::daemon_proc::dp_make_session_leader;
                                break;
                                default:
                                _exit( EXIT_SUCCESS );
                            }
                            break;
					    }
					    case cci_daemonize::daemon_proc::dp_make_session_leader :
					    {
                            //become leader of new session
                            setsid() == -1 ? dp = cci_daemonize::daemon_proc::dp_error :
                                                                    dp = cci_daemonize::daemon_proc::dp_fork_no_session_leader;
                            break;
					    }
					    case cci_daemonize::daemon_proc::dp_fork_no_session_leader :
					    {
                            //ensure we are not session leader
                            switch( fork() )
                            {
                                case -1 :
                                dp = cci_daemonize::daemon_proc::dp_error;
                                break;
                                case  0 :
                                dp = cci_daemonize::daemon_proc::dp_daemonized;						break;
                                default:
                                _exit( EXIT_SUCCESS );
                            }
                            break;
					    }
                        default :
                            break;
					}
					if ( dp == cci_daemonize::daemon_proc::dp_daemonized ) { break; }
				}
			}

	};
	//
	template<typename T>
	class custom_sys_init
	{
		private :

			//attributes
			std::unique_ptr<std::string> 	m_runtime_data;

		protected :

			//dtor
			~custom_sys_init()
			{}

		public :

			//accessors-inspctiors
			std::string runtime_data() const noexcept { return *m_runtime_data.get(); }

			//services
			void configure_init()
			{
				//
			}
	};

}
<commit_msg>evening<commit_after>//sys_init_policy.hpp    william k. johnon    2020

#include <memory>
#include <string>

//contrib
#include "ace/Log_Msg.h"
#include "ace/Trace.h"

//cci
#include <cci_time_utils.h>
#include <cci_daemonize.h>

using namespace cpp_real_stream;

namespace cci_policy
{

        //
	//system init policies
	//
	template<typename T>
	class runtime_sys_init
	{

		public :

			//ctor
			runtime_sys_init( T meta ) : m_tutils( std::make_unique<time_utils>() ) ,
						     m_meta( meta )
			{}

		private :

			//attributes
			std::unique_ptr<std::string> 	m_runtime_data;
			std::unique_ptr<cpp_real_stream::time_utils> 	m_tutils;
			T 				m_meta;

		protected :

			//dtor
			~runtime_sys_init()
			{}

		public :

			//accessors-inspctiors
			std::string runtime_data() const noexcept { return *m_runtime_data.get(); }
			cpp_real_stream::time_utils_ptr _t() { return m_tutils.get(); }
			//mutators
			void runtime_data( std::unique_ptr<std::string>& data )
			{ m_runtime_data = std::move( data ); }

			//services
			void configure_init ( T meta )
			{

				cci_daemonize::daemon_proc dp = cci_daemonize::daemon_proc::dp_fork_background_proc;

				ACE_TRACE ("runtime_sys_init::configure_init");

				while( dp != cci_daemonize::daemon_proc::dp_error )
				{
					switch( dp  )
					{

					    case cci_daemonize::daemon_proc::dp_fork_background_proc :
					    {

						//become background process
						switch( fork() )
						{
						    case -1 :
							dp = cci_daemonize::daemon_proc::dp_error;
							break;
						    case  0 :
							dp = cci_daemonize::daemon_proc::dp_make_session_leader;
							break;
						    default:
							_exit( EXIT_SUCCESS );
						}
						break;
					    }
					    case cci_daemonize::daemon_proc::dp_make_session_leader :
					    {
						//become leader of new session
						setsid() == -1 ? dp = cci_daemonize::daemon_proc::dp_error :
                                                                dp = cci_daemonize::daemon_proc::dp_fork_no_session_leader;
						break;
					    }
					    case cci_daemonize::daemon_proc::dp_fork_no_session_leader :
					    {
						//ensure we are not session leader
						switch( fork() )
						{
						    case -1 :
							dp = cci_daemonize::daemon_proc::dp_error;
							break;
						    case  0 :
							dp = cci_daemonize::daemon_proc::dp_daemonized;						break;
						    default:
							_exit( EXIT_SUCCESS );
						}
						break;
					    }
					}
					if ( dp == cci_daemonize::daemon_proc::dp_daemonized ) { break; }
				}
			}

	};
	//
	template<typename T>
	class custom_sys_init
	{
		private :

			//attributes
			std::unique_ptr<std::string> 	m_runtime_data;

		protected :

			//dtor
			~custom_sys_init()
			{}

		public :

			//accessors-inspctiors
			std::string runtime_data() const noexcept { return *m_runtime_data.get(); }

			//services
			void configure_init()
			{
				//
			}
	};

}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Facebook, Inc.
 *
 * 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 <folly/portability/String.h>

#if !FOLLY_HAVE_MEMRCHR
extern "C" void* memrchr(const void* s, int c, size_t n) {
  for (auto p = ((const char*)s) + n - 1; p >= (const char*)s; p--) {
    if (*p == (char)c) {
      return (void*)p;
    }
  }
  return nullptr;
}
#endif

#if defined(_WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
extern "C" char* strndup(const char* a, size_t len) {
  auto neededLen = strlen(a);
  if (neededLen > len) {
    neededLen = len;
  }
  char* buf = (char*)malloc((neededLen + 1) * sizeof(char));
  if (!buf) {
    return nullptr;
  }
  memcpy(buf, a, neededLen);
  buf[neededLen] = '\0';
  return buf;
}
#endif

#ifdef _WIN32
extern "C" {
void bzero(void* s, size_t n) {
  memset(s, 0, n);
}

int strcasecmp(const char* a, const char* b) {
  return _stricmp(a, b);
}

int strncasecmp(const char* a, const char* b, size_t c) {
  return _strnicmp(a, b, c);
}

char* strtok_r(char* str, char const* delim, char** ctx) {
  return strtok_s(str, delim, ctx);
}
}
#endif
<commit_msg>Forgot to fix the guard for String.cpp<commit_after>/*
 * Copyright 2016 Facebook, Inc.
 *
 * 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 <folly/portability/String.h>

#if !FOLLY_HAVE_MEMRCHR
extern "C" void* memrchr(const void* s, int c, size_t n) {
  for (auto p = ((const char*)s) + n - 1; p >= (const char*)s; p--) {
    if (*p == (char)c) {
      return (void*)p;
    }
  }
  return nullptr;
}
#endif

#if defined(_WIN32) || defined(__FreeBSD__)
extern "C" char* strndup(const char* a, size_t len) {
  auto neededLen = strlen(a);
  if (neededLen > len) {
    neededLen = len;
  }
  char* buf = (char*)malloc((neededLen + 1) * sizeof(char));
  if (!buf) {
    return nullptr;
  }
  memcpy(buf, a, neededLen);
  buf[neededLen] = '\0';
  return buf;
}
#endif

#ifdef _WIN32
extern "C" {
void bzero(void* s, size_t n) {
  memset(s, 0, n);
}

int strcasecmp(const char* a, const char* b) {
  return _stricmp(a, b);
}

int strncasecmp(const char* a, const char* b, size_t c) {
  return _strnicmp(a, b, c);
}

char* strtok_r(char* str, char const* delim, char** ctx) {
  return strtok_s(str, delim, ctx);
}
}
#endif
<|endoftext|>


<commit_before>/*
** Copyright 2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QFile>
#include <rrd.h>
#include <sstream>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/rrd/exceptions/open.hh"
#include "com/centreon/broker/rrd/exceptions/update.hh"
#include "com/centreon/broker/rrd/lib.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::rrd;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
lib::lib() {}

/**
 *  Copy constructor.
 *
 *  @param[in] l Object to copy.
 */
lib::lib(lib const& l)
  : backend(l), _filename(l._filename), _metric(l._metric) {}

/**
 *  Destructor.
 */
lib::~lib() {}

/**
 *  Assignment operator.
 *
 *  @param[in] l Object to copy.
 *
 *  @return This object.
 */
lib& lib::operator=(lib const& l) {
  backend::operator=(l);
  _filename = l._filename;
  _metric = l._metric;
  return (*this);
}

/**
 *  @brief Initiates the bulk load of multiple commands.
 *
 *  With the librrd backend, this method does nothing.
 */
void lib::begin() {
  return ;
}

/**
 *  Close the RRD file.
 */
void lib::close() {
  _filename.clear();
  _metric.clear();
  return ;
}

/**
 *  @brief Commit transaction started with begin().
 *
 *  With the librrd backend, the method does nothing.
 */
void lib::commit() {
  return ;
}

/**
 *  Normalize a metric name.
 *
 *  @param[in] metric Metric name.
 *
 *  @return Normalized metric name.
 */
QString lib::normalize_metric_name(QString const& metric) {
  QString normalized(metric);
  normalized.replace('.', '-');
  normalized.replace(':', '-');
  normalized.replace(',', '-');
  normalized.replace('{', '-');
  normalized.replace('}', '-');
  normalized.replace('[', '-');
  normalized.replace(']', '-');
  normalized.replace(' ', '-');
  normalized.replace("/", "_slash");
  normalized.replace("\\", "_bslash");
  return (normalized);
}

/**
 *  Open a RRD file which already exists.
 *
 *  @param[in] filename Path to the RRD file.
 *  @param[in] metric   Metric name.
 */
void lib::open(QString const& filename,
               QString const& metric) {
  // Close previous file.
  this->close();

  // Check that the file exists.
  if (!QFile::exists(filename))
    throw (exceptions::open() << "RRD: file '"
             << filename << "' does not exist");

  // Remember information for further operations.
  _filename = filename;
  _metric = normalize_metric_name(metric);

  return ;
}

/**
 *  Open a RRD file and create it if it does not exists.
 *
 *  @param[in] filename Path to the RRD file.
 *  @param[in] metric   Metric name.
 *  @param[in] length   Number of recording in the RRD file.
 *  @param[in] from     Timestamp of the first record.
 *  @param[in] interval Time interval between each record.
 */
void lib::open(QString const& filename,
               QString const& metric,
               unsigned int length,
               time_t from,
               time_t interval) {
  logging::debug << logging::HIGH << "RRD: opening file '"
    << filename << "'";

  // Close previous file.
  this->close();

  // Remember informations for further operations.
  _filename = filename;
  _metric = normalize_metric_name(metric);

  /* Find step of RRD file if already existing. */
  /* XXX : why is it here ?
  rrd_info_t* rrdinfo(rrd_info_r(_filename));
  time_t interval_offset(0);
  for (rrd_info_t* tmp = rrdinfo; tmp; tmp = tmp->next)
    if (!strcmp(rrdinfo->key, "step"))
      if (interval < static_cast<time_t>(rrdinfo->value.u_cnt))
        interval_offset = rrdinfo->value.u_cnt / interval - 1;
  rrd_info_free(rrdinfo);
  */

  /* Remove previous file. */
  QFile::remove(_filename);

  /* Set parameters. */
  std::ostringstream ds_oss;
  std::ostringstream rra1_oss;
  std::ostringstream rra2_oss;
  ds_oss << "DS:" << _metric.toStdString() << ":GAUGE:" << interval << ":U:U";
  rra1_oss << "RRA:AVERAGE:0.5:1:" << length;
  rra2_oss << "RRA:AVERAGE:0.5:12:" << length;
  std::string ds(ds_oss.str());
  std::string rra1(rra1_oss.str());
  std::string rra2(rra2_oss.str());
  char const* argv[4];
  argv[0] = ds.c_str();
  argv[1] = rra1.c_str();
  argv[2] = rra2.c_str();
  argv[3] = NULL;

  /* Create RRD file. */
  rrd_clear_error();
  if (rrd_create_r(_filename.toStdString().c_str(),
        interval,
        from,
        sizeof(argv) / sizeof(*argv) - 1,
        argv))
    throw (exceptions::open() << "RRD: could not create file '"
             << _filename << "': " << rrd_get_error());
  // XXX : is tuning really needed ?

  return ;
}

/**
 *  Update the RRD file with new value.
 *
 *  @param[in] t     Timestamp of value.
 *  @param[in] value Associated value.
 */
void lib::update(time_t t, QString const& value) {
  logging::debug << logging::HIGH << "RRD: updating file";

  // Build argument string.
  std::string arg;
  {
    std::ostringstream oss;
    oss << t << ":" << value.toStdString();
    arg = oss.str();
  }

  // Set argument table.
  char const* argv[2];
  argv[0] = arg.c_str();
  argv[1] = NULL;

  // Update RRD file.
  rrd_clear_error();
  if (rrd_update_r(_filename.toStdString().c_str(),
        _metric.toStdString().c_str(),
        sizeof(argv) / sizeof(*argv) - 1,
        argv))
    throw (exceptions::update() << "RRD: failed to update value for " \
             "metric " << _metric << ": " << rrd_get_error());

  return ;
}
<commit_msg>Added locking to RRD files before update to avoid conflict with the rebuild process.<commit_after>/*
** Copyright 2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <errno.h>
#include <fcntl.h>
#include <QFile>
#include <rrd.h>
#include <sstream>
#include <string.h>
#include <unistd.h>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/rrd/exceptions/open.hh"
#include "com/centreon/broker/rrd/exceptions/update.hh"
#include "com/centreon/broker/rrd/lib.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::rrd;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
lib::lib() {}

/**
 *  Copy constructor.
 *
 *  @param[in] l Object to copy.
 */
lib::lib(lib const& l)
  : backend(l), _filename(l._filename), _metric(l._metric) {}

/**
 *  Destructor.
 */
lib::~lib() {}

/**
 *  Assignment operator.
 *
 *  @param[in] l Object to copy.
 *
 *  @return This object.
 */
lib& lib::operator=(lib const& l) {
  backend::operator=(l);
  _filename = l._filename;
  _metric = l._metric;
  return (*this);
}

/**
 *  @brief Initiates the bulk load of multiple commands.
 *
 *  With the librrd backend, this method does nothing.
 */
void lib::begin() {
  return ;
}

/**
 *  Close the RRD file.
 */
void lib::close() {
  _filename.clear();
  _metric.clear();
  return ;
}

/**
 *  @brief Commit transaction started with begin().
 *
 *  With the librrd backend, the method does nothing.
 */
void lib::commit() {
  return ;
}

/**
 *  Normalize a metric name.
 *
 *  @param[in] metric Metric name.
 *
 *  @return Normalized metric name.
 */
QString lib::normalize_metric_name(QString const& metric) {
  QString normalized(metric);
  normalized.replace('.', '-');
  normalized.replace(':', '-');
  normalized.replace(',', '-');
  normalized.replace('{', '-');
  normalized.replace('}', '-');
  normalized.replace('[', '-');
  normalized.replace(']', '-');
  normalized.replace(' ', '-');
  normalized.replace("/", "_slash");
  normalized.replace("\\", "_bslash");
  return (normalized);
}

/**
 *  Open a RRD file which already exists.
 *
 *  @param[in] filename Path to the RRD file.
 *  @param[in] metric   Metric name.
 */
void lib::open(QString const& filename,
               QString const& metric) {
  // Close previous file.
  this->close();

  // Check that the file exists.
  if (!QFile::exists(filename))
    throw (exceptions::open() << "RRD: file '"
             << filename << "' does not exist");

  // Remember information for further operations.
  _filename = filename;
  _metric = normalize_metric_name(metric);

  return ;
}

/**
 *  Open a RRD file and create it if it does not exists.
 *
 *  @param[in] filename Path to the RRD file.
 *  @param[in] metric   Metric name.
 *  @param[in] length   Number of recording in the RRD file.
 *  @param[in] from     Timestamp of the first record.
 *  @param[in] interval Time interval between each record.
 */
void lib::open(QString const& filename,
               QString const& metric,
               unsigned int length,
               time_t from,
               time_t interval) {
  logging::debug << logging::HIGH << "RRD: opening file '"
    << filename << "'";

  // Close previous file.
  this->close();

  // Remember informations for further operations.
  _filename = filename;
  _metric = normalize_metric_name(metric);

  /* Find step of RRD file if already existing. */
  /* XXX : why is it here ?
  rrd_info_t* rrdinfo(rrd_info_r(_filename));
  time_t interval_offset(0);
  for (rrd_info_t* tmp = rrdinfo; tmp; tmp = tmp->next)
    if (!strcmp(rrdinfo->key, "step"))
      if (interval < static_cast<time_t>(rrdinfo->value.u_cnt))
        interval_offset = rrdinfo->value.u_cnt / interval - 1;
  rrd_info_free(rrdinfo);
  */

  /* Remove previous file. */
  QFile::remove(_filename);

  /* Set parameters. */
  std::ostringstream ds_oss;
  std::ostringstream rra1_oss;
  std::ostringstream rra2_oss;
  ds_oss << "DS:" << _metric.toStdString() << ":GAUGE:" << interval << ":U:U";
  rra1_oss << "RRA:AVERAGE:0.5:1:" << length;
  rra2_oss << "RRA:AVERAGE:0.5:12:" << length;
  std::string ds(ds_oss.str());
  std::string rra1(rra1_oss.str());
  std::string rra2(rra2_oss.str());
  char const* argv[4];
  argv[0] = ds.c_str();
  argv[1] = rra1.c_str();
  argv[2] = rra2.c_str();
  argv[3] = NULL;

  /* Create RRD file. */
  rrd_clear_error();
  if (rrd_create_r(_filename.toStdString().c_str(),
        interval,
        from,
        sizeof(argv) / sizeof(*argv) - 1,
        argv))
    throw (exceptions::open() << "RRD: could not create file '"
             << _filename << "': " << rrd_get_error());
  // XXX : is tuning really needed ?

  return ;
}

/**
 *  Update the RRD file with new value.
 *
 *  @param[in] t     Timestamp of value.
 *  @param[in] value Associated value.
 */
void lib::update(time_t t, QString const& value) {
  logging::debug << logging::HIGH << "RRD: updating file";

  // Build argument string.
  std::string arg;
  {
    std::ostringstream oss;
    oss << t << ":" << value.toStdString();
    arg = oss.str();
  }

  // Set argument table.
  char const* argv[2];
  argv[0] = arg.c_str();
  argv[1] = NULL;

  // Update RRD file.
  int fd(::open(_filename.toStdString().c_str(), O_WRONLY));
  if (fd < 0) {
    char const* msg(strerror(errno));
    logging::error << logging::MEDIUM << "RRD: could not open file '"
      << _filename << "': " << msg;
  }
  else {
    try {
      // Set lock.
      flock fl;
      memset(&fl, 0, sizeof(fl));
      fl.l_type = F_WRLCK;
      fl.l_whence = SEEK_SET;
      if (-1 == fcntl(fd, F_SETLK, &fl)) {
        char const* msg(strerror(errno));
        logging::error << logging::MEDIUM << "RRD: could not lock file '"
          << _filename << "': " << msg;
      }
      else {
        rrd_clear_error();
        if (rrd_update_r(_filename.toStdString().c_str(),
              _metric.toStdString().c_str(),
              sizeof(argv) / sizeof(*argv) - 1,
              argv))
          throw (exceptions::update()
                   << "RRD: failed to update value for metric "
                   << _metric << ": " << rrd_get_error());
      }
    }
    catch (...) {
      ::close(fd);
      throw ;
    }
    ::close(fd);
  }

  return ;
}
<|endoftext|>


<commit_before>//=============================================================================================================
/**
* @file     main.cpp
* @author   Daniel Strohmeier <daniel.strohmeier@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     March, 2018
*
* @section  LICENSE
*
* Copyright (C) 2018, Daniel Strohmeier and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Example of the computation of spectra, PSD and CSD
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <math.h>
#include <disp/plot.h>
#include <utils/spectral.h>
#include <mne/mne.h>

//*************************************************************************************************************
//=============================================================================================================
// Eigen
//=============================================================================================================

#include <Eigen/Core>

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QApplication>
#include <QtMath>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace Eigen;
using namespace DISPLIB;
using namespace UTILSLIB;

//*************************************************************************************************************
//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // Generate input data
    int iNSamples = 500;
    MatrixXd inputData = MatrixXd::Random(2, iNSamples);
    for (int n = 0; n < iNSamples; n++) {
        inputData(0, n) += 10.0 * sin(2.0 * M_PI *  10. * n / iNSamples );
        inputData(0, n) += 10.0 * sin(2.0 * M_PI * 100. * n / iNSamples);
        inputData(0, n) += 10.0 * sin(2.0 * M_PI * 200. * n / iNSamples);

        inputData(1, n) += 10.0 * sin(2.0 * M_PI *  50. * n / iNSamples);
        inputData(1, n) += 10.0 * sin(2.0 * M_PI * 100. * n / iNSamples);
        inputData(1, n) += 10.0 * sin(2.0 * M_PI * 150. * n / iNSamples);
    }

    //Generate hanning window
    QPair<MatrixXd, VectorXd> tapers = Spectral::generateTapers(iNSamples, "hanning");
    MatrixXd matTaps = tapers.first;
    VectorXd vecTapWeights = tapers.second;

    //Plot hanning window
    VectorXd hann = matTaps.row(0).transpose();
    Plot plotWindow(hann);
    plotWindow.setTitle("Hanning window");
    plotWindow.setXLabel("X Axes");
    plotWindow.setYLabel("Y Axes");
    plotWindow.setWindowTitle("Corresponding function to MATLABs plot");
    plotWindow.show();

    //Compute Spectrum of first row of input data
    int iNfft = iNSamples;
    MatrixXcd matTapSpectrumSeed = Spectral::computeTaperedSpectra(inputData.row(0), matTaps, iNfft);

    //Compute PSD
    RowVectorXd vecPsd = Spectral::psdFromTaperedSpectra(matTapSpectrumSeed, vecTapWeights, iNfft);

    //Plot PSD
    VectorXd psd = vecPsd.transpose();
    Plot plotPsd(psd);
    plotPsd.setTitle("PSD of Row 0");
    plotPsd.setXLabel("X Axes");
    plotPsd.setYLabel("Y Axes");
    plotPsd.setWindowTitle("Corresponding function to MATLABs plot");
    plotPsd.show();

    //Check PSD
    VectorXd psdTest = matTapSpectrumSeed.row(0).cwiseAbs2().transpose() / double(iNfft);
    psdTest *= 2.0;
    psdTest(0) /= 2.0;
    if (iNfft % 2 == 0){
        psdTest.tail(1) /= 2.0;
    }

    //Plot PSDTest
    Plot plotPsdTest(psdTest);
    plotPsdTest.setTitle("PSD of Row 0");
    plotPsdTest.setXLabel("X Axes");
    plotPsdTest.setYLabel("Y Axes");
    plotPsdTest.setWindowTitle("Corresponding function to MATLABs plot");
    plotPsdTest.show();

    //Compute CSD of matTapSpectrumSeed and matTapSpectrumSeed
    //The real part should be equivalent to the PSD of matTapSpectrumSeed)
    RowVectorXcd vecCsdSeed = Spectral::csdFromTaperedSpectra(matTapSpectrumSeed, matTapSpectrumSeed, vecTapWeights, vecTapWeights, iNfft);
    VectorXd psdTest2 = vecCsdSeed.real();

    //Plot PSDTest2
    Plot plotPsdTest2(psdTest2);
    plotPsdTest2.setTitle("PSD of Row 0");
    plotPsdTest2.setXLabel("X Axes");
    plotPsdTest2.setYLabel("Y Axes");
    plotPsdTest2.setWindowTitle("Corresponding function to MATLABs plot");
    plotPsdTest2.show();

    //Check energy
    RowVectorXd data_hann = inputData.row(0).cwiseProduct(matTaps.row(0));
    qDebug()<<"data0 energy"<<data_hann.row(0).cwiseAbs2().sum();
    qDebug()<<"sum psd"<<psd.sum();
    qDebug()<<"sum psdTest"<<psdTest.sum();
    qDebug()<<"sum psdTest2"<<psdTest2.sum();

    //Compute Spectrum of second row of input data
    MatrixXcd matTapSpectrumTarget = Spectral::computeTaperedSpectra(inputData.row(1), matTaps, iNfft);

    //Compute CSD between seed and target
    RowVectorXcd vecCsd = Spectral::csdFromTaperedSpectra(matTapSpectrumSeed, matTapSpectrumTarget, vecTapWeights, vecTapWeights, iNfft);

    //Plot real part of CSD
    VectorXd csd = vecCsd.transpose().real();
    Plot plotCsd(csd);
    plotCsd.setTitle("Real part of the CSD of Row 0 and 1");
    plotCsd.setXLabel("X Axes");
    plotCsd.setYLabel("Y Axes");
    plotCsd.setWindowTitle("Corresponding function to MATLABs plot");
    plotCsd.show();

    return a.exec();
}
<commit_msg>example<commit_after>//=============================================================================================================
/**
* @file     main.cpp
* @author   Daniel Strohmeier <daniel.strohmeier@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     March, 2018
*
* @section  LICENSE
*
* Copyright (C) 2018, Daniel Strohmeier and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Example of the computation of spectra, PSD and CSD
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <math.h>
#include <disp/plot.h>
#include <utils/spectral.h>
#include <mne/mne.h>

//*************************************************************************************************************
//=============================================================================================================
// Eigen
//=============================================================================================================

#include <Eigen/Core>

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QApplication>
#include <QtMath>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace Eigen;
using namespace DISPLIB;
using namespace UTILSLIB;

//*************************************************************************************************************
//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // Generate input data
    int iNSamples = 500;
    double dSampFreq = 23.0;
    MatrixXd inputData = MatrixXd::Random(2, iNSamples);
    for (int n = 0; n < iNSamples; n++) {
        inputData(0, n) += 10.0 * sin(2.0 * M_PI *  10. * n / iNSamples );
        inputData(0, n) += 10.0 * sin(2.0 * M_PI * 100. * n / iNSamples);
        inputData(0, n) += 10.0 * sin(2.0 * M_PI * 200. * n / iNSamples);

        inputData(1, n) += 10.0 * sin(2.0 * M_PI *  50. * n / iNSamples);
        inputData(1, n) += 10.0 * sin(2.0 * M_PI * 100. * n / iNSamples);
        inputData(1, n) += 10.0 * sin(2.0 * M_PI * 150. * n / iNSamples);
    }

    //Generate hanning window
    QPair<MatrixXd, VectorXd> tapers = Spectral::generateTapers(iNSamples, "hanning");
    MatrixXd matTaps = tapers.first;
    VectorXd vecTapWeights = tapers.second;

    //Plot hanning window
    VectorXd hann = matTaps.row(0).transpose();
    Plot plotWindow(hann);
    plotWindow.setTitle("Hanning window");
    plotWindow.setXLabel("X Axes");
    plotWindow.setYLabel("Y Axes");
    plotWindow.setWindowTitle("Corresponding function to MATLABs plot");
    plotWindow.show();

    //Compute Spectrum of first row of input data
    int iNfft = iNSamples;
    MatrixXcd matTapSpectrumSeed = Spectral::computeTaperedSpectra(inputData.row(0), matTaps, iNfft);

    //Compute PSD
    RowVectorXd vecPsd = Spectral::psdFromTaperedSpectra(matTapSpectrumSeed, vecTapWeights, iNfft, dSampFreq);

    //Plot PSD
    VectorXd psd = vecPsd.transpose();
    Plot plotPsd(psd);
    plotPsd.setTitle("PSD of Row 0");
    plotPsd.setXLabel("X Axes");
    plotPsd.setYLabel("Y Axes");
    plotPsd.setWindowTitle("Corresponding function to MATLABs plot");
    plotPsd.show();

    //Check PSD
    VectorXd psdTest = matTapSpectrumSeed.row(0).cwiseAbs2().transpose();
    psdTest *= 2.0;
    psdTest(0) /= 2.0;
    if (iNfft % 2 == 0){
        psdTest.tail(1) /= 2.0;
    }
    //Normalization
    psdTest /= dSampFreq;

    //Plot PSDTest
    Plot plotPsdTest(psdTest);
    plotPsdTest.setTitle("PSD of Row 0");
    plotPsdTest.setXLabel("X Axes");
    plotPsdTest.setYLabel("Y Axes");
    plotPsdTest.setWindowTitle("Corresponding function to MATLABs plot");
    plotPsdTest.show();

    //Compute CSD of matTapSpectrumSeed and matTapSpectrumSeed
    //The real part should be equivalent to the PSD of matTapSpectrumSeed)
    RowVectorXcd vecCsdSeed = Spectral::csdFromTaperedSpectra(matTapSpectrumSeed, matTapSpectrumSeed, vecTapWeights, vecTapWeights, iNfft, dSampFreq);
    VectorXd psdTest2 = vecCsdSeed.real();

    //Plot PSDTest2
    Plot plotPsdTest2(psdTest2);
    plotPsdTest2.setTitle("PSD of Row 0");
    plotPsdTest2.setXLabel("X Axes");
    plotPsdTest2.setYLabel("Y Axes");
    plotPsdTest2.setWindowTitle("Corresponding function to MATLABs plot");
    plotPsdTest2.show();

    //Check that sums of different psds of the same signal are equal
    qDebug()<<psd.sum();
    qDebug()<<psdTest.sum();
    qDebug()<<psdTest2.sum();
    RowVectorXd data_hann = inputData.row(0).cwiseProduct(matTaps.row(0));
    qDebug()<<data_hann.row(0).cwiseAbs2().sum() * double(iNSamples) / dSampFreq;

    //Compute Spectrum of second row of input data
    MatrixXcd matTapSpectrumTarget = Spectral::computeTaperedSpectra(inputData.row(1), matTaps, iNfft);

    //Compute CSD between seed and target
    RowVectorXcd vecCsd = Spectral::csdFromTaperedSpectra(matTapSpectrumSeed, matTapSpectrumTarget, vecTapWeights, vecTapWeights, iNfft, dSampFreq);

    //Plot real part of CSD
    VectorXd csd = vecCsd.transpose().real();
    Plot plotCsd(csd);
    plotCsd.setTitle("Real part of the CSD of Row 0 and 1");
    plotCsd.setXLabel("X Axes");
    plotCsd.setYLabel("Y Axes");
    plotCsd.setWindowTitle("Corresponding function to MATLABs plot");
    plotCsd.show();

    return a.exec();
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// Copyright (c) 2015 Michael G. Brehm
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//-----------------------------------------------------------------------------

#include "stdafx.h"
#include "Executable.h"

#include <cctype>
#include "LinuxException.h"

#pragma warning(push, 4)

// INTERPRETER_SCRIPT_MAGIC_ANSI
//
// Magic number present at the head of an ANSI interpreter script
static uint8_t INTERPRETER_SCRIPT_MAGIC_ANSI[] = { 0x23, 0x21 };

// INTERPRETER_SCRIPT_MAGIC_UTF8
//
// Magic number present at the head of a UTF-8 interpreter script
static uint8_t INTERPRETER_SCRIPT_MAGIC_UTF8[] = { 0xEF, 0xBB, 0xBF, 0x23, 0x21 };

//-----------------------------------------------------------------------------
// Executable Constructor (private)
//
// Arguments:
//
//	arch			- Executable architecture flag
//	format			- Executable binary format flag
//	originalpath	- Originally specified executable path
//	handle			- Handle instance open against the target file
//	arguments		- Processed command line arguments
//	environment		- Processed environment variables

Executable::Executable(enum class Architecture arch, enum class BinaryFormat format, const char_t* originalpath, std::shared_ptr<FileSystem::Handle> handle,
	string_vector_t&& arguments, string_vector_t&& environment) : m_architecture(arch), m_format(format), m_originalpath(originalpath),
	m_handle(std::move(handle)), m_arguments(std::move(arguments)), m_environment(std::move(environment))
{
}

//-----------------------------------------------------------------------------
// Executable::getArchitecture
//
// Gets the architecture flag for the executable

enum class Architecture Executable::getArchitecture(void) const
{
	return m_architecture;
}

//-----------------------------------------------------------------------------
// Executable::getFormat
//
// Gets the binary format of the executable

enum class BinaryFormat Executable::getFormat(void) const
{
	return m_format;
}

//-----------------------------------------------------------------------------
// Executable::FromFile (static)
//
// Creates an executable instance from a file system file
//
// Arguments:
//
//	ns				- Namespace in which to operate
//	root			- Root directory to assign to the process
//	current			- Working directory to assign to the process
//	path			- Path to the executable image

std::unique_ptr<Executable> Executable::FromFile(std::shared_ptr<class Namespace> ns, std::shared_ptr<FileSystem::Path> root,
	std::shared_ptr<FileSystem::Path> current, const char_t* path)
{
	if(path == nullptr) throw LinuxException{ LINUX_EFAULT };

	// Provide empty vectors for the arguments and environment variables
	return FromFile(std::move(ns), std::move(root), std::move(current), path, path, string_vector_t(), string_vector_t());
}

//-----------------------------------------------------------------------------
// Executable::FromFile (static)
//
// Creates an executable instance from a file system file
//
// Arguments:
//
//	ns				- Namespace in which to operate
//	root			- Root directory to assign to the process
//	current			- Working directory to assign to the process
//	path			- Path to the executable image
//	arguments		- Array of command-line arguments
//	environment		- Array of environment variables

std::unique_ptr<Executable> Executable::FromFile(std::shared_ptr<class Namespace> ns, std::shared_ptr<FileSystem::Path> root,
	std::shared_ptr<FileSystem::Path> current, const char_t* path, const char_t* const* arguments, const char_t* const* environment)
{
	if(path == nullptr) throw LinuxException{ LINUX_EFAULT };

	// Convert the C-style string arrays into vector<string> containers
	return FromFile(std::move(ns), std::move(root), std::move(current), path, path, StringArrayToVector(arguments), StringArrayToVector(environment));
}

//-----------------------------------------------------------------------------
// Executable::FromFile (private, static)
//
// Creates an executable instance from a file system file
//
// Arguments:
//
//	ns				- Namespace in which to operate
//	root			- Root directory to assign to the process
//	current			- Working directory to assign to the process
//	originalpath	- Original path provided for the executable
//	path			- Path to the executable image
//	arguments		- Vector of command-line arguments
//	environment		- Vector of environment variables

std::unique_ptr<Executable> Executable::FromFile(namespace_t ns, fspath_t root, fspath_t current, const char_t* originalpath,
	const char_t* path, string_vector_t&& arguments, string_vector_t&& environment)
{
	if(originalpath == nullptr) throw LinuxException{ LINUX_EFAULT };
	if(path == nullptr) throw LinuxException{ LINUX_EFAULT };

	// Acquire an execute-only handle for the provided path
	auto handle = FileSystem::OpenExecutable(ns, root, current, path);

	// Read in enough data from the beginning of the file to determine the executable type
	uint8_t magic[LINUX_EI_NIDENT];
	size_t read = handle->ReadAt(0, magic, LINUX_EI_NIDENT);

	// ELF BINARY
	//
	if((read >= LINUX_EI_NIDENT) && (memcmp(magic, LINUX_ELFMAG, LINUX_SELFMAG) == 0)) {

		// Move the file pointer back to the beginning of the file
		handle->Seek(0, LINUX_SEEK_SET);

		// This is a binary file, determine the architecture and complete the operation
		switch(magic[LINUX_EI_CLASS]) {

			// ELFCLASS32 --> Architecture::x86
			case LINUX_ELFCLASS32:
				return std::make_unique<Executable>(Architecture::x86, BinaryFormat::ELF, originalpath, std::move(handle), std::move(arguments), std::move(environment));
#ifdef _M_X64
			// ELFCLASS64: --> Architecture::x86_64
			case LINUX_ELFCLASS64:
				return std::make_unique<Executable>(Architecture::x86_64, BinaryFormat::ELF, originalpath, std::move(handle), std::move(arguments), std::move(environment));
#endif
			// Unknown ELFCLASS --> ENOEXEC
			default: throw LinuxException{ LINUX_ENOEXEC };
		}
	}

	// A.OUT BINARIES
	//
	// TODO - FUTURE (OMAGIC, NMAGIC, QMAGIC, etc)

	// INTERPRETER SCRIPT (UTF-8)
	//
	else if((read >= sizeof(INTERPRETER_SCRIPT_MAGIC_UTF8)) && (memcmp(magic, &INTERPRETER_SCRIPT_MAGIC_UTF8, sizeof(INTERPRETER_SCRIPT_MAGIC_UTF8)) == 0)) {

		return FromScript(std::move(ns), std::move(root), std::move(current), originalpath, std::move(handle), sizeof(INTERPRETER_SCRIPT_MAGIC_UTF8),
			std::move(arguments), std::move(environment));
	}

	// INTERPRETER SCRIPT (ANSI)
	//
	else if((read >= sizeof(INTERPRETER_SCRIPT_MAGIC_ANSI)) && (memcmp(magic, &INTERPRETER_SCRIPT_MAGIC_ANSI, sizeof(INTERPRETER_SCRIPT_MAGIC_ANSI)) == 0)) {

		return FromScript(std::move(ns), std::move(root), std::move(current), originalpath, std::move(handle), sizeof(INTERPRETER_SCRIPT_MAGIC_ANSI),
			std::move(arguments), std::move(environment));
	}

	// UNSUPPORTED FORMAT
	//
	else throw LinuxException{ LINUX_ENOEXEC };
}

//-----------------------------------------------------------------------------
// Executable::FromScript (private, static)
//
// Creates an executable instance from an interpreter script
//
// Arguments:
//
//	ns				- Namespace in which to operate
//	root			- Root directory to assign to the process
//	current			- Working directory to assign to the process
//	originalpath	- Original path provided for the executable
//	scripthandle	- Handle to the interpreter script
//	dataoffset		- Offset of data within the interpreter script
//	arguments		- Vector of command-line arguments
//	environment		- Vector of environment variables

std::unique_ptr<Executable> Executable::FromScript(namespace_t ns, fspath_t root, fspath_t current, const char_t* originalpath,
	fshandle_t scripthandle, size_t dataoffset, string_vector_t&& arguments, string_vector_t&& environment)
{
	char_t					buffer[MAX_PATH];			// Script data buffer

	if(originalpath == nullptr) throw LinuxException{ LINUX_EFAULT };

	char_t *begin, *end;					// String tokenizing pointers

	// Read up to MAX_PATH data from the interpreter script file
	char_t *eof = &buffer[0] + scripthandle->ReadAt(dataoffset, &buffer[0], sizeof(buffer));

	// Find the interperter path, if not present the script is not a valid target
	for(begin = &buffer[0]; (begin < eof) && (*begin) && (*begin != '\n') && (std::isspace(*begin)); begin++);
	for(end = begin; (end < eof) && (*end) && (*end != '\n') && (!std::isspace(*end)); end++);
	if(begin == end) throw LinuxException{ LINUX_ENOEXEC };
	std::string interpreter(begin, end);

	// Find the optional argument string that follows the interpreter path
	for(begin = end; (begin < eof) && (*begin) && (*begin != '\n') && (std::isspace(*begin)); begin++);
	for(end = begin; (end < eof) && (*end) && (*end != '\n') && (!std::isspace(*end)); end++);
	std::string argument(begin, end);

	// todo: recheck the old version, this doesn't look quite right, why am I replacing argv[0]
	// with the "filename" when it should already be set to that??
	(arguments);
	(environment);
	throw LinuxException{ LINUX_ENOEXEC };

	// [0] - INTERPRETER PATH
	// [1] - INTERPRETER ARGUMENTS	<--- document why this is in this slot if it's right
	// [2] - PATH_TO_SCRIPT			<--- shouldn't original argv[0] already have this?

	// [3] - ORIGINAL ARGV[1] ... [N]

	// OLD CODE HERE

	//// Create a new argument array to pass back in, using the parsed interpreter and argument
	//std::vector<const char_t*> newarguments;
	//newarguments.push_back(interpreter.c_str());
	//if(argument.length()) newarguments.push_back(argument.c_str());
	//newarguments.push_back(filename);

	//// Append the original argv[1] .. argv[n] pointers to the new argument array
	//if(arguments && (*arguments)) arguments++;
	//while((arguments) && (*arguments)) { newarguments.push_back(*arguments); arguments++; }
	//newarguments.push_back(nullptr);

	// Call back into FromFile with the interpreter path and modified arguments
	//return FromFile(ns, std::move(rootdir), std::move(workingdir), originalfilename, interpreter.c_str(), newarguments.data(), environment);
}

//-----------------------------------------------------------------------------
// Executable::getHandle
//
// Gets a reference to the handle instance opened for the executable

std::shared_ptr<FileSystem::Handle> Executable::getHandle(void) const
{
	return m_handle;
}

//-----------------------------------------------------------------------------
// Executable::getOriginalPath
//
// Gets the originally specified path of the executable

const char_t* Executable::getOriginalPath(void) const
{
	return m_originalpath.c_str();
}

//-----------------------------------------------------------------------------
// Executable::StringArrayToVector (static, private)
//
// Converts a null-terminated array of C-style strings into a vector<>
//
// Arguments:
//
//	strings		- Null-terminated array of C-style strings

Executable::string_vector_t Executable::StringArrayToVector(const char_t* const* strings)
{
	string_vector_t vec;
	while((strings) && (*strings)) { vec.push_back(*strings); strings++; }

	return vec;
}

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

#pragma warning(pop)
<commit_msg>Complete Executable::FromScript, the argument logic from the old version is indeed correct.  argv[0] is the target binary, followed optionally by the argument, followed by the original script path, followed by the previous argv[1..n]<commit_after>//-----------------------------------------------------------------------------
// Copyright (c) 2015 Michael G. Brehm
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//-----------------------------------------------------------------------------

#include "stdafx.h"
#include "Executable.h"

#include <cctype>
#include "LinuxException.h"

#pragma warning(push, 4)

// INTERPRETER_SCRIPT_MAGIC_ANSI
//
// Magic number present at the head of an ANSI interpreter script
static uint8_t INTERPRETER_SCRIPT_MAGIC_ANSI[] = { 0x23, 0x21 };

// INTERPRETER_SCRIPT_MAGIC_UTF8
//
// Magic number present at the head of a UTF-8 interpreter script
static uint8_t INTERPRETER_SCRIPT_MAGIC_UTF8[] = { 0xEF, 0xBB, 0xBF, 0x23, 0x21 };

//-----------------------------------------------------------------------------
// Executable Constructor (private)
//
// Arguments:
//
//	arch			- Executable architecture flag
//	format			- Executable binary format flag
//	originalpath	- Originally specified executable path
//	handle			- Handle instance open against the target file
//	arguments		- Processed command line arguments
//	environment		- Processed environment variables

Executable::Executable(enum class Architecture arch, enum class BinaryFormat format, const char_t* originalpath, std::shared_ptr<FileSystem::Handle> handle,
	string_vector_t&& arguments, string_vector_t&& environment) : m_architecture(arch), m_format(format), m_originalpath(originalpath),
	m_handle(std::move(handle)), m_arguments(std::move(arguments)), m_environment(std::move(environment))
{
}

//-----------------------------------------------------------------------------
// Executable::getArchitecture
//
// Gets the architecture flag for the executable

enum class Architecture Executable::getArchitecture(void) const
{
	return m_architecture;
}

//-----------------------------------------------------------------------------
// Executable::getFormat
//
// Gets the binary format of the executable

enum class BinaryFormat Executable::getFormat(void) const
{
	return m_format;
}

//-----------------------------------------------------------------------------
// Executable::FromFile (static)
//
// Creates an executable instance from a file system file
//
// Arguments:
//
//	ns				- Namespace in which to operate
//	root			- Root directory to assign to the process
//	current			- Working directory to assign to the process
//	path			- Path to the executable image

std::unique_ptr<Executable> Executable::FromFile(std::shared_ptr<class Namespace> ns, std::shared_ptr<FileSystem::Path> root,
	std::shared_ptr<FileSystem::Path> current, const char_t* path)
{
	if(path == nullptr) throw LinuxException{ LINUX_EFAULT };

	// Provide empty vectors for the arguments and environment variables
	return FromFile(std::move(ns), std::move(root), std::move(current), path, path, string_vector_t(), string_vector_t());
}

//-----------------------------------------------------------------------------
// Executable::FromFile (static)
//
// Creates an executable instance from a file system file
//
// Arguments:
//
//	ns				- Namespace in which to operate
//	root			- Root directory to assign to the process
//	current			- Working directory to assign to the process
//	path			- Path to the executable image
//	arguments		- Array of command-line arguments
//	environment		- Array of environment variables

std::unique_ptr<Executable> Executable::FromFile(std::shared_ptr<class Namespace> ns, std::shared_ptr<FileSystem::Path> root,
	std::shared_ptr<FileSystem::Path> current, const char_t* path, const char_t* const* arguments, const char_t* const* environment)
{
	if(path == nullptr) throw LinuxException{ LINUX_EFAULT };

	// Convert the C-style string arrays into vector<string> containers
	return FromFile(std::move(ns), std::move(root), std::move(current), path, path, StringArrayToVector(arguments), StringArrayToVector(environment));
}

//-----------------------------------------------------------------------------
// Executable::FromFile (private, static)
//
// Creates an executable instance from a file system file
//
// Arguments:
//
//	ns				- Namespace in which to operate
//	root			- Root directory to assign to the process
//	current			- Working directory to assign to the process
//	originalpath	- Original path provided for the executable
//	path			- Path to the executable image
//	arguments		- Vector of command-line arguments
//	environment		- Vector of environment variables

std::unique_ptr<Executable> Executable::FromFile(namespace_t ns, fspath_t root, fspath_t current, const char_t* originalpath,
	const char_t* path, string_vector_t&& arguments, string_vector_t&& environment)
{
	if(originalpath == nullptr) throw LinuxException{ LINUX_EFAULT };
	if(path == nullptr) throw LinuxException{ LINUX_EFAULT };

	// Acquire an execute-only handle for the provided path
	auto handle = FileSystem::OpenExecutable(ns, root, current, path);

	// Read in enough data from the beginning of the file to determine the executable type
	uint8_t magic[LINUX_EI_NIDENT];
	size_t read = handle->ReadAt(0, magic, LINUX_EI_NIDENT);

	// ELF BINARY
	//
	if((read >= LINUX_EI_NIDENT) && (memcmp(magic, LINUX_ELFMAG, LINUX_SELFMAG) == 0)) {

		// Move the file pointer back to the beginning of the file
		handle->Seek(0, LINUX_SEEK_SET);

		// This is a binary file, determine the architecture and complete the operation
		switch(magic[LINUX_EI_CLASS]) {

			// ELFCLASS32 --> Architecture::x86
			case LINUX_ELFCLASS32:
				return std::make_unique<Executable>(Architecture::x86, BinaryFormat::ELF, originalpath, std::move(handle), std::move(arguments), std::move(environment));
#ifdef _M_X64
			// ELFCLASS64: --> Architecture::x86_64
			case LINUX_ELFCLASS64:
				return std::make_unique<Executable>(Architecture::x86_64, BinaryFormat::ELF, originalpath, std::move(handle), std::move(arguments), std::move(environment));
#endif
			// Unknown ELFCLASS --> ENOEXEC
			default: throw LinuxException{ LINUX_ENOEXEC };
		}
	}

	// A.OUT BINARIES
	//
	// TODO - FUTURE (OMAGIC, NMAGIC, QMAGIC, etc)

	// INTERPRETER SCRIPT (UTF-8)
	//
	else if((read >= sizeof(INTERPRETER_SCRIPT_MAGIC_UTF8)) && (memcmp(magic, &INTERPRETER_SCRIPT_MAGIC_UTF8, sizeof(INTERPRETER_SCRIPT_MAGIC_UTF8)) == 0)) {

		return FromScript(std::move(ns), std::move(root), std::move(current), originalpath, std::move(handle), sizeof(INTERPRETER_SCRIPT_MAGIC_UTF8),
			std::move(arguments), std::move(environment));
	}

	// INTERPRETER SCRIPT (ANSI)
	//
	else if((read >= sizeof(INTERPRETER_SCRIPT_MAGIC_ANSI)) && (memcmp(magic, &INTERPRETER_SCRIPT_MAGIC_ANSI, sizeof(INTERPRETER_SCRIPT_MAGIC_ANSI)) == 0)) {

		return FromScript(std::move(ns), std::move(root), std::move(current), originalpath, std::move(handle), sizeof(INTERPRETER_SCRIPT_MAGIC_ANSI),
			std::move(arguments), std::move(environment));
	}

	// UNSUPPORTED FORMAT
	//
	else throw LinuxException{ LINUX_ENOEXEC };
}

//-----------------------------------------------------------------------------
// Executable::FromScript (private, static)
//
// Creates an executable instance from an interpreter script
//
// Arguments:
//
//	ns				- Namespace in which to operate
//	root			- Root directory to assign to the process
//	current			- Working directory to assign to the process
//	originalpath	- Original path provided for the executable
//	scripthandle	- Handle to the interpreter script
//	dataoffset		- Offset of data within the interpreter script
//	arguments		- Vector of command-line arguments
//	environment		- Vector of environment variables

std::unique_ptr<Executable> Executable::FromScript(namespace_t ns, fspath_t root, fspath_t current, const char_t* originalpath,
	fshandle_t scripthandle, size_t dataoffset, string_vector_t&& arguments, string_vector_t&& environment)
{
	char_t					buffer[MAX_PATH];			// Script data buffer
	string_vector_t			newarguments;				// New executable arguments

	if(originalpath == nullptr) throw LinuxException{ LINUX_EFAULT };

	char_t *begin, *end;					// String tokenizing pointers

	// Read up to MAX_PATH data from the interpreter script file
	char_t *eof = &buffer[0] + scripthandle->ReadAt(dataoffset, &buffer[0], sizeof(buffer));

	// Find the interperter path, if not present the script is not a valid target
	for(begin = &buffer[0]; (begin < eof) && (*begin) && (*begin != '\n') && (std::isspace(*begin)); begin++);
	for(end = begin; (end < eof) && (*end) && (*end != '\n') && (!std::isspace(*end)); end++);
	if(begin == end) throw LinuxException{ LINUX_ENOEXEC };
	std::string interpreter(begin, end);

	// Find the optional argument string that follows the interpreter path
	for(begin = end; (begin < eof) && (*begin) && (*begin != '\n') && (std::isspace(*begin)); begin++);
	for(end = begin; (end < eof) && (*end) && (*end != '\n') && (!std::isspace(*end)); end++);
	std::string argument(begin, end);

	// Create a new arguments vector for the target interpreter binary
	newarguments.push_back(interpreter);
	if(argument.length()) newarguments.push_back(std::move(argument));
	newarguments.emplace_back(originalpath);

	if(!arguments.empty()) {

		// Append the original argv[1] .. argv[n] arguments to the new vector (argv[0] is discarded if present)
		for(auto iterator = arguments.begin() + 1; iterator != arguments.end(); iterator++) newarguments.push_back(*iterator);
	}

	// Call back into FromFile with the interpreter binary as the target and new arguments
	return FromFile(ns, std::move(root), std::move(current), originalpath, interpreter.c_str(), std::move(newarguments), std::move(environment));
}

//-----------------------------------------------------------------------------
// Executable::getHandle
//
// Gets a reference to the handle instance opened for the executable

std::shared_ptr<FileSystem::Handle> Executable::getHandle(void) const
{
	return m_handle;
}

//-----------------------------------------------------------------------------
// Executable::getOriginalPath
//
// Gets the originally specified path of the executable

const char_t* Executable::getOriginalPath(void) const
{
	return m_originalpath.c_str();
}

//-----------------------------------------------------------------------------
// Executable::StringArrayToVector (static, private)
//
// Converts a null-terminated array of C-style strings into a vector<>
//
// Arguments:
//
//	strings		- Null-terminated array of C-style strings

Executable::string_vector_t Executable::StringArrayToVector(const char_t* const* strings)
{
	string_vector_t vec;
	while((strings) && (*strings)) { vec.push_back(*strings); strings++; }

	return vec;
}

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

#pragma warning(pop)
<|endoftext|>