<commit_before>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include "../core/Setup.h"

#include <algorithm>
#include <fstream>
#if defined(_WIN32)
#  pragma push_macro("WIN32_LEAN_AND_MEAN")
#  pragma push_macro("NOMINMAX")
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN
#  endif
#  ifndef NOMINMAX
#    define NOMINMAX
#  endif
#  include <Windows.h>
#  include <ShlObj.h>
#  include <Shlwapi.h>
#  include <strsafe.h>
#  pragma pop_macro("WIN32_LEAN_AND_MEAN")
#  pragma pop_macro("NOMINMAX")
#elif defined(__APPLE__)
#  include <TargetConditionals.h>
#  include <objc/message.h>
#  include <objc/NSObjCRuntime.h>
#  include <CoreFoundation/CoreFoundation.h>
#elif defined(__ANDROID__)
#  include "../core/android/EngineAndroid.hpp"
#elif defined(__linux__)
#  include <pwd.h>
#endif

#include "FileSystem.hpp"
#include "Archive.hpp"
#include "../core/Engine.hpp"
#include "../utils/Log.hpp"

#if defined(__APPLE__)
#  include "CfPointer.hpp"
#endif

namespace ouzel
{
    namespace storage
    {
        FileSystem::FileSystem(Engine& initEngine):
            engine(initEngine)
        {
#if defined(_WIN32)
            HINSTANCE instance = GetModuleHandleW(nullptr);
            if (!instance)
                throw std::system_error(GetLastError(), std::system_category(), "Failed to get module handle");
            std::vector<WCHAR> buffer(MAX_PATH + 1);
            for (;;)
            {
                if (!GetModuleFileNameW(instance, buffer.data(), static_cast<DWORD>(buffer.size())))
                    throw std::system_error(GetLastError(), std::system_category(), "Failed to get module filename");

                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                    buffer.resize(buffer.size() * 2);
                else
                    break;
            }

            const auto executablePath = Path{buffer.data(), Path::Format::native};
            appPath = executablePath.getDirectory();
            engine.log(Log::Level::info) << "Application directory: " << appPath;

#elif defined(__APPLE__)
            CFBundleRef bundle = CFBundleGetMainBundle();
            if (!bundle)
                throw std::runtime_error("Failed to get main bundle");

            CfPointer<CFURLRef> relativePath = CFBundleCopyResourcesDirectoryURL(bundle);
            if (!relativePath)
                throw std::runtime_error("Failed to get resource directory");

            CfPointer<CFURLRef> absolutePath = CFURLCopyAbsoluteURL(relativePath.get());
            CfPointer<CFStringRef> path = CFURLCopyFileSystemPath(absolutePath.get(), kCFURLPOSIXPathStyle);

            const CFIndex maximumSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path.get());
            auto resourceDirectory = std::make_unique<char[]>(static_cast<std::size_t>(maximumSize));
            const Boolean result = CFStringGetFileSystemRepresentation(path.get(), resourceDirectory.get(), maximumSize);
            if (!result)
                throw std::runtime_error("Failed to get resource directory");

            appPath = Path{resourceDirectory.get(), Path::Format::native};
            engine.log(Log::Level::info) << "Application directory: " << appPath;

#elif defined(__ANDROID__)
            // not available for Android

#elif defined(__linux__)
            char executableDirectory[PATH_MAX];

            ssize_t length;
            if ((length = readlink("/proc/self/exe", executableDirectory, sizeof(executableDirectory) - 1)) == -1)
                throw std::system_error(errno, std::system_category(), "Failed to get current directory");

            executableDirectory[length] = '\0';
            const auto executablePath = Path{executableDirectory, Path::Format::native};
            appPath = executablePath.getDirectory();
            engine.log(Log::Level::info) << "Application directory: " << appPath;
#endif
        }

        Path FileSystem::getStorageDirectory(const bool user) const
        {
#if defined(_WIN32)
            WCHAR appDataPath[MAX_PATH];

            HRESULT hr;
            if (FAILED(hr = SHGetFolderPathW(nullptr, (user ? CSIDL_LOCAL_APPDATA : CSIDL_COMMON_APPDATA) | CSIDL_FLAG_CREATE, nullptr, SHGFP_TYPE_CURRENT, appDataPath)))
                throw std::system_error(hr, std::system_category(), "Failed to get the path of the AppData directory");

            Path path = Path{appDataPath, Path::Format::native};

            HINSTANCE instance = GetModuleHandleW(nullptr);
            if (!instance)
                throw std::system_error(GetLastError(), std::system_category(), "Failed to get module handle");
            std::vector<WCHAR> buffer(MAX_PATH + 1);
            for (;;)
            {
                if (!GetModuleFileNameW(instance, buffer.data(), static_cast<DWORD>(buffer.size())))
                    throw std::system_error(GetLastError(), std::system_category(), "Failed to get module filename");

                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                    buffer.resize(buffer.size() * 2);
                else
                    break;
            }

            const auto executablePath = Path{buffer.data(), Path::Format::native};
            DWORD handle;
            const DWORD fileVersionSize = GetFileVersionInfoSizeW(executablePath.getNative().c_str(), &handle);
            if (!fileVersionSize)
                throw std::system_error(GetLastError(), std::system_category(), "Failed to get file version size");

            auto fileVersionBuffer = std::make_unique<char[]>(fileVersionSize);
            if (!GetFileVersionInfoW(executablePath.getNative().c_str(),
                                     0, fileVersionSize,
                                     fileVersionBuffer.get()))
                throw std::system_error(GetLastError(), std::system_category(), "Failed to get file version");

            LPWSTR companyName = nullptr;
            LPWSTR productName = nullptr;

            struct LANGANDCODEPAGE final
            {
                WORD wLanguage;
                WORD wCodePage;
            };
            LPVOID translationPointer;
            UINT translationLength;

            if (VerQueryValueW(fileVersionBuffer.get(),
                               L"\\VarFileInfo\\Translation",
                               &translationPointer,
                               &translationLength))
            {
                auto translation = static_cast<const LANGANDCODEPAGE*>(translationPointer);

                for (UINT i = 0; i < translationLength / sizeof(LANGANDCODEPAGE); ++i)
                {
                    constexpr size_t subBlockSize = 37U;
                    WCHAR subBlock[subBlockSize];

                    StringCchPrintfW(subBlock, subBlockSize,
                                     L"\\StringFileInfo\\%04x%04x\\CompanyName",
                                     translation[i].wLanguage,
                                     translation[i].wCodePage);

                    LPVOID companyNamePointer;
                    UINT companyNameLength;
                    if (VerQueryValueW(fileVersionBuffer.get(),
                                       subBlock,
                                       &companyNamePointer,
                                       &companyNameLength))
                        companyName = static_cast<LPWSTR>(companyNamePointer);

                    StringCchPrintfW(subBlock, subBlockSize,
                                     L"\\StringFileInfo\\%04x%04x\\ProductName",
                                     translation[i].wLanguage,
                                     translation[i].wCodePage);

                    LPVOID productNamePointer;
                    UINT productNameLength;
                    if (VerQueryValueW(fileVersionBuffer.get(),
                                       subBlock,
                                       &productNamePointer,
                                       &productNameLength))
                        productName = static_cast<LPWSTR>(productNamePointer);
                }
            }

            if (companyName)
                path /= companyName;
            else
                path /= OUZEL_DEVELOPER_NAME;

            if (getFileType(path) != FileType::directory)
                createDirectory(path);

            if (productName)
                path /= productName;
            else
                path /= OUZEL_APPLICATION_NAME;

            if (getFileType(path) != FileType::directory)
                createDirectory(path);

            return path;
#elif TARGET_OS_IOS || TARGET_OS_TV
            id fileManager = reinterpret_cast<id (*)(Class, SEL)>(&objc_msgSend)(objc_getClass("NSFileManager"), sel_getUid("defaultManager"));

            constexpr NSUInteger NSDocumentDirectory = 9U;
            constexpr NSUInteger NSUserDomainMask = 1U;
            constexpr NSUInteger NSLocalDomainMask = 2U;

            id documentDirectory = reinterpret_cast<id (*)(id, SEL, NSUInteger, NSUInteger, id, BOOL, id*)>(&objc_msgSend)(fileManager, sel_getUid("URLForDirectory:inDomain:appropriateForURL:create:error:"), NSDocumentDirectory, user ? NSUserDomainMask : NSLocalDomainMask, nil, YES, nil);

            if (!documentDirectory)
                throw std::runtime_error("Failed to get document directory");

            id documentDirectoryString = reinterpret_cast<id (*)(id, SEL)>(&objc_msgSend)(documentDirectory, sel_getUid("path"));
            auto pathUtf8String = reinterpret_cast<const char* (*)(id, SEL)>(&objc_msgSend)(documentDirectoryString, sel_getUid("UTF8String"));
            return Path{pathUtf8String, Path::Format::native};
#elif TARGET_OS_MAC
            id fileManager = reinterpret_cast<id (*)(Class, SEL)>(&objc_msgSend)(objc_getClass("NSFileManager"), sel_getUid("defaultManager"));

            constexpr NSUInteger NSApplicationSupportDirectory = 14U;
            constexpr NSUInteger NSUserDomainMask = 1U;
            constexpr NSUInteger NSLocalDomainMask = 2U;

            id applicationSupportDirectory = reinterpret_cast<id (*)(id, SEL, NSUInteger, NSUInteger, id, BOOL, id*)>(&objc_msgSend)(fileManager, sel_getUid("URLForDirectory:inDomain:appropriateForURL:create:error:"), NSApplicationSupportDirectory, user ? NSUserDomainMask : NSLocalDomainMask, nil, YES, nil);

            if (!applicationSupportDirectory)
                throw std::runtime_error("Failed to get application support directory");

            CFBundleRef bundle = CFBundleGetMainBundle();
            CFStringRef identifier = CFBundleGetIdentifier(bundle);

            if (!identifier)
                identifier = CFSTR(OUZEL_DEVELOPER_NAME "." OUZEL_APPLICATION_NAME);

            id path = reinterpret_cast<id (*)(id, SEL, CFStringRef)>(&objc_msgSend)(applicationSupportDirectory, sel_getUid("URLByAppendingPathComponent:"), identifier);
            reinterpret_cast<void (*)(id, SEL, id, BOOL, id, id)>(&objc_msgSend)(fileManager, sel_getUid("createDirectoryAtURL:withIntermediateDirectories:attributes:error:"), path, YES, nil, nil);
            id pathString = reinterpret_cast<id (*)(id, SEL)>(&objc_msgSend)(path, sel_getUid("path"));
            auto pathUtf8String = reinterpret_cast<const char* (*)(id, SEL)>(&objc_msgSend)(pathString, sel_getUid("UTF8String"));
            return Path{pathUtf8String, Path::Format::native};
#elif defined(__ANDROID__)
            static_cast<void>(user);

            auto& engineAndroid = static_cast<EngineAndroid&>(engine);
            return engineAndroid.getFilesDirectory();
#elif defined(__linux__)
            Path path;

            const char* homeDirectory = std::getenv("XDG_DATA_HOME");

            if (homeDirectory)
                path = Path{homeDirectory, Path::Format::native};
            else
            {
                struct passwd pwent;
                struct passwd* pwentp;
                std::vector<char> buffer(1024);
                int e;

                while ((e = getpwuid_r(getuid(), &pwent, buffer.data(), buffer.size(), &pwentp)) == ERANGE)
                    buffer.resize(buffer.size() * 2);

                if (e != 0)
                    throw std::runtime_error("Failed to get home directory");
                else
                    path = Path{pwent.pw_dir, Path::Format::native};

                path /= ".local";

                if (getFileType(path) != FileType::directory)
                    createDirectory(path);

                path /= "share";

                if (getFileType(path) != FileType::directory)
                    createDirectory(path);
            }

            path /= OUZEL_DEVELOPER_NAME;

            if (getFileType(path) != FileType::directory)
                createDirectory(path);

            path /= OUZEL_APPLICATION_NAME;

            if (getFileType(path) != FileType::directory)
                createDirectory(path);

            return path;
#else
            return Path{};
#endif
        }

