From 17b117e73df71925d73ee026b4f54aa1867ce0a5 Mon Sep 17 00:00:00 2001 From: Jesse Gilles Date: Mon, 20 Apr 2015 16:49:52 -0500 Subject: initial commit --- src/MTS_Buffer.cpp | 159 +++++++++++ src/MTS_Condition.cpp | 115 ++++++++ src/MTS_Lock.cpp | 114 ++++++++ src/MTS_Logger.cpp | 312 +++++++++++++++++++++ src/MTS_Object.cpp | 41 +++ src/MTS_SignalThread.cpp | 103 +++++++ src/MTS_System.cpp | 156 +++++++++++ src/MTS_Text.cpp | 701 +++++++++++++++++++++++++++++++++++++++++++++++ src/MTS_Thread.cpp | 227 +++++++++++++++ src/MTS_Timer.cpp | 103 +++++++ src/MTS_TimerThread.cpp | 116 ++++++++ 11 files changed, 2147 insertions(+) create mode 100644 src/MTS_Buffer.cpp create mode 100644 src/MTS_Condition.cpp create mode 100644 src/MTS_Lock.cpp create mode 100644 src/MTS_Logger.cpp create mode 100644 src/MTS_Object.cpp create mode 100644 src/MTS_SignalThread.cpp create mode 100644 src/MTS_System.cpp create mode 100644 src/MTS_Text.cpp create mode 100644 src/MTS_Thread.cpp create mode 100644 src/MTS_Timer.cpp create mode 100644 src/MTS_TimerThread.cpp (limited to 'src') diff --git a/src/MTS_Buffer.cpp b/src/MTS_Buffer.cpp new file mode 100644 index 0000000..91ece42 --- /dev/null +++ b/src/MTS_Buffer.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include +#include + +using namespace MTS; + +const uint32_t Buffer::DEFAULT_CAPACITY = 80; + +Buffer::Buffer(uint32_t capacity) { + setCapacity(capacity); +} + +Buffer::Buffer(const uint8_t* bytes, uint32_t count) +: m_vBuffer(bytes, bytes + count) { + +} + +Buffer::Buffer(const Buffer& other) +: m_vBuffer(other.m_vBuffer.begin(), other.m_vBuffer.end()) { + +} + +Buffer::~Buffer() { + +} + +Buffer& +Buffer::operator=(const Buffer& other) { + if (&other == this) { + return *this; + } + m_vBuffer = other.m_vBuffer; + return *this; +} + +const uint8_t* +Buffer::getBuffer() const { + return &m_vBuffer.at(0); +} + +std::string Buffer::str() const { + return std::string(reinterpret_cast(&m_vBuffer.at(0)), m_vBuffer.size()); +} + +uint32_t Buffer::getSize() const { + return m_vBuffer.size(); +} + +void Buffer::setSize(uint32_t newSize) { + m_vBuffer.resize(newSize); +} + +uint32_t Buffer::getCapacity() const { + return m_vBuffer.capacity(); +} + +void Buffer::setCapacity(uint32_t newCapacity) { + m_vBuffer.reserve(newCapacity); +} + +void Buffer::clear() { + m_vBuffer.clear(); +} + +void Buffer::compact() { + m_vBuffer.resize(m_vBuffer.size()); +} + +uint8_t Buffer::operator[](uint32_t index) const { + return m_vBuffer[index]; +} + +uint8_t Buffer::operator[](uint32_t index) { + return m_vBuffer[index]; +} + +const uint8_t& +Buffer::at(uint32_t index) const { + return m_vBuffer.at(index); +} + +uint8_t& +Buffer::at(uint32_t index) { + return m_vBuffer.at(index); +} + +Buffer& +Buffer::append(uint8_t byte) { + m_vBuffer.push_back(byte); + return *this; +} + +Buffer& Buffer::append(const uint8_t* bytes, uint32_t count) { + m_vBuffer.resize(m_vBuffer.size() + count); + std::copy(bytes, bytes + count, std::back_inserter(m_vBuffer)); + return *this; +} + +Buffer& +Buffer::insert(uint32_t index, uint8_t byte) { + m_vBuffer.insert(m_vBuffer.begin() + index, byte); + return *this; +} + +Buffer& +Buffer::insert(uint32_t index, const uint8_t* bytes, uint32_t count) { + m_vBuffer.insert(m_vBuffer.begin() + index, bytes, bytes + count); + return *this; +} + +Buffer& +Buffer::remove(uint32_t index) { + m_vBuffer.erase(m_vBuffer.begin() + index); + return *this; +} + +Buffer& +Buffer::remove(uint32_t start, uint32_t end) { + m_vBuffer.erase(m_vBuffer.begin() + start, m_vBuffer.begin() + end); + return *this; +} + +Buffer& +Buffer::replace(uint32_t start, uint32_t end, const uint8_t* bytes, +uint32_t count) { + if (end - start == count) { + if (start > end || end > m_vBuffer.size()) { + throw std::out_of_range("Buffer| index out of bounds"); + } + std::copy(bytes, bytes + count, m_vBuffer.begin()); + return *this; + } + return remove(start, end).insert(start, bytes, count); +} + +Buffer* Buffer::clone() const { + return new Buffer(*this); +} + diff --git a/src/MTS_Condition.cpp b/src/MTS_Condition.cpp new file mode 100644 index 0000000..d238d50 --- /dev/null +++ b/src/MTS_Condition.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace MTS; + +Condition::Condition(Lock* pLock) +: m_pLock(pLock) { + if (pLock == 0) { + throw std::invalid_argument("Condition| constructing lock is null"); + } +#ifdef WIN32 + m_apCondition.reset(CreateEvent(NULL, FALSE, FALSE, NULL)); + if (m_pCondition.get() == NULL) { + throw std::bad_alloc(); + } +#else + m_apCondition.reset(new pthread_cond_t()); + const uint32_t result = pthread_cond_init(m_apCondition.get(), NULL); + if (result != 0) { + throw std::runtime_error("Condition| failed to initialize condition"); + } +#endif +} + +Condition::~Condition() { + if (!m_apCondition.isNull()) { +#ifdef WIN32 + const BOOL ok = CloseHandle(m_apCondition.get()); + assert(ok); +#else + const uint32_t result = pthread_cond_destroy(m_apCondition.get()); + if (result != 0) { + printWarning("Condition| failed to destroy condition"); + } + assert(result == 0); +#endif + } +} + +void Condition::wait() { +#ifdef WIN32 + wait(INFINITE); +#else + const uint32_t result = pthread_cond_wait(m_apCondition.get(), + m_pLock->m_apMutex.get()); + if (result != 0) { + printWarning("Condition| failed to wait on condition"); + } + assert(result == 0); +#endif +} + +void Condition::wait(uint32_t millis) { + assert(m_pLock->isLocked()); + if(!m_pLock->isLocked()) { + printWarning("Condition| lock was not locked. not waiting on signal."); + return; + } +#ifdef WIN32 + ResetEvent(m_apCondition.get()); + m_pLock->unlock(); + const DWORD waitResult = WaitForSingleObject(m_apCondition.get(), millis); + assert(waitResult == WAIT_OBJECT_0 || waitResult == WAIT_TIMEOUT); + m_pLock->lock(); +#else + timespec abstime; + int64_t micros = System::timeMicros() + (millis * 1000); + abstime.tv_sec = static_cast(micros / 1000000); + abstime.tv_nsec = static_cast((micros % 1000000) * 1000); + const uint32_t result = pthread_cond_timedwait(m_apCondition.get(), + m_pLock->m_apMutex.get(), &abstime); + if (result != 0 && result != ETIMEDOUT) { + printWarning("Condition| failed to time wait on condition"); + } + assert(result == 0 || result == ETIMEDOUT); +#endif +} + +void Condition::signal() { +#ifdef WIN32 + const BOOL ok = SetEvent(m_apCondition.get()); + assert(ok); +#else + const uint32_t result = pthread_cond_broadcast(m_apCondition.get()); + if (result != 0) { + printWarning("Condition| failed to signal condition"); + } + assert(result == 0); +#endif +} diff --git a/src/MTS_Lock.cpp b/src/MTS_Lock.cpp new file mode 100644 index 0000000..dc2e7c0 --- /dev/null +++ b/src/MTS_Lock.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include +#include +#include + +using namespace MTS; + +Lock::Lock() +: m_bLocked(false) { +#ifdef WIN32 + m_apMutex.reset(CreateMutex(NULL, FALSE, NULL)); + if (m_apMutex.get() == NULL) { + throw std::bad_alloc(); + } +#else + m_apMutexAttr.reset(new pthread_mutexattr_t()); + int result = pthread_mutexattr_init(m_apMutexAttr.get()); + if (result != 0) { + throw std::runtime_error("failed to initialize mutex attributes"); + } + result = pthread_mutexattr_settype(m_apMutexAttr.get(), + PTHREAD_MUTEX_RECURSIVE); + if (result != 0) { + throw std::runtime_error("failed to set mutex recursive"); + } + m_apMutex.reset(new pthread_mutex_t()); + result = pthread_mutex_init(m_apMutex.get(), m_apMutexAttr.get()); + if (result != 0) { + throw std::runtime_error("failed to initialize mutex"); + } +#endif + +} + +Lock::~Lock() { + if (isLocked()) { + unlock(); + } +#ifdef WIN32 + const BOOL ok = CloseHandle(m_apMutex.release()); + assert(ok); +#else + if (!m_apMutex.isNull()) { + const int result = pthread_mutex_destroy(m_apMutex.get()); + if (result != 0) { + printWarning("Lock| Failed to destroy mutex"); + } + assert(result == 0); + } + if (!m_apMutexAttr.isNull()) { + const int result = pthread_mutexattr_destroy(m_apMutexAttr.get()); + if (result != 0) { + printWarning("Lock| Failed to destroy mutex attributes"); + } + assert(result == 0); + } +#endif +} + +void Lock::lock() { +#ifdef WIN32 + const DWORD waitResult = WaitForSingleObject(m_apMutex.get(), INFINITE); + assert(waitResult == WAIT_OBJECT_0); +#else + const int result = pthread_mutex_lock(m_apMutex.get()); + if (result != 0) { + printWarning("Lock| Failed to lock mutex"); + } + assert(result == 0); +#endif + m_bLocked = true; +} + +void Lock::unlock() { + m_bLocked = false; +#ifdef WIN32 + const BOOL ok = ReleaseMutex(m_apMutex.get()); + assert(ok); +#else + const int result = pthread_mutex_unlock(m_apMutex.get()); + if (result != 0) { + printWarning("Lock| Failed to unlock mutex"); + } + assert(result == 0); +#endif +} + +bool Lock::isLocked() const { + return m_bLocked; +} + +Condition* Lock::createCondition() { + return new Condition(this); +} diff --git a/src/MTS_Logger.cpp b/src/MTS_Logger.cpp new file mode 100644 index 0000000..93775fe --- /dev/null +++ b/src/MTS_Logger.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace MTS; + +const char* Logger::PrintLevel::OFF_LABEL = "OFF"; +const char* Logger::PrintLevel::FATAL_LABEL = "FATAL"; +const char* Logger::PrintLevel::ERROR_LABEL = "ERROR"; +const char* Logger::PrintLevel::WARNING_LABEL = "WARNING"; +const char* Logger::PrintLevel::INFO_LABEL = "INFO"; +const char* Logger::PrintLevel::CONFIG_LABEL = "CONFIG"; +const char* Logger::PrintLevel::DEBUG_LABEL = "DEBUG"; +const char* Logger::PrintLevel::TRACE_LABEL = "TRACE"; +const char* Logger::PrintLevel::MAXIMUM_LABEL = "MAXIMUM"; + +const int Logger::PrintLevel::OFF_LEVEL = 0; +const int Logger::PrintLevel::MINIMUM_LEVEL = 1; +const int Logger::PrintLevel::FATAL_LEVEL = 1; +const int Logger::PrintLevel::ERROR_LEVEL = 10; +const int Logger::PrintLevel::WARNING_LEVEL = 20; +const int Logger::PrintLevel::INFO_LEVEL = 30; +const int Logger::PrintLevel::CONFIG_LEVEL = 40; +const int Logger::PrintLevel::DEBUG_LEVEL = 50; +const int Logger::PrintLevel::TRACE_LEVEL = 60; +const int Logger::PrintLevel::MAXIMUM_LEVEL = 100; + +volatile int Logger::m_iPrintLevel = Logger::PrintLevel::MAXIMUM_LEVEL; +std::string Logger::m_sPrintLevel = Logger::PrintLevel::MAXIMUM_LABEL; +Logger::PrintMode Logger::m_eMode = Logger::PrintMode::STDOUT_ONLY; +FILE* Logger::m_pFile = NULL; +int Logger::m_iLogFacility = -1; +Lock Logger::m_oPrintLock; +std::string Logger::m_sIdent; +std::string Logger::m_sFileName; + +int Logger::getPrintLevel() { + return m_iPrintLevel; +} + +const std::string& Logger::getPrintLevelString() { + if (m_iPrintLevel == PrintLevel::OFF_LEVEL) + m_sPrintLevel = std::string(PrintLevel::OFF_LABEL); + else if (m_iPrintLevel == PrintLevel::FATAL_LEVEL) + m_sPrintLevel = std::string(PrintLevel::FATAL_LABEL); + else if (m_iPrintLevel > PrintLevel::FATAL_LEVEL && m_iPrintLevel <= PrintLevel::ERROR_LEVEL) + m_sPrintLevel = std::string(PrintLevel::ERROR_LABEL); + else if (m_iPrintLevel > PrintLevel::ERROR_LEVEL && m_iPrintLevel <= PrintLevel::WARNING_LEVEL) + m_sPrintLevel = std::string(PrintLevel::WARNING_LABEL); + else if (m_iPrintLevel > PrintLevel::WARNING_LEVEL && m_iPrintLevel <= PrintLevel::INFO_LEVEL) + m_sPrintLevel = std::string(PrintLevel::INFO_LABEL); + else if (m_iPrintLevel > PrintLevel::INFO_LEVEL && m_iPrintLevel <= PrintLevel::CONFIG_LEVEL) + m_sPrintLevel = std::string(PrintLevel::CONFIG_LABEL); + else if (m_iPrintLevel > PrintLevel::CONFIG_LEVEL && m_iPrintLevel <= PrintLevel::DEBUG_LEVEL) + m_sPrintLevel = std::string(PrintLevel::DEBUG_LABEL); + else if (m_iPrintLevel > PrintLevel::DEBUG_LEVEL && m_iPrintLevel <= PrintLevel::TRACE_LEVEL) + m_sPrintLevel = std::string(PrintLevel::TRACE_LABEL); + else + m_sPrintLevel = std::string(PrintLevel::MAXIMUM_LABEL); + + return m_sPrintLevel; +} + +void Logger::setPrintLevel(int32_t level, bool silent) { + m_iPrintLevel = level; + if (!silent) { + printf(level, "Logger Level Changed to %d\n", level); + } +} + +bool Logger::isPrintable(int32_t level) { + int32_t currentLevel = getPrintLevel(); + return (level <= currentLevel) && (currentLevel > PrintLevel::OFF_LEVEL); +} + +int32_t Logger::syslogPrintLevelConversion(const int32_t& level) { + if (level < 10) { + return LOG_EMERG; + } else if (level < 20) { + return LOG_ERR; + } else if (level < 30) { + return LOG_WARNING; + } else if (level < 50) { + return LOG_INFO; + } else { + return LOG_DEBUG; + } +} + +void Logger::printMessage(const int32_t& level, const char* label, const char* format, va_list argptr) { + + m_oPrintLock.lock(); + switch (m_eMode) { + case Logger::PrintMode::STDOUT_ONLY: + ::printf("%s|%s|", MTS::Text::time(MTS::System::timeMicros()).c_str(), label); + vprintf(format, argptr); + ::printf("\n"); + break; + + case Logger::PrintMode::FILE_ONLY: + fprintf(m_pFile, "%s|%s| ", MTS::Text::time(MTS::System::timeMicros()).c_str(), label); + vfprintf(m_pFile, format, argptr); + fprintf(m_pFile, "\n"); + fflush(m_pFile); + break; + + case Logger::PrintMode::SYSLOG_ONLY: + if (level <= Logger::PrintLevel::TRACE_LEVEL) { + vsyslog(syslogPrintLevelConversion(level), format, argptr); + } + break; + + case Logger::PrintMode::STDOUT_AND_FILE: { + const std::string timestr(MTS::Text::time(MTS::System::timeMicros())); + va_list argptr2; + va_copy(argptr2, argptr); + ::printf("%s|%s|", timestr.c_str(), label); + vprintf(format, argptr); + ::printf("\n"); + fprintf(m_pFile, "%s|%s| ", timestr.c_str(), label); + vfprintf(m_pFile, format, argptr2); + fprintf(m_pFile, "\n"); + fflush(m_pFile); + va_end(argptr2); + } + break; + + case Logger::PrintMode::STDOUT_AND_SYSLOG: { + if (level <= Logger::PrintLevel::TRACE_LEVEL) { + va_list argptr2; + va_copy(argptr2, argptr); + vsyslog(syslogPrintLevelConversion(level), format, argptr2); + va_end(argptr2); + } + ::printf("%s|", MTS::Text::time(MTS::System::timeMicros()).c_str()); + ::printf("%s|", label); + vprintf(format, argptr); + ::printf("\n"); + } + break; + + case Logger::PrintMode::NO_PRINTING: + default: + break; + + } + m_oPrintLock.unlock(); +} + +void Logger::printfFatal(const char* format, ...) { + if (isPrintable(PrintLevel::FATAL_LEVEL)) { + va_list argptr; + va_start(argptr, format); + printMessage(PrintLevel::FATAL_LEVEL, PrintLevel::FATAL_LABEL, format, argptr); + va_end(argptr); + } +} + +void Logger::printfError(const char* format, ...) { + if (isPrintable(PrintLevel::ERROR_LEVEL)) { + va_list argptr; + va_start(argptr, format); + printMessage(PrintLevel::ERROR_LEVEL, PrintLevel::ERROR_LABEL, format, argptr); + va_end(argptr); + } +} + +void Logger::printfWarning(const char* format, ...) { + if (isPrintable(PrintLevel::WARNING_LEVEL)) { + va_list argptr; + va_start(argptr, format); + printMessage(PrintLevel::WARNING_LEVEL, PrintLevel::WARNING_LABEL, format, argptr); + va_end(argptr); + } +} + +void Logger::printfInfo(const char* format, ...) { + if (isPrintable(PrintLevel::INFO_LEVEL)) { + va_list argptr; + va_start(argptr, format); + printMessage(PrintLevel::INFO_LEVEL, PrintLevel::INFO_LABEL, format, argptr); + va_end(argptr); + } +} + +void Logger::printfConfig(const char* format, ...) { + if (isPrintable(PrintLevel::CONFIG_LEVEL)) { + va_list argptr; + va_start(argptr, format); + printMessage(PrintLevel::CONFIG_LEVEL, PrintLevel::CONFIG_LABEL, format, argptr); + va_end(argptr); + } +} + +void Logger::printfDebug(const char* format, ...) { + if (isPrintable(PrintLevel::DEBUG_LEVEL)) { + va_list argptr; + va_start(argptr, format); + printMessage(PrintLevel::DEBUG_LEVEL, PrintLevel::DEBUG_LABEL, format, argptr); + va_end(argptr); + } +} + +void Logger::printfTrace(const char* format, ...) { + if (isPrintable(PrintLevel::TRACE_LEVEL)) { + va_list argptr; + va_start(argptr, format); + printMessage(PrintLevel::TRACE_LEVEL, PrintLevel::TRACE_LABEL, format, argptr); + va_end(argptr); + } +} + +void Logger::printfGeneric(int level, const char* label, const char* format, ...) { + va_list argptr; + va_start(argptr, format); + printMessage(level, label, format, argptr); + va_end(argptr); +} + +void Logger::printf(int level, const char* format, ...) { + if (isPrintable(level)) { + va_list argptr; + va_start(argptr, format); + m_oPrintLock.lock(); + vprintf(format, argptr); + m_oPrintLock.unlock(); + va_end(argptr); + } +} + +void Logger::printf(const char* format, ...) { + if (isPrintable(PrintLevel::MAXIMUM_LEVEL)) { + va_list argptr; + va_start(argptr, format); + m_oPrintLock.lock(); + vprintf(format, argptr); + m_oPrintLock.unlock(); + va_end(argptr); + } +} + +bool Logger::setup(const PrintMode& mode) { + m_oPrintLock.lock(); + m_eMode = mode; + m_oPrintLock.unlock(); + return true; +} + +bool Logger::setup(const PrintMode& mode, const std::string& filename) { + /* close the handle and reopen it each time setup() is called in case + * we are being used with programs like logrotate, etc + * + * if the file is different, switch to the new file */ + + m_oPrintLock.lock(); + if (m_pFile) { + fclose(m_pFile); + } + if (m_sFileName != filename) { + m_sFileName = filename; + } + m_pFile = fopen(m_sFileName.c_str(), "a"); + m_iLogFacility = -1; + m_oPrintLock.unlock(); + + if (!m_pFile) { + fprintf(stderr, "Error opening logfile %s\n", m_sFileName.c_str()); + return false; + } + m_eMode = mode; + return true; +} + +bool Logger::setup(const PrintMode& mode, const std::string& ident, const int& option, const int& facility) { + m_oPrintLock.lock(); + m_pFile = NULL; + m_sFileName = ""; + m_iLogFacility = facility; + m_sIdent = ident; + m_eMode = mode; + m_oPrintLock.unlock(); + openlog(m_sIdent.c_str(), option, m_iLogFacility); + return true; +} + diff --git a/src/MTS_Object.cpp b/src/MTS_Object.cpp new file mode 100644 index 0000000..c798c70 --- /dev/null +++ b/src/MTS_Object.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include +#include + +using namespace MTS; + +Object::Object() { +} + +Object::~Object() { +} + +std::string Object::toString() const { + return std::string("MTS::Object"); +} + +std::string Object::toIDD() const { + std::stringstream ss; + ss << typeid(*this).name() << "@" << reinterpret_cast(this); + return ss.str().erase(0, 6); +} diff --git a/src/MTS_SignalThread.cpp b/src/MTS_SignalThread.cpp new file mode 100644 index 0000000..99975c0 --- /dev/null +++ b/src/MTS_SignalThread.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include + +using namespace MTS; + +SignalThread::SignalThread(const std::string& name) +: Thread(name, true) +, m_bShouldExecute(false) +, m_bCurrentlyExecuting(false) +, m_ui32WaitMillis(200) +{ + init(); +} + +SignalThread::SignalThread(const std::string& name, uint32_t waitMillis) +: Thread(name, true) +, m_bShouldExecute(false) +, m_bCurrentlyExecuting(false) +, m_ui32WaitMillis(waitMillis) +{ + init(); +} + +void SignalThread::init() +{ + printConfig("SignalThread| %s - starting up", Thread::getName().c_str()); + m_apStateLock.reset(new MTS::Lock); + m_apConditionLock.reset(new MTS::Lock); + m_apCondition.reset(m_apConditionLock->createCondition()); +} + +SignalThread::~SignalThread() +{ + stop(); + m_apStateLock.reset(); + m_apConditionLock.reset(); + m_apCondition.reset(); + printConfig("SignalThread| %s - shutting down", Thread::getName().c_str()); +} + +void SignalThread::signal() +{ + m_apConditionLock->lock(); + m_bShouldExecute = true; + m_apCondition->signal(); + m_apConditionLock->unlock(); +} + +void SignalThread::run() +{ + while (! Thread::isCanceled()) + { + m_apConditionLock->lock(); + if (! m_bShouldExecute) + { + m_apCondition->wait(m_ui32WaitMillis); + } + if (m_bShouldExecute) + { + printTrace("SignalThread| %s - starting execute() function", Thread::getName().c_str()); + m_apStateLock->lock(); + m_bCurrentlyExecuting = true; + m_apStateLock->unlock(); + execute(); + m_apStateLock->lock(); + m_bCurrentlyExecuting = false; + m_apStateLock->unlock(); + printTrace("SignalThread| %s - finished execute() function", Thread::getName().c_str()); + } + m_bShouldExecute = false; + m_apConditionLock->unlock(); + } +} + +bool SignalThread::isExecuting() const +{ + bool retval = false; + m_apStateLock->lock(); + retval = m_bCurrentlyExecuting; + m_apStateLock->unlock(); + + return retval; +} diff --git a/src/MTS_System.cpp b/src/MTS_System.cpp new file mode 100644 index 0000000..e1ed348 --- /dev/null +++ b/src/MTS_System.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include +#include +#include + +#ifdef WIN32 +#include + +//WIN32: FILETIME structure has a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601. + +static int64_t getEpochTimeMicros() { + const SYSTEMTIME EPOCH = {1970, 1, 4, 1, 0, 0, 0, 0}; + FILETIME ft; + BOOL ok = SystemTimeToFileTime(&EPOCH, &ft); + assert(ok); + int64_t epochTimeMicros = ((static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) / 10; + return epochTimeMicros; +} + +static int64_t getSystemTimeMicros() { + SYSTEMTIME st; + GetSystemTime(&st); + FILETIME ft; + BOOL ok = SystemTimeToFileTime(&st, &ft); + assert(ok); + int64_t systemTimeMicros = ((static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) / 10; + return systemTimeMicros; +} + +static int64_t getClockFrequency() { + LARGE_INTEGER freq; + BOOL ok = QueryPerformanceFrequency(&freq); + assert(ok); + return freq.QuadPart; +} + +static int64_t getClockValue() { + LARGE_INTEGER value; + BOOL ok = QueryPerformanceCounter(&value); + assert(ok); + return value.QuadPart; +} + +#else +#include +#endif + +using namespace MTS; + +uint64_t System::timeMicros() { + int64_t micros = 0; +#ifdef WIN32 + static const int64_t EPOCH_TIME_MICROS = getEpochTimeMicros(); + micros = getSystemTimeMicros() - EPOCH_TIME_MICROS; +#else + timespec ts; + int result = clock_gettime(CLOCK_REALTIME, &ts); + if (result == 0) { + micros = (static_cast(ts.tv_sec) * 1000000) + + (ts.tv_nsec / 1000); + } +#endif + return micros; +} + +uint64_t System::precisionTimeMicros() { + int64_t micros = 0; +#ifdef WIN32 + static const double TO_MICROS = 1000000.0 / getClockFrequency(); + int64_t value = getClockValue(); + micros = static_cast(value * TO_MICROS); +#else + micros = timeMicros(); +#endif + return micros; +} + +bool System::isBigEndian() { + static union { + uint32_t i; + char c[4]; + } endian = { 0x01020304 }; + + return endian.c[0] == 1; +} + +void System::swapBytes(uint8_t* const pBuffer, const uint32_t iSize) { + if (iSize > 1 && pBuffer != 0) { + uint8_t cByte = 0; + uint32_t i; + uint32_t j; + for (i = 0, j = iSize - 1; i < j; i++, j--) { + cByte = pBuffer[i]; + pBuffer[i] = pBuffer[j]; + pBuffer[j] = cByte; + } + } +} + +int32_t System::cmd(const std::string& cmd, std::string& result) { + std::string output; + FILE * stream; + const int max_buffer = 256; + char buffer[max_buffer]; + int32_t code = -1; + + stream = popen(cmd.c_str(), "r"); + if (stream) { + while (!feof(stream)) + if (fgets(buffer, max_buffer, stream) != NULL) + output.append(buffer); + code = pclose(stream); + } + + result = output; + + return code; +} + +int32_t System::readFile(const std::string& path, std::string& result) { + std::ifstream infile(path.c_str()); + std::stringstream ss; + + if (!infile.is_open()) { + return -1; + } + + ss << infile.rdbuf(); + + infile.close(); + + result = ss.str(); + + return 0; +} + diff --git a/src/MTS_Text.cpp b/src/MTS_Text.cpp new file mode 100644 index 0000000..d823bfe --- /dev/null +++ b/src/MTS_Text.cpp @@ -0,0 +1,701 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +//#include +#include +#include +#include +#include + +using namespace MTS; + +//strftime +//%a Abbreviated weekday name * Thu +//%A Full weekday name * Thursday +//%b Abbreviated month name * Aug +//%B Full month name * August +//%c Date and time representation * Thu Aug 23 14:55:02 2001 +//%d Day of the month (01-31) 23 +//%H Hour in 24h format (00-23) 14 +//%I Hour in 12h format (01-12) 02 +//%j Day of the year (001-366) 235 +//%m Month as a decimal number (01-12) 08 +//%M Minute (00-59) 55 +//%p AM or PM designation PM +//%S Second (00-61) 02 +//%U Week number with the first Sunday as the first day of week one (00-53) 33 +//%w Weekday as a decimal number with Sunday as 0 (0-6) 4 +//%W Week number with the first Monday as the first day of week one (00-53) 34 +//%x Date representation * 08/23/01 +//%X Time representation * 14:55:02 +//%y Year, last two digits (00-99) 01 +//%Y Year 2001 +//%Z Timezone name or abbreviation CDT +//%% A % sign % + +//Example +///* strftime example */ +//#include +//#include +// +//int main () +//{ +// time_t rawtime; +// struct tm * timeinfo; +// char buffer [80]; +// +// time ( &rawtime ); +// timeinfo = localtime ( &rawtime ); +// +// strftime (buffer,80,"Now it's %I:%M%p.",timeinfo); +// puts (buffer); +// +// return 0; +//} + +std::string Text::time(const uint64_t& iTimeMicros, const TIMEFORMAT& eTime) { + int64_t now = iTimeMicros / 1000; + int64_t millis = now % 1000; + int64_t secs = (now / 1000) % 60; + int64_t mins = (now / 60000) % 60; + int64_t hours = (now / 3600000) % 24; + std::stringstream sBuffer; + + switch (eTime) { + case HHcMMcSScmmm: + sBuffer << hours << ":" << mins << ":" << secs << ":" << millis; + return sBuffer.str(); + break; + case HHcMMcSS: + sBuffer << (hours < 10 ? "0" : "") << hours << ":" << (mins < 10 ? "0" : "") << mins << ":" << (secs < 10 ? "0" : "") << secs; + return sBuffer.str(); + break; + + } + return std::string("UNKNOWN-TIME-FORMAT"); +} + +std::string Text::date(const tm& stTime, const DATEFORMAT& eDate) { + char buffer[80]; + + switch (eDate) { + case MMsDDsYY: + strftime(buffer, 80, "%x", &stTime); + return std::string(buffer); + break; + case MMsDDsYY_HHcMMcSS: + strftime(buffer, 80, "%m/%d/%Y %H:%M:%S", &stTime); + return std::string(buffer); + break; + case RFC_1123: + std::stringstream sBuffer; + //Thu, 01 Jan 1970 00:00:01 GMT + //Week + switch (stTime.tm_wday) { + case 0: + sBuffer << "Sun, "; + break; + case 1: + sBuffer << "Mon, "; + break; + case 2: + sBuffer << "Tue, "; + break; + case 3: + sBuffer << "Wed, "; + break; + case 4: + sBuffer << "Thu, "; + break; + case 5: + sBuffer << "Fri, "; + break; + case 6: + sBuffer << "Sat, "; + break; + } + + //Day of Month + sBuffer << (stTime.tm_mday < 10 ? "0" : "") << stTime.tm_mday; + + //Month + switch (stTime.tm_mon) { + case 0: + sBuffer << " Jan "; + break; + case 1: + sBuffer << " Feb "; + break; + case 2: + sBuffer << " Mar "; + break; + case 3: + sBuffer << " Apr "; + break; + case 4: + sBuffer << " May "; + break; + case 5: + sBuffer << " Jun "; + break; + case 6: + sBuffer << " Jul "; + break; + case 7: + sBuffer << " Aug "; + break; + case 8: + sBuffer << " Sep "; + break; + case 9: + sBuffer << " Oct "; + break; + case 10: + sBuffer << " Nov "; + break; + case 11: + sBuffer << " Dec "; + break; + } + + sBuffer << (stTime.tm_year + 1900); + sBuffer << (stTime.tm_hour < 10 ? " 0" : " ") << stTime.tm_hour << ":" << (stTime.tm_min < 10 ? "0" : "") << stTime.tm_min << ":" << (stTime.tm_sec < 10 ? "0" : "") + << stTime.tm_sec; + sBuffer << " GMT"; + return sBuffer.str(); + break; + } + return std::string("UNKNOWN-DATE-FORMAT"); +} + +bool Text::datetimeIsBefore(const std::string& time1, const std::string& time2) { + + struct tm tm1; + struct tm tm2; + + strptime(time1.c_str(), "%x %T", &tm1); + strptime(time2.c_str(), "%x %T", &tm2); + + return difftime(mktime(&tm2), mktime(&tm1)) > 0; +} + +std::vector Text::split(const std::string& str, char delimiter, int limit) { + return split(str, std::string(1, delimiter), limit); +} + +std::vector Text::split(const std::string& str, const std::string& delimiter, int limit) { + std::vector result; + if(str.size() == 0) { + return result; + } + if (limit <= 0) { + limit = std::numeric_limits::max(); + } + size_t start = 0; + size_t end = str.find(delimiter, start); + for (int i = 1; (i < limit) && (end != std::string::npos); ++i) { + result.push_back(str.substr(start, end - start)); + start = end + delimiter.length(); + end = str.find(delimiter, start); + } + result.push_back(str.substr(start)); + return result; +} + +std::string Text::join(std::vector list, char delimiter) { + + std::stringstream ss; + for (uint32_t i = 0; i < list.size(); i++) { + ss << list[i]; + if (i < list.size() - 1) + ss << delimiter; + } + return ss.str(); +} + +std::string Text::replace(const std::string& original, const std::string& from, const std::string& to) { + size_t start_pos = 0; + std::string str(original); + while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } + return str; +} + +uint32_t Text::count(const std::string& str, const std::string& element) { + uint32_t count = 0; + size_t start_pos = 0; + while ((start_pos = str.find(element, start_pos)) != std::string::npos) { + start_pos++; + count++; + } + return count; +} + +uint32_t Text::count(const std::string& str, const uint8_t& element) { + uint32_t count = 0; + size_t start_pos = 0; + while ((start_pos = str.find(element, start_pos)) != std::string::npos) { + start_pos++; + count++; + } + return count; +} + +bool Text::endsWith(const std::string& str, const std::string& key) { + if (key.size() > str.size()) return false; + return std::equal(str.begin() + str.size() - key.size(), str.end(), key.begin()); +} + +std::string Text::getLine(const std::string& source, const size_t& start, size_t& cursor) { + char delimiters[2]; + delimiters[0] = '\n'; + delimiters[1] = '\r'; + if(start > source.size()) { + cursor = std::string::npos; + return ""; + } + size_t end = source.find_first_of(delimiters, start, 2); + std::string line(source.substr(start, end - start)); + //printDebug("[TEXT] Start [%d] Cursor[%d] Size[%d] Line: %s", start, end, source.size(), line.c_str()); + if (end < source.size()) { + if (end < source.size() - 1) + if ((source[end] == '\n' && source[end + 1] == '\r') || (source[end] == '\r' && source[end + 1] == '\n')) { + //Advance an additional character in scenarios where lines end in \r\n or \n\r + end++; + } + end++; + } + cursor = end; + return line; +} + +std::string Text::trim(const std::string& str) { + size_t length = str.length(); + size_t start = length; + for (size_t i = 0; i < length; ++i) { + if (!isspace(static_cast(str[i]))) { + start = i; + break; + } + } + size_t end = std::string::npos; + for (size_t i = length - 1; i != std::string::npos; --i) { + if (!isspace(static_cast(str[i]))) { + end = i + 1; + break; + } + } + return str.substr(start, end - start); +} + +std::string Text::trim(const std::string& str, const uint8_t& element) { + size_t length = str.length(); + size_t start = length; + for (size_t i = 0; i < length; ++i) { + if (static_cast(str[i]) != element) { + start = i; + break; + } + } + size_t end = std::string::npos; + for (size_t i = length - 1; i != std::string::npos; --i) { + if (static_cast(str[i]) != element) { + end = i + 1; + break; + } + } + return str.substr(start, end - start); +} + + +std::string Text::strip(const std::string& str, const std::vector& elements) { + std::string result(str); + for (uint32_t i = 0; i < elements.size(); i++) { + result.erase (std::remove(result.begin(), result.end(), elements[i]), result.end()); + } + return result; +} + +std::string Text::strip(const std::string& str, const uint8_t& element) { + std::string result(str); + result.erase (std::remove(result.begin(), result.end(), element), result.end()); + return result; +} + +std::string Text::toLowerCase(const std::string& str) { + std::string result(str); + size_t length = result.length(); + for (size_t i = 0; i < length; ++i) { + result[i] = static_cast(tolower(static_cast(result[i]))); + } + return result; +} + +std::string Text::toUpperCase(const std::string& str) { + std::string result(str); + size_t length = result.length(); + for (size_t i = 0; i < length; ++i) { + result[i] = static_cast(toupper(static_cast(result[i]))); + } + return result; +} + +std::string Text::toCapitalized(const std::string& str) { + std::string result; + result = str; + if (str.size() == 0) + return result; + else if (str.size() == 1) + return toUpperCase(result); + else + return toUpperCase(result.substr(0, 1)) + toLowerCase(result.substr(1)); +} + +std::string Text::toCamelCase(const std::string& str) { + std::string result; + if (str.size() == 0) { + return result; + } + + std::vector parts = MTS::Text::split(str, ' '); + + if (parts.size() == 0 || parts[0].size() == 0) { + return result; + } + result.append(MTS::Text::toLowerCase(parts[0])); + + for (uint32_t i = 1; i < parts.size(); i++) { + result.append(MTS::Text::toCapitalized(parts[i])); + } + + return result; +} + +std::string Text::toCommandLineEscaped(const std::string& str) { + std::string result(str); + result = Text::replace(result, "#", "\\#"); + result = Text::replace(result, ".", "\\."); + result = Text::replace(result, "&", "\\&"); + result = Text::replace(result, "?", "\\?"); + return result; +} + +std::wstring Text::widen(const std::string& str) { + std::wstringstream wss; + size_t length = str.length(); + for (size_t i = 0; i < length; ++i) { + wss << wss.widen(str[i]); + } + return wss.str(); +} + +std::string Text::narrow(const std::wstring& str) { + std::wstringstream wss; + std::stringstream ss; + size_t length = str.length(); + for (size_t i = 0; i < length; ++i) { + ss << wss.narrow(str[i], '?'); + } + return ss.str(); +} + +std::string Text::format(bool value) { + std::stringstream ss; + ss.setf(ss.boolalpha); + ss << value; + return ss.str(); +} + +std::string Text::format(double value, std::streamsize percision) { + std::stringstream ss; + ss.setf(ss.fixed, ss.floatfield); + ss.precision(percision); + ss << value; + std::string str = ss.str(); + // strip trailing zeros + size_t pos = str.find_last_not_of('0'); + if (pos != std::string::npos) { + if (str[pos] == '.') { + pos += 2; + } else { + pos += 1; + } + } + return str.substr(0, pos); +} + +std::string Text::format(int8_t value) { + return format(static_cast(value)); +} + +std::string Text::format(int16_t value) { + return format(static_cast(value)); +} + +std::string Text::format(int32_t value) { + return format(static_cast(value)); +} + +std::string Text::format(int64_t value) { + std::stringstream ss; + ss.setf(ss.dec, ss.basefield); + ss << value; + return ss.str(); +} + +std::string Text::format(uint8_t value) { + return format(static_cast(value)); +} + +std::string Text::format(uint16_t value) { + return format(static_cast(value)); +} + +std::string Text::format(uint32_t value) { + return format(static_cast(value)); +} + +std::string Text::format(uint64_t value) { + std::stringstream ss; + ss.setf(ss.dec, ss.basefield); + ss << value; + return ss.str(); +} + +static std::string toHexString(uint64_t value, bool pad, std::streamsize padSize) { + std::stringstream ss; + ss.unsetf(ss.showbase); + ss.setf(ss.hex, ss.basefield); + ss.setf(ss.uppercase); + if (pad) { + ss.width(padSize); + ss.fill('0'); + } + ss << value; + return ss.str(); +} + +std::string Text::formatHex(int8_t value, bool pad) { + return formatHex(static_cast(value), pad); +} + +std::string Text::formatHex(int16_t value, bool pad) { + return formatHex(static_cast(value), pad); +} + +std::string Text::formatHex(int32_t value, bool pad) { + return formatHex(static_cast(value), pad); +} + +std::string Text::formatHex(int64_t value, bool pad) { + return formatHex(static_cast(value), pad); +} + +std::string Text::formatHex(uint8_t value, bool pad) { + return toHexString(value, pad, 2); +} + +std::string Text::formatHex(uint16_t value, bool pad) { + return toHexString(value, pad, 4); +} + +std::string Text::formatHex(uint32_t value, bool pad) { + return toHexString(value, pad, 8); +} + +std::string Text::formatHex(uint64_t value, bool pad) { + return toHexString(value, pad, 16); +} + +std::string Text::formatHex(const Buffer& value) { + char hex[4]; + std::string hexstr; + for (uint32_t i = 0; i < value.getSize(); i++) { + sprintf(hex, "%X", value.at(i)); + hexstr.append(hex); + } + return hexstr; +} + +bool Text::parse(bool& value, const std::string& str) { + if (str.empty()) { + return false; + } + std::istringstream ss(str); + ss.setf(ss.boolalpha); + ss.unsetf(ss.skipws); + ss >> value; + return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK); +} + +bool Text::parse(double& value, const std::string& str) { + if (str.empty()) { + return false; + } + std::istringstream ss(str); + ss.setf(ss.fixed, ss.basefield); + ss.unsetf(ss.skipws); + ss >> value; + return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK); +} + +bool Text::parse(int8_t& value, const std::string& str) { + int64_t i64 = 0; + if (!parse(i64, str)) { + return false; + } + if (i64 < INT8_MIN || i64 > INT8_MAX) { + return false; + } + value = static_cast(i64); + return true; +} + +bool Text::parse(int16_t& value, const std::string& str) { + int64_t i64 = 0; + if (!parse(i64, str)) { + return false; + } + if (i64 < INT16_MIN || i64 > INT16_MAX) { + return false; + } + value = static_cast(i64); + return true; +} + +bool Text::parse(int32_t& value, const std::string& str) { + int64_t i64 = 0; + if (!parse(i64, str)) { + return false; + } + if (i64 < INT32_MIN || i64 > INT32_MAX) { + return false; + } + value = static_cast(i64); + return true; +} + +bool Text::parse(int64_t& value, const std::string& str) { + if (str.empty()) { + return false; + } + std::istringstream ss(str); + ss.setf(ss.dec, ss.basefield); + ss.unsetf(ss.skipws); + ss >> value; + return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK); +} + +bool Text::parse(uint8_t& value, const std::string& str) { + uint64_t u64 = 0; + if (!parse(u64, str)) { + return false; + } + if (u64 > UINT8_MAX) { + return false; + } + value = static_cast(u64); + return true; +} + +bool Text::parse(uint16_t& value, const std::string& str) { + uint64_t u64 = 0; + if (!parse(u64, str)) { + return false; + } + if (u64 > UINT16_MAX) { + return false; + } + value = static_cast(u64); + return true; +} + +bool Text::parse(uint32_t& value, const std::string& str) { + uint64_t u64 = 0; + if (!parse(u64, str)) { + return false; + } + if (u64 > UINT32_MAX) { + return false; + } + value = static_cast(u64); + return true; +} + +bool Text::parse(uint64_t& value, const std::string& str) { + if (str.empty()) { + return false; + } + std::istringstream ss(str); + ss.setf(ss.dec, ss.basefield); + ss.unsetf(ss.skipws); + ss >> value; + return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK); +} + +bool Text::parseHex(uint8_t& value, const std::string& str) { + uint64_t u64 = 0; + if (!parseHex(u64, str)) { + return false; + } + if (u64 > UINT8_MAX) { + return false; + } + value = static_cast(u64); + return true; +} + +bool Text::parseHex(uint16_t& value, const std::string& str) { + uint64_t u64 = 0; + if (!parseHex(u64, str)) { + return false; + } + if (u64 > UINT16_MAX) { + return false; + } + value = static_cast(u64); + return true; +} + +bool Text::parseHex(uint32_t& value, const std::string& str) { + uint64_t u64 = 0; + if (!parseHex(u64, str)) { + return false; + } + if (u64 > UINT32_MAX) { + return false; + } + value = static_cast(u64); + return true; +} + +bool Text::parseHex(uint64_t& value, const std::string& str) { + + if (str.empty()) { + return false; + } + std::istringstream ss(str); + ss >> std::hex >> value; + return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK); +} + diff --git a/src/MTS_Thread.cpp b/src/MTS_Thread.cpp new file mode 100644 index 0000000..3537731 --- /dev/null +++ b/src/MTS_Thread.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include +#include +#include + +using namespace MTS; + +Thread::Thread(const std::string& name, bool managed) +: m_pThread(NULL) +, m_sName(name) +, m_bManaged(managed) +, m_bComplete(true) +, m_bCanceled(true) +{ + printConfig("Thread| %s()", getName().c_str()); + m_apThreadLock.reset(new Lock()); + m_apStateLock.reset(new Lock()); + m_apCompleteCondition.reset(m_apStateLock->createCondition()); +} + +Thread::~Thread() { + m_bCanceled = true; + Thread::stop(); + m_apCompleteCondition.reset(); + m_apStateLock.reset(); + m_apThreadLock.reset(); + printConfig("Thread| %s - deconstructed", getName().c_str()); +} + +void Thread::sleep(uint32_t millis) { +#ifdef WIN32 + Sleep(millis); +#else + Lock lock; + Condition* condition = lock.createCondition(); + lock.lock(); + condition->wait(millis); + lock.unlock(); + delete condition; +#endif +} + +const std::string& Thread::getName() const { + return m_sName; +} + +void Thread::start() { + m_apThreadLock->lock(); + try { + if (m_pThread == NULL) { + reset(); +#ifdef WIN32 + m_pThread = CreateThread(NULL, 0, &doInBackground, this, 0, NULL); +#else + m_pThread = new (std::nothrow) pthread_t; + if (m_pThread != NULL) { + const int result = pthread_create(m_pThread, NULL, + &doInBackground, this); + assert(result == 0); + if (result != 0) { + delete m_pThread; + m_pThread = NULL; + } + } + +#endif + assert(m_pThread != NULL); + if (m_pThread != NULL) { + printConfig("Thread| %s - started (%p)", + getName().c_str(), m_pThread); + } else { + printWarning("Thread| Failed to start runnable %s", + getName().c_str()); + m_apStateLock->lock(); + m_bCanceled = true; + m_bComplete = true; + m_apStateLock->unlock(); + } + } + } catch (...) { + printWarning("Thread| Failed to start runnable %s", getName().c_str()); + assert(false); + } + m_apThreadLock->unlock(); +} + +void Thread::stop() { + m_apThreadLock->lock(); + cancel(); + if (m_pThread != NULL) { + wait(1500); + +#ifdef WIN32 + if (!isDone()) { + TerminateThread(m_pThread, 1); + printConfig("Thread| %s - terminated", getName().c_str()); + } + const BOOL ok = CloseHandle(m_pThread); + assert(ok); +#else + if (!isDone()) { + printConfig("Thread| %s - terminated", getName().c_str()); + } + delete m_pThread; +#endif + m_pThread = NULL; + } else if (!isDone()) { + done(); + } + m_apThreadLock->unlock(); +} + +void Thread::wait() { + m_apStateLock->lock(); + if (!m_bComplete) { + m_apCompleteCondition->wait(); + } + m_apStateLock->unlock(); +} + +void Thread::wait(uint32_t millis) { + m_apStateLock->lock(); + if (!m_bComplete) { + m_apCompleteCondition->wait(millis); + } + m_apStateLock->unlock(); +} + +bool Thread::isAlive() const { + bool result = false; + m_apThreadLock->lock(); + result = (m_pThread != NULL); + m_apThreadLock->unlock(); + return result; +} + +bool Thread::isCanceled() const { + bool result = false; + m_apStateLock->lock(); + result = m_bCanceled; + m_apStateLock->unlock(); + return result; +} + +void Thread::cancel() { + m_apStateLock->lock(); + if (!m_bCanceled) { + m_bCanceled = true; + printConfig("Thread| %s - cancelled", getName().c_str()); + } + m_apStateLock->unlock(); +} + +bool Thread::isDone() const { + bool result = false; + m_apStateLock->lock(); + result = m_bComplete; + m_apStateLock->unlock(); + return result; +} + +void Thread::done() { + m_apStateLock->lock(); + m_bComplete = true; + m_apCompleteCondition->signal(); + printConfig("Thread| %s - done", getName().c_str()); + m_apStateLock->unlock(); +} + +void Thread::reset() { + m_apStateLock->lock(); + m_bCanceled = false; + m_bComplete = false; + m_apStateLock->unlock(); +} + +bool Thread::isManaged() const { + return m_bManaged; +} + +#ifdef WIN32 +DWORD WINAPI Thread::doInBackground(__in LPVOID parameter) { +#else +void* Thread::doInBackground(void* parameter) { +#endif + + Thread* runnable = static_cast(parameter); + assert(runnable != NULL); + if (runnable != NULL) { + printConfig("Thread| %s - initializing\n", runnable->getName().c_str()); + try { + runnable->run(); + } catch (...) { + printWarning("Thread| exception caught while running %s", + runnable->getName().c_str()); + } + printConfig("Thread| %s - finalizing", runnable->getName().c_str()); + bool managed = runnable->isManaged(); + runnable->done(); + if (!managed) { + printConfig("Thread| %s - deleted", runnable->getName().c_str()); + delete runnable; + } + } + return 0; +} + diff --git a/src/MTS_Timer.cpp b/src/MTS_Timer.cpp new file mode 100644 index 0000000..2158c29 --- /dev/null +++ b/src/MTS_Timer.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include + +using namespace MTS; + +Timer::Timer() +: m_iStart(0) +, m_iPause(0) +, m_bStarted(false) +, m_bPaused(false) +{ + +} + +Timer::~Timer() { + +} + +void Timer::start() { + if(m_bStarted) { + return; + } + + m_iStart = System::timeMicros(); + m_bStarted = true; + m_bPaused = false; +} + +void Timer::stop() { + m_bStarted = false; +} + +void Timer::pause() { + if(m_bPaused || !m_bStarted) { + return; + } + + m_iPause = System::timeMicros(); + m_bPaused = true; +} + +void Timer::resume() { + if(!m_bPaused) { + return; + } + + m_iStart += System::timeMicros() + m_iPause; + m_bPaused = false; +} + +void Timer::reset() { + m_iStart = System::timeMicros(); + m_bPaused = false; +} + +bool Timer::isRunning() { + return !m_bPaused && m_bStarted; +} + +uint64_t Timer::getMicros() { + if(!m_bStarted) { + return 0; + } + + if(m_bPaused) { + return m_iPause - m_iStart; + } + + return System::timeMicros() - m_iStart; +} + +uint64_t Timer::getMillis() { + return getMicros() / 1000; +} + +uint64_t Timer::getSeconds() { + return getMicros() / 1000000; +} + +uint64_t Timer::getMinutes() { + return getMicros() / (1000000*60); +} + diff --git a/src/MTS_TimerThread.cpp b/src/MTS_TimerThread.cpp new file mode 100644 index 0000000..5a69c46 --- /dev/null +++ b/src/MTS_TimerThread.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 by Multi-Tech Systems + * + * This file is part of libmts. + * + * libmts is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts. If not, see . + * + */ + +#include +#include + +using namespace MTS; + +TimerThread::TimerThread(const std::string& name) +: Thread(name, true) +, m_bCurrentlyExecuting(false) +, m_bExecutionStopped(false) +, m_ui32IntervalMillis(1000) +{ + init(); +} + +TimerThread::TimerThread(const std::string& name, uint32_t intervalMillis) +: Thread(name, true) +, m_bCurrentlyExecuting(false) +, m_bExecutionStopped(false) +, m_ui32IntervalMillis(intervalMillis) +{ + init(); +} + +void TimerThread::init() +{ + printConfig("TimerThread| %s - starting up", Thread::getName().c_str()); + m_apStateLock.reset(new MTS::Lock); +} + +TimerThread::~TimerThread() +{ + stop(); + m_apStateLock.reset(); + printConfig("TimerThread| %s - shutting down", Thread::getName().c_str()); +} + +void TimerThread::stopExecution() +{ + m_apStateLock->lock(); + m_bExecutionStopped = true; + m_apStateLock->unlock(); + printDebug("TimerThread| %s - stopping execution of task", Thread::getName().c_str()); +} + +void TimerThread::restartExecution() +{ + m_apStateLock->lock(); + m_bExecutionStopped = false; + m_apStateLock->unlock(); + printDebug("TimerThread| %s - restarting execution of task", Thread::getName().c_str()); +} + +void TimerThread::run() +{ + uint32_t intervalMillis; + bool executionStopped; + + while (! Thread::isCanceled()) + { + m_apStateLock->lock(); + intervalMillis = m_ui32IntervalMillis; + executionStopped = m_bExecutionStopped; + m_apStateLock->unlock(); + + if (! executionStopped) + { + printTrace("TimerThread| %s - starting execute() function", Thread::getName().c_str()); + m_apStateLock->lock(); + m_bCurrentlyExecuting = true; + m_apStateLock->unlock(); + execute(); + m_apStateLock->lock(); + m_bCurrentlyExecuting = false; + m_apStateLock->unlock(); + printTrace("TimerThread| %s - finished execute() function", Thread::getName().c_str()); + } + Thread::sleep(intervalMillis); + } +} + +bool TimerThread::isExecuting() const +{ + bool retval = false; + m_apStateLock->lock(); + retval = m_bCurrentlyExecuting; + m_apStateLock->unlock(); + + return retval; +} + +void TimerThread::updateIntervalMillis(uint32_t newMillis) +{ + m_apStateLock->lock(); + m_ui32IntervalMillis = newMillis; + m_apStateLock->unlock(); +} -- cgit v1.2.3