summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/datetime
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/datetime')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt40
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp265
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service13
6 files changed, 454 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb
new file mode 100644
index 000000000..089aaf59f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb
@@ -0,0 +1,26 @@
+
+SUMMARY = "PCH BMC time service"
+DESCRIPTION = "This service will read date/time from PCH device periodically, and set the BMC system time accordingly"
+
+SRC_URI = "\
+ file://CMakeLists.txt \
+ file://pch-time-sync.cpp \
+ "
+PV = "0.1"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+S = "${WORKDIR}"
+
+SYSTEMD_SERVICE_${PN} = "pch-time-sync.service"
+
+inherit cmake
+inherit obmc-phosphor-systemd
+
+DEPENDS += " \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ i2c-tools \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format
new file mode 100644
index 000000000..dd2770837
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format
@@ -0,0 +1,98 @@
+---
+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: false
+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: true
+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
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: 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/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt
new file mode 100644
index 000000000..a4cf8155f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project (pch-time-sync CXX)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+# boost support
+find_package (Boost REQUIRED)
+# pkg_check_modules(Boost boost REQUIRED)
+include_directories (${Boost_INCLUDE_DIRS})
+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)
+
+# import sdbusplus
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED)
+include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS})
+link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS})
+
+# import phosphor-logging
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (LOGGING phosphor-logging REQUIRED)
+include_directories (${LOGGING_INCLUDE_DIRS})
+link_directories (${LOGGING_LIBRARY_DIRS})
+
+add_executable (pch-time-sync pch-time-sync.cpp)
+
+target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}
+ phosphor_logging)
+target_link_libraries (${PROJECT_NAME} i2c)
+
+install (TARGETS pch-time-sync DESTINATION bin)
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json
new file mode 100644
index 000000000..583c255a3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/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
+} \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp
new file mode 100644
index 000000000..0c1014589
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp
@@ -0,0 +1,265 @@
+/* Copyright 2019 Intel
+ *
+ * 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 <time.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <chrono>
+#include <iostream>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+extern "C" {
+#include <i2c/smbus.h>
+#include <linux/i2c-dev.h>
+}
+
+static constexpr uint32_t syncIntervalNormalMS = 60000;
+static constexpr uint32_t syncIntervalFastMS = (syncIntervalNormalMS / 2);
+
+static uint32_t syncIntervalMS = syncIntervalNormalMS;
+
+// will update bmc time if the time difference beyond this value
+static constexpr uint8_t timeDiffAllowedSecond = 1;
+
+static inline uint8_t bcd2Decimal(uint8_t hex)
+{
+ uint8_t dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);
+ return dec;
+}
+
+class I2CFile
+{
+ private:
+ int fd = -1;
+
+ public:
+ I2CFile(const int& i2cBus, const int& slaveAddr, const int& flags)
+ {
+ std::string i2cDev = "/dev/i2c-" + std::to_string(i2cBus);
+
+ fd = open(i2cDev.c_str(), flags);
+ if (fd < 0)
+ {
+ throw std::runtime_error("Unable to open i2c device.");
+ }
+
+ if (ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0)
+ {
+ close(fd);
+ fd = -1;
+ throw std::runtime_error("Unable to set i2c slave address.");
+ }
+ }
+
+ uint8_t i2cReadByteData(const uint8_t& offset)
+ {
+ int ret = i2c_smbus_read_byte_data(fd, offset);
+
+ if (ret < 0)
+ {
+ throw std::runtime_error("i2c read failed");
+ }
+ return static_cast<uint8_t>(ret);
+ }
+
+ ~I2CFile()
+ {
+ if (!(fd < 0))
+ {
+ close(fd);
+ }
+ }
+};
+
+class PCHSync
+{
+ private:
+ bool getPCHDate(uint8_t& year, uint8_t& month, uint8_t& day, uint8_t& hour,
+ uint8_t& minute, uint8_t& second)
+ {
+ try
+ {
+ constexpr uint8_t pchDevI2CBusNumber = 0x03;
+ constexpr uint8_t pchDevI2CSlaveAddress = 0x44;
+ constexpr uint8_t pchDevRegRTCYear = 0x0f;
+ constexpr uint8_t pchDevRegRTCMonth = 0x0e;
+ constexpr uint8_t pchDevRegRTCDay = 0x0d;
+ constexpr uint8_t pchDevRegRTCHour = 0x0b;
+ constexpr uint8_t pchDevRegRTCMinute = 0x0a;
+ constexpr uint8_t pchDevRegRTCSecond = 0x09;
+ I2CFile pchDev(pchDevI2CBusNumber, pchDevI2CSlaveAddress,
+ O_RDWR | O_CLOEXEC);
+ year = pchDev.i2cReadByteData(pchDevRegRTCYear);
+ year = bcd2Decimal(year);
+ if (year > 99)
+ {
+ return false;
+ }
+
+ month = pchDev.i2cReadByteData(pchDevRegRTCMonth);
+ month = bcd2Decimal(month);
+ if ((month < 1) || (month > 12))
+ {
+ return false;
+ }
+
+ day = pchDev.i2cReadByteData(pchDevRegRTCDay);
+ day = bcd2Decimal(day);
+ if ((day < 1) || (day > 31))
+ {
+ return false;
+ }
+
+ hour = pchDev.i2cReadByteData(pchDevRegRTCHour);
+ hour = bcd2Decimal(hour);
+ if (hour >= 24)
+ {
+ return false;
+ }
+
+ minute = pchDev.i2cReadByteData(pchDevRegRTCMinute);
+ minute = bcd2Decimal(minute);
+ if (minute >= 60)
+ {
+ return false;
+ }
+
+ second = pchDev.i2cReadByteData(pchDevRegRTCSecond);
+ second = bcd2Decimal(second);
+ if (second >= 60)
+ {
+ return false;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool getSystemTime(time_t& timeSeconds)
+ {
+ struct timespec sTime = {0};
+ int ret = 0;
+
+ ret = clock_gettime(CLOCK_REALTIME, &sTime);
+
+ if (ret != 0)
+ {
+ return false;
+ }
+ timeSeconds = sTime.tv_sec;
+ return true;
+ }
+
+ bool setSystemTime(uint32_t timeSeconds)
+ {
+ struct timespec sTime = {0};
+ int ret = 0;
+
+ sTime.tv_sec = timeSeconds;
+ sTime.tv_nsec = 0;
+
+ ret = clock_settime(CLOCK_REALTIME, &sTime);
+
+ return (ret == 0);
+ }
+
+ bool updateBMCTime()
+ {
+ int ret = 0;
+ time_t BMCTimeSeconds = 0;
+ time_t PCHTimeSeconds = 0;
+ struct tm tm = {0};
+
+ // get PCH and system time
+ if (!getPCHDate(year, month, day, hour, minute, second))
+ {
+ return false;
+ };
+
+ if (!getSystemTime(BMCTimeSeconds))
+ {
+ return false;
+ }
+
+ std::string dateString =
+ "20" + std::to_string(year) + "-" + std::to_string(month) + "-" +
+ std::to_string(day) + " " + std::to_string(hour) + ":" +
+ std::to_string(minute) + ":" + std::to_string(second);
+
+ strptime(dateString.c_str(), "%Y-%m-%d %H:%M:%S", &tm);
+
+ PCHTimeSeconds = mktime(&tm);
+ if (PCHTimeSeconds == -1)
+ {
+ return false;
+ }
+
+ if (std::abs(PCHTimeSeconds - BMCTimeSeconds) > timeDiffAllowedSecond)
+ {
+ if (!setSystemTime(PCHTimeSeconds))
+ {
+ return false;
+ }
+ std::cout << "Update BMC time to " << dateString << std::endl;
+ }
+
+ return true;
+ }
+
+ void startSyncTimer()
+ {
+ if (updateBMCTime())
+ {
+ syncIntervalMS = syncIntervalNormalMS;
+ }
+ else
+ {
+ std::cout << "Update BMC time Fail" << std::endl;
+ syncIntervalMS = syncIntervalFastMS;
+ }
+
+ syncTimer->expires_after(std::chrono::milliseconds(syncIntervalMS));
+ syncTimer->async_wait(
+ [this](const boost::system::error_code& ec) { startSyncTimer(); });
+ }
+
+ std::unique_ptr<boost::asio::steady_timer> syncTimer;
+ uint8_t year, month, day, hour, minute, second;
+
+ public:
+ PCHSync(boost::asio::io_service& io)
+ {
+ syncTimer = std::make_unique<boost::asio::steady_timer>(io);
+ startSyncTimer();
+ }
+
+ ~PCHSync() = default;
+};
+
+int main(int argc, char** argv)
+{
+ boost::asio::io_service io;
+ PCHSync pchSyncer(io);
+
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Starting PCH time sync service");
+
+ io.run();
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service
new file mode 100644
index 000000000..cf9c3053f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=PCH BMC time sync service
+Conflicts=systemd-timesyncd.service
+
+[Service]
+Restart=always
+RestartSec=10
+ExecStart=/usr/bin/pch-time-sync
+StartLimitInterval=0
+Type=simple
+
+[Install]
+WantedBy=sysinit.target