        std::vector<std::byte> FileSystem::readFile(const Path& filename, const bool searchResources)
        {
            if (searchResources)
                for (auto& archive : archives)
                    if (archive.second.fileExists(filename))
                        return archive.second.readFile(filename);

#if defined(__ANDROID__)
            if (!filename.isAbsolute())
            {
                auto& engineAndroid = static_cast<EngineAndroid&>(engine);

                auto asset = AAssetManager_open(engineAndroid.getAssetManager(), filename.getNative().c_str(), AASSET_MODE_STREAMING);

                if (!asset)
                    throw std::runtime_error("Failed to open file " + std::string(filename));

                std::vector<std::byte> data;
                std::byte buffer[1024];

                for (;;)
                {
                    const int bytesRead = AAsset_read(asset, buffer, sizeof(buffer));

                    if (bytesRead < 0)
                        throw std::runtime_error("Failed to read from file");
                    else if (bytesRead == 0)
                        break;

                    data.insert(data.end(), buffer, buffer + bytesRead);
                }

                AAsset_close(asset);

                return data;
            }
#endif

            const auto path = getPath(filename, searchResources);

            // file does not exist
            if (path.isEmpty())
                throw std::runtime_error("Failed to find file " + std::string(filename));

            std::ifstream file(path, std::ios::binary);
            if (!file)
                throw std::runtime_error("Failed to open file " + std::string(filename));

            std::vector<std::byte> data;
            std::byte buffer[1024];

            while (!file.eof())
            {
                file.read(reinterpret_cast<char*>(buffer), sizeof(buffer));
                data.insert(data.end(), buffer, buffer + file.gcount());
            }

            return data;
        }

        bool FileSystem::resourceFileExists(const Path& filename) const
        {
            if (filename.isAbsolute())
                return fileExists(filename);
            else
            {
                Path result = appPath / filename;

                if (fileExists(result))
                    return true;
                else
                    for (const auto& path : resourcePaths)
                    {
                        if (path.isAbsolute()) // if resource path is absolute
                            result = path / filename;
                        else
                            result = appPath / path / filename;

                        if (fileExists(result))
                            return true;
                    }

                return false;
            }
        }

        bool FileSystem::directoryExists(const Path& dirname) const
        {
#if defined(__ANDROID__)
            auto& engineAndroid = static_cast<EngineAndroid&>(engine);

            auto assetDir = AAssetManager_openDir(engineAndroid.getAssetManager(), dirname.getNative().c_str());
            const auto exists = AAssetDir_getNextFileName(assetDir) != nullptr;
            AAssetDir_close(assetDir);

            if (exists) return true;
#endif

            return getFileType(dirname) == FileType::directory;
        }

        bool FileSystem::fileExists(const Path& filename) const
        {
#if defined(__ANDROID__)
            auto& engineAndroid = static_cast<EngineAndroid&>(engine);

            auto asset = AAssetManager_open(engineAndroid.getAssetManager(), filename.getNative().c_str(), AASSET_MODE_STREAMING);

            if (asset)
            {
                AAsset_close(asset);
                return true;
            }
#endif

            return getFileType(filename) == FileType::regular;
        }
    } // namespace storage
} // namespace ouzel
<commit_msg>Make length const<commit_after>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include "../core/Setup.h"

#include <algorithm>
#include <fstream>
#if defined(_WIN32)
#  pragma push_macro("WIN32_LEAN_AND_MEAN")
#  pragma push_macro("NOMINMAX")
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN
#  endif
#  ifndef NOMINMAX
#    define NOMINMAX
#  endif
#  include <Windows.h>
#  include <ShlObj.h>
#  include <Shlwapi.h>
#  include <strsafe.h>
#  pragma pop_macro("WIN32_LEAN_AND_MEAN")
#  pragma pop_macro("NOMINMAX")
#elif defined(__APPLE__)
#  include <TargetConditionals.h>
#  include <objc/message.h>
#  include <objc/NSObjCRuntime.h>
#  include <CoreFoundation/CoreFoundation.h>
#elif defined(__ANDROID__)
#  include "../core/android/EngineAndroid.hpp"
#elif defined(__linux__)
#  include <pwd.h>
#endif

#include "FileSystem.hpp"
#include "Archive.hpp"
#include "../core/Engine.hpp"
#include "../utils/Log.hpp"

#if defined(__APPLE__)
#  include "CfPointer.hpp"
#endif

namespace ouzel
{
    namespace storage
    {
        FileSystem::FileSystem(Engine& initEngine):
            engine(initEngine)
        {
#if defined(_WIN32)
            HINSTANCE instance = GetModuleHandleW(nullptr);
            if (!instance)
                throw std::system_error(GetLastError(), std::system_category(), "Failed to get module handle");
            std::vector<WCHAR> buffer(MAX_PATH + 1);
            for (;;)
            {
                if (!GetModuleFileNameW(instance, buffer.data(), static_cast<DWORD>(buffer.size())))
                    throw std::system_error(GetLastError(), std::system_category(), "Failed to get module filename");

                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                    buffer.resize(buffer.size() * 2);
                else
                    break;
            }

            const auto executablePath = Path{buffer.data(), Path::Format::native};
            appPath = executablePath.getDirectory();
            engine.log(Log::Level::info) << "Application directory: " << appPath;

#elif defined(__APPLE__)
            CFBundleRef bundle = CFBundleGetMainBundle();
            if (!bundle)
                throw std::runtime_error("Failed to get main bundle");

            CfPointer<CFURLRef> relativePath = CFBundleCopyResourcesDirectoryURL(bundle);
            if (!relativePath)
                throw std::runtime_error("Failed to get resource directory");

            CfPointer<CFURLRef> absolutePath = CFURLCopyAbsoluteURL(relativePath.get());
            CfPointer<CFStringRef> path = CFURLCopyFileSystemPath(absolutePath.get(), kCFURLPOSIXPathStyle);

            const CFIndex maximumSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path.get());
            auto resourceDirectory = std::make_unique<char[]>(static_cast<std::size_t>(maximumSize));
            const Boolean result = CFStringGetFileSystemRepresentation(path.get(), resourceDirectory.get(), maximumSize);
            if (!result)
                throw std::runtime_error("Failed to get resource directory");

