Add HSBP Manager Daemon

This is the initial commit for the hsbp-manager
daemon. Currently it reads a json configuration
and detects whether the cpld is available. More
feaures will be added in small patches.

Tested:

busctl introspect --no-pager xyz.openbmc_project.HsbpManager /xyz/openbmc_project/inventory/item/hsbp/J85894_HSBP_1
NAME                                TYPE      SIGNATURE RESULT/VALUE    FLAGS
org.freedesktop.DBus.Introspectable interface -         -               -
.Introspect                         method    -         s               -
org.freedesktop.DBus.Peer           interface -         -               -
.GetMachineId                       method    -         s               -
.Ping                               method    -         -               -
org.freedesktop.DBus.Properties     interface -         -               -
.Get                                method    ss        v               -
.GetAll                             method    s         a{sv}           -
.Set                                method    ssv       -               -
.PropertiesChanged                  signal    sa{sv}as  -               -
xyz.openbmc_project.Inventory.Item  interface -         -               -
.Present                            property  b         true            emits-change
.PrettyName                         property  s         "J85894 HSBP 1" emits-change

Change-Id: Ibbce272e045f8643af74b778f273168442623919
Signed-off-by: Feist, James <james.feist@linux.intel.com>
diff --git a/hsbp-manager/.clang-format b/hsbp-manager/.clang-format
new file mode 100644
index 0000000..ea71ad6
--- /dev/null
+++ b/hsbp-manager/.clang-format
@@ -0,0 +1,99 @@
+---
+Language:        Cpp
+# BasedOnStyle:  LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands:   true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+  AfterClass:      true
+  AfterControlStatement: true
+  AfterEnum:       true
+  AfterFunction:   true
+  AfterNamespace:  true
+  AfterObjCDeclaration: true
+  AfterStruct:     true
+  AfterUnion:      true
+  BeforeCatch:     true
+  BeforeElse:      true
+  IndentBraces:    false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit:     80
+CommentPragmas:  '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+PointerAlignment: Left
+DisableFormat:   false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+  - Regex:           '^[<"](gtest|gmock)'
+    Priority:        5
+  - Regex:           '^"config.h"'
+    Priority:        -1
+  - Regex:           '^".*\.hpp"'
+    Priority:        1
+  - Regex:           '^<.*\.h>'
+    Priority:        2
+  - Regex:           '^<.*'
+    Priority:        3
+  - Regex:           '.*'
+    Priority:        4
+IndentCaseLabels: true
+IndentWidth:     4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+ReflowComments:  true
+SortIncludes:    true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles:  false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard:        Cpp11
+TabWidth:        4
+UseTab:          Never
+...
+
diff --git a/hsbp-manager/.gitignore b/hsbp-manager/.gitignore
new file mode 100644
index 0000000..a007fea
--- /dev/null
+++ b/hsbp-manager/.gitignore
@@ -0,0 +1 @@
+build/*
diff --git a/hsbp-manager/CMakeLists.txt b/hsbp-manager/CMakeLists.txt
new file mode 100644
index 0000000..20560c9
--- /dev/null
+++ b/hsbp-manager/CMakeLists.txt
@@ -0,0 +1,98 @@
+cmake_minimum_required (VERSION 3.1 FATAL_ERROR)
+set (BUILD_SHARED_LIBRARIES OFF)
+include (ExternalProject)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
+if (NOT YOCTO) # to download gtest
+    include ("cmake/HunterGate.cmake")
+    huntergate (URL "https://github.com/ruslo/hunter/archive/v0.18.64.tar.gz"
+                SHA1 "baf9c8cc4f65306f0e442b5419967b4c4c04589a")
+endif ()
+
+project (hsbp-manager CXX)
+
+set (
+    CMAKE_CXX_FLAGS
+    "${CMAKE_CXX_FLAGS} -lstdc++fs \
+    -Werror \
+    -Wall \
+    -Wextra \
+    -Wshadow \
+    -Wnon-virtual-dtor \
+    -Wold-style-cast \
+    -Wcast-align \
+    -Wunused \
+    -Woverloaded-virtual \
+    -Wpedantic \
+    -Wconversion \
+    -Wmisleading-indentation \
+    -Wduplicated-cond \
+    -Wduplicated-branches \
+    -Wlogical-op \
+    -Wnull-dereference \
+    -Wuseless-cast \
+    -Wdouble-promotion \
+    -Wformat=2 \
+    -fno-rtti"
+)
+
+option (YOCTO "Enable Building in Yocto" OFF)
+
+if (NOT YOCTO)
+    externalproject_add (
+        Boost URL
+        https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.gz
+        URL_MD5 b50944c0c13f81ce2c006802a1186f5a SOURCE_DIR
+        "${CMAKE_BINARY_DIR}/boost-src" BINARY_DIR
+        "${CMAKE_BINARY_DIR}/boost-build" CONFIGURE_COMMAND "" BUILD_COMMAND ""
+        INSTALL_COMMAND mkdir -p "${CMAKE_BINARY_DIR}/prefix/include/" && cp -R
+        ${CMAKE_BINARY_DIR}/boost-src/boost ${CMAKE_BINARY_DIR}/prefix/include
+    ) # requires apt install autoconf-archive and autoconf
+    externalproject_add (sdbusplus-project PREFIX
+                         ${CMAKE_BINARY_DIR}/sdbusplus-project GIT_REPOSITORY
+                         https://github.com/openbmc/sdbusplus.git GIT_TAG
+                         bed15f0cee4784acdf151cca14efdfb98cb9d397 SOURCE_DIR
+                         ${CMAKE_BINARY_DIR}/sdbusplus-src BINARY_DIR
+                         ${CMAKE_BINARY_DIR}/sdbusplus-build CONFIGURE_COMMAND
+                         "" BUILD_COMMAND cd ${CMAKE_BINARY_DIR}/sdbusplus-src
+                         && ./bootstrap.sh && ./configure --enable-transaction
+                         && make -j libsdbusplus.la INSTALL_COMMAND ""
+                         LOG_DOWNLOAD ON)
+
+    include_directories (SYSTEM ${CMAKE_BINARY_DIR}/sdbusplus-src)
+    link_directories (${CMAKE_BINARY_DIR}/sdbusplus-src/.libs)
+
+    include_directories (SYSTEM ${CMAKE_BINARY_DIR}/boost-src)
+    set (CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/boost-src ${CMAKE_PREFIX_PATH})
+
+    option (HUNTER_ENABLED "Enable hunter package pulling" ON)
+    hunter_add_package (GTest)
+
+    find_package (GTest CONFIG REQUIRED)
+endif ()
+
+add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions (-DBOOST_ALL_NO_LIB)
+add_definitions (-DBOOST_NO_RTTI)
+add_definitions (-DBOOST_NO_TYPEID)
+add_definitions (-DBOOST_ASIO_DISABLE_THREADS)
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+add_executable (hsbp-manager src/hsbp_manager.cpp)
+
+target_link_libraries (hsbp-manager -lsystemd)
+target_link_libraries (hsbp-manager i2c)
+target_link_libraries (hsbp-manager ${Boost_LIBRARIES})
+target_link_libraries (hsbp-manager sdbusplus)
+
+if (NOT YOCTO)
+    add_dependencies (hsbp-manager sdbusplus-project)
+endif ()
+
+set (SERVICE_FILES ${PROJECT_SOURCE_DIR}/service_files/hsbp-manager.service)
+
+install (TARGETS hsbp-manager DESTINATION bin)
+install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/)
diff --git a/hsbp-manager/LICENCE b/hsbp-manager/LICENCE
new file mode 100644
index 0000000..729f4d4
--- /dev/null
+++ b/hsbp-manager/LICENCE
@@ -0,0 +1,13 @@
+Copyright 2019 Intel Corporation
+
+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.
diff --git a/hsbp-manager/cmake-format.json b/hsbp-manager/cmake-format.json
new file mode 100644
index 0000000..4a701ae
--- /dev/null
+++ b/hsbp-manager/cmake-format.json
@@ -0,0 +1,12 @@
+{
+  "enum_char": ".",
+  "line_ending": "unix",
+  "bullet_char": "*",
+  "max_subargs_per_line": 99,
+  "command_case": "lower",
+  "tab_size": 4,
+  "line_width": 80,
+  "separate_fn_name_with_space": true,
+  "dangle_parens": true,
+  "separate_ctrl_name_with_space": true
+}
diff --git a/hsbp-manager/cmake/HunterGate.cmake b/hsbp-manager/cmake/HunterGate.cmake
new file mode 100644
index 0000000..97f69cc
--- /dev/null
+++ b/hsbp-manager/cmake/HunterGate.cmake
@@ -0,0 +1,514 @@
+# Copyright (c) 2013-2015, Ruslan Baratov
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+#   list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+#
+# 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.
+
+# This is a gate file to Hunter package manager.
+# Include this file using `include` command and add package you need, example:
+#
+#     cmake_minimum_required(VERSION 3.0)
+#
+#     include("cmake/HunterGate.cmake")
+#     HunterGate(
+#         URL "https://github.com/path/to/hunter/archive.tar.gz"
+#         SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
+#     )
+#
+#     project(MyProject)
+#
+#     hunter_add_package(Foo)
+#     hunter_add_package(Boo COMPONENTS Bar Baz)
+#
+# Projects:
+#     * https://github.com/hunter-packages/gate/
+#     * https://github.com/ruslo/hunter
+
+option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
+if(HUNTER_ENABLED)
+  if(CMAKE_VERSION VERSION_LESS "3.0")
+    message(FATAL_ERROR "At least CMake version 3.0 required for hunter dependency management."
+      " Update CMake or set HUNTER_ENABLED to OFF.")
+  endif()
+endif()
+
+include(CMakeParseArguments) # cmake_parse_arguments
+
+option(HUNTER_STATUS_PRINT "Print working status" ON)
+option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
+
+set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki")
+
+function(hunter_gate_status_print)
+  foreach(print_message ${ARGV})
+    if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
+      message(STATUS "[hunter] ${print_message}")
+    endif()
+  endforeach()
+endfunction()
+
+function(hunter_gate_status_debug)
+  foreach(print_message ${ARGV})
+    if(HUNTER_STATUS_DEBUG)
+      string(TIMESTAMP timestamp)
+      message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
+    endif()
+  endforeach()
+endfunction()
+
+function(hunter_gate_wiki wiki_page)
+  message("------------------------------ WIKI -------------------------------")
+  message("    ${HUNTER_WIKI}/${wiki_page}")
+  message("-------------------------------------------------------------------")
+  message("")
+  message(FATAL_ERROR "")
+endfunction()
+
+function(hunter_gate_internal_error)
+  message("")
+  foreach(print_message ${ARGV})
+    message("[hunter ** INTERNAL **] ${print_message}")
+  endforeach()
+  message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
+  message("")
+  hunter_gate_wiki("error.internal")
+endfunction()
+
+function(hunter_gate_fatal_error)
+  cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}")
+  string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki)
+  if(have_no_wiki)
+    hunter_gate_internal_error("Expected wiki")
+  endif()
+  message("")
+  foreach(x ${hunter_UNPARSED_ARGUMENTS})
+    message("[hunter ** FATAL ERROR **] ${x}")
+  endforeach()
+  message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
+  message("")
+  hunter_gate_wiki("${hunter_WIKI}")
+endfunction()
+
+function(hunter_gate_user_error)
+  hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data")
+endfunction()
+
+function(hunter_gate_self root version sha1 result)
+  string(COMPARE EQUAL "${root}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("root is empty")
+  endif()
+
+  string(COMPARE EQUAL "${version}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("version is empty")
+  endif()
+
+  string(COMPARE EQUAL "${sha1}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("sha1 is empty")
+  endif()
+
+  string(SUBSTRING "${sha1}" 0 7 archive_id)
+
+  if(EXISTS "${root}/cmake/Hunter")
+    set(hunter_self "${root}")
+  else()
+    set(
+        hunter_self
+        "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
+    )
+  endif()
+
+  set("${result}" "${hunter_self}" PARENT_SCOPE)
+endfunction()
+
+# Set HUNTER_GATE_ROOT cmake variable to suitable value.
+function(hunter_gate_detect_root)
+  # Check CMake variable
+  string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty)
+  if(not_empty)
+    set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
+    return()
+  endif()
+
+  # Check environment variable
+  string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty)
+  if(not_empty)
+    set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
+    return()
+  endif()
+
+  # Check HOME environment variable
+  string(COMPARE NOTEQUAL "$ENV{HOME}" "" result)
+  if(result)
+    set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
+    hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
+    return()
+  endif()
+
+  # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
+  if(WIN32)
+    string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result)
+    if(result)
+      set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
+      hunter_gate_status_debug(
+          "HUNTER_ROOT set using SYSTEMDRIVE environment variable"
+      )
+      return()
+    endif()
+
+    string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result)
+    if(result)
+      set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
+      hunter_gate_status_debug(
+          "HUNTER_ROOT set using USERPROFILE environment variable"
+      )
+      return()
+    endif()
+  endif()
+
+  hunter_gate_fatal_error(
+      "Can't detect HUNTER_ROOT"
+      WIKI "error.detect.hunter.root"
+  )
+endfunction()
+
+macro(hunter_gate_lock dir)
+  if(NOT HUNTER_SKIP_LOCK)
+    if("${CMAKE_VERSION}" VERSION_LESS "3.2")
+      hunter_gate_fatal_error(
+          "Can't lock, upgrade to CMake 3.2 or use HUNTER_SKIP_LOCK"
+          WIKI "error.can.not.lock"
+      )
+    endif()
+    hunter_gate_status_debug("Locking directory: ${dir}")
+    file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
+    hunter_gate_status_debug("Lock done")
+  endif()
+endmacro()
+
+function(hunter_gate_download dir)
+  string(
+      COMPARE
+      NOTEQUAL
+      "$ENV{HUNTER_DISABLE_AUTOINSTALL}"
+      ""
+      disable_autoinstall
+  )
+  if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
+    hunter_gate_fatal_error(
+        "Hunter not found in '${dir}'"
+        "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
+        "Settings:"
+        "  HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
+        "  HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
+        WIKI "error.run.install"
+    )
+  endif()
+  string(COMPARE EQUAL "${dir}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("Empty 'dir' argument")
+  endif()
+
+  string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
+  endif()
+
+  string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
+  if(is_bad)
+    hunter_gate_internal_error("HUNTER_GATE_URL empty")
+  endif()
+
+  set(done_location "${dir}/DONE")
+  set(sha1_location "${dir}/SHA1")
+
+  set(build_dir "${dir}/Build")
+  set(cmakelists "${dir}/CMakeLists.txt")
+
+  hunter_gate_lock("${dir}")
+  if(EXISTS "${done_location}")
+    # while waiting for lock other instance can do all the job
+    hunter_gate_status_debug("File '${done_location}' found, skip install")
+    return()
+  endif()
+
+  file(REMOVE_RECURSE "${build_dir}")
+  file(REMOVE_RECURSE "${cmakelists}")
+
+  file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
+
+  # Disabling languages speeds up a little bit, reduces noise in the output
+  # and avoids path too long windows error
+  file(
+      WRITE
+      "${cmakelists}"
+      "cmake_minimum_required(VERSION 3.0)\n"
+      "project(HunterDownload LANGUAGES NONE)\n"
+      "include(ExternalProject)\n"
+      "ExternalProject_Add(\n"
+      "    Hunter\n"
+      "    URL\n"
+      "    \"${HUNTER_GATE_URL}\"\n"
+      "    URL_HASH\n"
+      "    SHA1=${HUNTER_GATE_SHA1}\n"
+      "    DOWNLOAD_DIR\n"
+      "    \"${dir}\"\n"
+      "    SOURCE_DIR\n"
+      "    \"${dir}/Unpacked\"\n"
+      "    CONFIGURE_COMMAND\n"
+      "    \"\"\n"
+      "    BUILD_COMMAND\n"
+      "    \"\"\n"
+      "    INSTALL_COMMAND\n"
+      "    \"\"\n"
+      ")\n"
+  )
+
+  if(HUNTER_STATUS_DEBUG)
+    set(logging_params "")
+  else()
+    set(logging_params OUTPUT_QUIET)
+  endif()
+
+  hunter_gate_status_debug("Run generate")
+
+  # Need to add toolchain file too.
+  # Otherwise on Visual Studio + MDD this will fail with error:
+  # "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
+  if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
+    set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}")
+  else()
+    # 'toolchain_arg' can't be empty
+    set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
+  endif()
+
+  execute_process(
+      COMMAND "${CMAKE_COMMAND}" "-H${dir}" "-B${build_dir}" "-G${CMAKE_GENERATOR}" "${toolchain_arg}"
+      WORKING_DIRECTORY "${dir}"
+      RESULT_VARIABLE download_result
+      ${logging_params}
+  )
+
+  if(NOT download_result EQUAL 0)
+    hunter_gate_internal_error("Configure project failed")
+  endif()
+
+  hunter_gate_status_print(
+      "Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
+      "  ${HUNTER_GATE_URL}"
+      "  -> ${dir}"
+  )
+  execute_process(
+      COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
+      WORKING_DIRECTORY "${dir}"
+      RESULT_VARIABLE download_result
+      ${logging_params}
+  )
+
+  if(NOT download_result EQUAL 0)
+    hunter_gate_internal_error("Build project failed")
+  endif()
+
+  file(REMOVE_RECURSE "${build_dir}")
+  file(REMOVE_RECURSE "${cmakelists}")
+
+  file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
+  file(WRITE "${done_location}" "DONE")
+
+  hunter_gate_status_debug("Finished")
+endfunction()
+
+# Must be a macro so master file 'cmake/Hunter' can
+# apply all variables easily just by 'include' command
+# (otherwise PARENT_SCOPE magic needed)
+macro(HunterGate)
+  if(HUNTER_GATE_DONE)
+    # variable HUNTER_GATE_DONE set explicitly for external project
+    # (see `hunter_download`)
+    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
+  endif()
+
+  # First HunterGate command will init Hunter, others will be ignored
+  get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
+
+  if(NOT HUNTER_ENABLED)
+    # Empty function to avoid error "unknown function"
+    function(hunter_add_package)
+    endfunction()
+  elseif(_hunter_gate_done)
+    hunter_gate_status_debug("Secondary HunterGate (use old settings)")
+    hunter_gate_self(
+        "${HUNTER_CACHED_ROOT}"
+        "${HUNTER_VERSION}"
+        "${HUNTER_SHA1}"
+        _hunter_self
+    )
+    include("${_hunter_self}/cmake/Hunter")
+  else()
+    set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
+
+    string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
+    if(_have_project_name)
+      hunter_gate_fatal_error(
+          "Please set HunterGate *before* 'project' command. "
+          "Detected project: ${PROJECT_NAME}"
+          WIKI "error.huntergate.before.project"
+      )
+    endif()
+
+    cmake_parse_arguments(
+        HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
+    )
+
+    string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
+    string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
+    string(
+        COMPARE
+        NOTEQUAL
+        "${HUNTER_GATE_UNPARSED_ARGUMENTS}"
+        ""
+        _have_unparsed
+    )
+    string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
+    string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
+
+    if(_have_unparsed)
+      hunter_gate_user_error(
+          "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
+      )
+    endif()
+    if(_empty_sha1)
+      hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
+    endif()
+    if(_empty_url)
+      hunter_gate_user_error("URL suboption of HunterGate is mandatory")
+    endif()
+    if(_have_global)
+      if(HUNTER_GATE_LOCAL)
+        hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
+      endif()
+      if(_have_filepath)
+        hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
+      endif()
+    endif()
+    if(HUNTER_GATE_LOCAL)
+      if(_have_global)
+        hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
+      endif()
+      if(_have_filepath)
+        hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
+      endif()
+    endif()
+    if(_have_filepath)
+      if(_have_global)
+        hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
+      endif()
+      if(HUNTER_GATE_LOCAL)
+        hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
+      endif()
+    endif()
+
+    hunter_gate_detect_root() # set HUNTER_GATE_ROOT
+
+    # Beautify path, fix probable problems with windows path slashes
+    get_filename_component(
+        HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
+    )
+    hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
+    if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
+      string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
+      if(NOT _contain_spaces EQUAL -1)
+        hunter_gate_fatal_error(
+            "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
+            "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
+            "(Use at your own risk!)"
+            WIKI "error.spaces.in.hunter.root"
+        )
+      endif()
+    endif()
+
+    string(
+        REGEX
+        MATCH
+        "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
+        HUNTER_GATE_VERSION
+        "${HUNTER_GATE_URL}"
+    )
+    string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
+    if(_is_empty)
+      set(HUNTER_GATE_VERSION "unknown")
+    endif()
+
+    hunter_gate_self(
+        "${HUNTER_GATE_ROOT}"
+        "${HUNTER_GATE_VERSION}"
+        "${HUNTER_GATE_SHA1}"
+        _hunter_self
+    )
+
+    set(_master_location "${_hunter_self}/cmake/Hunter")
+    if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter")
+      # Hunter downloaded manually (e.g. by 'git clone')
+      set(_unused "xxxxxxxxxx")
+      set(HUNTER_GATE_SHA1 "${_unused}")
+      set(HUNTER_GATE_VERSION "${_unused}")
+    else()
+      get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
+      set(_done_location "${_archive_id_location}/DONE")
+      set(_sha1_location "${_archive_id_location}/SHA1")
+
+      # Check Hunter already downloaded by HunterGate
+      if(NOT EXISTS "${_done_location}")
+        hunter_gate_download("${_archive_id_location}")
+      endif()
+
+      if(NOT EXISTS "${_done_location}")
+        hunter_gate_internal_error("hunter_gate_download failed")
+      endif()
+
+      if(NOT EXISTS "${_sha1_location}")
+        hunter_gate_internal_error("${_sha1_location} not found")
+      endif()
+      file(READ "${_sha1_location}" _sha1_value)
+      string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
+      if(NOT _is_equal)
+        hunter_gate_internal_error(
+            "Short SHA1 collision:"
+            "  ${_sha1_value} (from ${_sha1_location})"
+            "  ${HUNTER_GATE_SHA1} (HunterGate)"
+        )
+      endif()
+      if(NOT EXISTS "${_master_location}")
+        hunter_gate_user_error(
+            "Master file not found:"
+            "  ${_master_location}"
+            "try to update Hunter/HunterGate"
+        )
+      endif()
+    endif()
+    include("${_master_location}")
+    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
+  endif()
+endmacro()
\ No newline at end of file
diff --git a/hsbp-manager/include/utils.hpp b/hsbp-manager/include/utils.hpp
new file mode 100644
index 0000000..eec2cd6
--- /dev/null
+++ b/hsbp-manager/include/utils.hpp
@@ -0,0 +1,77 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <cstdint>
+#include <string>
+#include <variant>
+#include <vector>
+
+using GetSubTreeType = std::vector<
+    std::pair<std::string,
+              std::vector<std::pair<std::string, std::vector<std::string>>>>>;
+using BasicVariantType =
+    std::variant<std::vector<std::string>, std::string, int64_t, uint64_t,
+                 double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>;
+
+namespace mapper
+{
+constexpr const char* busName = "xyz.openbmc_project.ObjectMapper";
+constexpr const char* path = "/xyz/openbmc_project/object_mapper";
+constexpr const char* interface = "xyz.openbmc_project.ObjectMapper";
+constexpr const char* subtree = "GetSubTree";
+} // namespace mapper
+
+namespace entityManager
+{
+constexpr const char* busName = "xyz.openbmc_project.EntityManager";
+} // namespace entityManager
+
+namespace inventory
+{
+constexpr const char* interface = "xyz.openbmc_project.Inventory.Item";
+} // namespace inventory
+
+namespace hsbp
+{
+enum class registers : uint8_t
+{
+    fpgaIdH = 0x0,
+    fpgaIdL = 0x1,
+    typeId = 0x2,
+    bootVer = 0x3,
+    fpgaVer = 0x4,
+    securityRev = 0x5,
+    funSupported = 0x6,
+    numDisks = 0x7,
+    presence = 0x8,
+    ssdIFDET = 0x9,
+    ifdetPart = 0xA,
+    statusLocate = 0xB,
+    statusFail = 0xC,
+    statusRebuild = 0xD,
+    ledOverride = 0xE,
+    ledStatus = 0xF,
+    ledPattern0 = 0x10,
+    ledPattern1 = 0x11,
+    ledPattern2 = 0x12,
+    ledPattern3 = 0x13,
+    ledPattern4 = 0x14,
+    ledPattern5 = 0x15,
+    ledPattern6 = 0x16,
+    ledPattern7 = 0x17,
+};
+
+} // namespace hsbp
diff --git a/hsbp-manager/service_files/hsbp-manager.service b/hsbp-manager/service_files/hsbp-manager.service
new file mode 100644
index 0000000..b9637d0
--- /dev/null
+++ b/hsbp-manager/service_files/hsbp-manager.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=HSBP Manager
+
+[Service]
+Type=dbus
+BusName=xyz.openbmc_project.HsbpManager
+Restart=always
+RestartSec=5
+ExecStart=/usr/bin/hsbp-manager
+
+[Install]
+WantedBy=multi-user.target
diff --git a/hsbp-manager/src/hsbp_manager.cpp b/hsbp-manager/src/hsbp_manager.cpp
new file mode 100644
index 0000000..110d32d
--- /dev/null
+++ b/hsbp-manager/src/hsbp_manager.cpp
@@ -0,0 +1,201 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "utils.hpp"
+
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <iostream>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <string>
+
+extern "C" {
+#include <i2c/smbus.h>
+#include <linux/i2c-dev.h>
+}
+
+constexpr const char* configType =
+    "xyz.openbmc_project.Configuration.Intel_HSBP_CPLD";
+
+boost::asio::io_context io;
+auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+sdbusplus::asio::object_server objServer(conn);
+
+struct Backplane
+{
+
+    Backplane(size_t busIn, size_t addressIn, const std::string& nameIn) :
+        bus(busIn), address(addressIn), name(nameIn)
+    {
+    }
+
+    void run()
+    {
+        file = open(("/dev/i2c-" + std::to_string(bus)).c_str(), O_RDWR);
+        if (file < 0)
+        {
+            std::cerr << "unable to open bus " << bus << "\n";
+            return;
+        }
+
+        if (ioctl(file, I2C_SLAVE_FORCE, address) < 0)
+        {
+            std::cerr << "unable to set address to " << address << "\n";
+            return;
+        }
+
+        hsbpItemIface = objServer.add_interface(
+            "/xyz/openbmc_project/inventory/item/hsbp/" +
+                boost::replace_all_copy(name, " ", "_"),
+            inventory::interface);
+        hsbpItemIface->register_property("Present", present(true));
+        hsbpItemIface->register_property("PrettyName", name);
+        hsbpItemIface->initialize();
+
+        if (!present())
+        {
+            // backplane isn't there
+            return;
+        }
+    }
+
+    bool present(bool update = false)
+    {
+        static bool present = false;
+        if (update)
+        {
+            present = i2c_smbus_read_byte(file) >= 0;
+        }
+        return present;
+    }
+    ~Backplane()
+    {
+        objServer.remove_interface(hsbpItemIface);
+        if (file >= 0)
+        {
+            close(file);
+        }
+    }
+
+    size_t bus;
+    size_t address;
+    int file = -1;
+    std::string name;
+    std::string type;
+
+    std::shared_ptr<sdbusplus::asio::dbus_interface> hsbpItemIface;
+    std::vector<std::shared_ptr<sdbusplus::asio::dbus_interface>>
+        driveItemIfaces;
+};
+
+std::unordered_map<std::string, Backplane> backplanes;
+
+void populate()
+{
+    conn->async_method_call(
+        [](const boost::system::error_code ec, const GetSubTreeType& subtree) {
+            if (ec)
+            {
+                std::cerr << "Error contacting mapper " << ec.message() << "\n";
+                return;
+            }
+            for (const auto& [path, objDict] : subtree)
+            {
+                if (objDict.empty())
+                {
+                    continue;
+                }
+
+                const std::string& owner = objDict.begin()->first;
+                conn->async_method_call(
+                    [path](const boost::system::error_code ec2,
+                           const boost::container::flat_map<
+                               std::string, BasicVariantType>& resp) {
+                        if (ec2)
+                        {
+                            std::cerr << "Error Getting Config "
+                                      << ec2.message() << "\n";
+                            return;
+                        }
+                        backplanes.clear();
+                        std::optional<size_t> bus;
+                        std::optional<size_t> address;
+                        std::optional<std::string> name;
+                        for (const auto& [key, value] : resp)
+                        {
+                            if (key == "Bus")
+                            {
+                                bus = std::get<uint64_t>(value);
+                            }
+                            else if (key == "Address")
+                            {
+                                address = std::get<uint64_t>(value);
+                            }
+                            else if (key == "Name")
+                            {
+                                name = std::get<std::string>(value);
+                            }
+                        }
+                        if (!bus || !address || !name)
+                        {
+                            std::cerr << "Illegal configuration at " << path
+                                      << "\n";
+                            return;
+                        }
+                        const auto& [backplane, status] = backplanes.emplace(
+                            *name, Backplane(*bus, *address, *name));
+                        backplane->second.run();
+                    },
+                    owner, path, "org.freedesktop.DBus.Properties", "GetAll",
+                    configType);
+            }
+        },
+        mapper::busName, mapper::path, mapper::interface, mapper::subtree, "/",
+        0, std::array<const char*, 1>{configType});
+}
+
+int main()
+{
+    boost::asio::steady_timer callbackTimer(io);
+
+    conn->request_name("xyz.openbmc_project.HsbpManager");
+
+    sdbusplus::bus::match::match match(
+        *conn,
+        "type='signal',member='PropertiesChanged',arg0='" +
+            std::string(configType) + "'",
+        [&callbackTimer](sdbusplus::message::message&) {
+            callbackTimer.expires_after(std::chrono::seconds(2));
+            callbackTimer.async_wait([](const boost::system::error_code ec) {
+                if (ec == boost::asio::error::operation_aborted)
+                {
+                    // timer was restarted
+                    return;
+                }
+                else if (ec)
+                {
+                    std::cerr << "Timer error" << ec.message() << "\n";
+                    return;
+                }
+                populate();
+            });
+        });
+
+    io.post([]() { populate(); });
+    io.run();
+}