<commit_before>/*
* Testing operating system specific wrapper code
* (C) 2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"
#include <botan/internal/os_utils.h>

// For __ud2 intrinsic
#if defined(BOTAN_TARGET_COMPILER_IS_MSVC)
   #include <intrin.h>
#endif

namespace Botan_Tests {

namespace {

/*
uint32_t get_process_id();
uint64_t get_cpu_cycle_counter();
uint64_t get_system_timestamp_ns();
size_t get_memory_locking_limit();
void* allocate_locked_pages(size_t length);
void free_locked_pages(void* ptr, size_t length);
int run_cpu_instruction_probe(std::function<int ()> probe_fn);
*/

class OS_Utils_Tests final : public Test
   {
   public:
      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;

         results.push_back(test_get_process_id());
         results.push_back(test_get_cpu_cycle_counter());
         results.push_back(test_get_high_resolution_clock());
         results.push_back(test_get_system_timestamp());
         results.push_back(test_memory_locking());
         results.push_back(test_cpu_instruction_probe());

         return results;
         }

   private:

      Test::Result test_get_process_id()
         {
         Test::Result result("OS::get_process_id");

         uint32_t pid1 = Botan::OS::get_process_id();
         uint32_t pid2 = Botan::OS::get_process_id();

         result.test_eq("PID same across calls", static_cast<size_t>(pid1), static_cast<size_t>(pid2));

#if defined(BOTAN_TARGET_OS_IS_INCLUDEOS) || defined(BOTAN_TARGET_OS_IS_LLVM)
         result.test_eq("PID is expected to be zero on this platform", pid1, size_t(0));
#else
         result.test_ne("PID is non-zero on systems with processes", pid1, 0);
#endif

         return result;
         }

      Test::Result test_get_cpu_cycle_counter()
         {
         Test::Result result("OS::get_cpu_cycle_counter");

         const uint64_t proc_ts1 = Botan::OS::get_cpu_cycle_counter();

         if(proc_ts1 == 0)
            {
            const uint64_t proc_ts2 = Botan::OS::get_cpu_cycle_counter();
            result.test_is_eq("Disabled processor timestamp stays at zero", proc_ts1, proc_ts2);
            return result;
            }

         size_t counts = 0;
         while(counts < 100 && (Botan::OS::get_cpu_cycle_counter() == proc_ts1))
            ++counts;

         result.test_lt("CPU cycle counter eventually changes value", counts, 10);

         return result;
         }

      Test::Result test_get_high_resolution_clock()
         {
         // TODO better tests

         Test::Result result("OS::get_high_resolution_clock");

         const uint64_t hr_ts1 = Botan::OS::get_high_resolution_clock();
         result.test_ne("high resolution timestamp value is never zero", hr_ts1, 0);

         size_t counts = 0;
         while(counts < 100 && (Botan::OS::get_high_resolution_clock() == hr_ts1))
            ++counts;

         result.test_lt("high resolution clock eventually changes value", counts, 128);

         return result;
         }

      Test::Result test_get_system_timestamp()
         {
         // TODO better tests
         Test::Result result("OS::get_system_timestamp_ns");

         uint64_t sys_ts1 = Botan::OS::get_system_timestamp_ns();
         result.test_ne("System timestamp value is never zero", sys_ts1, 0);

         // do something that consumes a little time
         Botan::OS::get_process_id();

         uint64_t sys_ts2 = Botan::OS::get_system_timestamp_ns();

         result.confirm("System time moves forward", sys_ts1 <= sys_ts2);

         return result;
         }

      Test::Result test_memory_locking()
         {
         Test::Result result("OS memory locked pages");

         // TODO any tests...

         return result;
         }

      Test::Result test_cpu_instruction_probe()
         {
         Test::Result result("OS::run_cpu_instruction_probe");

         // OS::run_cpu_instruction_probe only implemented for Unix signals or Windows SEH

         std::function<int ()> ok_fn = []() -> int { return 5; };
         const int run_rc = Botan::OS::run_cpu_instruction_probe(ok_fn);

         if(run_rc == -3)
            {
            result.test_note("run_cpu_instruction_probe not implemented on this platform");
            return {result};
            }

         result.confirm("Correct result returned by working probe fn", run_rc == 5);

         std::function<int ()> crash_probe;

#if defined(BOTAN_TARGET_COMPILER_IS_MSVC)
         crash_probe = []() -> int { __ud2(); return 3; };

#elif defined(BOTAN_USE_GCC_INLINE_ASM)

#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
         crash_probe = []() -> int { asm volatile("ud2"); return 3; };

#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
         //ARM: asm volatile (".word 0xf7f0a000\n");
         // illegal instruction in both ARM and Thumb modes
         crash_probe = []() -> int { asm volatile(".word 0xe7f0def0\n"); return 3; };

#else
         /*
         PPC: "The instruction with primary opcode 0, when the instruction does not consist
         entirely of binary zeros"
         Others ?
         */
#endif

#endif

         if(crash_probe)
            {
            const int crash_rc = Botan::OS::run_cpu_instruction_probe(crash_probe);
            result.confirm("Result for function executing undefined opcode", crash_rc < 0);
            }

         return result;
         }
   };

BOTAN_REGISTER_TEST("os_utils", OS_Utils_Tests);

}

}
<commit_msg>Make cpu cycle test a little more lax<commit_after>/*
* Testing operating system specific wrapper code
* (C) 2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"
#include <botan/internal/os_utils.h>

// For __ud2 intrinsic
#if defined(BOTAN_TARGET_COMPILER_IS_MSVC)
   #include <intrin.h>
#endif

namespace Botan_Tests {

namespace {

/*
uint32_t get_process_id();
uint64_t get_cpu_cycle_counter();
uint64_t get_system_timestamp_ns();
size_t get_memory_locking_limit();
void* allocate_locked_pages(size_t length);
void free_locked_pages(void* ptr, size_t length);
int run_cpu_instruction_probe(std::function<int ()> probe_fn);
*/

class OS_Utils_Tests final : public Test
   {
   public:
      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;

         results.push_back(test_get_process_id());
         results.push_back(test_get_cpu_cycle_counter());
         results.push_back(test_get_high_resolution_clock());
         results.push_back(test_get_system_timestamp());
         results.push_back(test_memory_locking());
         results.push_back(test_cpu_instruction_probe());

         return results;
         }

   private:

      Test::Result test_get_process_id()
         {
         Test::Result result("OS::get_process_id");

         uint32_t pid1 = Botan::OS::get_process_id();
         uint32_t pid2 = Botan::OS::get_process_id();

         result.test_eq("PID same across calls", static_cast<size_t>(pid1), static_cast<size_t>(pid2));

#if defined(BOTAN_TARGET_OS_IS_INCLUDEOS) || defined(BOTAN_TARGET_OS_IS_LLVM)
         result.test_eq("PID is expected to be zero on this platform", pid1, size_t(0));
#else
         result.test_ne("PID is non-zero on systems with processes", pid1, 0);
#endif

         return result;
         }

      Test::Result test_get_cpu_cycle_counter()
         {
         const size_t max_trials = 1024;
         const size_t max_repeats = 32;

         Test::Result result("OS::get_cpu_cycle_counter");

         const uint64_t proc_ts1 = Botan::OS::get_cpu_cycle_counter();

         if(proc_ts1 == 0)
            {
            const uint64_t proc_ts2 = Botan::OS::get_cpu_cycle_counter();
            result.test_is_eq("Disabled processor timestamp stays at zero", proc_ts1, proc_ts2);
            return result;
            }

         size_t counts = 0;
         while(counts < max_trials && (Botan::OS::get_cpu_cycle_counter() == proc_ts1))
            ++counts;

         result.test_lt("CPU cycle counter eventually changes value", counts, max_repeats);

         return result;
         }

      Test::Result test_get_high_resolution_clock()
         {
         const size_t max_trials = 1024;
         const size_t max_repeats = 128;

         Test::Result result("OS::get_high_resolution_clock");

         // TODO better tests
         const uint64_t hr_ts1 = Botan::OS::get_high_resolution_clock();
         result.test_ne("high resolution timestamp value is never zero", hr_ts1, 0);

         size_t counts = 0;
         while(counts < max_trials && (Botan::OS::get_high_resolution_clock() == hr_ts1))
            ++counts;

         result.test_lt("high resolution clock eventually changes value", counts, max_repeats);

         return result;
         }

      Test::Result test_get_system_timestamp()
         {
         // TODO better tests
         Test::Result result("OS::get_system_timestamp_ns");

         uint64_t sys_ts1 = Botan::OS::get_system_timestamp_ns();
         result.test_ne("System timestamp value is never zero", sys_ts1, 0);

         // do something that consumes a little time
         Botan::OS::get_process_id();

         uint64_t sys_ts2 = Botan::OS::get_system_timestamp_ns();

         result.confirm("System time moves forward", sys_ts1 <= sys_ts2);

         return result;
         }

      Test::Result test_memory_locking()
         {
         Test::Result result("OS memory locked pages");

         // TODO any tests...

         return result;
         }

      Test::Result test_cpu_instruction_probe()
         {
         Test::Result result("OS::run_cpu_instruction_probe");

         // OS::run_cpu_instruction_probe only implemented for Unix signals or Windows SEH

         std::function<int ()> ok_fn = []() -> int { return 5; };
         const int run_rc = Botan::OS::run_cpu_instruction_probe(ok_fn);

         if(run_rc == -3)
            {
            result.test_note("run_cpu_instruction_probe not implemented on this platform");
            return {result};
            }

         result.confirm("Correct result returned by working probe fn", run_rc == 5);

         std::function<int ()> crash_probe;

#if defined(BOTAN_TARGET_COMPILER_IS_MSVC)
         crash_probe = []() -> int { __ud2(); return 3; };

#elif defined(BOTAN_USE_GCC_INLINE_ASM)

#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
         crash_probe = []() -> int { asm volatile("ud2"); return 3; };

#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
         //ARM: asm volatile (".word 0xf7f0a000\n");
         // illegal instruction in both ARM and Thumb modes
         crash_probe = []() -> int { asm volatile(".word 0xe7f0def0\n"); return 3; };

#else
         /*
         PPC: "The instruction with primary opcode 0, when the instruction does not consist
         entirely of binary zeros"
         Others ?
         */
#endif

#endif

         if(crash_probe)
            {
            const int crash_rc = Botan::OS::run_cpu_instruction_probe(crash_probe);
            result.confirm("Result for function executing undefined opcode", crash_rc < 0);
            }

         return result;
         }
   };

BOTAN_REGISTER_TEST("os_utils", OS_Utils_Tests);

}

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/
#ifndef TIGHTDB_BINARY_DATA_HPP
#define TIGHTDB_BINARY_DATA_HPP

#include <cstddef>
#include <algorithm>
#include <ostream>

#include <tightdb/util/features.h>
#include <tightdb/utilities.hpp>