            appPath = Path{resourceDirectory.get(), Path::Format::native};
            engine.log(Log::Level::info) << "Application directory: " << appPath;

#elif defined(__ANDROID__)
            // not available for Android

#elif defined(__linux__)
            char executableDirectory[PATH_MAX];

            const ssize_t length = readlink("/proc/self/exe", executableDirectory, sizeof(executableDirectory) - 1);
            if (length == -1)
                throw std::system_error(errno, std::system_category(), "Failed to get current directory");

            executableDirectory[length] = '\0';
            const auto executablePath = Path{executableDirectory, Path::Format::native};
            appPath = executablePath.getDirectory();
            engine.log(Log::Level::info) << "Application directory: " << appPath;
#endif
        }

        Path FileSystem::getStorageDirectory(const bool user) const
        {
#if defined(_WIN32)
            WCHAR appDataPath[MAX_PATH];

            HRESULT hr;
            if (FAILED(hr = SHGetFolderPathW(nullptr, (user ? CSIDL_LOCAL_APPDATA : CSIDL_COMMON_APPDATA) | CSIDL_FLAG_CREATE, nullptr, SHGFP_TYPE_CURRENT, appDataPath)))
                throw std::system_error(hr, std::system_category(), "Failed to get the path of the AppData directory");

            Path path = Path{appDataPath, Path::Format::native};

            HINSTANCE instance = GetModuleHandleW(nullptr);
            if (!instance)
                throw std::system_error(GetLastError(), std::system_category(), "Failed to get module handle");
            std::vector<WCHAR> buffer(MAX_PATH + 1);
            for (;;)
            {
                if (!GetModuleFileNameW(instance, buffer.data(), static_cast<DWORD>(buffer.size())))
                    throw std::system_error(GetLastError(), std::system_category(), "Failed to get module filename");

                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                    buffer.resize(buffer.size() * 2);
                else
                    break;
            }

            const auto executablePath = Path{buffer.data(), Path::Format::native};
            DWORD handle;
            const DWORD fileVersionSize = GetFileVersionInfoSizeW(executablePath.getNative().c_str(), &handle);
            if (!fileVersionSize)
                throw std::system_error(GetLastError(), std::system_category(), "Failed to get file version size");

            auto fileVersionBuffer = std::make_unique<char[]>(fileVersionSize);
            if (!GetFileVersionInfoW(executablePath.getNative().c_str(),
                                     0, fileVersionSize,
                                     fileVersionBuffer.get()))
                throw std::system_error(GetLastError(), std::system_category(), "Failed to get file version");

            LPWSTR companyName = nullptr;
            LPWSTR productName = nullptr;

            struct LANGANDCODEPAGE final
            {
                WORD wLanguage;
                WORD wCodePage;
            };
            LPVOID translationPointer;
            UINT translationLength;

            if (VerQueryValueW(fileVersionBuffer.get(),
                               L"\\VarFileInfo\\Translation",
                               &translationPointer,
                               &translationLength))
            {
                auto translation = static_cast<const LANGANDCODEPAGE*>(translationPointer);

                for (UINT i = 0; i < translationLength / sizeof(LANGANDCODEPAGE); ++i)
                {
                    constexpr size_t subBlockSize = 37U;
                    WCHAR subBlock[subBlockSize];

                    StringCchPrintfW(subBlock, subBlockSize,
                                     L"\\StringFileInfo\\%04x%04x\\CompanyName",
                                     translation[i].wLanguage,
                                     translation[i].wCodePage);

                    LPVOID companyNamePointer;
                    UINT companyNameLength;
                    if (VerQueryValueW(fileVersionBuffer.get(),
                                       subBlock,
                                       &companyNamePointer,
                                       &companyNameLength))
                        companyName = static_cast<LPWSTR>(companyNamePointer);

                    StringCchPrintfW(subBlock, subBlockSize,
                                     L"\\StringFileInfo\\%04x%04x\\ProductName",
                                     translation[i].wLanguage,
                                     translation[i].wCodePage);

                    LPVOID productNamePointer;
                    UINT productNameLength;
                    if (VerQueryValueW(fileVersionBuffer.get(),
                                       subBlock,
                                       &productNamePointer,
                                       &productNameLength))
                        productName = static_cast<LPWSTR>(productNamePointer);
                }
            }

            if (companyName)
                path /= companyName;
            else
                path /= OUZEL_DEVELOPER_NAME;

            if (getFileType(path) != FileType::directory)
                createDirectory(path);

            if (productName)
                path /= productName;
            else
                path /= OUZEL_APPLICATION_NAME;

            if (getFileType(path) != FileType::directory)
                createDirectory(path);

            return path;
#elif TARGET_OS_IOS || TARGET_OS_TV
            id fileManager = reinterpret_cast<id (*)(Class, SEL)>(&objc_msgSend)(objc_getClass("NSFileManager"), sel_getUid("defaultManager"));

            constexpr NSUInteger NSDocumentDirectory = 9U;
            constexpr NSUInteger NSUserDomainMask = 1U;
            constexpr NSUInteger NSLocalDomainMask = 2U;

            id documentDirectory = reinterpret_cast<id (*)(id, SEL, NSUInteger, NSUInteger, id, BOOL, id*)>(&objc_msgSend)(fileManager, sel_getUid("URLForDirectory:inDomain:appropriateForURL:create:error:"), NSDocumentDirectory, user ? NSUserDomainMask : NSLocalDomainMask, nil, YES, nil);

            if (!documentDirectory)
                throw std::runtime_error("Failed to get document directory");

            id documentDirectoryString = reinterpret_cast<id (*)(id, SEL)>(&objc_msgSend)(documentDirectory, sel_getUid("path"));
            auto pathUtf8String = reinterpret_cast<const char* (*)(id, SEL)>(&objc_msgSend)(documentDirectoryString, sel_getUid("UTF8String"));
            return Path{pathUtf8String, Path::Format::native};
#elif TARGET_OS_MAC
            id fileManager = reinterpret_cast<id (*)(Class, SEL)>(&objc_msgSend)(objc_getClass("NSFileManager"), sel_getUid("defaultManager"));

            constexpr NSUInteger NSApplicationSupportDirectory = 14U;
            constexpr NSUInteger NSUserDomainMask = 1U;
            constexpr NSUInteger NSLocalDomainMask = 2U;

            id applicationSupportDirectory = reinterpret_cast<id (*)(id, SEL, NSUInteger, NSUInteger, id, BOOL, id*)>(&objc_msgSend)(fileManager, sel_getUid("URLForDirectory:inDomain:appropriateForURL:create:error:"), NSApplicationSupportDirectory, user ? NSUserDomainMask : NSLocalDomainMask, nil, YES, nil);

            if (!applicationSupportDirectory)
                throw std::runtime_error("Failed to get application support directory");

            CFBundleRef bundle = CFBundleGetMainBundle();
            CFStringRef identifier = CFBundleGetIdentifier(bundle);

            if (!identifier)
                identifier = CFSTR(OUZEL_DEVELOPER_NAME "." OUZEL_APPLICATION_NAME);

            id path = reinterpret_cast<id (*)(id, SEL, CFStringRef)>(&objc_msgSend)(applicationSupportDirectory, sel_getUid("URLByAppendingPathComponent:"), identifier);
            reinterpret_cast<void (*)(id, SEL, id, BOOL, id, id)>(&objc_msgSend)(fileManager, sel_getUid("createDirectoryAtURL:withIntermediateDirectories:attributes:error:"), path, YES, nil, nil);
            id pathString = reinterpret_cast<id (*)(id, SEL)>(&objc_msgSend)(path, sel_getUid("path"));
            auto pathUtf8String = reinterpret_cast<const char* (*)(id, SEL)>(&objc_msgSend)(pathString, sel_getUid("UTF8String"));
            return Path{pathUtf8String, Path::Format::native};
#elif defined(__ANDROID__)
            static_cast<void>(user);

            auto& engineAndroid = static_cast<EngineAndroid&>(engine);
            return engineAndroid.getFilesDirectory();
#elif defined(__linux__)
            Path path;

            const char* homeDirectory = std::getenv("XDG_DATA_HOME");

            if (homeDirectory)
                path = Path{homeDirectory, Path::Format::native};
            else
            {
                struct passwd pwent;
                struct passwd* pwentp;
                std::vector<char> buffer(1024);
                int e;

                while ((e = getpwuid_r(getuid(), &pwent, buffer.data(), buffer.size(), &pwentp)) == ERANGE)
                    buffer.resize(buffer.size() * 2);

                if (e != 0)
                    throw std::runtime_error("Failed to get home directory");
                else
                    path = Path{pwent.pw_dir, Path::Format::native};

                path /= ".local";

                if (getFileType(path) != FileType::directory)
                    createDirectory(path);

                path /= "share";

                if (getFileType(path) != FileType::directory)
                    createDirectory(path);
            }

            path /= OUZEL_DEVELOPER_NAME;

            if (getFileType(path) != FileType::directory)
                createDirectory(path);

            path /= OUZEL_APPLICATION_NAME;

            if (getFileType(path) != FileType::directory)
                createDirectory(path);

            return path;
#else
            return Path{};
#endif
        }

        std::vector<std::byte> FileSystem::readFile(const Path& filename, const bool searchResources)
        {
            if (searchResources)
                for (auto& archive : archives)
                    if (archive.second.fileExists(filename))
                        return archive.second.readFile(filename);

#if defined(__ANDROID__)
            if (!filename.isAbsolute())
            {
                auto& engineAndroid = static_cast<EngineAndroid&>(engine);

                auto asset = AAssetManager_open(engineAndroid.getAssetManager(), filename.getNative().c_str(), AASSET_MODE_STREAMING);

                if (!asset)
                    throw std::runtime_error("Failed to open file " + std::string(filename));

                std::vector<std::byte> data;
                std::byte buffer[1024];

                for (;;)
                {
                    const int bytesRead = AAsset_read(asset, buffer, sizeof(buffer));

                    if (bytesRead < 0)
                        throw std::runtime_error("Failed to read from file");
                    else if (bytesRead == 0)
                        break;

                    data.insert(data.end(), buffer, buffer + bytesRead);
                }

                AAsset_close(asset);

                return data;
            }
#endif

            const auto path = getPath(filename, searchResources);

            // file does not exist
            if (path.isEmpty())
                throw std::runtime_error("Failed to find file " + std::string(filename));

            std::ifstream file(path, std::ios::binary);
            if (!file)
                throw std::runtime_error("Failed to open file " + std::string(filename));

            std::vector<std::byte> data;
            std::byte buffer[1024];

            while (!file.eof())
            {
                file.read(reinterpret_cast<char*>(buffer), sizeof(buffer));
                data.insert(data.end(), buffer, buffer + file.gcount());
            }

            return data;
        }

        bool FileSystem::resourceFileExists(const Path& filename) const
        {
            if (filename.isAbsolute())
                return fileExists(filename);
            else
            {
                Path result = appPath / filename;

                if (fileExists(result))
                    return true;
                else
                    for (const auto& path : resourcePaths)
                    {
                        if (path.isAbsolute()) // if resource path is absolute
                            result = path / filename;
                        else
                            result = appPath / path / filename;

                        if (fileExists(result))
                            return true;
                    }

                return false;
            }
        }

        bool FileSystem::directoryExists(const Path& dirname) const
        {
#if defined(__ANDROID__)
            auto& engineAndroid = static_cast<EngineAndroid&>(engine);

            auto assetDir = AAssetManager_openDir(engineAndroid.getAssetManager(), dirname.getNative().c_str());
            const auto exists = AAssetDir_getNextFileName(assetDir) != nullptr;
            AAssetDir_close(assetDir);

            if (exists) return true;
#endif

            return getFileType(dirname) == FileType::directory;
        }

        bool FileSystem::fileExists(const Path& filename) const
        {
#if defined(__ANDROID__)
            auto& engineAndroid = static_cast<EngineAndroid&>(engine);

            auto asset = AAssetManager_open(engineAndroid.getAssetManager(), filename.getNative().c_str(), AASSET_MODE_STREAMING);

            if (asset)
            {
                AAsset_close(asset);
                return true;
            }
#endif

            return getFileType(filename) == FileType::regular;
        }
    } // namespace storage
} // namespace ouzel
<|endoftext|>


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

#ifdef BOARD_xsim
static int numWords = 0x5000/4;
static int iterCnt = 1;
#elif defined(SIMULATION)
static int numWords = 4096;
static int iterCnt = 1;
#else
static int numWords = 0x1240000/4; // make sure to allocate at least one entry of each size
static int iterCnt = 128;
#endif
#ifdef PCIE
static int burstLen = 32;
#else
static int burstLen = 2;
#endif

#ifdef NumEngineServers
int numEngineServers = NumEngineServers;
#else
int numEngineServers = 1;
#endif

static sem_t test_sem;
static size_t alloc_sz = numWords*sizeof(unsigned int);

class MemwriteIndication : public MemwriteIndicationWrapper
{
public:
    MemwriteIndication(int id, int tile=DEFAULT_TILE) : MemwriteIndicationWrapper(id,tile) {}
    void started(uint32_t words) {
        fprintf(stderr, "Memwrite::started: words=%x\n", words);
    }
    void writeDone ( uint32_t srcGen ) {
        fprintf(stderr, "Memwrite::writeDone (%08x)\n", srcGen);
        sem_post(&test_sem);
    }
    void reportStateDbg(uint32_t streamWrCnt, uint32_t srcGen) {
        fprintf(stderr, "Memwrite::reportStateDbg: streamWrCnt=%08x srcGen=%d\n", streamWrCnt, srcGen);
    }
};