namespace tightdb {

/// A reference to a chunk of binary data.
///
/// This class does not own the referenced memory, nor does it in any
/// other way attempt to manage the lifetime of it.
///
/// \sa StringData
class BinaryData {
public:
    BinaryData() TIGHTDB_NOEXCEPT: m_data(0), m_size(0) {}
    BinaryData(const char* data, std::size_t size) TIGHTDB_NOEXCEPT: m_data(data), m_size(size) {}
    template<std::size_t N> explicit BinaryData(const char (&data)[N]): m_data(data), m_size(N) {}
    ~BinaryData() TIGHTDB_NOEXCEPT {}

    char operator[](std::size_t i) const TIGHTDB_NOEXCEPT { return m_data[i]; }

    const char* data() const TIGHTDB_NOEXCEPT { return m_data; }
    std::size_t size() const TIGHTDB_NOEXCEPT { return m_size; }

    friend bool operator==(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    friend bool operator!=(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;

    //@{
    /// Trivial bytewise lexicographical comparison.
    friend bool operator<(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    friend bool operator>(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    friend bool operator<=(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    friend bool operator>=(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    //@}

    bool begins_with(BinaryData) const TIGHTDB_NOEXCEPT;
    bool ends_with(BinaryData) const TIGHTDB_NOEXCEPT;
    bool contains(BinaryData) const TIGHTDB_NOEXCEPT;

    template<class C, class T>
    friend std::basic_ostream<C,T>& operator<<(std::basic_ostream<C,T>&, const BinaryData&);

protected:
    const char* m_data;
    std::size_t m_size;
};

// Implementation:

inline bool operator==(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return a.m_size == b.m_size && safe_equal(a.m_data, a.m_data + a.m_size, b.m_data);
}

inline bool operator!=(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return !(a == b);
}

inline bool operator<(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return std::lexicographical_compare(a.m_data, a.m_data + a.m_size,
                                        b.m_data, b.m_data + b.m_size);
}

inline bool operator>(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return b < a;
}

inline bool operator<=(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return !(b < a);
}

inline bool operator>=(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return !(a < b);
}

inline bool BinaryData::begins_with(BinaryData d) const TIGHTDB_NOEXCEPT
{
    return d.m_size <= m_size && safe_equal(m_data, m_data + d.m_size, d.m_data);
}

inline bool BinaryData::ends_with(BinaryData d) const TIGHTDB_NOEXCEPT
{
    return d.m_size <= m_size && safe_equal(m_data + m_size - d.m_size, m_data + m_size, d.m_data);
}

inline bool BinaryData::contains(BinaryData d) const TIGHTDB_NOEXCEPT
{
    return d.m_size == 0 ||
        std::search(m_data, m_data + m_size, d.m_data, d.m_data + d.m_size) != m_data + m_size;
}

template<class C, class T>
inline std::basic_ostream<C,T>& operator<<(std::basic_ostream<C,T>& out, const BinaryData& d)
{
    out << "BinaryData("<<static_cast<const void*>(d.m_data)<<", "<<d.m_size<<")";
    return out;
}

} // namespace tightdb

#endif // TIGHTDB_BINARY_DATA_HPP
<commit_msg>added set() method to binary data<commit_after>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/
#ifndef TIGHTDB_BINARY_DATA_HPP
#define TIGHTDB_BINARY_DATA_HPP

#include <cstddef>
#include <algorithm>
#include <ostream>

#include <tightdb/util/features.h>
#include <tightdb/utilities.hpp>

namespace tightdb {

/// A reference to a chunk of binary data.
///
/// This class does not own the referenced memory, nor does it in any
/// other way attempt to manage the lifetime of it.
///
/// \sa StringData
class BinaryData {
public:
    BinaryData() TIGHTDB_NOEXCEPT: m_data(0), m_size(0) {}
    BinaryData(const char* data, std::size_t size) TIGHTDB_NOEXCEPT: m_data(data), m_size(size) {}
    template<std::size_t N> explicit BinaryData(const char (&data)[N]): m_data(data), m_size(N) {}
    ~BinaryData() TIGHTDB_NOEXCEPT {}

    void set(const char* data, std::size_t size) { m_data = data; m_size = size; }
    char operator[](std::size_t i) const TIGHTDB_NOEXCEPT { return m_data[i]; }

    const char* data() const TIGHTDB_NOEXCEPT { return m_data; }
    std::size_t size() const TIGHTDB_NOEXCEPT { return m_size; }

    friend bool operator==(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    friend bool operator!=(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;

    //@{
    /// Trivial bytewise lexicographical comparison.
    friend bool operator<(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    friend bool operator>(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    friend bool operator<=(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    friend bool operator>=(const BinaryData&, const BinaryData&) TIGHTDB_NOEXCEPT;
    //@}

    bool begins_with(BinaryData) const TIGHTDB_NOEXCEPT;
    bool ends_with(BinaryData) const TIGHTDB_NOEXCEPT;
    bool contains(BinaryData) const TIGHTDB_NOEXCEPT;

    template<class C, class T>
    friend std::basic_ostream<C,T>& operator<<(std::basic_ostream<C,T>&, const BinaryData&);

protected:
    const char* m_data;
    std::size_t m_size;
};

// Implementation:

inline bool operator==(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return a.m_size == b.m_size && safe_equal(a.m_data, a.m_data + a.m_size, b.m_data);
}

inline bool operator!=(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return !(a == b);
}

inline bool operator<(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return std::lexicographical_compare(a.m_data, a.m_data + a.m_size,
                                        b.m_data, b.m_data + b.m_size);
}

inline bool operator>(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return b < a;
}

inline bool operator<=(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return !(b < a);
}

inline bool operator>=(const BinaryData& a, const BinaryData& b) TIGHTDB_NOEXCEPT
{
    return !(a < b);
}

inline bool BinaryData::begins_with(BinaryData d) const TIGHTDB_NOEXCEPT
{
    return d.m_size <= m_size && safe_equal(m_data, m_data + d.m_size, d.m_data);
}

inline bool BinaryData::ends_with(BinaryData d) const TIGHTDB_NOEXCEPT
{
    return d.m_size <= m_size && safe_equal(m_data + m_size - d.m_size, m_data + m_size, d.m_data);
}

inline bool BinaryData::contains(BinaryData d) const TIGHTDB_NOEXCEPT
{
    return d.m_size == 0 ||
        std::search(m_data, m_data + m_size, d.m_data, d.m_data + d.m_size) != m_data + m_size;
}

template<class C, class T>
inline std::basic_ostream<C,T>& operator<<(std::basic_ostream<C,T>& out, const BinaryData& d)
{
    out << "BinaryData("<<static_cast<const void*>(d.m_data)<<", "<<d.m_size<<")";
    return out;
}

} // namespace tightdb

#endif // TIGHTDB_BINARY_DATA_HPP
<|endoftext|>


<commit_before>#include "evdev.h"
#include "osdebugout.h"
#include <cassert>
#include <sstream>
#include "../hidproxy.h"
#include "qemu-usb/input-keymap-linux-to-qcode.h"

#ifdef USING_X11
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
extern Display *g_GSdsp;
extern Window g_GSwin;
#endif

namespace usb_hid { namespace evdev {

#define test_bit(nr, addr) \
	(((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
#define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)

bool FindHid(const std::string &evphys, std::string& hid_dev)
{
	int fd;
	int res;
	char buf[256];

	std::stringstream str;
	struct dirent* dp;

	DIR* dirp = opendir("/dev/input/");
	if(dirp == NULL) {
		perror("Error opening /dev/input/");
		return false;
	}

	while((dp = readdir(dirp)) != NULL)
	{
		if(strncmp(dp->d_name, "hidraw", 6) == 0) {
			OSDebugOut("%s\n", dp->d_name);

			str.clear(); str.str("");
			str << "/dev/input/" << dp->d_name;
			fd = open(str.str().c_str(), O_RDWR|O_NONBLOCK);

			if (fd < 0) {
				perror("Unable to open device");
				continue;
			}

			memset(buf, 0x0, sizeof(buf));
			//res = ioctl(fd, HIDIOCGRAWNAME(256), buf);

/*			res = ioctl(fd, HIDIOCGRAWPHYS(256), buf);
			if (res < 0)
				perror("HIDIOCGRAWPHYS");
			else
				OSDebugOut("Raw Phys: %s\n", buf);*/
			close(fd);
			if (evphys == buf) {
				closedir(dirp);
				hid_dev = str.str();
				return true;
			}
		}
	}
quit:
	closedir(dirp);
	return false;
}

int EvDev::TokenOut(const uint8_t *data, int len)
{
	return len;
}

int EvDev::Open()
{
	// Make sure there is atleast two types so we won't go beyond array length
	assert( (int)HIDTYPE_MOUSE == 1 );
	int t;
	std::stringstream name;
	char buf[1024];

	unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
	unsigned long absbit[NBITS(ABS_MAX)] = { 0 };

	memset(mAxisMap, -1, sizeof(mAxisMap));
	memset(mBtnMap, -1, sizeof(mBtnMap));

	mAxisCount = 0;
	mButtonCount = 0;
	mHandle = -1;

	std::string path;
	if (!LoadSetting(mDevType, mPort, APINAME, N_DEVICE, path))
	{
		OSDebugOut("Cannot load evdev hid device setting!\n");
		return 1;
	}

	if(path.empty() || !file_exists(path))
		goto quit;

	/*if (GetEvdevName(joypath, buf)) {
		name << buf;
		name << " (evdev)";
	}*/

	if ((mHandle = open(path.c_str(), O_RDWR | O_NONBLOCK)) < 0)
	{
		OSDebugOut("Cannot open device: %s\n", path.c_str());
		goto quit;
	}

/*	if ((ioctl(mHandle, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) &&
		(ioctl(mHandle, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0)) {
		// Probably isn't a evdev joystick
		SysMessage(APINAME ": Getting atleast some of the bits failed: %s\n", strerror(errno));
		goto quit;
	}*/

	/*unsigned int version;
	if (ioctl(mHandle, EVIOCGVERSION, &version) < 0)
	{
		SysMessage(APINAME ": Get version failed: %s\n", strerror(errno));
		return false;
	}*/

/*	for (int i = 0; i < KEY_MAX; ++i) {
		if (test_bit(i, keybit)) {
			OSDebugOut("Joystick has button: 0x%x\n", i);
			mBtnMap[i] = mButtonCount;
			++mButtonCount;
		}
	}*/

	if (!mReaderThreadIsRunning)
	{
		if (mReaderThread.joinable())
			mReaderThread.join();
		mReaderThread = std::thread(EvDev::ReaderThread, this);
	}
	return 0;

quit:
	Close();
	return 1;
}

int EvDev::Close()
{
	if (mHandle != -1)
		close(mHandle);

	mHandle = -1;
	return 0;
}

void EvDev::ReaderThread(void *ptr)
{
	ssize_t len;
	input_event events[32];

	EvDev *dev = static_cast<EvDev *>(ptr);
	HIDState *hs = dev->mHIDState;
	int32_t lastX = 0, lastY = 0;
	bool shift = false;
	bool grabbed = false;

	dev->mReaderThreadIsRunning = true;

	while (dev->mHandle != -1)
	{
		//Non-blocking read sets len to -1 and errno to EAGAIN if no new data
		while((len = read(dev->mHandle, &events, sizeof(events))) > -1)
		{
			InputEvent ev{};
			len /= sizeof(events[0]);
			for (int i = 0; i < len; i++)
			{
				input_event& event = events[i];
				switch (event.type)
				{
					case EV_ABS:
					{
						OSDebugOut("EV_ABS: %d, val: %d\n", event.code, event.value);

						if (dev->mHIDType == HIDTYPE_MOUSE) // usually mouse position is expected to be relative
							continue;

						if (!hs->ptr.eh_entry)
							continue;

						ev.type = INPUT_EVENT_KIND_ABS;
						if (event.code == ABS_X)
						{
							ev.u.abs.axis = INPUT_AXIS_X;
							ev.u.abs.value = event.value;
							hs->ptr.eh_entry(hs, &ev);
						}
						else if (event.code == ABS_Y)
						{
							ev.u.abs.axis = INPUT_AXIS_Y;
							ev.u.abs.value = event.value;
							hs->ptr.eh_entry(hs, &ev);
						}
					}
					break;
					case EV_REL:
					{
						OSDebugOut("EV_REL: %d, val: %d\n", event.code, event.value);
						if (!hs->ptr.eh_entry)
							continue;

						ev.type = INPUT_EVENT_KIND_REL;
						ev.u.rel.value = event.value;
						if (event.code == ABS_X)
						{
							ev.u.rel.axis = INPUT_AXIS_X;
							hs->ptr.eh_entry(hs, &ev);
						}
						else if (event.code == ABS_Y)
						{
							ev.u.rel.axis = INPUT_AXIS_X;
							hs->ptr.eh_entry(hs, &ev);
						}
					}
					break;
					case EV_KEY:
					{
						OSDebugOut("EV_KEY: 0x%02x (%d), val: %d\n", event.code, event.code, event.value);

#ifdef USING_X11 //FIXME not thread-safe
						if (event.code == KEY_LEFTSHIFT || event.code == KEY_RIGHTSHIFT)
							shift = (event.value > 0);

						if (event.code == KEY_F12 && (event.value == 1) && shift) {
							if (!grabbed) {
								grabbed = true;
								XGrabPointer(g_GSdsp, g_GSwin, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, g_GSwin, None, CurrentTime);
								XGrabKeyboard(g_GSdsp, g_GSwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
								// Hides globally :(
								XFixesHideCursor(g_GSdsp, g_GSwin);
							} else {
								grabbed = false;
								XUngrabPointer(g_GSdsp, CurrentTime);
								XUngrabKeyboard(g_GSdsp, CurrentTime);
								XFixesShowCursor(g_GSdsp, g_GSwin);
							}
						}
#endif

						if (hs->kbd.eh_entry) {

							QKeyCode qcode = Q_KEY_CODE_UNMAPPED;
							if (event.code < (uint16_t)qemu_input_map_linux_to_qcode_len)
								qcode = qemu_input_map_linux_to_qcode[event.code];

							if (event.value < 2) {
								ev.type = INPUT_EVENT_KIND_KEY;
								ev.u.key.down = (event.value == 1); // 2 if repeat
								ev.u.key.key.type = KEY_VALUE_KIND_QCODE;
								ev.u.key.key.u.qcode = qcode;

								hs->kbd.eh_entry(hs, &ev);
							}
						}

						if (hs->ptr.eh_entry) {
							ev.type = INPUT_EVENT_KIND_BTN;
							switch(event.code)
							{
								case BTN_LEFT:
									ev.u.btn.button = INPUT_BUTTON_LEFT;
									ev.u.btn.down = (event.value == 1);
									hs->ptr.eh_entry(hs, &ev);
								break;
								case BTN_RIGHT:
									ev.u.btn.button = INPUT_BUTTON_RIGHT;
									ev.u.btn.down = (event.value == 1);
									hs->ptr.eh_entry(hs, &ev);
								break;
								case BTN_MIDDLE:
									ev.u.btn.button = INPUT_BUTTON_MIDDLE;
									ev.u.btn.down = (event.value == 1);
									hs->ptr.eh_entry(hs, &ev);
								break;
								default:
								break;
							}
						}
					}
					break;
					case EV_SYN: //TODO useful?
					{
						OSDebugOut("EV_SYN: %d, val: %d\n", event.code, event.value);
						switch(event.code) {
							case SYN_REPORT:
								if (hs->ptr.eh_sync) //TODO sync here?
									hs->ptr.eh_sync(hs);
							break;
							case SYN_DROPPED:
								//restore last good state
							break;
						}
					}
					break;
					default:
					break;
				}
			}

			if (len < sizeof(input_event) && errno != EAGAIN)
			{
				OSDebugOut("%s: evdev read error %d\n", APINAME, errno);
				break;
			}
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
	OSDebugOut(TEXT("ReaderThread exited.\n"));

	dev->mReaderThreadIsRunning = false;
}

REGISTER_USBHID(APINAME, EvDev);
#undef APINAME

}} //namespace<commit_msg>Fix HID mouse's vertical axis<commit_after>#include "evdev.h"
#include "osdebugout.h"
#include <cassert>
#include <sstream>
#include "../hidproxy.h"
#include "qemu-usb/input-keymap-linux-to-qcode.h"

#ifdef USING_X11
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
extern Display *g_GSdsp;
extern Window g_GSwin;
#endif

namespace usb_hid { namespace evdev {

#define test_bit(nr, addr) \
	(((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
#define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)

bool FindHid(const std::string &evphys, std::string& hid_dev)
{
	int fd;
	int res;
	char buf[256];

	std::stringstream str;
	struct dirent* dp;

	DIR* dirp = opendir("/dev/input/");
	if(dirp == NULL) {
		perror("Error opening /dev/input/");
		return false;
	}

	while((dp = readdir(dirp)) != NULL)
	{
		if(strncmp(dp->d_name, "hidraw", 6) == 0) {
			OSDebugOut("%s\n", dp->d_name);

			str.clear(); str.str("");
			str << "/dev/input/" << dp->d_name;
			fd = open(str.str().c_str(), O_RDWR|O_NONBLOCK);

			if (fd < 0) {
				perror("Unable to open device");
				continue;
			}

			memset(buf, 0x0, sizeof(buf));
			//res = ioctl(fd, HIDIOCGRAWNAME(256), buf);

/*			res = ioctl(fd, HIDIOCGRAWPHYS(256), buf);
			if (res < 0)
				perror("HIDIOCGRAWPHYS");
			else
				OSDebugOut("Raw Phys: %s\n", buf);*/
			close(fd);
			if (evphys == buf) {
				closedir(dirp);
				hid_dev = str.str();
				return true;
			}
		}
	}
quit:
	closedir(dirp);
	return false;
}

int EvDev::TokenOut(const uint8_t *data, int len)
{
	return len;
}

int EvDev::Open()
{
	// Make sure there is atleast two types so we won't go beyond array length
	assert( (int)HIDTYPE_MOUSE == 1 );
	int t;
	std::stringstream name;
	char buf[1024];

	unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
	unsigned long absbit[NBITS(ABS_MAX)] = { 0 };

	memset(mAxisMap, -1, sizeof(mAxisMap));
	memset(mBtnMap, -1, sizeof(mBtnMap));

	mAxisCount = 0;
	mButtonCount = 0;
	mHandle = -1;

	std::string path;
	if (!LoadSetting(mDevType, mPort, APINAME, N_DEVICE, path))
	{
		OSDebugOut("Cannot load evdev hid device setting!\n");
		return 1;
	}

	if(path.empty() || !file_exists(path))
		goto quit;

	/*if (GetEvdevName(joypath, buf)) {
		name << buf;
		name << " (evdev)";
	}*/

	if ((mHandle = open(path.c_str(), O_RDWR | O_NONBLOCK)) < 0)
	{
		OSDebugOut("Cannot open device: %s\n", path.c_str());
		goto quit;
	}

/*	if ((ioctl(mHandle, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) &&
		(ioctl(mHandle, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0)) {
		// Probably isn't a evdev joystick
		SysMessage(APINAME ": Getting atleast some of the bits failed: %s\n", strerror(errno));
		goto quit;
	}*/

	/*unsigned int version;
	if (ioctl(mHandle, EVIOCGVERSION, &version) < 0)
	{
		SysMessage(APINAME ": Get version failed: %s\n", strerror(errno));
		return false;
	}*/

/*	for (int i = 0; i < KEY_MAX; ++i) {
		if (test_bit(i, keybit)) {
			OSDebugOut("Joystick has button: 0x%x\n", i);
			mBtnMap[i] = mButtonCount;
			++mButtonCount;
		}
	}*/

	if (!mReaderThreadIsRunning)
	{
		if (mReaderThread.joinable())
			mReaderThread.join();
		mReaderThread = std::thread(EvDev::ReaderThread, this);
	}
	return 0;

quit:
	Close();
	return 1;
}

int EvDev::Close()
{
	if (mHandle != -1)
		close(mHandle);

	mHandle = -1;
	return 0;
}

void EvDev::ReaderThread(void *ptr)
{
	ssize_t len;
	input_event events[32];

	EvDev *dev = static_cast<EvDev *>(ptr);
	HIDState *hs = dev->mHIDState;
	int32_t lastX = 0, lastY = 0;
	bool shift = false;
	bool grabbed = false;

	dev->mReaderThreadIsRunning = true;

	while (dev->mHandle != -1)
	{
		//Non-blocking read sets len to -1 and errno to EAGAIN if no new data
		while((len = read(dev->mHandle, &events, sizeof(events))) > -1)
		{
			InputEvent ev{};
			len /= sizeof(events[0]);
			for (int i = 0; i < len; i++)
			{
				input_event& event = events[i];
				switch (event.type)
				{
					case EV_ABS:
					{
						OSDebugOut("EV_ABS: %d, val: %d\n", event.code, event.value);

						if (dev->mHIDType == HIDTYPE_MOUSE) // usually mouse position is expected to be relative
							continue;

						if (!hs->ptr.eh_entry)
							continue;

						ev.type = INPUT_EVENT_KIND_ABS;
						if (event.code == ABS_X)
						{
							ev.u.abs.axis = INPUT_AXIS_X;
							ev.u.abs.value = event.value;
							hs->ptr.eh_entry(hs, &ev);
						}
						else if (event.code == ABS_Y)
						{
							ev.u.abs.axis = INPUT_AXIS_Y;
							ev.u.abs.value = event.value;
							hs->ptr.eh_entry(hs, &ev);
						}
					}
					break;
					case EV_REL:
					{
						OSDebugOut("EV_REL: %d, val: %d\n", event.code, event.value);
						if (!hs->ptr.eh_entry)
							continue;

						ev.type = INPUT_EVENT_KIND_REL;
						ev.u.rel.value = event.value;
						if (event.code == ABS_X)
						{
							ev.u.rel.axis = INPUT_AXIS_X;
							hs->ptr.eh_entry(hs, &ev);
						}
						else if (event.code == ABS_Y)
						{
							ev.u.rel.axis = INPUT_AXIS_Y;
							hs->ptr.eh_entry(hs, &ev);
						}
					}
					break;
					case EV_KEY:
					{
						OSDebugOut("EV_KEY: 0x%02x (%d), val: %d\n", event.code, event.code, event.value);

#ifdef USING_X11 //FIXME not thread-safe
						if (event.code == KEY_LEFTSHIFT || event.code == KEY_RIGHTSHIFT)
							shift = (event.value > 0);

						if (event.code == KEY_F12 && (event.value == 1) && shift) {
							if (!grabbed) {
								grabbed = true;
								XGrabPointer(g_GSdsp, g_GSwin, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, g_GSwin, None, CurrentTime);
								XGrabKeyboard(g_GSdsp, g_GSwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
								// Hides globally :(
								XFixesHideCursor(g_GSdsp, g_GSwin);
							} else {
								grabbed = false;
								XUngrabPointer(g_GSdsp, CurrentTime);
								XUngrabKeyboard(g_GSdsp, CurrentTime);
								XFixesShowCursor(g_GSdsp, g_GSwin);
							}
						}
#endif

						if (hs->kbd.eh_entry) {

							QKeyCode qcode = Q_KEY_CODE_UNMAPPED;
							if (event.code < (uint16_t)qemu_input_map_linux_to_qcode_len)
								qcode = qemu_input_map_linux_to_qcode[event.code];

							if (event.value < 2) {
								ev.type = INPUT_EVENT_KIND_KEY;
								ev.u.key.down = (event.value == 1); // 2 if repeat
								ev.u.key.key.type = KEY_VALUE_KIND_QCODE;
								ev.u.key.key.u.qcode = qcode;

								hs->kbd.eh_entry(hs, &ev);
							}
						}

						if (hs->ptr.eh_entry) {
							ev.type = INPUT_EVENT_KIND_BTN;
							switch(event.code)
							{
								case BTN_LEFT:
									ev.u.btn.button = INPUT_BUTTON_LEFT;
									ev.u.btn.down = (event.value == 1);
									hs->ptr.eh_entry(hs, &ev);
								break;
								case BTN_RIGHT:
									ev.u.btn.button = INPUT_BUTTON_RIGHT;
									ev.u.btn.down = (event.value == 1);
									hs->ptr.eh_entry(hs, &ev);
								break;
								case BTN_MIDDLE:
									ev.u.btn.button = INPUT_BUTTON_MIDDLE;
									ev.u.btn.down = (event.value == 1);
									hs->ptr.eh_entry(hs, &ev);
								break;
								default:
								break;
							}
						}
					}
					break;
					case EV_SYN: //TODO useful?
					{
						OSDebugOut("EV_SYN: %d, val: %d\n", event.code, event.value);
						switch(event.code) {
							case SYN_REPORT:
								if (hs->ptr.eh_sync) //TODO sync here?
									hs->ptr.eh_sync(hs);
							break;
							case SYN_DROPPED:
								//restore last good state
							break;
						}
					}
					break;
					default:
					break;
				}
			}

			if (len < sizeof(input_event) && errno != EAGAIN)
			{
				OSDebugOut("%s: evdev read error %d\n", APINAME, errno);
				break;
			}
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
	OSDebugOut(TEXT("ReaderThread exited.\n"));

	dev->mReaderThreadIsRunning = false;
}

REGISTER_USBHID(APINAME, EvDev);
#undef APINAME

}} //namespace<|endoftext|>


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

/**
 * @file mdiafwd.H
 * @brief internal mdia declarations
 */

#include <mdia/mdia.H>
#include <mdia/mdiareasoncodes.H>
#include <targeting/common/attributes.H>
#include <targeting/common/targetservice.H>
#include <vector>
#include <map>

/**
 * @brief forwards
 */
class MdiaSmTest;
class MdiaTest;
class MdiaMbaTest;
class MdiaCommandMonitorTest;
class MdiaTraceTest;
class MdiaWorkItemTest;

namespace MDIA
{

/**
 * forwards
 */
class StateMachine;
class WorkItem;
class CommandMonitor;
struct Globals;
struct WorkFlowProperties;

/**
 * @brief per mba diagnostic mode
 */
enum DiagMode
{
    ONE_PATTERN,
    FOUR_PATTERNS,
    NINE_PATTERNS,
};

/**
 * @brief misc constants
 */
enum
{

    // mcc dstlfir unit regs
    DSTLFIR                 = 0x0C010D00,
    DSTLFIR_MASK            = 0x0C010D03,
    DSTLFIR_ACT0            = 0x0C010D06,
    DSTLFIR_ACT1            = 0x0C010D07,
    DSTLCFG2                = 0x0C010D0E,

    // ocmb mcbist unit regs
    OCMB_MCBIST_FIR         = 0x08011800,
    OCMB_MCBIST_FIR_AND     = 0x08011801,
    OCMB_MCBIST_FIR_MASK    = 0x08011803,
    OCMB_MCBIST_FIR_ACT0    = 0x08011806,
    OCMB_MCBIST_FIR_ACT1    = 0x08011807,

    // ocmb omidlfir unit regs
    OMIDLFIR                = 0x07013340,
    OMIDLFIR_MASK           = 0x07013343,
    OMIDLFIR_ACT0           = 0x07013346,
    OMIDLFIR_ACT1           = 0x07013347,

    // proc regs
    IPOLL_MASK              = 0x000F0033,
    IPOLL_STATUS            = 0x000F0034,
    GLOBAL_CS_FIR           = 0x570F001C,
    GLOBAL_RE_FIR           = 0x570F001B,
    GLOBAL_UCS_FIR          = 0x570F002A,
    GLOBAL_HA_FIR           = 0x570F002B,

    // mc chiplet registers
    MC0_CHIPLET_HA_FIR      = 0x0C040004,
    MC0_CHIPLET_HA_FIR_MASK = 0x0C040044,
    MC1_CHIPLET_HA_FIR      = 0x0D040004,
    MC1_CHIPLET_HA_FIR_MASK = 0x0D040044,
    MC2_CHIPLET_HA_FIR      = 0x0E040004,
    MC2_CHIPLET_HA_FIR_MASK = 0x0E040044,
    MC3_CHIPLET_HA_FIR      = 0x0F040004,
    MC3_CHIPLET_HA_FIR_MASK = 0x0F040044,
};

/**
 * @brief workflow status
 */
enum WorkFlowStatus
{
    /**
     * @brief workflow in progress or hasn't started yet
     */
    IN_PROGRESS,

    /**
     * @brief indicates workflow stopped because a maint command timed out
     */
    COMMAND_TIMED_OUT,

    /**
     * @brief indicates workflow stopped because of a failure
     */
    FAILED,

    /**
     * @brief workflow finished
     */
    COMPLETE,
};

/**
* @brief Workflow container of workflow phases
*/
typedef std::vector<uint64_t> WorkFlow;

/**
* @brief WorkflowAssocMap target / workflow association map
*/
typedef std::map<TARGETING::TargetHandle_t, WorkFlow> WorkFlowAssocMap;

/**
* @brief WorkflowAssoc target / workflow association list element
*/
typedef WorkFlowAssocMap::const_iterator WorkFlowAssoc;

/**
* @brief MonitorIDs container of monitorIDs unique to a target
*/
typedef std::vector<uint64_t> MonitorIDs;

/**
 * @brief getDiagnosticMode get the mode (scrub, init, one, four, nine)
 *
 * @param[in] i_globals policy flags needed to determine the mode
 * @param[in] i_target the mba/mcbist target for which the mode is determined
 * @param[out] o_mode the mode for the target mba/mcbist
 *
 * @retval 0 no error
 * @retval !0 unexpected error occurred
 */
errlHndl_t getDiagnosticMode(
        const Globals & i_globals,
        TARGETING::TargetHandle_t i_trgt,
        DiagMode & o_mode);

/**
 * @brief getWorkFlow get the workflow for an mba/mcbist target
 *
 * @param[in] i_mode the diagnostic mode for the target
 * @param[out] o_wf the workflow for the mba/mcbist target
 * @param[in] i_globals policy flags needed to determine MNFG status
 *
 * @retval 0 no error
 * @retval !0 unexpected error occurred
 */
errlHndl_t getWorkFlow(
        DiagMode i_mode,
        WorkFlow & o_wf,
        const Globals & i_globals);

/**
 * @brief doStepCleanup shut down threads and pools on step exit
 *
 * @param[in] i_globals contains objects to be cleaned up
 *
 * @return nullptr on success; non-nullptr on error
 */
errlHndl_t doStepCleanup(const Globals & i_globals);

/**
 * @brief check if hw state has been changed for an mba
 *        or mcbist's associated targets
 *
 * @param[in] i_trgt input mba/mcbist target
 *
 * @retval true if hw state has been changed or else
 */
bool isHWStateChanged(TARGETING::TargetHandle_t i_trgt);

/**
 * @brief clear hw changed state for an mba
 *        or mcbist's associated targets
 *
 * @param[in] i_trgt input mba/mcbist target
 *
 */
void clearHWStateChanged(TARGETING::TargetHandle_t i_trgt);

}
#endif
<commit_msg>MDIA: Fix OMIDLFIR addr in timeout FFDC<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/diag/mdia/mdiafwd.H $                                 */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef __MDIA_MDIAFWD_H
#define __MDIA_MDIAFWD_H

/**
 * @file mdiafwd.H
 * @brief internal mdia declarations
 */

#include <mdia/mdia.H>
#include <mdia/mdiareasoncodes.H>
#include <targeting/common/attributes.H>
#include <targeting/common/targetservice.H>
#include <vector>
#include <map>

/**
 * @brief forwards
 */
class MdiaSmTest;
class MdiaTest;
class MdiaMbaTest;
class MdiaCommandMonitorTest;
class MdiaTraceTest;
class MdiaWorkItemTest;

namespace MDIA
{

/**
 * forwards
 */
class StateMachine;
class WorkItem;
class CommandMonitor;
struct Globals;
struct WorkFlowProperties;

/**
 * @brief per mba diagnostic mode
 */
enum DiagMode
{
    ONE_PATTERN,
    FOUR_PATTERNS,
    NINE_PATTERNS,
};

/**
 * @brief misc constants
 */
enum
{

    // mcc dstlfir unit regs
    DSTLFIR                 = 0x0C010D00,
    DSTLFIR_MASK            = 0x0C010D03,
    DSTLFIR_ACT0            = 0x0C010D06,
    DSTLFIR_ACT1            = 0x0C010D07,
    DSTLCFG2                = 0x0C010D0E,

    // ocmb mcbist unit regs
    OCMB_MCBIST_FIR         = 0x08011800,
    OCMB_MCBIST_FIR_AND     = 0x08011801,
    OCMB_MCBIST_FIR_MASK    = 0x08011803,
    OCMB_MCBIST_FIR_ACT0    = 0x08011806,
    OCMB_MCBIST_FIR_ACT1    = 0x08011807,

    // ocmb omidlfir unit regs
    OMIDLFIR                = 0x08012800,
    OMIDLFIR_MASK           = 0x08012803,
    OMIDLFIR_ACT0           = 0x08012806,
    OMIDLFIR_ACT1           = 0x08012807,

    // proc regs
    IPOLL_MASK              = 0x000F0033,
    IPOLL_STATUS            = 0x000F0034,
    GLOBAL_CS_FIR           = 0x570F001C,
    GLOBAL_RE_FIR           = 0x570F001B,
    GLOBAL_UCS_FIR          = 0x570F002A,
    GLOBAL_HA_FIR           = 0x570F002B,

    // mc chiplet registers
    MC0_CHIPLET_HA_FIR      = 0x0C040004,
    MC0_CHIPLET_HA_FIR_MASK = 0x0C040044,
    MC1_CHIPLET_HA_FIR      = 0x0D040004,
    MC1_CHIPLET_HA_FIR_MASK = 0x0D040044,
    MC2_CHIPLET_HA_FIR      = 0x0E040004,
    MC2_CHIPLET_HA_FIR_MASK = 0x0E040044,
    MC3_CHIPLET_HA_FIR      = 0x0F040004,
    MC3_CHIPLET_HA_FIR_MASK = 0x0F040044,
};

/**
 * @brief workflow status
 */
enum WorkFlowStatus
{
    /**
     * @brief workflow in progress or hasn't started yet
     */
    IN_PROGRESS,

    /**
     * @brief indicates workflow stopped because a maint command timed out
     */
    COMMAND_TIMED_OUT,

    /**
     * @brief indicates workflow stopped because of a failure
     */
    FAILED,

    /**
     * @brief workflow finished
     */
    COMPLETE,
};

/**
* @brief Workflow container of workflow phases
*/
typedef std::vector<uint64_t> WorkFlow;

/**
* @brief WorkflowAssocMap target / workflow association map
*/
typedef std::map<TARGETING::TargetHandle_t, WorkFlow> WorkFlowAssocMap;

/**
* @brief WorkflowAssoc target / workflow association list element
*/
typedef WorkFlowAssocMap::const_iterator WorkFlowAssoc;

/**
* @brief MonitorIDs container of monitorIDs unique to a target
*/
typedef std::vector<uint64_t> MonitorIDs;

/**
 * @brief getDiagnosticMode get the mode (scrub, init, one, four, nine)
 *
 * @param[in] i_globals policy flags needed to determine the mode
 * @param[in] i_target the mba/mcbist target for which the mode is determined
 * @param[out] o_mode the mode for the target mba/mcbist
 *
 * @retval 0 no error
 * @retval !0 unexpected error occurred
 */
errlHndl_t getDiagnosticMode(
        const Globals & i_globals,
        TARGETING::TargetHandle_t i_trgt,
        DiagMode & o_mode);

/**
 * @brief getWorkFlow get the workflow for an mba/mcbist target
 *
 * @param[in] i_mode the diagnostic mode for the target
 * @param[out] o_wf the workflow for the mba/mcbist target
 * @param[in] i_globals policy flags needed to determine MNFG status
 *
 * @retval 0 no error
 * @retval !0 unexpected error occurred
 */
errlHndl_t getWorkFlow(
        DiagMode i_mode,
        WorkFlow & o_wf,
        const Globals & i_globals);

/**
 * @brief doStepCleanup shut down threads and pools on step exit
 *
 * @param[in] i_globals contains objects to be cleaned up
 *
 * @return nullptr on success; non-nullptr on error
 */
errlHndl_t doStepCleanup(const Globals & i_globals);

/**
 * @brief check if hw state has been changed for an mba
 *        or mcbist's associated targets
 *
 * @param[in] i_trgt input mba/mcbist target
 *
 * @retval true if hw state has been changed or else
 */
bool isHWStateChanged(TARGETING::TargetHandle_t i_trgt);

/**
 * @brief clear hw changed state for an mba
 *        or mcbist's associated targets
 *
 * @param[in] i_trgt input mba/mcbist target
 *
 */
void clearHWStateChanged(TARGETING::TargetHandle_t i_trgt);

}
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "validationinterface.h"

static CMainSignals g_signals;

CMainSignals& GetMainSignals()
{
    return g_signals;
}

void RegisterValidationInterface(CValidationInterface* pwalletIn) {
    g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
    g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
    g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
    g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
    g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
    g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
    g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
    g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
    g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
}

void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
    g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
    g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
    g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
    g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
    g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
    g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
    g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
    g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
    g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
}

void UnregisterAllValidationInterfaces() {
    g_signals.BlockFound.disconnect_all_slots();
    g_signals.ScriptForMining.disconnect_all_slots();
    g_signals.BlockChecked.disconnect_all_slots();
    g_signals.Broadcast.disconnect_all_slots();
    g_signals.Inventory.disconnect_all_slots();
    g_signals.SetBestChain.disconnect_all_slots();
    g_signals.UpdatedTransaction.disconnect_all_slots();
    g_signals.SyncTransaction.disconnect_all_slots();
    g_signals.UpdatedBlockTip.disconnect_all_slots();
}

void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) {
    g_signals.SyncTransaction(tx, pindex, pblock);
}
<commit_msg>Added TXLock<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "validationinterface.h"

static CMainSignals g_signals;

CMainSignals& GetMainSignals()
{
    return g_signals;
}

void RegisterValidationInterface(CValidationInterface* pwalletIn) {
    g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
    g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
    g_signals.NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1));
    g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
    g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
    g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
    g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
    g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
    g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
    g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
}

void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
    g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
    g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
    g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
    g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
    g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
    g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
    g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
    g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
    g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
}

void UnregisterAllValidationInterfaces() {
    g_signals.BlockFound.disconnect_all_slots();
    g_signals.ScriptForMining.disconnect_all_slots();
    g_signals.BlockChecked.disconnect_all_slots();
    g_signals.Broadcast.disconnect_all_slots();
    g_signals.Inventory.disconnect_all_slots();
    g_signals.SetBestChain.disconnect_all_slots();
    g_signals.UpdatedTransaction.disconnect_all_slots();
    g_signals.NotifyTransactionLock.disconnect_all_slots();
    g_signals.SyncTransaction.disconnect_all_slots();
    g_signals.UpdatedBlockTip.disconnect_all_slots();
}

void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) {
    g_signals.SyncTransaction(tx, pindex, pblock);
}
<|endoftext|>


<commit_before>/*
 * SessionPanmirrorPubMed.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionPanmirrorPubMed.hpp"

#include <shared_core/Error.hpp>
#include <shared_core/json/Json.hpp>

#include <core/Exec.hpp>
#include <core/json/JsonRpc.hpp>
#include <core/http/Util.hpp>

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

#include "SessionPanmirrorUtils.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace panmirror {
namespace pubmed {

namespace {

const char * const kPubMedEUtilsHost = "https://eutils.ncbi.nlm.nih.gov";

struct PubMedDocument
{
   PubMedDocument(const std::string& doi = "") : doi(doi) {}
   bool empty() { return doi.empty(); }
   std::string doi;
   std::vector<std::string> pubTypes;
   std::string title;
   std::vector<std::string> authors;
   std::string lastAuthor;
   std::string source;
   std::string volume;
   std::string issue;
   std::string pubDate;
};

json::Object pubMedDocumentJson(const PubMedDocument& doc)
{
   // all fields are optional save for doi
   json::Object docJson;

   // doi (required)
   docJson["doi"] = doc.doi;

   // pubTypes
   if (doc.pubTypes.size() > 0)
   {
      json::Array pubTypesJson;
      for (auto pubType : doc.pubTypes)
         pubTypesJson.push_back(pubType);
      docJson["pubTypes"] = pubTypesJson;
   }

   // authors
   if (doc.authors.size() > 0)
   {
      json::Array authorsJson;
      for (auto author : doc.authors)
         authorsJson.push_back(author);
      docJson["authors"] = authorsJson;
   }

   // lastAuthor
   if (!doc.lastAuthor.empty())
      docJson["lastAuthor"] = doc.lastAuthor;

   // title
   if (!doc.title.empty())
      docJson["title"] = doc.title;

   // source
   if (!doc.source.empty())
   {
      docJson["source"] = doc.source;
      if (!doc.volume.empty())
         docJson["volume"] = doc.volume;
      if (!doc.issue.empty())
         docJson["issue"] = doc.issue;
   }

   // pubDate
   if (!doc.pubDate.empty())
      docJson["pubDate"] = doc.pubDate;

   return docJson;

}

PubMedDocument resultToPubMedDocument(json::Object resultJson)
{
   // look for doi (the only required field)
   std::string doi;
   const char * const kArticleIds = "articleids";
   if (resultJson.hasMember(kArticleIds) && resultJson[kArticleIds].isArray())
   {
     json::Array articleIdsJson = resultJson[kArticleIds].getArray();
     for (json::Value articleIdJson : articleIdsJson)
     {
        if (articleIdJson.isObject())
        {
           std::string idtype, value;
           json::readObject(articleIdJson.getObject(),
                           "idtype", idtype,
                           "value", value);
           if (idtype == "doi")
           {
              doi = value;
              break;
           }
        }
     }
   }

   // if there is no doi then return an empty doc
   if (doi.empty())
      return PubMedDocument();

   // create doc with doi
   PubMedDocument doc(doi);

   // look for pubtypes
   json::Array pubTypesJson;
   json::readObject(resultJson, "pubtype", pubTypesJson);
   if (pubTypesJson.getSize() > 0)
   {
      for (auto pubTypeJson : pubTypesJson)
      {
         if (pubTypeJson.isString())
            doc.pubTypes.push_back(pubTypeJson.getString());
      }
   }

   // look for authors
   json::Array authorsJson;
   json::readObject(resultJson, "authors", authorsJson);
   if (authorsJson.getSize() > 0)
   {
      for (auto authorJson : authorsJson)
      {
         if (authorJson.isObject() && authorJson.getObject().hasMember("name"))
         {
            json::Value nameJson = authorJson.getObject()["name"];
            if (nameJson.isString())
               doc.authors.push_back(nameJson.getString());
         }
      }
   }

   // read lastAuthor, title, source, volume, issue, pubDate
   json::readObject(resultJson, "lastauthor", doc.lastAuthor);
   json::readObject(resultJson, "title", doc.title);
   json::readObject(resultJson, "source", doc.source);
   json::readObject(resultJson, "volume", doc.volume);
   json::readObject(resultJson, "issue", doc.issue);
   json::readObject(resultJson, "pubdate", doc.pubDate);

   return doc;
}

void pubMedRequest(const std::string& resource,
                   http::Fields params,
                   const json::JsonRpcFunctionContinuation& cont,
                   const JsonHandler& handler)
{

   // add json retmode
   params.push_back(std::make_pair("tool", "rstudio"));
   params.push_back(std::make_pair("email", "pubmed@rstudio.com"));
   params.push_back(std::make_pair("retmode", "json"));

   // build query string
   std::string queryString;
   core::http::util::buildQueryString(params, &queryString);
   if (queryString.length() > 0)
      queryString = "?" + queryString;

   // build the url and make the request
   boost::format fmt("%s/%s%s");
   const std::string url = boost::str(fmt % kPubMedEUtilsHost % resource % queryString);

   asyncDownloadFile(url, boost::bind(jsonRpcDownloadHandler, cont, _1, ERROR_LOCATION, handler));
}

void pubMedSearch(const json::JsonRpcRequest& request,
                  const json::JsonRpcFunctionContinuation& cont)
{
   // extract query
   std::string query;
   Error error = json::readParams(request.params, &query);
   if (error)
   {
     json::JsonRpcResponse response;
     setErrorResponse(error, &response);
     cont(Success(), &response);
     return;
   }

   http::Fields params;
   params.push_back(std::make_pair("db", "pubmed"));
   params.push_back(std::make_pair("term", query));
   params.push_back(std::make_pair("sort", "relevance"));
   params.push_back(std::make_pair("retmax", "30"));

   pubMedRequest("entrez/eutils/esearch.fcgi", params, cont,
                 [](const core::json::JsonRpcFunctionContinuation& cont, core::json::Value json) {

      // validate json
      Error error =json.validate(module_context::resourceFileAsString("schema/pubmed-esearch.json"));
      if (error)
      {
         resolveJsonRpcContinuation(cont, kStatusError, json::Value(), core::errorMessage(error));
         return;
      }

      // read ids
      std::vector<std::string> ids;
      json.getObject()["esearchresult"]
          .getObject()["idlist"]
          .getArray()
          .toVectorString(ids);

      // fetch documents
      http::Fields summaryParams;
      summaryParams.push_back(std::make_pair("db", "pubmed"));
      summaryParams.push_back(std::make_pair("id", boost::algorithm::join(ids, ",")));
      pubMedRequest("entrez/eutils/esummary.fcgi", summaryParams, cont,
                    [](const core::json::JsonRpcFunctionContinuation& cont, core::json::Value json) {

         // validate json
         Error error =json.validate(module_context::resourceFileAsString("schema/pubmed-esummary.json"));
         if (error)
         {
            resolveJsonRpcContinuation(cont, kStatusError, json::Value(), core::errorMessage(error));
            return;
         }

         // read ids
         std::vector<std::string> ids;
         json.getObject()["result"]
             .getObject()["uids"]
             .getArray()
             .toVectorString(ids);

         // read docs
         json::Array docsJson;
         json::Object resultsJson = json.getObject()["result"].getObject();
         for (auto id : ids)
         {
            if (resultsJson.hasMember(id))
            {
               json::Object resultJson = resultsJson[id].getObject();
               PubMedDocument doc = resultToPubMedDocument(resultJson);
               if (!doc.empty())
                  docsJson.push_back(pubMedDocumentJson(doc));
            }
         }

         // resolve
         resolveJsonRpcContinuation(cont, kStatusOK, docsJson);

      });

   });

}

} // end anonymous namespace

Error initialize()
{
   ExecBlock initBlock;
   initBlock.addFunctions()
      (boost::bind(module_context::registerAsyncRpcMethod, "pubmed_search", pubMedSearch))
   ;
   return initBlock.execute();
}

} // end namespace pubmed
} // end namespace panmirror
} // end namespace modules
} // end namespace session
} // end namespace rstudio
<commit_msg>limit pubmed results to 25<commit_after>/*
 * SessionPanmirrorPubMed.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionPanmirrorPubMed.hpp"

#include <shared_core/Error.hpp>
#include <shared_core/json/Json.hpp>

#include <core/Exec.hpp>
#include <core/json/JsonRpc.hpp>
#include <core/http/Util.hpp>

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

#include "SessionPanmirrorUtils.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace panmirror {
namespace pubmed {

namespace {

const char * const kPubMedEUtilsHost = "https://eutils.ncbi.nlm.nih.gov";

struct PubMedDocument
{
   PubMedDocument(const std::string& doi = "") : doi(doi) {}
   bool empty() { return doi.empty(); }
   std::string doi;
   std::vector<std::string> pubTypes;
   std::string title;
   std::vector<std::string> authors;
   std::string lastAuthor;
   std::string source;
   std::string volume;
   std::string issue;
   std::string pubDate;
};

json::Object pubMedDocumentJson(const PubMedDocument& doc)
{
   // all fields are optional save for doi
   json::Object docJson;

   // doi (required)
   docJson["doi"] = doc.doi;

   // pubTypes
   if (doc.pubTypes.size() > 0)
   {
      json::Array pubTypesJson;
      for (auto pubType : doc.pubTypes)
         pubTypesJson.push_back(pubType);
      docJson["pubTypes"] = pubTypesJson;
   }

   // authors
   if (doc.authors.size() > 0)
   {
      json::Array authorsJson;
      for (auto author : doc.authors)
         authorsJson.push_back(author);
      docJson["authors"] = authorsJson;
   }

   // lastAuthor
   if (!doc.lastAuthor.empty())
      docJson["lastAuthor"] = doc.lastAuthor;

   // title
   if (!doc.title.empty())
      docJson["title"] = doc.title;

   // source
   if (!doc.source.empty())
   {
      docJson["source"] = doc.source;
      if (!doc.volume.empty())
         docJson["volume"] = doc.volume;
      if (!doc.issue.empty())
         docJson["issue"] = doc.issue;
   }

   // pubDate
   if (!doc.pubDate.empty())
      docJson["pubDate"] = doc.pubDate;

   return docJson;

}

PubMedDocument resultToPubMedDocument(json::Object resultJson)
{
   // look for doi (the only required field)
   std::string doi;
   const char * const kArticleIds = "articleids";
   if (resultJson.hasMember(kArticleIds) && resultJson[kArticleIds].isArray())
   {
     json::Array articleIdsJson = resultJson[kArticleIds].getArray();
     for (json::Value articleIdJson : articleIdsJson)
     {
        if (articleIdJson.isObject())
        {
           std::string idtype, value;
           json::readObject(articleIdJson.getObject(),
                           "idtype", idtype,
                           "value", value);
           if (idtype == "doi")
           {
              doi = value;
              break;
           }
        }
     }
   }

   // if there is no doi then return an empty doc
   if (doi.empty())
      return PubMedDocument();

   // create doc with doi
   PubMedDocument doc(doi);

   // look for pubtypes
   json::Array pubTypesJson;
   json::readObject(resultJson, "pubtype", pubTypesJson);
   if (pubTypesJson.getSize() > 0)
   {
      for (auto pubTypeJson : pubTypesJson)
      {
         if (pubTypeJson.isString())
            doc.pubTypes.push_back(pubTypeJson.getString());
      }
   }

   // look for authors
   json::Array authorsJson;
   json::readObject(resultJson, "authors", authorsJson);
   if (authorsJson.getSize() > 0)
   {
      for (auto authorJson : authorsJson)
      {
         if (authorJson.isObject() && authorJson.getObject().hasMember("name"))
         {
            json::Value nameJson = authorJson.getObject()["name"];
            if (nameJson.isString())
               doc.authors.push_back(nameJson.getString());
         }
      }
   }

   // read lastAuthor, title, source, volume, issue, pubDate
   json::readObject(resultJson, "lastauthor", doc.lastAuthor);
   json::readObject(resultJson, "title", doc.title);
   json::readObject(resultJson, "source", doc.source);
   json::readObject(resultJson, "volume", doc.volume);
   json::readObject(resultJson, "issue", doc.issue);
   json::readObject(resultJson, "pubdate", doc.pubDate);

   return doc;
}

void pubMedRequest(const std::string& resource,
                   http::Fields params,
                   const json::JsonRpcFunctionContinuation& cont,
                   const JsonHandler& handler)
{

   // add json retmode
   params.push_back(std::make_pair("tool", "rstudio"));
   params.push_back(std::make_pair("email", "pubmed@rstudio.com"));
   params.push_back(std::make_pair("retmode", "json"));

   // build query string
   std::string queryString;
   core::http::util::buildQueryString(params, &queryString);
   if (queryString.length() > 0)
      queryString = "?" + queryString;

   // build the url and make the request
   boost::format fmt("%s/%s%s");
   const std::string url = boost::str(fmt % kPubMedEUtilsHost % resource % queryString);

   asyncDownloadFile(url, boost::bind(jsonRpcDownloadHandler, cont, _1, ERROR_LOCATION, handler));
}

void pubMedSearch(const json::JsonRpcRequest& request,
                  const json::JsonRpcFunctionContinuation& cont)
{
   // extract query
   std::string query;
   Error error = json::readParams(request.params, &query);
   if (error)
   {
     json::JsonRpcResponse response;
     setErrorResponse(error, &response);
     cont(Success(), &response);
     return;
   }

   http::Fields params;
   params.push_back(std::make_pair("db", "pubmed"));
   params.push_back(std::make_pair("term", query));
   params.push_back(std::make_pair("sort", "relevance"));
   params.push_back(std::make_pair("retmax", "25"));

   pubMedRequest("entrez/eutils/esearch.fcgi", params, cont,
                 [](const core::json::JsonRpcFunctionContinuation& cont, core::json::Value json) {

      // validate json
      Error error =json.validate(module_context::resourceFileAsString("schema/pubmed-esearch.json"));
      if (error)
      {
         resolveJsonRpcContinuation(cont, kStatusError, json::Value(), core::errorMessage(error));
         return;
      }

      // read ids
      std::vector<std::string> ids;
      json.getObject()["esearchresult"]
          .getObject()["idlist"]
          .getArray()
          .toVectorString(ids);

      // fetch documents
      http::Fields summaryParams;
      summaryParams.push_back(std::make_pair("db", "pubmed"));
      summaryParams.push_back(std::make_pair("id", boost::algorithm::join(ids, ",")));
      pubMedRequest("entrez/eutils/esummary.fcgi", summaryParams, cont,
                    [](const core::json::JsonRpcFunctionContinuation& cont, core::json::Value json) {

         // validate json
         Error error =json.validate(module_context::resourceFileAsString("schema/pubmed-esummary.json"));
         if (error)
         {
            resolveJsonRpcContinuation(cont, kStatusError, json::Value(), core::errorMessage(error));
            return;
         }

         // read ids
         std::vector<std::string> ids;
         json.getObject()["result"]
             .getObject()["uids"]
             .getArray()
             .toVectorString(ids);

         // read docs
         json::Array docsJson;
         json::Object resultsJson = json.getObject()["result"].getObject();
         for (auto id : ids)
         {
            if (resultsJson.hasMember(id))
            {
               json::Object resultJson = resultsJson[id].getObject();
               PubMedDocument doc = resultToPubMedDocument(resultJson);
               if (!doc.empty())
                  docsJson.push_back(pubMedDocumentJson(doc));
            }
         }

         // resolve
         resolveJsonRpcContinuation(cont, kStatusOK, docsJson);

      });

   });

}

} // end anonymous namespace

Error initialize()
{
   ExecBlock initBlock;
   initBlock.addFunctions()
      (boost::bind(module_context::registerAsyncRpcMethod, "pubmed_search", pubMedSearch))
   ;
   return initBlock.execute();
}

} // end namespace pubmed
} // end namespace panmirror
} // end namespace modules
} // end namespace session
} // end namespace rstudio
<|endoftext|>


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

// TODO: more generous default width
// TODO: align scaling with default width

// TODO: test on ipad

// TODO: investigate why pdf doesn't work

// TODO: investigate why overview doesn't work properly
// TODO: consider 'o' for overview mode

// TODO: consider search plugin

// TODO: larger knitr default image size

// TODO: custom code navigator for presentations

// TODO: (docs) expand current documentation into multiple pages
// TODO: (docs) presentations quick reference
// TODO: (docs) custom css mechanisms
// TODO: (docs) depends for presentations
// TODO: (docs) per-slide transitions

#include "SessionPresentation.hpp"

#include <boost/bind.hpp>

#include <core/Exec.hpp>
#include <core/http/Util.hpp>
#include <core/FileSerializer.hpp>
#include <core/text/TemplateFilter.hpp>

#include <r/RSexp.hpp>
#include <r/RExec.hpp>
#include <r/RRoutines.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/projects/SessionProjects.hpp>

#include "../SessionRPubs.hpp"

#include "PresentationLog.hpp"
#include "PresentationState.hpp"
#include "SlideRequestHandler.hpp"

using namespace core;

namespace session {
namespace modules {
namespace presentation {

namespace {

void showPresentation(const FilePath& filePath)
{
   // initialize state
   presentation::state::init(filePath);

   // notify the client
   ClientEvent event(client_events::kShowPresentationPane,
                     presentation::state::asJson());
   module_context::enqueClientEvent(event);
}

SEXP rs_showPresentation(SEXP fileSEXP)
{
   try
   {
      // validate path
      FilePath filePath(r::sexp::asString(fileSEXP));
      if (!filePath.exists())
         throw r::exec::RErrorException("File path " + filePath.absolutePath() +
                                        " does not exist.");

      showPresentation(filePath);
   }
   catch(const r::exec::RErrorException& e)
   {
      r::exec::error(e.message());
   }

   return R_NilValue;
}

SEXP rs_showPresentationHelpDoc(SEXP helpDocSEXP)
{
   try
   {
      // verify a presentation is active
      if (!presentation::state::isActive())
      {
         throw r::exec::RErrorException(
                                 "No presentation is currently active");
      }

      // resolve against presentation directory
      std::string helpDoc = r::sexp::asString(helpDocSEXP);
      FilePath helpDocPath = presentation::state::directory().childPath(
                                                                  helpDoc);
      if (!helpDocPath.exists())
      {
         throw r::exec::RErrorException("Path " + helpDocPath.absolutePath()
                                        + " not found.");
      }

      // build url and fire event
      std::string url = "help/presentation/?file=";
      std::string file = module_context::createAliasedPath(helpDocPath);
      url += http::util::urlEncode(file, true);

      ClientEvent event(client_events::kShowHelp, url);
      module_context::enqueClientEvent(event);
   }
   catch(const r::exec::RErrorException& e)
   {
      r::exec::error(e.message());
   }

   return R_NilValue;
}

Error setPresentationSlideIndex(const json::JsonRpcRequest& request,
                                json::JsonRpcResponse*)
{
   int index = 0;
   Error error = json::readParam(request.params, 0, &index);
   if (error)
      return error;

   presentation::state::setSlideIndex(index);

   presentation::log().onSlideIndexChanged(index);

   return Success();
}

Error createNewPresentation(const json::JsonRpcRequest& request,
                            json::JsonRpcResponse* pResponse)
{
   // get file path
   std::string file;
   Error error = json::readParam(request.params, 0, &file);
   if (error)
      return error;
   FilePath filePath = module_context::resolveAliasedPath(file);

   // process template
   std::map<std::string,std::string> vars;
   vars["name"] = filePath.stem();
   core::text::TemplateFilter filter(vars);

   // read file with template filter
   FilePath templatePath = session::options().rResourcesPath().complete(
                                             "templates/r_presentation.Rpres");
   std::string presContents;
   error = core::readStringFromFile(templatePath, filter, &presContents);
   if (error)
      return error;

   // write file
   return core::writeStringToFile(filePath,
                                  presContents,
                                  string_utils::LineEndingNative);
}

Error showPresentationPane(const json::JsonRpcRequest& request,
                            json::JsonRpcResponse* pResponse)
{
   std::string file;
   Error error = json::readParam(request.params, 0, &file);
   if (error)
      return error;

   FilePath filePath = module_context::resolveAliasedPath(file);
   if (!filePath.exists())
      return core::fileNotFoundError(filePath, ERROR_LOCATION);

   showPresentation(filePath);

   return Success();
}

Error closePresentationPane(const json::JsonRpcRequest&,
                            json::JsonRpcResponse*)
{
   presentation::state::clear();

   return Success();
}

Error presentationExecuteCode(const json::JsonRpcRequest& request,
                              json::JsonRpcResponse* pResponse)
{
   // get the code
   std::string code;
   Error error = json::readParam(request.params, 0, &code);
   if (error)
      return error;

   // confirm we are active
   if (!presentation::state::isActive())
   {
      pResponse->setError(json::errc::MethodUnexpected);
      return Success();
   }

   // execute within the context of either the tutorial project directory
   // or presentation directory
   RestoreCurrentPathScope restorePathScope(
                                          module_context::safeCurrentPath());
   if (presentation::state::isTutorial() &&
       projects::projectContext().hasProject())
   {
      error = projects::projectContext().directory().makeCurrentPath();
   }
   else
   {
      error = presentation::state::directory().makeCurrentPath();
   }
   if (error)
      return error;

   // actually execute the code (show error in the console)
   error = r::exec::executeString(code);
   if (error)
   {
      std::string errMsg = "Error executing code: " + code + "\n";
      errMsg += r::endUserErrorMessage(error);
      module_context::consoleWriteError(errMsg + "\n");
   }

   return Success();
}

Error setWorkingDirectory(const json::JsonRpcRequest& request,
                            json::JsonRpcResponse*)
{
   // get the path
   std::string path;
   Error error = json::readParam(request.params, 0, &path);
   if (error)
      return error;

   // set current path
   FilePath filePath = module_context::resolveAliasedPath(path);
   return filePath.makeCurrentPath();
}

Error tutorialFeedback(const json::JsonRpcRequest& request,
                       json::JsonRpcResponse* pResponse)
{
   // get the feedback
   std::string feedback;
   Error error = json::readParam(request.params, 0, &feedback);
   if (error)
      return error;

   // confirm we are active
   if (!presentation::state::isActive())
   {
      pResponse->setError(json::errc::MethodUnexpected);
      return Success();
   }

   // record the feedback
   presentation::log().recordFeedback(feedback);

   return Success();
}

Error tutorialQuizResponse(const json::JsonRpcRequest& request,
                           json::JsonRpcResponse* pResponse)
{
   // get the params
   int slideIndex, answer;
   bool correct;
   Error error = json::readParams(request.params,
                                  &slideIndex,
                                  &answer,
                                  &correct);
   if (error)
      return error;

   // confirm we are active
   if (!presentation::state::isActive())
   {
      pResponse->setError(json::errc::MethodUnexpected);
      return Success();
   }

   // record the feedback
   presentation::log().recordQuizResponse(slideIndex, answer, correct);

   return Success();
}

Error createStandalonePresentation(const json::JsonRpcRequest& request,
                                   json::JsonRpcResponse* pResponse)
{
   std::string pathParam;
   Error error = json::readParam(request.params, 0, &pathParam);
   if (error)
      return error;
   FilePath targetPath = module_context::resolveAliasedPath(pathParam);

   std::string errMsg;
   if (!savePresentationAsStandalone(targetPath, &errMsg))
   {
      pResponse->setError(systemError(boost::system::errc::io_error,
                                      ERROR_LOCATION),
                          json::toJsonString(errMsg));
   }

   return Success();
}

Error createDesktopViewInBrowserPresentation(
                                   const json::JsonRpcRequest& request,
                                   json::JsonRpcResponse* pResponse)
{
   // save to view in browser path
   FilePath targetPath = presentation::state::viewInBrowserPath();
   std::string errMsg;
   if (savePresentationAsStandalone(targetPath, &errMsg))
   {
      pResponse->setResult(module_context::createAliasedPath(targetPath));
   }
   else
   {
      pResponse->setError(systemError(boost::system::errc::io_error,
                                      ERROR_LOCATION),
                          json::toJsonString(errMsg));
   }

   return Success();
}

Error createPresentationRpubsSource(const json::JsonRpcRequest& request,
                                    json::JsonRpcResponse* pResponse)
{
   // use a stable location in the presentation directory for the Rpubs
   // source file so that update works across sessions
   std::string stem = presentation::state::filePath().stem();
   FilePath filePath = presentation::state::directory().childPath(
                                                      stem + "-rpubs.html");

   std::string errMsg;
   if (savePresentationAsRpubsSource(filePath, &errMsg))
   {
      json::Object resultJson;
      resultJson["published"] = !rpubs::previousUploadId(filePath).empty();
      resultJson["source_file_path"] = module_context::createAliasedPath(
                                                                     filePath);
      pResponse->setResult(resultJson);
   }
   else
   {
      pResponse->setError(systemError(boost::system::errc::io_error,
                                      ERROR_LOCATION),
                          json::toJsonString(errMsg));
   }

   return Success();
}

} // anonymous namespace

json::Value presentationStateAsJson()
{
   return presentation::state::asJson();
}

Error initialize()
{
   // register rs_showPresentation
   R_CallMethodDef methodDefShowPresentation;
   methodDefShowPresentation.name = "rs_showPresentation" ;
   methodDefShowPresentation.fun = (DL_FUNC) rs_showPresentation;
   methodDefShowPresentation.numArgs = 1;
   r::routines::addCallMethod(methodDefShowPresentation);

   // register rs_showPresentationHelpDoc
   R_CallMethodDef methodDefShowHelpDoc;
   methodDefShowHelpDoc.name = "rs_showPresentationHelpDoc" ;
   methodDefShowHelpDoc.fun = (DL_FUNC) rs_showPresentationHelpDoc;
   methodDefShowHelpDoc.numArgs = 1;
   r::routines::addCallMethod(methodDefShowHelpDoc);

   // initialize presentation log
   Error error = log().initialize();
   if (error)
      return error;

   using boost::bind;
   using namespace session::module_context;
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerUriHandler, "/presentation", handlePresentationPaneRequest))
      (bind(registerRpcMethod, "create_standalone_presentation", createStandalonePresentation))
      (bind(registerRpcMethod, "create_desktop_view_in_browser_presentation",
                                createDesktopViewInBrowserPresentation))
      (bind(registerRpcMethod, "create_presentation_rpubs_source", createPresentationRpubsSource))
      (bind(registerRpcMethod, "set_presentation_slide_index", setPresentationSlideIndex))
      (bind(registerRpcMethod, "create_new_presentation", createNewPresentation))
      (bind(registerRpcMethod, "show_presentation_pane", showPresentationPane))
      (bind(registerRpcMethod, "close_presentation_pane", closePresentationPane))
      (bind(registerRpcMethod, "presentation_execute_code", presentationExecuteCode))
      (bind(registerRpcMethod, "set_working_directory", setWorkingDirectory))
      (bind(registerRpcMethod, "tutorial_feedback", tutorialFeedback))
      (bind(registerRpcMethod, "tutorial_quiz_response", tutorialQuizResponse))
      (bind(presentation::state::initialize))
      (bind(sourceModuleRFile, "SessionPresentation.R"));

   return initBlock.execute();
}

} // namespace presentation
} // namespace modules
} // namesapce session

<commit_msg>update todos<commit_after>/*
 * SessionPresentation.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

// TODO: custom code navigator for presentations

// TODO: more generous default width
// TODO: align scaling with default width

// TODO: (docs) expand current documentation into multiple pages
// TODO: (docs) presentations quick reference
// TODO: (docs) custom css mechanisms
// TODO: (docs) depends for presentations
// TODO: (docs) per-slide transitions
// TODO: (docs) remove overview note

#include "SessionPresentation.hpp"

#include <boost/bind.hpp>

#include <core/Exec.hpp>
#include <core/http/Util.hpp>
#include <core/FileSerializer.hpp>
#include <core/text/TemplateFilter.hpp>

#include <r/RSexp.hpp>
#include <r/RExec.hpp>
#include <r/RRoutines.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/projects/SessionProjects.hpp>

#include "../SessionRPubs.hpp"

#include "PresentationLog.hpp"
#include "PresentationState.hpp"
#include "SlideRequestHandler.hpp"

using namespace core;

namespace session {
namespace modules {
namespace presentation {

namespace {

void showPresentation(const FilePath& filePath)
{
   // initialize state
   presentation::state::init(filePath);

   // notify the client
   ClientEvent event(client_events::kShowPresentationPane,
                     presentation::state::asJson());
   module_context::enqueClientEvent(event);
}

SEXP rs_showPresentation(SEXP fileSEXP)
{
   try
   {
      // validate path
      FilePath filePath(r::sexp::asString(fileSEXP));
      if (!filePath.exists())
         throw r::exec::RErrorException("File path " + filePath.absolutePath() +
                                        " does not exist.");

      showPresentation(filePath);
   }
   catch(const r::exec::RErrorException& e)
   {
      r::exec::error(e.message());
   }

   return R_NilValue;
}

SEXP rs_showPresentationHelpDoc(SEXP helpDocSEXP)
{
   try
   {
      // verify a presentation is active
      if (!presentation::state::isActive())
      {
         throw r::exec::RErrorException(
                                 "No presentation is currently active");
      }

      // resolve against presentation directory
      std::string helpDoc = r::sexp::asString(helpDocSEXP);
      FilePath helpDocPath = presentation::state::directory().childPath(
                                                                  helpDoc);
      if (!helpDocPath.exists())
      {
         throw r::exec::RErrorException("Path " + helpDocPath.absolutePath()
                                        + " not found.");
      }

      // build url and fire event
      std::string url = "help/presentation/?file=";
      std::string file = module_context::createAliasedPath(helpDocPath);
      url += http::util::urlEncode(file, true);

      ClientEvent event(client_events::kShowHelp, url);
      module_context::enqueClientEvent(event);
   }
   catch(const r::exec::RErrorException& e)
   {
      r::exec::error(e.message());
   }

   return R_NilValue;
}

Error setPresentationSlideIndex(const json::JsonRpcRequest& request,
                                json::JsonRpcResponse*)
{
   int index = 0;
   Error error = json::readParam(request.params, 0, &index);
   if (error)
      return error;

   presentation::state::setSlideIndex(index);

   presentation::log().onSlideIndexChanged(index);

   return Success();
}

Error createNewPresentation(const json::JsonRpcRequest& request,
                            json::JsonRpcResponse* pResponse)
{
   // get file path
   std::string file;
   Error error = json::readParam(request.params, 0, &file);
   if (error)
      return error;
   FilePath filePath = module_context::resolveAliasedPath(file);

   // process template
   std::map<std::string,std::string> vars;
   vars["name"] = filePath.stem();
   core::text::TemplateFilter filter(vars);

   // read file with template filter
   FilePath templatePath = session::options().rResourcesPath().complete(
                                             "templates/r_presentation.Rpres");
   std::string presContents;
   error = core::readStringFromFile(templatePath, filter, &presContents);
   if (error)
      return error;

   // write file
   return core::writeStringToFile(filePath,
                                  presContents,
                                  string_utils::LineEndingNative);
}

Error showPresentationPane(const json::JsonRpcRequest& request,
                            json::JsonRpcResponse* pResponse)
{
   std::string file;
   Error error = json::readParam(request.params, 0, &file);
   if (error)
      return error;

   FilePath filePath = module_context::resolveAliasedPath(file);
   if (!filePath.exists())
      return core::fileNotFoundError(filePath, ERROR_LOCATION);

   showPresentation(filePath);

   return Success();
}

Error closePresentationPane(const json::JsonRpcRequest&,
                            json::JsonRpcResponse*)
{
   presentation::state::clear();

   return Success();
}

Error presentationExecuteCode(const json::JsonRpcRequest& request,
                              json::JsonRpcResponse* pResponse)
{
   // get the code
   std::string code;
   Error error = json::readParam(request.params, 0, &code);
   if (error)
      return error;

   // confirm we are active
   if (!presentation::state::isActive())
   {
      pResponse->setError(json::errc::MethodUnexpected);
      return Success();
   }

   // execute within the context of either the tutorial project directory
   // or presentation directory
   RestoreCurrentPathScope restorePathScope(
                                          module_context::safeCurrentPath());
   if (presentation::state::isTutorial() &&
       projects::projectContext().hasProject())
   {
      error = projects::projectContext().directory().makeCurrentPath();
   }
   else
   {
      error = presentation::state::directory().makeCurrentPath();
   }
   if (error)
      return error;

   // actually execute the code (show error in the console)
   error = r::exec::executeString(code);
   if (error)
   {
      std::string errMsg = "Error executing code: " + code + "\n";
      errMsg += r::endUserErrorMessage(error);
      module_context::consoleWriteError(errMsg + "\n");
   }

   return Success();
}

Error setWorkingDirectory(const json::JsonRpcRequest& request,
                            json::JsonRpcResponse*)
{
   // get the path
   std::string path;
   Error error = json::readParam(request.params, 0, &path);
   if (error)
      return error;

   // set current path
   FilePath filePath = module_context::resolveAliasedPath(path);
   return filePath.makeCurrentPath();
}

Error tutorialFeedback(const json::JsonRpcRequest& request,
                       json::JsonRpcResponse* pResponse)
{
   // get the feedback
   std::string feedback;
   Error error = json::readParam(request.params, 0, &feedback);
   if (error)
      return error;

   // confirm we are active
   if (!presentation::state::isActive())
   {
      pResponse->setError(json::errc::MethodUnexpected);
      return Success();
   }

   // record the feedback
   presentation::log().recordFeedback(feedback);

   return Success();
}

Error tutorialQuizResponse(const json::JsonRpcRequest& request,
                           json::JsonRpcResponse* pResponse)
{
   // get the params
   int slideIndex, answer;
   bool correct;
   Error error = json::readParams(request.params,
                                  &slideIndex,
                                  &answer,
                                  &correct);
   if (error)
      return error;

   // confirm we are active
   if (!presentation::state::isActive())
   {
      pResponse->setError(json::errc::MethodUnexpected);
      return Success();
   }

   // record the feedback
   presentation::log().recordQuizResponse(slideIndex, answer, correct);

   return Success();
}

Error createStandalonePresentation(const json::JsonRpcRequest& request,
                                   json::JsonRpcResponse* pResponse)
{
   std::string pathParam;
   Error error = json::readParam(request.params, 0, &pathParam);
   if (error)
      return error;
   FilePath targetPath = module_context::resolveAliasedPath(pathParam);

   std::string errMsg;
   if (!savePresentationAsStandalone(targetPath, &errMsg))
   {
      pResponse->setError(systemError(boost::system::errc::io_error,
                                      ERROR_LOCATION),
                          json::toJsonString(errMsg));
   }

   return Success();
}

Error createDesktopViewInBrowserPresentation(
                                   const json::JsonRpcRequest& request,
                                   json::JsonRpcResponse* pResponse)
{
   // save to view in browser path
   FilePath targetPath = presentation::state::viewInBrowserPath();
   std::string errMsg;
   if (savePresentationAsStandalone(targetPath, &errMsg))
   {
      pResponse->setResult(module_context::createAliasedPath(targetPath));
   }
   else
   {
      pResponse->setError(systemError(boost::system::errc::io_error,
                                      ERROR_LOCATION),
                          json::toJsonString(errMsg));
   }

   return Success();
}

Error createPresentationRpubsSource(const json::JsonRpcRequest& request,
                                    json::JsonRpcResponse* pResponse)
{
   // use a stable location in the presentation directory for the Rpubs
   // source file so that update works across sessions
   std::string stem = presentation::state::filePath().stem();
   FilePath filePath = presentation::state::directory().childPath(
                                                      stem + "-rpubs.html");

   std::string errMsg;
   if (savePresentationAsRpubsSource(filePath, &errMsg))
   {
      json::Object resultJson;
      resultJson["published"] = !rpubs::previousUploadId(filePath).empty();
      resultJson["source_file_path"] = module_context::createAliasedPath(
                                                                     filePath);
      pResponse->setResult(resultJson);
   }
   else
   {
      pResponse->setError(systemError(boost::system::errc::io_error,
                                      ERROR_LOCATION),
                          json::toJsonString(errMsg));
   }

   return Success();
}

} // anonymous namespace

json::Value presentationStateAsJson()
{
   return presentation::state::asJson();
}

Error initialize()
{
   // register rs_showPresentation
   R_CallMethodDef methodDefShowPresentation;
   methodDefShowPresentation.name = "rs_showPresentation" ;
   methodDefShowPresentation.fun = (DL_FUNC) rs_showPresentation;
   methodDefShowPresentation.numArgs = 1;
   r::routines::addCallMethod(methodDefShowPresentation);

   // register rs_showPresentationHelpDoc
   R_CallMethodDef methodDefShowHelpDoc;
   methodDefShowHelpDoc.name = "rs_showPresentationHelpDoc" ;
   methodDefShowHelpDoc.fun = (DL_FUNC) rs_showPresentationHelpDoc;
   methodDefShowHelpDoc.numArgs = 1;
   r::routines::addCallMethod(methodDefShowHelpDoc);

   // initialize presentation log
   Error error = log().initialize();
   if (error)
      return error;

   using boost::bind;
   using namespace session::module_context;
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerUriHandler, "/presentation", handlePresentationPaneRequest))
      (bind(registerRpcMethod, "create_standalone_presentation", createStandalonePresentation))
      (bind(registerRpcMethod, "create_desktop_view_in_browser_presentation",
                                createDesktopViewInBrowserPresentation))
      (bind(registerRpcMethod, "create_presentation_rpubs_source", createPresentationRpubsSource))
      (bind(registerRpcMethod, "set_presentation_slide_index", setPresentationSlideIndex))
      (bind(registerRpcMethod, "create_new_presentation", createNewPresentation))
      (bind(registerRpcMethod, "show_presentation_pane", showPresentationPane))
      (bind(registerRpcMethod, "close_presentation_pane", closePresentationPane))
      (bind(registerRpcMethod, "presentation_execute_code", presentationExecuteCode))
      (bind(registerRpcMethod, "set_working_directory", setWorkingDirectory))
      (bind(registerRpcMethod, "tutorial_feedback", tutorialFeedback))
      (bind(registerRpcMethod, "tutorial_quiz_response", tutorialQuizResponse))
      (bind(presentation::state::initialize))
      (bind(sourceModuleRFile, "SessionPresentation.R"));

   return initBlock.execute();
}

} // namespace presentation
} // namespace modules
} // namesapce session

<|endoftext|>