int main(int argc, const char **argv)
{
    int mismatch = 0;
    uint32_t sg = 0;
    int max_error = 10;

    if (sem_init(&test_sem, 1, 0)) {
        fprintf(stderr, "error: failed to init test_sem\n");
        exit(1);
    }
    fprintf(stderr, "testmemwrite: start %s %s\n", __DATE__, __TIME__);
    DmaManager *dma = platformInit();
    MemwriteRequestProxy *device = new MemwriteRequestProxy(IfcNames_MemwriteRequestS2H);
    MemwriteIndication deviceIndication(IfcNames_MemwriteIndicationH2S);

    alloc_sz *= numEngineServers;

    fprintf(stderr, "main::allocating %lx bytes of memory...\n", alloc_sz);
    int dstAlloc = portalAlloc(alloc_sz, 0);
    unsigned int *dstBuffer = (unsigned int *)portalMmap(dstAlloc, alloc_sz);
#ifdef FPGA0_CLOCK_FREQ
    long req_freq = FPGA0_CLOCK_FREQ, freq = 0;
    setClockFrequency(0, req_freq, &freq);
    fprintf(stderr, "Requested FCLK[0]=%ld actually %ld\n", req_freq, freq);
#endif
    unsigned int ref_dstAlloc = dma->reference(dstAlloc);
    for (int i = 0; i < numWords*numEngineServers; i++)
        dstBuffer[i] = 0xDEADBEEF;
    portalCacheFlush(dstAlloc, dstBuffer, alloc_sz, 1);
    fprintf(stderr, "testmemwrite: flush and invalidate complete\n");
    fprintf(stderr, "testmemwrite: starting write %08x\n", numWords);

    burstLen = 2; // words
    while (burstLen <= 2) {
      portalTimerStart(0);
      device->startWrite(ref_dstAlloc, 0, numWords, burstLen, iterCnt);
      sem_wait(&test_sem);
      mismatch = 0;
      for (int i = 0; i < numWords; i++) {
        if (dstBuffer[i] != sg) {
	  mismatch++;
	  if (max_error-- > 0)
	    fprintf(stderr, "testmemwrite: [%d] actual %08x expected %08x\n", i, dstBuffer[i], sg);
        }
        sg++;
      }
      platformStatistics();
      fprintf(stderr, "testmemwrite: mismatch count %d.\n", mismatch);
      burstLen *= 2;
      if (mismatch)
	exit(mismatch);
    }
}
<commit_msg>added type cast to fix ndk-build of testmemwrite.cpp<commit_after>/* Copyright (c) 2014 Quanta Research Cambridge, Inc
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
#include "monkit.h"
#include "dmaManager.h"
#include "MemwriteIndication.h"
#include "MemwriteRequest.h"

#ifdef BOARD_xsim
static int numWords = 0x5000/4;
static int iterCnt = 1;
#elif defined(SIMULATION)
static int numWords = 4096;
static int iterCnt = 1;
#else
static int numWords = 0x1240000/4; // make sure to allocate at least one entry of each size
static int iterCnt = 128;
#endif
#ifdef PCIE
static int burstLen = 32;
#else
static int burstLen = 2;
#endif

#ifdef NumEngineServers
int numEngineServers = NumEngineServers;
#else
int numEngineServers = 1;
#endif

static sem_t test_sem;
static size_t alloc_sz = numWords*sizeof(unsigned int);

class MemwriteIndication : public MemwriteIndicationWrapper
{
public:
    MemwriteIndication(int id, int tile=DEFAULT_TILE) : MemwriteIndicationWrapper(id,tile) {}
    void started(uint32_t words) {
        fprintf(stderr, "Memwrite::started: words=%x\n", words);
    }
    void writeDone ( uint32_t srcGen ) {
        fprintf(stderr, "Memwrite::writeDone (%08x)\n", srcGen);
        sem_post(&test_sem);
    }
    void reportStateDbg(uint32_t streamWrCnt, uint32_t srcGen) {
        fprintf(stderr, "Memwrite::reportStateDbg: streamWrCnt=%08x srcGen=%d\n", streamWrCnt, srcGen);
    }
};

int main(int argc, const char **argv)
{
    int mismatch = 0;
    uint32_t sg = 0;
    int max_error = 10;

    if (sem_init(&test_sem, 1, 0)) {
        fprintf(stderr, "error: failed to init test_sem\n");
        exit(1);
    }
    fprintf(stderr, "testmemwrite: start %s %s\n", __DATE__, __TIME__);
    DmaManager *dma = platformInit();
    MemwriteRequestProxy *device = new MemwriteRequestProxy(IfcNames_MemwriteRequestS2H);
    MemwriteIndication deviceIndication(IfcNames_MemwriteIndicationH2S);

    alloc_sz *= numEngineServers;

    fprintf(stderr, "main::allocating %lx bytes of memory...\n", (long)alloc_sz);
    int dstAlloc = portalAlloc(alloc_sz, 0);
    unsigned int *dstBuffer = (unsigned int *)portalMmap(dstAlloc, alloc_sz);
#ifdef FPGA0_CLOCK_FREQ
    long req_freq = FPGA0_CLOCK_FREQ, freq = 0;
    setClockFrequency(0, req_freq, &freq);
    fprintf(stderr, "Requested FCLK[0]=%ld actually %ld\n", req_freq, freq);
#endif
    unsigned int ref_dstAlloc = dma->reference(dstAlloc);
    for (int i = 0; i < numWords*numEngineServers; i++)
        dstBuffer[i] = 0xDEADBEEF;
    portalCacheFlush(dstAlloc, dstBuffer, alloc_sz, 1);
    fprintf(stderr, "testmemwrite: flush and invalidate complete\n");
    fprintf(stderr, "testmemwrite: starting write %08x\n", numWords);

    burstLen = 2; // words
    while (burstLen <= 2) {
      portalTimerStart(0);
      device->startWrite(ref_dstAlloc, 0, numWords, burstLen, iterCnt);
      sem_wait(&test_sem);
      mismatch = 0;
      for (int i = 0; i < numWords; i++) {
        if (dstBuffer[i] != sg) {
	  mismatch++;
	  if (max_error-- > 0)
	    fprintf(stderr, "testmemwrite: [%d] actual %08x expected %08x\n", i, dstBuffer[i], sg);
        }
        sg++;
      }
      platformStatistics();
      fprintf(stderr, "testmemwrite: mismatch count %d.\n", mismatch);
      burstLen *= 2;
      if (mismatch)
	exit(mismatch);
    }
}
<|endoftext|>


<commit_before>/*
 * Remember which servers (socket addresses) failed recently.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "failure.hxx"
#include "pool.hxx"
#include "net/SocketAddress.hxx"
#include "net/AllocatedSocketAddress.hxx"
#include "util/djbhash.h"
#include "util/DeleteDisposer.hxx"
#include "util/Expiry.hxx"

#include <daemon/log.h>

#include <boost/intrusive/unordered_set.hpp>

#include <assert.h>
#include <time.h>

struct Failure
    : boost::intrusive::unordered_set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

    const AllocatedSocketAddress address;

    Expiry expires;

    Expiry fade_expires = Expiry::AlreadyExpired();

    enum failure_status status;

    Failure(SocketAddress _address, enum failure_status _status,
            Expiry _expires)
        :address(_address),
         expires(_expires),
         status(_status) {}

    bool CanExpire() const {
        return status != FAILURE_MONITOR;
    }

    gcc_pure
    bool IsExpired() const {
        return CanExpire() && expires.IsExpired();
    }

    gcc_pure
    bool IsFade() const {
        return !fade_expires.IsExpired();
    }

    enum failure_status GetStatus() const {
        if (!IsExpired())
            return status;
        else if (IsFade())
            return FAILURE_FADE;
        else
            return FAILURE_OK;
    }

    bool OverrideStatus(Expiry now, enum failure_status new_status,
                        std::chrono::seconds duration);

    struct Hash {
        gcc_pure
        size_t operator()(const SocketAddress a) const {
            assert(!a.IsNull());

            return djb_hash(a.GetAddress(), a.GetSize());
        }

        gcc_pure
        size_t operator()(const Failure &f) const {
            return djb_hash(f.address.GetAddress(), f.address.GetSize());
        }
    };

    struct Equal {
        gcc_pure
        bool operator()(const SocketAddress a, const SocketAddress b) const {
            return a == b;
        }

        gcc_pure
        bool operator()(const SocketAddress a, const Failure &b) const {
            return a == b.address;
        }
    };
};

typedef boost::intrusive::unordered_set<Failure,
                                        boost::intrusive::hash<Failure::Hash>,
                                        boost::intrusive::equal<Failure::Equal>,
                                        boost::intrusive::constant_time_size<false>> FailureSet;

static constexpr size_t N_FAILURE_BUCKETS = 97;

static FailureSet::bucket_type failure_buckets[N_FAILURE_BUCKETS];

static FailureSet failures(FailureSet::bucket_traits(failure_buckets,
                                                     N_FAILURE_BUCKETS));

void
failure_init()
{
}

void
failure_deinit(void)
{
    failures.clear_and_dispose(DeleteDisposer());
}

bool
Failure::OverrideStatus(Expiry now, enum failure_status new_status,
                        std::chrono::seconds duration)
{
    if (IsExpired()) {
        /* expired: override in any case */
    } else if (new_status == status) {
        /* same status: update expiry */
    } else if (new_status == FAILURE_FADE) {
        /* store "fade" expiry in special attribute, until the other
           failure status expires */
        fade_expires.Touch(now, duration);
        return true;
    } else if (status == FAILURE_FADE) {
        /* copy the "fade" expiry to the special attribute, and
           overwrite the FAILURE_FADE status */
        fade_expires = expires;
    } else if (new_status < status)
        return false;

    expires.Touch(now, duration);
    status = new_status;
    return true;
}

void
failure_set(SocketAddress address,
            enum failure_status status, std::chrono::seconds duration)
{
    assert(!address.IsNull());
    assert(status > FAILURE_OK);

    const Expiry now = Expiry::Now();

    FailureSet::insert_commit_data hint;
    auto result = failures.insert_check(address, Failure::Hash(),
                                        Failure::Equal(), hint);
    if (result.second) {
        Failure *failure = new Failure(address, status,
                                       Expiry::Touched(now, duration));
        failures.insert_commit(*failure, hint);
    } else {
        Failure &failure = *result.first;
        failure.OverrideStatus(now, status, duration);
    }
}

void
failure_add(SocketAddress address)
{
    failure_set(address, FAILURE_FAILED, std::chrono::seconds(20));
}

static bool
match_status(enum failure_status current, enum failure_status match)
{
    /* FAILURE_OK is a catch-all magic value */
    return match == FAILURE_OK || current == match;
}

static void
failure_unset2(Failure &failure, enum failure_status status)
{
    if (status == FAILURE_FADE)
        failure.fade_expires = Expiry::AlreadyExpired();

    if (!match_status(failure.status, status) && !failure.IsExpired())
        /* don't update if the current status is more serious than the
           one to be removed */
        return;

    if (status != FAILURE_OK && failure.IsFade()) {
        failure.status = FAILURE_FADE;
        failure.expires = failure.fade_expires;
        failure.fade_expires = Expiry::AlreadyExpired();
    } else {
        failures.erase_and_dispose(failures.iterator_to(failure),
                                   DeleteDisposer());
    }
}

void
failure_unset(SocketAddress address, enum failure_status status)
{
    assert(!address.IsNull());

    auto i = failures.find(address, Failure::Hash(), Failure::Equal());
    if (i != failures.end())
        failure_unset2(*i, status);
}

enum failure_status
failure_get_status(SocketAddress address)
{
    assert(!address.IsNull());

    auto i = failures.find(address, Failure::Hash(), Failure::Equal());
    if (i == failures.end())
        return FAILURE_OK;

    return i->GetStatus();
}
<commit_msg>failure: include cleanup<commit_after>/*
 * Remember which servers (socket addresses) failed recently.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "failure.hxx"
#include "pool.hxx"
#include "net/SocketAddress.hxx"
#include "net/AllocatedSocketAddress.hxx"
#include "util/djbhash.h"
#include "util/DeleteDisposer.hxx"
#include "util/Expiry.hxx"

#include <boost/intrusive/unordered_set.hpp>

#include <assert.h>
#include <time.h>

struct Failure
    : boost::intrusive::unordered_set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

    const AllocatedSocketAddress address;

    Expiry expires;

    Expiry fade_expires = Expiry::AlreadyExpired();

    enum failure_status status;

    Failure(SocketAddress _address, enum failure_status _status,
            Expiry _expires)
        :address(_address),
         expires(_expires),
         status(_status) {}

    bool CanExpire() const {
        return status != FAILURE_MONITOR;
    }

    gcc_pure
    bool IsExpired() const {
        return CanExpire() && expires.IsExpired();
    }

    gcc_pure
    bool IsFade() const {
        return !fade_expires.IsExpired();
    }

    enum failure_status GetStatus() const {
        if (!IsExpired())
            return status;
        else if (IsFade())
            return FAILURE_FADE;
        else
            return FAILURE_OK;
    }

    bool OverrideStatus(Expiry now, enum failure_status new_status,
                        std::chrono::seconds duration);

    struct Hash {
        gcc_pure
        size_t operator()(const SocketAddress a) const {
            assert(!a.IsNull());

            return djb_hash(a.GetAddress(), a.GetSize());
        }

        gcc_pure
        size_t operator()(const Failure &f) const {
            return djb_hash(f.address.GetAddress(), f.address.GetSize());
        }
    };

    struct Equal {
        gcc_pure
        bool operator()(const SocketAddress a, const SocketAddress b) const {
            return a == b;
        }

        gcc_pure
        bool operator()(const SocketAddress a, const Failure &b) const {
            return a == b.address;
        }
    };
};

typedef boost::intrusive::unordered_set<Failure,
                                        boost::intrusive::hash<Failure::Hash>,
                                        boost::intrusive::equal<Failure::Equal>,
                                        boost::intrusive::constant_time_size<false>> FailureSet;

static constexpr size_t N_FAILURE_BUCKETS = 97;

static FailureSet::bucket_type failure_buckets[N_FAILURE_BUCKETS];

static FailureSet failures(FailureSet::bucket_traits(failure_buckets,
                                                     N_FAILURE_BUCKETS));

void
failure_init()
{
}

void
failure_deinit(void)
{
    failures.clear_and_dispose(DeleteDisposer());
}

bool
Failure::OverrideStatus(Expiry now, enum failure_status new_status,
                        std::chrono::seconds duration)
{
    if (IsExpired()) {
        /* expired: override in any case */
    } else if (new_status == status) {
        /* same status: update expiry */
    } else if (new_status == FAILURE_FADE) {
        /* store "fade" expiry in special attribute, until the other
           failure status expires */
        fade_expires.Touch(now, duration);
        return true;
    } else if (status == FAILURE_FADE) {
        /* copy the "fade" expiry to the special attribute, and
           overwrite the FAILURE_FADE status */
        fade_expires = expires;
    } else if (new_status < status)
        return false;

    expires.Touch(now, duration);
    status = new_status;
    return true;
}

void
failure_set(SocketAddress address,
            enum failure_status status, std::chrono::seconds duration)
{
    assert(!address.IsNull());
    assert(status > FAILURE_OK);

    const Expiry now = Expiry::Now();

    FailureSet::insert_commit_data hint;
    auto result = failures.insert_check(address, Failure::Hash(),
                                        Failure::Equal(), hint);
    if (result.second) {
        Failure *failure = new Failure(address, status,
                                       Expiry::Touched(now, duration));
        failures.insert_commit(*failure, hint);
    } else {
        Failure &failure = *result.first;
        failure.OverrideStatus(now, status, duration);
    }
}

void
failure_add(SocketAddress address)
{
    failure_set(address, FAILURE_FAILED, std::chrono::seconds(20));
}

static bool
match_status(enum failure_status current, enum failure_status match)
{
    /* FAILURE_OK is a catch-all magic value */
    return match == FAILURE_OK || current == match;
}

static void
failure_unset2(Failure &failure, enum failure_status status)
{
    if (status == FAILURE_FADE)
        failure.fade_expires = Expiry::AlreadyExpired();

    if (!match_status(failure.status, status) && !failure.IsExpired())
        /* don't update if the current status is more serious than the
           one to be removed */
        return;

    if (status != FAILURE_OK && failure.IsFade()) {
        failure.status = FAILURE_FADE;
        failure.expires = failure.fade_expires;
        failure.fade_expires = Expiry::AlreadyExpired();
    } else {
        failures.erase_and_dispose(failures.iterator_to(failure),
                                   DeleteDisposer());
    }
}

void
failure_unset(SocketAddress address, enum failure_status status)
{
    assert(!address.IsNull());

    auto i = failures.find(address, Failure::Hash(), Failure::Equal());
    if (i != failures.end())
        failure_unset2(*i, status);
}

enum failure_status
failure_get_status(SocketAddress address)
{
    assert(!address.IsNull());

    auto i = failures.find(address, Failure::Hash(), Failure::Equal());
    if (i == failures.end())
        return FAILURE_OK;

    return i->GetStatus();
}
<|endoftext|>


<commit_before>#include <stdplus/exception.hpp>
#include <stdplus/fd/line.hpp>
#include <stdplus/fd/ops.hpp>

namespace stdplus
{
namespace fd
{

LineReader::LineReader(Fd& fd) : fd(fd)
{
}

const std::string* LineReader::readLine()
{
    if (hit_eof)
    {
        throw exception::Eof("readLine");
    }
    if (line_complete)
    {
        line.clear();
    }
    while (true)
    {
        if (buf_data.empty())
        {
            try
            {
                buf_data = read(fd, buf);
                if (buf_data.empty())
                {
                    return nullptr;
                }
            }
            catch (const exception::Eof&)
            {
                hit_eof = true;
                return &line;
            }
        }
        line_complete = false;
        for (size_t i = 0; i < buf_data.size(); ++i)
        {
            if (buf_data[i] == '\n')
            {
                line.insert(line.end(), buf_data.begin(), buf_data.begin() + i);
                buf_data = buf_data.subspan(i + 1);
                line_complete = true;
                return &line;
            }
        }
        line.insert(line.end(), buf_data.begin(), buf_data.end());
        buf_data = {};
    }
}

} // namespace fd
} // namespace stdplus
<commit_msg>fd/line: Memcpy is faster than insert<commit_after>#include <cstring>
#include <stdplus/exception.hpp>
#include <stdplus/fd/line.hpp>
#include <stdplus/fd/ops.hpp>

namespace stdplus
{
namespace fd
{

LineReader::LineReader(Fd& fd) : fd(fd)
{
}

const std::string* LineReader::readLine()
{
    if (hit_eof)
    {
        throw exception::Eof("readLine");
    }
    if (line_complete)
    {
        line.clear();
    }
    while (true)
    {
        if (buf_data.empty())
        {
            try
            {
                buf_data = read(fd, buf);
                if (buf_data.empty())
                {
                    return nullptr;
                }
            }
            catch (const exception::Eof&)
            {
                hit_eof = true;
                return &line;
            }
        }
        line_complete = false;
        for (size_t i = 0; i < buf_data.size(); ++i)
        {
            if (buf_data[i] == '\n')
            {
                auto oldsize = line.size();
                line.resize(oldsize + i);
                std::memcpy(line.data() + oldsize, buf_data.data(), i);
                buf_data = buf_data.subspan(i + 1);
                line_complete = true;
                return &line;
            }
        }
        auto oldsize = line.size();
        line.resize(oldsize + buf_data.size());
        std::memcpy(line.data() + oldsize, buf_data.data(), buf_data.size());
        buf_data = {};
    }
}

} // namespace fd
} // namespace stdplus
<|endoftext|>


<commit_before>// Copyright (c) 2013-2018 Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
//    and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/** \file field4d.hpp
 *
 *  \brief Base class for Density and Potential.
 */

#ifndef __FIELD4D_HPP__
#define __FIELD4D_HPP__

namespace sirius {
// TODO: add symmetrize_scalar, symmetrize_vector
class Field4D
{
  private:
      /// Four components of the field: scalar, vector_z, vector_x, vector_y
      std::array<std::unique_ptr<Periodic_function<double>>, 4> components_;
  protected:
    Simulation_context& ctx_;

    void symmetrize(Periodic_function<double>* f__,
                    Periodic_function<double>* gz__,
                    Periodic_function<double>* gx__,
                    Periodic_function<double>* gy__)
    {
        PROFILE("sirius::Field4D::symmetrize");

        /* quick exit: the only symmetry operation is identity */
        if (ctx_.unit_cell().symmetry().num_mag_sym() == 1) {
            return;
        }

        auto& comm = ctx_.comm();

        auto& remap_gvec = ctx_.remap_gvec();

        if (ctx_.control().print_hash_) {
            auto h = f__->hash_f_pw();
            if (ctx_.comm().rank() == 0) {
                print_hash("f_unsymmetrized(G)", h);
            }
        }

        ctx_.unit_cell().symmetry().symmetrize_function(&f__->f_pw_local(0), remap_gvec, ctx_.sym_phase_factors());

        if (ctx_.control().print_hash_) {
            auto h = f__->hash_f_pw();
            if (ctx_.comm().rank() == 0) {
                print_hash("f_symmetrized(G)", h);
            }
        }

        /* symmetrize PW components */
        switch (ctx_.num_mag_dims()) {
            case 1: {
                ctx_.unit_cell().symmetry().symmetrize_vector_function(&gz__->f_pw_local(0), remap_gvec, ctx_.sym_phase_factors());
                break;
            }
            case 3: {
                if (ctx_.control().print_hash_) {
                    auto h1 = gx__->hash_f_pw();
                    auto h2 = gy__->hash_f_pw();
                    auto h3 = gz__->hash_f_pw();
                    if (ctx_.comm().rank() == 0) {
                        print_hash("fx_unsymmetrized(G)", h1);
                        print_hash("fy_unsymmetrized(G)", h2);
                        print_hash("fz_unsymmetrized(G)", h3);
                    }
                }

                ctx_.unit_cell().symmetry().symmetrize_vector_function(&gx__->f_pw_local(0),
                                                                       &gy__->f_pw_local(0),
                                                                       &gz__->f_pw_local(0),
                                                                       remap_gvec,
                                                                       ctx_.sym_phase_factors());

                if (ctx_.control().print_hash_) {
                    auto h1 = gx__->hash_f_pw();
                    auto h2 = gy__->hash_f_pw();
                    auto h3 = gz__->hash_f_pw();
                    if (ctx_.comm().rank() == 0) {
                        print_hash("fx_symmetrized(G)", h1);
                        print_hash("fy_symmetrized(G)", h2);
                        print_hash("fz_symmetrized(G)", h3);
                    }
                }
                break;
            }
        }

        if (ctx_.full_potential()) {
            /* symmetrize MT components */
            ctx_.unit_cell().symmetry().symmetrize_function(f__->f_mt(), comm);
            switch (ctx_.num_mag_dims()) {
                case 1: {
                    ctx_.unit_cell().symmetry().symmetrize_vector_function(gz__->f_mt(), comm);
                    break;
                }
                case 3: {
                    ctx_.unit_cell().symmetry().symmetrize_vector_function(gx__->f_mt(), gy__->f_mt(), gz__->f_mt(), comm);
                    break;
                }
            }
        }
    }

  public:
    Field4D(Simulation_context& ctx__, int lmmax__)
        : ctx_(ctx__)
    {
        for (int i = 0; i < ctx_.num_mag_dims() + 1; i++) {
            components_[i] = std::unique_ptr<Periodic_function<double>>(new Periodic_function<double>(ctx_, lmmax__));
        }
    }

    Periodic_function<double>& scalar()
    {
        return *(components_[0]);
    }

    Periodic_function<double> const& scalar() const
    {
        return *(components_[0]);
    }

    Periodic_function<double>& vector(int i)
    {
        assert(i >= 0 && i <= 2);
        return *(components_[i + 1]);
    }

    Periodic_function<double> const& vector(int i) const
    {
        assert(i >= 0 && i <= 2);
        return *(components_[i + 1]);
    }

    Periodic_function<double>& component(int i)
    {
        assert(i >= 0 && i <= 3);
        return *(components_[i]);
    }

    Periodic_function<double> const& component(int i) const
    {
        assert(i >= 0 && i <= 3);
        return *(components_[i]);
    }

    void allocate()
    {
        for (int i = 0; i < ctx_.num_mag_dims() + 1; i++) {
            components_[i]->allocate_mt(true);
        }
    }
};

}

#endif
<commit_msg>move common functionality to base class<commit_after>// Copyright (c) 2013-2018 Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
//    and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/** \file field4d.hpp
 *
 *  \brief Base class for Density and Potential.
 */

#ifndef __FIELD4D_HPP__
#define __FIELD4D_HPP__

namespace sirius {
// TODO: add symmetrize_scalar, symmetrize_vector
class Field4D
{
  private:
    /// Four components of the field: scalar, vector_z, vector_x, vector_y
    std::array<std::unique_ptr<Periodic_function<double>>, 4> components_;

    /// Default mixer.
    std::unique_ptr<Mixer<double>> mixer_{nullptr};
  protected:
    Simulation_context& ctx_;

    void symmetrize(Periodic_function<double>* f__,
                    Periodic_function<double>* gz__,
                    Periodic_function<double>* gx__,
                    Periodic_function<double>* gy__)
    {
        PROFILE("sirius::Field4D::symmetrize");

        /* quick exit: the only symmetry operation is identity */
        if (ctx_.unit_cell().symmetry().num_mag_sym() == 1) {
            return;
        }

        auto& comm = ctx_.comm();

        auto& remap_gvec = ctx_.remap_gvec();

        if (ctx_.control().print_hash_) {
            auto h = f__->hash_f_pw();
            if (ctx_.comm().rank() == 0) {
                print_hash("f_unsymmetrized(G)", h);
            }
        }

        ctx_.unit_cell().symmetry().symmetrize_function(&f__->f_pw_local(0), remap_gvec, ctx_.sym_phase_factors());

        if (ctx_.control().print_hash_) {
            auto h = f__->hash_f_pw();
            if (ctx_.comm().rank() == 0) {
                print_hash("f_symmetrized(G)", h);
            }
        }

        /* symmetrize PW components */
        switch (ctx_.num_mag_dims()) {
            case 1: {
                ctx_.unit_cell().symmetry().symmetrize_vector_function(&gz__->f_pw_local(0), remap_gvec, ctx_.sym_phase_factors());
                break;
            }
            case 3: {
                if (ctx_.control().print_hash_) {
                    auto h1 = gx__->hash_f_pw();
                    auto h2 = gy__->hash_f_pw();
                    auto h3 = gz__->hash_f_pw();
                    if (ctx_.comm().rank() == 0) {
                        print_hash("fx_unsymmetrized(G)", h1);
                        print_hash("fy_unsymmetrized(G)", h2);
                        print_hash("fz_unsymmetrized(G)", h3);
                    }
                }

                ctx_.unit_cell().symmetry().symmetrize_vector_function(&gx__->f_pw_local(0),
                                                                       &gy__->f_pw_local(0),
                                                                       &gz__->f_pw_local(0),
                                                                       remap_gvec,
                                                                       ctx_.sym_phase_factors());

                if (ctx_.control().print_hash_) {
                    auto h1 = gx__->hash_f_pw();
                    auto h2 = gy__->hash_f_pw();
                    auto h3 = gz__->hash_f_pw();
                    if (ctx_.comm().rank() == 0) {
                        print_hash("fx_symmetrized(G)", h1);
                        print_hash("fy_symmetrized(G)", h2);
                        print_hash("fz_symmetrized(G)", h3);
                    }
                }
                break;
            }
        }

        if (ctx_.full_potential()) {
            /* symmetrize MT components */
            ctx_.unit_cell().symmetry().symmetrize_function(f__->f_mt(), comm);
            switch (ctx_.num_mag_dims()) {
                case 1: {
                    ctx_.unit_cell().symmetry().symmetrize_vector_function(gz__->f_mt(), comm);
                    break;
                }
                case 3: {
                    ctx_.unit_cell().symmetry().symmetrize_vector_function(gx__->f_mt(), gy__->f_mt(), gz__->f_mt(), comm);
                    break;
                }
            }
        }
    }

  public:
    Field4D(Simulation_context& ctx__, int lmmax__)
        : ctx_(ctx__)
    {
        for (int i = 0; i < ctx_.num_mag_dims() + 1; i++) {
            components_[i] = std::unique_ptr<Periodic_function<double>>(new Periodic_function<double>(ctx_, lmmax__));
        }
    }

    Periodic_function<double>& scalar()
    {
        return *(components_[0]);
    }

    Periodic_function<double> const& scalar() const
    {
        return *(components_[0]);
    }

    Periodic_function<double>& vector(int i)
    {
        assert(i >= 0 && i <= 2);
        return *(components_[i + 1]);
    }

    Periodic_function<double> const& vector(int i) const
    {
        assert(i >= 0 && i <= 2);
        return *(components_[i + 1]);
    }

    Periodic_function<double>& component(int i)
    {
        assert(i >= 0 && i <= 3);
        return *(components_[i]);
    }

    Periodic_function<double> const& component(int i) const
    {
        assert(i >= 0 && i <= 3);
        return *(components_[i]);
    }

    void allocate()
    {
        for (int i = 0; i < ctx_.num_mag_dims() + 1; i++) {
            components_[i]->allocate_mt(true);
        }
    }

    inline void fft_transform(int direction__)
    {
        for (int i = 0; i < ctx_.num_mag_dims() + 1; i++) {
            component(i).fft_transform(direction__);
        }
    }

    void mixer_input() // TODO: split f_rg(i) between comm_ortho_fft communicator
    {
        int k{0};

        for (int j = 0; j < ctx_.num_mag_dims() + 1; j++) {
            for (int ialoc = 0; ialoc < ctx_.unit_cell().spl_num_atoms().local_size(); ialoc++) {
                for (int i = 0; i < static_cast<int>(component(j).f_mt(ialoc).size()); i++) {
                    mixer_->input_local(k++, component(j).f_mt(ialoc)[i]);
                }
            }
            for (int i = 0; i < ctx_.fft().local_size(); i++) {
                mixer_->input_local(k++, component(j).f_rg(i));
            }
        }
    }

    void mixer_output()
    {
        int k{0};

        for (int j = 0; j < ctx_.num_mag_dims() + 1; j++) {
            for (int ialoc = 0; ialoc < ctx_.unit_cell().spl_num_atoms().local_size(); ialoc++) {
                auto& f_mt = const_cast<Spheric_function<spectral, double>&>(component(j).f_mt(ialoc));
                for (int i = 0; i < static_cast<int>(component(j).f_mt(ialoc).size()); i++) {
                    f_mt[i] = mixer_->output_local(k++);
                }
            }
            for (int i = 0; i < ctx_.fft().local_size(); i++) {
                component(j).f_rg(i) = mixer_->output_local(k++);
            }
            component(j).sync_mt();
        }
    }

    void mixer_init(Mixer_input mixer_cfg__)
    {
        int sz{0};
        for (int ialoc = 0; ialoc < ctx_.unit_cell().spl_num_atoms().local_size(); ialoc++) {
            sz += static_cast<int>(scalar().f_mt(ialoc).size());
        }
        sz += ctx_.fft().local_size();

        mixer_ = Mixer_factory<double>(0, (ctx_.num_mag_dims() + 1) * sz, mixer_cfg__, ctx_.comm());
        mixer_input();
        mixer_->initialize();
    }

    double mix(double rss_min__)
    {
        mixer_input();
        double rms = mixer_->mix(rss_min__);
        mixer_output();
        return rms;
    }

    Mixer<double>& mixer()
    {
        return *mixer_;
    }

};

} // namespace sirius

#endif
<|endoftext|>


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

/**
 * @file land_detector_main.cpp
 * Land detection algorithm
 *
 * @author Johan Jansen <jnsn.johan@gmail.com>
 * @author Lorenz Meier <lorenz@px4.io>
 */

#include <px4_config.h>
#include <px4_defines.h>
#include <px4_tasks.h>
#include <px4_posix.h>
#include <unistd.h>					//usleep
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <drivers/drv_hrt.h>
#include <systemlib/systemlib.h>	//Scheduler

#include "FixedwingLandDetector.h"
#include "MulticopterLandDetector.h"
#include "VtolLandDetector.h"
#include "RoverLandDetector.h"

namespace land_detector
{

extern "C" __EXPORT int land_detector_main(int argc, char *argv[]);

static char _currentMode[12];

int LandDetector::task_spawn(int argc, char *argv[])
{
	if (argc < 2) {
		print_usage();
		return -1;
	}

	LandDetector *obj;

	if (!strcmp(argv[1], "fixedwing")) {
		obj = new FixedwingLandDetector();

	} else if (!strcmp(argv[1], "multicopter")) {
		obj = new MulticopterLandDetector();

	} else if (!strcmp(argv[1], "vtol")) {
		obj = new VtolLandDetector();

	} else if (!strcmp(argv[1], "ugv")) {
		obj = new RoverLandDetector();

	} else {
		print_usage("unknown mode");
		return -1;
	}

	if (!obj) {
		PX4_ERR("alloc failed");
		return -1;
	}

	int ret = obj->start();

	if (ret < 0) {
		delete obj;
		return ret;
	}

	// Remember current active mode
	strncpy(_currentMode, argv[1], sizeof(_currentMode) - 1);
	_currentMode[sizeof(_currentMode) - 1] = '\0';

	wait_until_running(); // this will wait until _object is set from the cycle method
	_task_id = task_id_is_work_queue;
	return 0;
}

int LandDetector::print_status()
{
	PX4_INFO("running (%s)", _currentMode);
	LandDetector::LandDetectionState state = get_state();

	switch (state) {
	case LandDetector::LandDetectionState::FLYING:
		PX4_INFO("State: Flying");
		break;

	case LandDetector::LandDetectionState::LANDED:
		PX4_INFO("State: Landed");
		break;

	case LandDetector::LandDetectionState::FREEFALL:
		PX4_INFO("State: Freefall");
		break;

	default:
		PX4_ERR("State: unknown");
		break;
	}

	return 0;
}

int LandDetector::print_usage(const char *reason)
{
	if (reason) {
		PX4_ERR("%s\n", reason);
	}

	PRINT_MODULE_DESCRIPTION(
		R"DESCR_STR(
### Description
Module to detect the freefall and landed state of the vehicle, and publishing the `vehicle_land_detected` topic.
Each vehicle type (multirotor, fixedwing, vtol, ...) provides its own algorithm, taking into account various
states, such as commanded thrust, arming state and vehicle motion.

### Implementation
Every type is implemented in its own class with a common base class. The base class maintains a state (landed, maybe_landed, ground_contact).
Each possible state is implemented in the derived classes. A hysteresis and a fixed priority of each internal state determines the actual land_detector
state.

#### Multicopter Land Detector
ground_contact: thrust setpoint and velocity in z-direction must be below a defined threshold for time GROUND_CONTACT_TRIGGER_TIME_US.
When ground_contact is detected, the position controller turns off the thrust setpoint in body x and y.

maybe_landed: it requires ground_contact together with a tighter thrust setpoint threshold and no velocity in the horizontal direction. The trigger
time is defined by MAYBE_LAND_TRIGGER_TIME. When maybe_landed is detected, the position controller sets the thrust setpoint to zero.

landed: it requires maybe_landed to be true for time LAND_DETECTOR_TRIGGER_TIME_US.

The module runs periodically on the HP work queue.
)DESCR_STR");

	PRINT_MODULE_USAGE_NAME("land_detector", "system");
	PRINT_MODULE_USAGE_COMMAND_DESCR("start", "Start the background task");
	PRINT_MODULE_USAGE_ARG("fixedwing|multicopter|vtol|rover", "Select vehicle type", false);
	PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
	return 0;
}

int land_detector_main(int argc, char *argv[])
{
	return LandDetector::main(argc, argv);
}

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

/**
 * @file land_detector_main.cpp
 * Land detection algorithm
 *
 * @author Johan Jansen <jnsn.johan@gmail.com>
 * @author Lorenz Meier <lorenz@px4.io>
 */

#include <px4_config.h>
#include <px4_defines.h>
#include <px4_tasks.h>
#include <px4_posix.h>
#include <unistd.h>					//usleep
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <drivers/drv_hrt.h>
#include <systemlib/systemlib.h>	//Scheduler

#include "FixedwingLandDetector.h"
#include "MulticopterLandDetector.h"
#include "VtolLandDetector.h"
#include "RoverLandDetector.h"

namespace land_detector
{

extern "C" __EXPORT int land_detector_main(int argc, char *argv[]);

static char _currentMode[12];

int LandDetector::task_spawn(int argc, char *argv[])
{
	if (argc < 2) {
		print_usage();
		return -1;
	}

	LandDetector *obj;

	if (!strcmp(argv[1], "fixedwing")) {
		obj = new FixedwingLandDetector();

	} else if (!strcmp(argv[1], "multicopter")) {
		obj = new MulticopterLandDetector();

	} else if (!strcmp(argv[1], "vtol")) {
		obj = new VtolLandDetector();

	} else if (!strcmp(argv[1], "ugv")) {
		obj = new RoverLandDetector();

	} else {
		print_usage("unknown mode");
		return -1;
	}

	if (!obj) {
		PX4_ERR("alloc failed");
		return -1;
	}

	int ret = obj->start();

	if (ret < 0) {
		delete obj;
		return ret;
	}

	// Remember current active mode
	strncpy(_currentMode, argv[1], sizeof(_currentMode) - 1);
	_currentMode[sizeof(_currentMode) - 1] = '\0';

	wait_until_running(); // this will wait until _object is set from the cycle method
	_task_id = task_id_is_work_queue;
	return 0;
}

int LandDetector::print_status()
{
	PX4_INFO("running (%s)", _currentMode);
	LandDetector::LandDetectionState state = get_state();

	switch (state) {
	case LandDetector::LandDetectionState::FLYING:
		PX4_INFO("State: Flying");
		break;

	case LandDetector::LandDetectionState::LANDED:
		PX4_INFO("State: Landed");
		break;

	case LandDetector::LandDetectionState::FREEFALL:
		PX4_INFO("State: Freefall");
		break;

	default:
		PX4_ERR("State: unknown");
		break;
	}

	return 0;
}

int LandDetector::print_usage(const char *reason)
{
	if (reason) {
		PX4_ERR("%s\n", reason);
	}

	PRINT_MODULE_DESCRIPTION(
		R"DESCR_STR(
### Description
Module to detect the freefall and landed state of the vehicle, and publishing the `vehicle_land_detected` topic.
Each vehicle type (multirotor, fixedwing, vtol, ...) provides its own algorithm, taking into account various
states, such as commanded thrust, arming state and vehicle motion.

### Implementation
Every type is implemented in its own class with a common base class. The base class maintains a state (landed,
maybe_landed, ground_contact). Each possible state is implemented in the derived classes. A hysteresis and a fixed
priority of each internal state determines the actual land_detector state.

#### Multicopter Land Detector
**ground_contact**: thrust setpoint and velocity in z-direction must be below a defined threshold for time
GROUND_CONTACT_TRIGGER_TIME_US. When ground_contact is detected, the position controller turns off the thrust setpoint
in body x and y.

**maybe_landed**: it requires ground_contact together with a tighter thrust setpoint threshold and no velocity in the
horizontal direction. The trigger time is defined by MAYBE_LAND_TRIGGER_TIME. When maybe_landed is detected, the
position controller sets the thrust setpoint to zero.

**landed**: it requires maybe_landed to be true for time LAND_DETECTOR_TRIGGER_TIME_US.

The module runs periodically on the HP work queue.
)DESCR_STR");

	PRINT_MODULE_USAGE_NAME("land_detector", "system");
	PRINT_MODULE_USAGE_COMMAND_DESCR("start", "Start the background task");
	PRINT_MODULE_USAGE_ARG("fixedwing|multicopter|vtol|rover", "Select vehicle type", false);
	PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
	return 0;
}

int land_detector_main(int argc, char *argv[])
{
	return LandDetector::main(argc, argv);
}

}
<|endoftext|>