replace common qcom sources with samsung ones

This commit is contained in:
SaschaNes
2025-08-12 22:13:00 +02:00
parent ba24dcded9
commit 6f7753de11
5682 changed files with 2450203 additions and 103634 deletions

View File

@@ -0,0 +1,5 @@
cc_library_headers {
name: "libloc_base_util_headers",
vendor: true,
export_include_dirs: [".", "base_util", ],
}

View File

@@ -0,0 +1,2 @@
LOCAL_PATH := $(call my-dir)
include $(call all-makefiles-under,$(LOCAL_PATH))

View File

@@ -0,0 +1,38 @@
cc_library_shared {
name: "libloc_base_util",
vendor: true,
owner: "qti",
cflags: [
"-fno-short-enums",
] + GNSS_CFLAGS,
arch: {
arm: {
cflags: ["-DANDROID_32_BIT_PTR_SUPPORT"],
},
},
header_libs: [
"libutils_headers",
"libloc_base_util_headers",
],
shared_libs: [
"libsqlite",
"libssl",
"liblog",
],
srcs: [
"src/config_file.cpp",
"src/log.cpp",
"src/memorystream.cpp",
"src/nvparam_mgr.cpp",
"src/postcard.cpp",
"src/sync.cpp",
"src/string_routines.cpp",
"src/time_routines.cpp",
],
}

View File

@@ -0,0 +1,9 @@
# Makefile.am for gps loc-base-util
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = loc-base-util.pc
EXTRA_DIST = $(pkgconfig_DATA)

View File

@@ -0,0 +1,246 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Array template
GENERAL DESCRIPTION
This component implements an array of any type
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_ARRAY_H__
#define __XTRAT_WIFI_ARRAY_H__
#include <base_util/log.h>
#include <base_util/list.h>
namespace qc_loc_fw
{
template<typename T>
class Array
{
private:
static const char * const TAG;
public:
typedef T * Iterator;
Array() :
m_pArray(0), m_size(0)
{
}
Array(const Array<T> & rhs) :
m_pArray(0), m_size(0)
{
(void) operator =(rhs);
}
virtual ~Array()
{
flush();
}
int setSize(const unsigned int size)
{
int result = 1;
flush();
if(size > 0)
{
m_pArray = new T[size];
if(0 != m_pArray)
{
m_size = size;
result = 0;
}
else
{
m_size = 0;
result = 2;
}
}
else
{
// invalid size
result = 3;
}
if(0 != result)
{
log_error(TAG, "set size failed %d", result);
}
return result;
}
void flush()
{
if(0 != m_pArray)
{
delete[] m_pArray;
m_pArray = 0;
}
m_size = 0;
}
int insert(const List<T> & list)
{
int result = 1;
if(list.getSize() > 0)
{
unsigned int new_size = m_size + list.getSize();
T * pNewArray = new T[new_size];
if(0 != pNewArray)
{
for (unsigned int i = 0; i < m_size; ++i)
{
pNewArray[i] = m_pArray[i];
}
const SingleListNode<T> * pNode = list.getHead();
for (unsigned int j = m_size; j < new_size; ++j)
{
pNewArray[j] = pNode->getValue();
pNode = pNode->getNext();
}
m_size = new_size;
if(0 != m_pArray)
{
delete[] m_pArray;
}
m_pArray = pNewArray;
result = 0;
}
else
{
result = 2;
}
}
else
{
// do nothing. it's okay to insert empty list into an array
result = 0;
}
if(0 != result)
{
log_error(TAG, "insertion failed %d", result);
}
return result;
}
T & operator [](const unsigned int index)
{
if(index < m_size)
{
return m_pArray[index];
}
else
{
log_error(TAG, "index out of range\n");
// could be null reference, but we're doomed anyway
return m_pArray[0];
}
}
const T & operator [](const unsigned int index) const
{
if(index < m_size)
{
return m_pArray[index];
}
else
{
log_error(TAG, "index out of range\n");
// could be null reference, but we're doomed anyway
return m_pArray[0];
}
}
unsigned int getSize() const
{
return m_size;
}
const Array<T> & operator =(const Array<T> & rhs)
{
int result = 1;
if(&rhs == this)
{
// do nothing for self-assignment
return *this;
}
flush();
int new_size = rhs.getSize();
if(new_size > 0)
{
T * pNewArray = new T[new_size];
if(0 != pNewArray)
{
for (int i = 0; i < new_size; ++i)
{
pNewArray[i] = rhs.m_pArray[i];
}
m_size = new_size;
if(0 != m_pArray)
{
delete[] m_pArray;
}
m_pArray = pNewArray;
result = 0;
}
else
{
result = 2;
}
}
else
{
// do nothing. it's okay to insert empty array into an array
result = 0;
}
if(0 != result)
{
log_error(TAG, "assignment failed %d", result);
}
return *this;
}
// used in searching or sorting
const T * getRawArray() const
{
return m_pArray;
}
T * getRawArray()
{
return m_pArray;
}
Iterator begin()
{
return Iterator(m_pArray);
}
Iterator end()
{
return Iterator(m_pArray + m_size);
}
private:
T * m_pArray;
unsigned int m_size;
};
template<typename T>
const char * const Array<T>::TAG = "Array";
} // namespace qc_loc_fw
#endif //#ifndef __XTRAT_WIFI_ARRAY_H__

View File

@@ -0,0 +1,44 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Config file
GENERAL DESCRIPTION
This header declares a config file parser
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_CONFIG_FILE_H__
#define __XTRAT_WIFI_CONFIG_FILE_H__
namespace qc_loc_fw
{
class ConfigFile
{
public:
static ConfigFile * createInstance(const char * const filename, const size_t max_line_length = 1023,
const bool verbose = false);
virtual ~ConfigFile() = 0;
virtual bool loaded() const = 0;
enum RETURN_CODE
{
NO_ERROR_RESULT_SET = 0, NOT_FOUND = 1000
};
virtual int getString(const char * const name, const char ** pStr) = 0;
virtual int getStringDup(const char * const name, const char ** pStr, const char * const strDefault = 0) = 0;
virtual int getInt32(const char * const name, int & value) = 0;
virtual int getInt32Default(const char * const name, int & value, const int & Default) = 0;
virtual int get_PZ_Int32Default(const char * const name, int & value, const int & Default) = 0;
virtual int get_PNZ_Int32Default(const char * const name, int & value, const int & Default) = 0;
virtual int getDouble(const char * const name, double & value) = 0;
virtual int getDoubleDefault(const char * const name, double & value, const double & Default) = 0;
};
} // namespace qc_loc_fw
#endif //#ifndef __XTRAT_WIFI_CONFIG_FILE_H__

View File

@@ -0,0 +1,89 @@
# configure.ac -- Autoconf script for gps loc-base-util
#
# Process this file with autoconf to produce a configure script
# Requires autoconf tool later than 2.61
AC_PREREQ(2.61)
# Initialize the gps loc-base-util package version 1.0.0
AC_INIT([loc-base-util],1.0.0)
# Does not strictly follow GNU Coding standards
AM_INIT_AUTOMAKE([foreign subdir-objects])
# Disables auto rebuilding of configure, Makefile.ins
AM_MAINTAINER_MODE
# Verifies the --srcdir is correct by checking for the path
AC_CONFIG_SRCDIR([Makefile.am])
# defines some macros variable to be included by source
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
# Checks for programs.
AC_PROG_LIBTOOL
AC_PROG_CXX
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_AWK
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
PKG_PROG_PKG_CONFIG
# Checks for libraries.
AC_ARG_WITH([core_includes],
AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
[Specify the location of the core headers]),
[core_incdir=$withval],
with_core_includes=no)
if test "x$with_core_includes" != "xno"; then
CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
fi
AC_ARG_WITH([locpla_includes],
AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
[specify the path to locpla-includes in loc-pla_git.bb]),
[locpla_incdir=$withval],
with_locpla_includes=no)
if test "x$with_locpla_includes" != "xno"; then
AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
fi
AC_ARG_WITH([core_includes],
AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
[Specify the location of the core headers]),
[core_incdir=$withval],
with_core_includes=no)
if test "x$with_core_includes" != "xno"; then
CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
fi
AC_SUBST([CPPFLAGS])
AC_ARG_WITH([glib],
AC_HELP_STRING([--with-glib],
[enable glib, building HLOS systems which use glib]))
if (test "x${with_glib}" = "xyes"); then
AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
AC_MSG_ERROR(GThread >= 2.16 is required))
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
AC_MSG_ERROR(GLib >= 2.16 is required))
GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
fi
AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
AC_CONFIG_FILES([ \
Makefile \
src/Makefile \
loc-base-util.pc
])
AC_OUTPUT

View File

@@ -0,0 +1,541 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
List template
GENERAL DESCRIPTION
This component implements a list of any type
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_LIST_H__
#define __XTRAT_WIFI_LIST_H__
#include <new>
// for size_t, qsort
#include <stdlib.h>
#include <base_util/log.h>
namespace qc_loc_fw
{
// the reason we do not use STL/STLport is for portability.
// the availability of STL on other linux targets are not clear to
// me at this time
// also STL may or may not work well with JNI/NDK code for C++ exception
template<typename T>
class SingleListNode
{
public:
SingleListNode(const T & rhs) :
m_pNext(0), m_value(rhs)
{
}
inline const SingleListNode<T> * getNext() const
{
return m_pNext;
}
inline SingleListNode<T> * getNext()
{
return m_pNext;
}
inline void setNext(SingleListNode<T> * const pNext)
{
m_pNext = pNext;
}
inline T & getValue()
{
return m_value;
}
inline const T & getValue() const
{
return m_value;
}
inline T * getPointer()
{
return &m_value;
}
inline const T * getPointer() const
{
return &m_value;
}
private:
SingleListNode<T> * m_pNext;
T m_value;
};
template<typename T>
class List;
template<typename T>
class ConstListIterator
{
protected:
static const char * const TAG;
ConstListIterator(SingleListNode<T> * const pNode) :
m_pNode(pNode)
{
}
friend class List<T> ;
public:
typedef T ValueType;
inline bool operator==(const ConstListIterator & rhs) const
{
return (m_pNode == rhs.m_pNode);
}
inline bool operator!=(const ConstListIterator & rhs) const
{
return (m_pNode != rhs.m_pNode);
}
void operator++()
{
if(0 != m_pNode)
{
m_pNode = m_pNode->getNext();
}
else
{
log_error(TAG, "operator ++ with null iterator");
}
}
bool isLastNode()
{
bool is_last = false;
if(0 != m_pNode)
{
if (m_pNode->getNext() == 0)
{
is_last = true;
}
}
else
{
log_error(TAG, "isLastNode called with null iterator");
}
return is_last;
}
const T& operator*() const
{
if(0 == m_pNode)
{
log_error(TAG, "operator * with null iterator");
}
return this->m_pNode->getValue();
}
const T* ptr() const
{
if(0 == m_pNode)
{
log_error(TAG, "ptr with null iterator");
return 0;
}
else
{
return m_pNode->getPointer();
}
}
inline const T* operator->() const
{
return this->m_pNode->getPointer();
}
protected:
SingleListNode<T> * m_pNode;
};
// note: to access any inherited member in a templated base class
// we need to either address full class name ::, or add this->
// this is new in C++ to avoid parser conflicts
template<typename T>
class ListIterator : public ConstListIterator<T>
{
private:
ListIterator(SingleListNode<T> * const pNode) :
ConstListIterator<T>(pNode)
{
}
friend class List<T> ;
public:
T& operator*() const
{
if(0 == this->m_pNode)
{
log_error(this->TAG, "operator * with null iterator");
}
return this->m_pNode->getValue();
}
T* ptr() const
{
if(0 == this->m_pNode)
{
log_error(this->TAG, "ptr with null iterator");
return 0;
}
else
{
return this->m_pNode->getPointer();
}
}
inline T* operator->() const
{
return this->m_pNode->getPointer();
}
};
template<typename T>
class List
{
private:
static const char * const TAG;
public:
typedef T ValueType;
typedef ListIterator<T> Iterator;
typedef ConstListIterator<T> ConstIterator;
List() :
m_pHead(0), m_size(0)
{
}
int append(const List<T> & rhs)
{
int result = 0;
for (List<T>::ConstIterator it = rhs.begin(); it != rhs.end(); ++it)
{
if(0 != add_head(*it))
{
result = 2;
break;
}
}
return result;
}
inline int append_reverse(const List<T> & rhs)
{
return append(rhs);
}
virtual ~List()
{
flush();
}
void flush()
{
SingleListNode<T> * pNode = m_pHead;
while (0 != pNode)
{
SingleListNode<T> * pNextNode = pNode->getNext();
delete pNode;
pNode = pNextNode;
}
m_size = 0;
m_pHead = 0;
}
int add(const T& rhs)
{
int result = 1;
SingleListNode<T> * pNewNode = new SingleListNode<T>(rhs);
if(0 != pNewNode)
{
pNewNode->setNext(m_pHead);
m_pHead = pNewNode;
++m_size;
result = 0;
}
else
{
// we're dead
result = 2;
}
if(0 != result)
{
log_error(TAG, "add : failed %d", result);
}
return result;
}
int add_tail (const T& rhs)
{
int result = 1;
SingleListNode<T> * pPrevNode = 0;
SingleListNode<T> * pNode = m_pHead;
SingleListNode<T> * pNewNode = new SingleListNode<T>(rhs);
if (0 == pNewNode)
{
result = 2;
}
else
{
while (0 != pNode)
{
pPrevNode = pNode;
pNode = pNode->getNext();
}
if (pPrevNode == 0)
{
m_pHead = pNewNode;
}
else
{
pPrevNode->setNext (pNewNode);
}
++m_size;
result = 0;
}
return result;
}
inline int add_head(const T& rhs)
{
return add(rhs);
}
int sort(bool reverse = false)
{
SingleListNode<T> ** nodes = 0;
int result = 1;
do
{
if(0 >= m_size)
{
// empty list
result = 0;
break;
}
nodes = new (std::nothrow) SingleListNode<T> *[m_size];
if(0 == nodes)
{
result = 3;
break;
}
// fill the array with null pointers
for (size_t i = 0; i < m_size; ++i)
{
nodes[i] = 0;
}
// create an array of node pointers
size_t index = 0;
for (SingleListNode<T> * pNode = m_pHead; (pNode != 0) && (index < m_size); pNode = pNode->getNext())
{
nodes[index] = pNode;
++index;
}
if(index != m_size)
{
// inconsistent size and actual list content
result = 4;
break;
}
if(!reverse)
{
qsort(nodes, m_size, sizeof(SingleListNode<T> *), _comparator);
}
else
{
qsort(nodes, m_size, sizeof(SingleListNode<T> *), _reverse_comparator);
}
// note we have checked that the list cannot be empty, so node[0] is always defined
m_pHead = nodes[0];
// note we have checked that the list cannot be empty, so m_size is at least 1
for (size_t i = 0; i < (m_size - 1); ++i)
{
nodes[i]->setNext(nodes[i + 1]);
}
// note we have checked that the list cannot be empty, so m_size is at least 1
nodes[m_size - 1]->setNext(0);
delete[] nodes;
nodes = 0;
result = 0;
} while (0);
if(0 != nodes)
{
delete[] nodes;
nodes = 0;
}
if(0 != result)
{
log_error(TAG, "sort : failed %d", result);
}
return result;
}
int remove(const T& rhs, const bool ok_if_not_found = false)
{
int result = 1;
SingleListNode<T> * pPrevNode = 0;
SingleListNode<T> * pNode = m_pHead;
while (0 != pNode)
{
if(rhs == pNode->getValue())
{
if(0 != pPrevNode)
{
pPrevNode->setNext(pNode->getNext());
}
else
{
// we're the head
m_pHead = pNode->getNext();
}
--m_size;
delete pNode;
pNode = 0;
result = 0;
break;
}
pPrevNode = pNode;
pNode = pNode->getNext();
}
if(0 != result)
{
if((1 == result) && ok_if_not_found)
{
// we couldn't find it, but caller said it's okay
result = 0;
}
else
{
log_error(TAG, "remove: failed %d", result);
}
}
return result;
}
Iterator erase(const Iterator & target)
{
int result = 1;
SingleListNode<T> * pPrevNode = 0;
SingleListNode<T> * pNode = m_pHead;
SingleListNode<T> * pNextNode = 0;
while (0 != pNode)
{
if(target == Iterator(pNode))
{
pNextNode = pNode->getNext();
if(0 != pPrevNode)
{
pPrevNode->setNext(pNextNode);
}
else
{
// we're the head
m_pHead = pNextNode;
}
--m_size;
delete pNode;
pNode = 0;
result = 0;
break;
}
pPrevNode = pNode;
pNode = pNode->getNext();
}
if(0 != result)
{
log_error(TAG, "erase: failed %d", result);
}
return Iterator(pNextNode);
}
inline Iterator begin()
{
return Iterator(m_pHead);
}
inline Iterator end()
{
return Iterator(0);
}
inline ConstIterator begin() const
{
return ConstIterator(m_pHead);
}
inline ConstIterator end() const
{
return ConstIterator(0);
}
inline size_t getSize() const
{
return m_size;
}
protected:
SingleListNode<T> * m_pHead;
size_t m_size;
static int _comparator(const void * lhs, const void * rhs)
{
const SingleListNode<T> * const left_node = *reinterpret_cast<SingleListNode<T> * const *>(lhs);
const SingleListNode<T> * const right_node = *reinterpret_cast<SingleListNode<T> * const *>(rhs);
return list_comparator(left_node->getValue(), right_node->getValue());
}
static int _reverse_comparator(const void * lhs, const void * rhs)
{
return _comparator(rhs, lhs);
}
};
template<typename T>
const char * const List<T>::TAG = "List";
template<typename T>
const char * const ConstListIterator<T>::TAG = "List";
} // namespace qc_loc_fw
#endif //#ifndef __XTRAT_WIFI_LIST_H__

View File

@@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: loc-base-util
Description: QTI GPS Loc base utils
Version: @VERSION
Libs: -L${libdir} -lloc_base_util
Cflags: -I${includedir} -I${includedir}/loc-base-util

View File

@@ -0,0 +1,46 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Log utility
GENERAL DESCRIPTION
This header declares a logging utility
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_LOG_H__
#define __XTRAT_WIFI_LOG_H__
namespace qc_loc_fw
{
enum ERROR_LEVEL
{
EL_LOG_OFF = 0, EL_ERROR = 1, EL_WARNING = 2, EL_INFO = 3, EL_DEBUG = 4, EL_VERBOSE = 5, EL_LOG_ALL = 100
};
// bits masks for Error Output preference
enum ERROR_OUTPUT
{
EO_ANDROID = 0x1, EO_STDOUT = 0x2, EO_ALL = 0x3
};
void log_error(const char * const local_log_tag, const char * const format, ...);
void log_warning(const char * const local_log_tag, const char * const format, ...);
void log_info(const char * const local_log_tag, const char * const format, ...);
void log_debug(const char * const local_log_tag, const char * const format, ...);
void log_verbose(const char * const local_log_tag, const char * const format, ...);
int log_set_global_level(const ERROR_LEVEL level);
int log_set_global_tag(const char * const tag);
int log_flush_all_local_level();
int log_flush_local_level_for_tag(const char *const tag);
int log_set_local_level_for_tag(const char *const tag, const ERROR_LEVEL level);
int log_set_local_level_for_tag(const char *const tag, const ERROR_LEVEL level,
const ERROR_OUTPUT output);
bool is_log_verbose_enabled(const char * const local_log_tag);
} // namespace qc_loc_fw
#endif //#ifndef __XTRAT_WIFI_LOG_H__

View File

@@ -0,0 +1,65 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Memory stream
GENERAL DESCRIPTION
This header declares two memory streams, one for input and one for output
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_MEMORY_STREAM_H__
#define __XTRAT_WIFI_MEMORY_STREAM_H__
#include <stddef.h>
namespace qc_loc_fw
{
class MemoryStreamBase
{
public:
virtual ~MemoryStreamBase() = 0;
typedef unsigned char BYTE;
virtual size_t getSize() const = 0;
virtual const BYTE * getBuffer() const = 0;
};
class OutMemoryStream: public MemoryStreamBase
{
public:
static OutMemoryStream * createInstance();
virtual ~OutMemoryStream() = 0;
// note: only OutMemoryStream supports the non-const version of getBuffer
virtual BYTE * getBufferNonConst() = 0;
virtual int append(const void * const pData, const size_t length) = 0;
virtual size_t getPutCursor() const = 0;
};
class InMemoryStream: public MemoryStreamBase
{
public:
static InMemoryStream * createInstance();
// take ownership of the memory block from given OutMemoryStream 'os'
// after this statement, 'os' is no longer usable, and won't delete the memory block at destruction
// instead, this newly created InMemoryStream will have to delete that memory block
static InMemoryStream * createInstance(OutMemoryStream * const os);
virtual ~InMemoryStream() = 0;
virtual int setBufferOwnership(const void ** const ppIn, const size_t length) = 0;
virtual int setBufferNoDup(const void * const pIn, const size_t length) = 0;
virtual int extract(void * const pData, const size_t length) = 0;
virtual size_t getGetCursor() const = 0;
virtual int setGetCursor(const size_t cursor) = 0;
virtual size_t getCapacity() const = 0;
virtual InMemoryStream * clone() const = 0;
};
} // namespace qc_loc_fw
#endif //#ifndef __XTRAT_WIFI_MEMORY_STREAM_H__

View File

@@ -0,0 +1,146 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
GTP storage manager for persistent parameters
GENERAL DESCRIPTION
This declares the public interface of storage manager for
permanent parameters.
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_NVPARAM_MGR_H__
#define __XTRAT_WIFI_NVPARAM_MGR_H__
#include <stdint.h>
namespace qc_loc_fw
{
// Below is the list of parameter names to be shared among modules
// for 32-bit pseudo client ID, this will be 32 bit signed,
// for 64 bit signed or unsigned
#define PARAM_NAME_PSEUDO_CLIENT_ID "PSEUDO_CLIENT_ID"
#define PARAM_NAME_PSEUDO_CLIENT_ID_64BIT "PSEUDO_CLIENT_ID_64BIT"
// list of error code currently supported by nv param manager
// for saveXXXParam and getXXXParam
typedef enum
{
NV_PARAM_ERR_NO_ERR = 0,
// the parameter is not available
NV_PARAM_ERR_PARAM_NOT_FOUND = 1,
NV_PARAM_ERR_PRRAM_NOT_VALID = 2,
// sqlite is locked and operation can not be performed now,
// if the operation is critical, suggest application to
// wait a few seconds and try again.
NV_PARAM_ERR_SQLITE_BUSY = 3,
// other sqlite error
NV_PARAM_ERR_SQLITE_OTHER_ERR = 4,
// leave some range for extension
NV_PARAM_ERR_OTHER_ERR = 100
} nv_param_err_code;
// NOTE: to use this class, it is user's responsibility to make sure
// that nv param name is unique. It is recommended nv param name to
// start with your module name to avoid collision.
class NvParamMgr
{
public:
// returns singleton NvParamMgr implementation class
// NOTE: If the returned poiner is non-NULL, please
// call NvParamMgr::releaseInstance after usage.
static NvParamMgr* getInstance();
// releases the refence to NvParamMgr implementation class
// NOTE: calling this function need to be paired when getInstance()
// is returning non-NULL pointer.
static void releaseInstance();
// Below APIs are thread safe with current sqlite based implementation.
//
// The APIs will save the given param value into the permanent storage file.
// Return value is defined in nv_param_err_code.
//
// Note: If returned error code is NV_PARAM_ERR_SQLITE_BUSY, the sqlite file
// is locked and operation can not be performed now,
// if the operation is critical, suggest application to
// wait a few seconds and try again.
virtual nv_param_err_code saveInt32Param (const char* param_name,
const int param_value) = 0;
virtual nv_param_err_code saveBoolParam (const char* param_name,
const bool param_value) = 0;
virtual nv_param_err_code saveFloatParam (const char* param_name,
const float param_value) = 0;
virtual nv_param_err_code saveUInt32Param (const char* param_name,
const unsigned int param_value) = 0;
virtual nv_param_err_code saveInt64Param (const char* param_name,
const long long param_value) = 0;
virtual nv_param_err_code saveUInt64Param (const char* param_name,
const unsigned long long param_value) = 0;
virtual nv_param_err_code saveStringParam (const char* param_name,
const char* param_value) = 0;
virtual nv_param_err_code saveBlobParam (const char* param_name,
const unsigned char* param_value,
unsigned int param_size_in_bytes) = 0;
// Below APIs are thread safe with current sqlite based implementation.
//
// The APIs will retrive the given param value from the permanent storage file
// If the param can not be retrieved, param_value will not be
// modified.
//
// Return value is defined in nv_param_err_code, 0 for success.
//
// Note: If returned error code is NV_PARAM_ERR_SQLITE_BUSY,
// the sqlite file is locked and operation can not be performed now,
// if the operation is critical, suggest application to
// wait a few seconds and try again.
virtual nv_param_err_code getInt32Param (const char* param_name,
int & param_value) = 0;
virtual nv_param_err_code getBoolParam (const char* param_name,
bool & param_value) = 0;
virtual nv_param_err_code getFloatParam (const char* param_name,
float & param_value) = 0;
virtual nv_param_err_code getUInt32Param (const char* param_name,
unsigned int & param_value) = 0;
virtual nv_param_err_code getInt64Param (const char* param_name,
long long & param_value) = 0;
virtual nv_param_err_code getUInt64Param (const char* param_name,
unsigned long long & param_value) = 0;
// 0 or NV_PARAM_ERR_NO_ERR: when successful
// NOTE: memory returned via param_value need to be freed by caller
// via delete [] when return code is 0 (NV_PARAM_ERR_NO_ERROR)
virtual nv_param_err_code getStringParam (const char* param_name,
char* &param_value,
unsigned int &param_size_in_bytes) = 0;
// 0 or NV_PARAM_ERR_NO_ERR: when successful
// NOTE: memory returned via param_value need to be freed by caller
// via delete [] when return code is 0 (NV_PARAM_ERR_NO_ERROR)
virtual nv_param_err_code getBlobParam (const char* param_name,
unsigned char* &param_value,
unsigned int &param_size_in_bytes) = 0;
protected:
// allow constructor to be made only via getInstance
NvParamMgr() {};
// prohibit calling delete on the pointer returned from
// NvParamMgr::getInstance()
virtual ~NvParamMgr() {};
};
} // namespace qc_loc_fw
#endif // #ifndef __XTRAT_WIFI_NVPARAM_MGR_H__

View File

@@ -0,0 +1,158 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
IPC message
GENERAL DESCRIPTION
This header declares two IPC messages, one for input and one for output
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_POSTCARD_H__
#define __XTRAT_WIFI_POSTCARD_H__
#include <stdint.h>
#include <base_util/memorystream.h>
namespace qc_loc_fw
{
class PostcardBase
{
public:
virtual ~PostcardBase() = 0;
typedef double DOUBLE;
typedef float FLOAT;
typedef long long INT64;
typedef unsigned long long UINT64;
typedef int32_t INT32;
typedef uint32_t UINT32;
typedef int16_t INT16;
typedef uint16_t UINT16;
typedef char INT8;
typedef unsigned char UINT8;
typedef bool BOOL;
typedef void* PTR;
};
class OutPostcard: public PostcardBase
{
public:
// we only use 2 bytes to hold the name
static const size_t MAX_ENCODE_NAME_LENGTH = 256;
virtual ~OutPostcard() = 0;
static OutPostcard * createInstance();
virtual int init() = 0;
virtual int finalize() = 0;
virtual const MemoryStreamBase * getEncodedBuffer() const = 0;
virtual OutMemoryStream * getInternalBuffer() = 0;
virtual int addDouble(const char * const name, const DOUBLE & value) = 0;
virtual int addFloat(const char * const name, const FLOAT & value) = 0;
virtual int addInt64(const char * const name, const INT64 & value) = 0;
virtual int addUInt64(const char * const name, const UINT64 & value) = 0;
virtual int addInt32(const char * const name, const INT32 & value) = 0;
virtual int addUInt32(const char * const name, const UINT32 & value) = 0;
virtual int addInt16(const char * const name, const INT16 & value) = 0;
virtual int addUInt16(const char * const name, const UINT16 & value) = 0;
virtual int addInt8(const char * const name, const INT8 & value) = 0;
virtual int addUInt8(const char * const name, const UINT8 & value) = 0;
virtual int addBool(const char * const name, const BOOL & value) = 0;
virtual int addString(const char * const name, const char * const str) = 0;
virtual int addPtr(const char * const name, const PTR & value) = 0;
virtual int addBlob(const char * const name, const void * const blob, const size_t length) = 0;
virtual int addCard(const char * const name, const OutPostcard * const pCard) = 0;
virtual int addArrayDouble(const char * const name, const int num_element, const DOUBLE array[]) = 0;
virtual int addArrayFloat(const char * const name, const int num_element, const FLOAT array[]) = 0;
virtual int addArrayInt64(const char * const name, const int num_element, const INT64 array[]) = 0;
virtual int addArrayUInt64(const char * const name, const int num_element, const UINT64 array[]) = 0;
virtual int addArrayInt32(const char * const name, const int num_element, const INT32 array[]) = 0;
virtual int addArrayUInt32(const char * const name, const int num_element, const UINT32 array[]) = 0;
virtual int addArrayInt16(const char * const name, const int num_element, const INT16 array[]) = 0;
virtual int addArrayUInt16(const char * const name, const int num_element, const UINT16 array[]) = 0;
virtual int addArrayInt8(const char * const name, const int num_element, const INT8 array[]) = 0;
virtual int addArrayUInt8(const char * const name, const int num_element, const UINT8 array[]) = 0;
virtual int addArrayBool(const char * const name, const int num_element, const BOOL array[]) = 0;
virtual int addArrayPtr (const char * const name, const int num_element, const PTR array[]) = 0;
};
class InPostcard: public PostcardBase
{
public:
virtual ~InPostcard() = 0;
static InPostcard * createInstance();
// assume ownership of the memory stream pointed by pInMem
// the memory stream object will be deleted in our destructor
// whether the actual memory block will be deleted with the destructor of
// that InMemoryStream depends on the ownership setting of that InMemoryStream
static InPostcard * createInstance(InMemoryStream * const pInMem);
// assume ownership of the memory stream pointed by pCard->getEncodedBuffer
// the memory stream object will be deleted in our destructor
// pCard becomes useless can can only be deleted after this operation
static InPostcard * createInstance(OutPostcard * const pCard);
// doesn't assume ownership of the memory pointed by pIn
// the memory block won't be deleted in our destructor
virtual int init(const void * const pIn, const size_t length, bool assume_ownership = false) = 0;
virtual const MemoryStreamBase * getBuffer() const = 0;
static const int FIELD_NOT_FOUND = -1;
virtual int getDouble(const char * const name, DOUBLE & value) = 0;
virtual int getFloat(const char * const name, FLOAT & value) = 0;
virtual int getInt64(const char * const name, INT64 & value) = 0;
virtual int getUInt64(const char * const name, UINT64 & value) = 0;
virtual int getInt32(const char * const name, INT32 & value) = 0;
virtual int getUInt32(const char * const name, UINT32 & value) = 0;
virtual int getInt16(const char * const name, INT16 & value) = 0;
virtual int getUInt16(const char * const name, UINT16 & value) = 0;
virtual int getInt8(const char * const name, INT8 & value) = 0;
virtual int getUInt8(const char * const name, UINT8 & value) = 0;
//virtual int getArrayUInt8(const char * const name, UINT8 array[]) = 0;
virtual int getBool(const char * const name, BOOL & value) = 0;
virtual int getString(const char * const name, const char ** pStr) = 0;
virtual int getStringDup(const char * const name, const char ** pStr) = 0;
virtual int getDoubleDefault(const char * const name, DOUBLE & value) = 0;
virtual int getFloatDefault(const char * const name, FLOAT & value) = 0;
virtual int getInt64Default(const char * const name, INT64 & value) = 0;
virtual int getUInt64Default(const char * const name, UINT64 & value) = 0;
virtual int getInt32Default(const char * const name, INT32 & value) = 0;
virtual int getUInt32Default(const char * const name, UINT32 & value) = 0;
virtual int getInt16Default(const char * const name, INT16 & value) = 0;
virtual int getUInt16Default(const char * const name, UINT16 & value) = 0;
virtual int getInt8Default(const char * const name, INT8 & value) = 0;
virtual int getUInt8Default(const char * const name, UINT8 & value) = 0;
virtual int getBoolDefault(const char * const name, BOOL & value) = 0;
virtual int getStringOptional(const char * const name, const char ** pStr) = 0;
virtual int getPtr(const char * const name, PTR & value) = 0;
virtual int getBlob(const char * const name, const void ** const pBlob, size_t * const pLength) = 0;
virtual int getCard(const char * const name, InPostcard ** const ppCard, const int index = 0) = 0;
// Note for alignment issue, we cannot directly return a pointer pointing to internal buffer
// so we have to explicitly allocate and de-allocate a memory block according to alignment rule
// call these functions twice. first set array to 0 and get the number of elements
virtual int getArrayDouble(const char * const name, int * const pNumElem, DOUBLE * const array = 0) = 0;
virtual int getArrayFloat(const char * const name, int * const pNumElem, FLOAT * const array = 0) = 0;
virtual int getArrayInt64(const char * const name, int * const pNumElem, INT64 * const array = 0) = 0;
virtual int getArrayUInt64(const char * const name, int * const pNumElem, UINT64 * const array = 0) = 0;
virtual int getArrayInt32(const char * const name, int * const pNumElem, INT32 * const array = 0) = 0;
virtual int getArrayUInt32(const char * const name, int * const pNumElem, UINT32 * const array = 0) = 0;
virtual int getArrayInt16(const char * const name, int * const pNumElem, INT16 * const array = 0) = 0;
virtual int getArrayUInt16(const char * const name, int * const pNumElem, UINT16 * const array = 0) = 0;
virtual int getArrayInt8(const char * const name, int * const pNumElem, INT8 * const array = 0) = 0;
virtual int getArrayUInt8(const char * const name, int * const pNumElem, UINT8 * const array = 0) = 0;
virtual int getArrayBool(const char * const name, int * const pNumElem, BOOL * const array = 0) = 0;
virtual int getArrayPtr (const char * const name, int * const pNumElem, PTR * const array = 0) = 0;
};
} // namespace qc_loc_fw
#endif // #ifndef __XTRAT_WIFI_POSTCARD_H__

View File

@@ -0,0 +1,143 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Queue template
GENERAL DESCRIPTION
This component implements a queue of any type
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_QUEUE_H__
#define __XTRAT_WIFI_QUEUE_H__
#include <base_util/list.h>
#include <base_util/log.h>
namespace qc_loc_fw
{
template<typename T>
class Queue: public List<T>
{
private:
static const char * const TAG;
public:
Queue()
{
}
virtual ~Queue()
{
}
int push(const T& rhs)
{
// our specific requirement says pushing, or enqueuing, should be as fast as possible
// this is exactly what list does for us: always O(1) for insertion at the head
return this->add(rhs);
}
int top(T * const pValue)
{
int result = 1;
do
{
if(0 == pValue)
{
result = 2;
break;
}
SingleListNode<T> * pLastNode = 0;
//SingleListNode<T> * pSecondLastNode = 0;
SingleListNode<T> * pNode = List<T>::m_pHead;
while (0 != pNode)
{
//pSecondLastNode = pLastNode;
pLastNode = pNode;
pNode = pNode->getNext();
}
if(0 != pLastNode)
{
*pValue = pLastNode->getValue();
}
else
{
// we started with an empty queue
result = 3;
break;
}
result = 0;
} while (false);
if(0 != result)
{
log_error(TAG, "top: failed %d", result);
}
return result;
}
int pop(T * const pValue)
{
int result = 1;
do
{
if(0 == pValue)
{
result = 2;
break;
}
SingleListNode<T> * pLastNode = 0;
SingleListNode<T> * pSecondLastNode = 0;
SingleListNode<T> * pNode = List<T>::m_pHead;
while (0 != pNode)
{
pSecondLastNode = pLastNode;
pLastNode = pNode;
pNode = pNode->getNext();
}
if(0 != pSecondLastNode)
{
pSecondLastNode->setNext(0);
List<T>::m_size = List<T>::m_size - 1;
}
else
{
// nothing, we only had 1 element and we just removed it
List<T>::m_pHead = 0;
List<T>::m_size = 0;
}
if(0 != pLastNode)
{
*pValue = pLastNode->getValue();
delete pLastNode;
pLastNode = 0;
}
else
{
// we started with an empty queue
result = 3;
break;
}
result = 0;
} while (false);
if(0 != result)
{
log_error(TAG, "pop: failed %d", result);
}
return result;
}
};
template<typename T>
const char * const Queue<T>::TAG = "Queue";
} // namespace qc_loc_fw
#endif //#ifndef __XTRAT_WIFI_QUEUE_H__

View File

@@ -0,0 +1,67 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef SHUTDOWN_TIMER_H
#define SHUTDOWN_TIMER_H
#include "LocTimer.h"
#include "loc_cfg.h"
#include "log_util.h"
#include <string>
#include <functional>
#define PROCESS_SHUTDOWN_TIMEOUT_IN_MS 300000
namespace qc_loc_fw {
class ProcessShutdownTimer : public loc_util::LocTimer {
public:
~ProcessShutdownTimer() = default;
ProcessShutdownTimer(std::string name, const std::function<void()> shutdownCb) :
loc_util::LocTimer(), mShutdownCb(shutdownCb), mActive(false),
mShutdownTimerInMs(PROCESS_SHUTDOWN_TIMEOUT_IN_MS), mLaunchTriggerMask(0),
mProcessName(name) {
const loc_param_s_type gpsConfTable[] = {
{"PROCESS_SHUTDOWN_TIMER_IN_MS", &mShutdownTimerInMs, NULL, 'n'}};
UTIL_READ_CONF(LOC_PATH_GPS_CONF, gpsConfTable);
}
inline void start() {
if (mLaunchTriggerMask > 0) {
LOC_LOGd("Started shutdown timer for process %s", mProcessName.c_str());
mActive = true;
loc_util::LocTimer::start(mShutdownTimerInMs, false);
}
}
inline void stop() {
if (mLaunchTriggerMask > 0) {
LOC_LOGd("Stopped shutdown timer for process %s", mProcessName.c_str());
mActive = false;
loc_util::LocTimer::stop();
}
}
inline void restart() {
if (mLaunchTriggerMask > 0) {
LOC_LOGd("Restarted shutdown timer for process %s", mProcessName.c_str());
stop();
start();
}
}
inline bool isActive() {
return mActive;
}
inline void setLaunchTriggerMask(int16_t launchTriggerMask) {
mLaunchTriggerMask = launchTriggerMask;
}
private:
inline virtual void timeOutCallback() override {
mShutdownCb();
}
const std::function<void()> mShutdownCb;
bool mActive;
std::string mProcessName;
uint32_t mShutdownTimerInMs;
uint16_t mLaunchTriggerMask;
};
} // namespace qc_loc_fw
#endif /* SHUTDOWN_TIMER_H */

View File

@@ -0,0 +1,51 @@
AM_CFLAGS = \
-I../ \
-I../../base_util \
-I../../ \
-D__func__=__PRETTY_FUNCTION__ \
-fno-short-enums
h_sources = \
../config_file.h \
../log.h \
../postcard.h \
../sync.h \
../queue.h \
../list.h \
../memorystream.h \
../nvparam_mgr.h \
../time_routines.h \
../vector.h \
../array.h \
../string_routines.h \
../shutdown_timer.h
libloc_base_util_la_SOURCES = \
config_file.cpp \
log.cpp \
memorystream.cpp \
nvparam_mgr.cpp \
postcard.cpp \
sync.cpp \
string_routines.cpp \
time_routines.cpp
library_includedir = $(pkgincludedir)
library_include_HEADERS = $(h_sources)
if USE_GLIB
libloc_base_util_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@ -Dstrlcat=g_strlcat -Dstrlcpy=g_strlcpy -include glib.h
libloc_base_util_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
libloc_base_util_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@ -Dstrlcat=g_strlcat -Dstrlcpy=g_strlcpy -include glib.h
else
libloc_base_util_la_CFLAGS = $(AM_CFLAGS)
libloc_base_util_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
libloc_base_util_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
endif
libloc_base_util_la_LIBADD = -lstdc++ -ldl -lsqlite3
#Create and Install libraries
lib_LTLIBRARIES = libloc_base_util.la
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = ../loc-base-util.pc
EXTRA_DIST = $(pkgconfig_DATA)

View File

@@ -0,0 +1,734 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Config file parser
GENERAL DESCRIPTION
This component parses any specified config file and allows to be queried later
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#include <new>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <base_util/log.h>
#include <base_util/list.h>
#include <base_util/config_file.h>
#define BREAK_IF_ZERO(ERR,X) if(0==(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO(ERR,X) if(0!=(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO_RC(ERR,RC,X) if(0!=(RC=(X))) {result = (ERR); break;}
namespace qc_loc_fw
{
static const char * const TAG = "ConfigFile";
ConfigFile::~ConfigFile()
{
// dummy
}
struct ConfigPair
{
const char * name;
const char * value;
};
class ConfigFileImpl: public ConfigFile
{
public:
ConfigFileImpl(const char * const filename, const size_t max_line_length, const bool verbose);
~ConfigFileImpl();
bool loaded() const
{
return m_loaded;
}
;
int getString(const char * const name, const char ** pStr);
int getStringDup(const char * const name, const char ** pStr, const char * const strDefault);
int getInt32(const char * const name, int & value);
int getInt32Default(const char * const name, int & value, const int & Default);
int get_PZ_Int32Default(const char * const name, int & value, const int & Default);
int get_PNZ_Int32Default(const char * const name, int & value, const int & Default);
int getDouble(const char * const name, double & value);
int getDoubleDefault(const char * const name, double & value, const double & Default);
private:
bool m_loaded;
typedef List<ConfigPair> PAIRS;
PAIRS m_config;
void trim(size_t & cursor_begin, size_t & cursor_end, const char * const line);
void substring(char * dest, const size_t capacity, const char * const src, const size_t begin, const size_t end);
int find_name(size_t & cursor_begin, size_t & cursor_end, const char * const line, size_t & name_begin,
size_t & name_end);
int find_equal(size_t & cursor_begin, size_t & cursor_end, const char * const line);
int find_value(size_t & cursor_begin, size_t & cursor_end, const char * const line, size_t & value_begin,
size_t & value_end);
const char * subStringDup(const char * const src, const size_t begin, const size_t end);
};
void ConfigFileImpl::trim(size_t & cursor_begin, size_t & cursor_end, const char * const line)
{
// check arguments
if(cursor_end <= cursor_begin)
{
// empty line already
return;
}
// left trim
for (; cursor_begin < cursor_end; ++cursor_begin)
{
if(!isspace(line[cursor_begin]))
{
break;
}
}
// right trim
for (; cursor_begin < cursor_end; --cursor_end)
{
if(!isspace(line[cursor_end - 1]))
{
break;
}
}
}
void ConfigFileImpl::substring(char * dest, const size_t capacity, const char * const src, const size_t begin,
const size_t end)
{
memset(dest, 0, capacity);
for (size_t i = begin, d = 0; ((i < end) && (d < capacity)); ++i, ++d)
{
dest[d] = src[i];
}
}
const char * ConfigFileImpl::subStringDup(const char * const src, const size_t begin, const size_t end)
{
char * dest = 0;
int result = 1;
do
{
if(begin >= end)
{
result = 2;
}
BREAK_IF_ZERO(3, src);
size_t length = end - begin;
dest = new (std::nothrow) char[length + 1];
BREAK_IF_ZERO(4, dest);
memcpy(dest, src + begin, length);
dest[length] = '\0';
result = 0;
} while (0);
if(0 != result)
{
delete[] dest;
log_error(TAG, "subStringDup failed %d", result);
return 0;
}
else
{
return dest;
}
}
int ConfigFileImpl::find_name(size_t & cursor_begin, size_t & cursor_end, const char * const line, size_t & name_begin,
size_t & name_end)
{
if(0 == line)
{
return 1;
}
if(cursor_begin >= cursor_end)
{
return 2;
}
bool found = false;
for (size_t i = cursor_begin; i < cursor_end; ++i)
{
if(!found)
{
if(isalpha(line[i]))
{
found = true;
name_begin = i;
name_end = i + 1;
}
else
{
break;
}
}
else
{
if(isalnum(line[i]) || ('-' == line[i]) || ('_' == line[i]))
{
name_end = i + 1;
continue;
}
else
{
break;
}
}
}
if(found)
{
cursor_begin = name_end;
trim(cursor_begin, cursor_end, line);
return 0;
}
else
{
return 3;
}
}
int ConfigFileImpl::find_equal(size_t & cursor_begin, size_t & cursor_end, const char * const line)
{
if(0 == line)
{
return 1;
}
if(cursor_begin >= cursor_end)
{
return 2;
}
if('=' == line[cursor_begin])
{
++cursor_begin;
trim(cursor_begin, cursor_end, line);
return 0;
}
return 3;
}
int ConfigFileImpl::find_value(size_t & cursor_begin, size_t & cursor_end, const char * const line,
size_t & value_begin, size_t & value_end)
{
if(0 == line)
{
return 1;
}
if(cursor_begin >= cursor_end)
{
return 2;
}
value_begin = cursor_begin;
value_end = cursor_end;
cursor_begin = cursor_end;
if('"' == line[value_begin])
{
if(value_end - value_begin >= 2)
{
if('"' == line[value_end - 1])
{
// remove double quote
++value_begin;
--value_end;
}
else
{
// start with " but doesn't end with one
return 3;
}
}
else
{
// start with " but doesn't end with one
return 4;
}
}
return 0;
}
ConfigFileImpl::ConfigFileImpl(const char * const filename, const size_t max_line_length, const bool verbose) :
m_loaded(false)
{
ConfigPair pair;
pair.name = 0;
pair.value = 0;
char * line_debug = 0;
char * line = 0;
FILE * file = 0;
int result = 1;
int line_index = 0;
do
{
BREAK_IF_ZERO(2, filename);
file = fopen(filename, "r");
BREAK_IF_ZERO(3, file);
line = new (std::nothrow) char[max_line_length + 1];
BREAK_IF_ZERO(4, line);
if(verbose)
{
line_debug = new (std::nothrow) char[max_line_length + 1];
BREAK_IF_ZERO(5, line_debug);
line_debug[0] = '\0';
}
line[0] = '\0';
result = 100;
while (0 != fgets(line, max_line_length + 1, file))
{
++line_index;
//log_verbose(TAG, "line [%s]", line);
size_t length = strlen(line);
if(length >= max_line_length)
{
// line too long
result = 101;
break;
}
// token type 1: # comment till the end of line
// token type 2: name, can only contain alphanumeric,'_', and '-'
// token type 3: '='
// token type 4: value: anything starting from the first non-space char after '=' to the end of this (trimmed) line
size_t cursor_begin = 0;
size_t cursor_end = length;
trim(cursor_begin, cursor_end, line);
if(verbose)
{
substring(line_debug, max_line_length + 1, line, cursor_begin, cursor_end);
log_debug(TAG, "line trimed [%s]", line_debug);
}
if(cursor_begin >= cursor_end)
{
// empty line already
if(verbose)
{
log_verbose(TAG, "Line[%d], skip empty line", line_index);
}
}
else if('#' == line[cursor_begin])
{
// this whole line is comment
cursor_begin = cursor_end;
if(verbose)
{
log_verbose(TAG, "Line[%d], skip comment line", line_index);
}
}
else
{
// we shall see name = value pattern
size_t name_begin = cursor_end;
size_t name_end = cursor_end;
size_t value_begin = cursor_end;
size_t value_end = cursor_end;
BREAK_IF_NON_ZERO(110, find_name(cursor_begin, cursor_end, line, name_begin, name_end));
BREAK_IF_NON_ZERO(111, find_equal(cursor_begin, cursor_end, line));
BREAK_IF_NON_ZERO(112, find_value(cursor_begin, cursor_end, line, value_begin, value_end));
if(cursor_begin < cursor_end)
{
// still anything after 'value' token!?
// error
result = 113;
break;
}
if(verbose)
{
substring(line_debug, max_line_length + 1, line, name_begin, name_end);
log_verbose(TAG, "name [%s]", line_debug);
substring(line_debug, max_line_length + 1, line, value_begin, value_end);
log_verbose(TAG, "value [%s]", line_debug);
}
pair.name = subStringDup(line, name_begin, name_end);
pair.value = subStringDup(line, value_begin, value_end);
BREAK_IF_ZERO(114, pair.name);
BREAK_IF_ZERO(115, pair.value);
BREAK_IF_NON_ZERO(116, m_config.add(pair));
// we don't own them now
pair.name = 0;
pair.value = 0;
}
// reset the string
line[0] = '\0';
if(line_debug)
{
line_debug[0] = '\0';
}
}
if(100 != result)
{
break;
}
BREAK_IF_NON_ZERO(10, ferror(file));
m_loaded = true;
result = 0;
} while (0);
delete[] line;
line = 0;
delete[] pair.name;
pair.name = 0;
delete[] pair.value;
pair.value = 0;
delete[] line_debug;
line_debug = 0;
if(0 != file)
{
(void) fclose(file);
file = 0;
}
if(0 != result)
{
log_error(TAG, "ConfigFileImpl: cannot load config file result [%d] [%s], error [%d][%s], line[%d]", result,
filename, errno, strerror(errno), line_index);
}
}
ConfigFileImpl::~ConfigFileImpl()
{
for (PAIRS::Iterator it = m_config.begin(); it != m_config.end(); ++it)
{
ConfigPair & pair = (*it);
delete[] pair.name;
delete[] pair.value;
pair.name = 0;
pair.value = 0;
}
m_config.flush();
}
int ConfigFileImpl::getString(const char * const name, const char ** pStr)
{
int result = 1;
do
{
if(!m_loaded)
{
result = 2;
break;
}
BREAK_IF_ZERO(3, name);
BREAK_IF_ZERO(4, pStr);
*pStr = 0;
result = NOT_FOUND;
for (PAIRS::Iterator it = m_config.begin(); it != m_config.end(); ++it)
{
ConfigPair & pair = (*it);
if(0 == strcmp(name, pair.name))
{
*pStr = pair.value;
result = NO_ERROR_RESULT_SET;
break;
}
}
} while (0);
if((NO_ERROR_RESULT_SET != result) && (NOT_FOUND != result))
{
if(name)
{
log_error(TAG, "getString failed [%s] %d", name, result);
}
else
{
log_error(TAG, "getString failed %d", result);
}
}
return result;
}
int ConfigFileImpl::getStringDup(const char * const name, const char ** pStr, const char * const strDefault)
{
int result = 1;
do
{
if(!m_loaded)
{
// if not loaded, set return to NOT_FOUND, so that default value (strDefault) can be returned.
result = NOT_FOUND;
}
else
{
BREAK_IF_ZERO(3, name);
BREAK_IF_ZERO(4, pStr);
*pStr = 0;
result = NOT_FOUND;
for (PAIRS::Iterator it = m_config.begin(); it != m_config.end(); ++it)
{
ConfigPair & pair = (*it);
if(0 == strcmp(name, pair.name))
{
size_t length = strlen(pair.value) + 1;
*pStr = new (std::nothrow) char[length];
BREAK_IF_ZERO(101, *pStr);
memcpy((void *) *pStr, (const void *) pair.value, length);
result = NO_ERROR_RESULT_SET;
break;
}
}
}
if((NOT_FOUND == result) && (0 != strDefault))
{
size_t length = strlen(strDefault) + 1;
*pStr = new (std::nothrow) char[length];
BREAK_IF_ZERO(111, *pStr);
memcpy((void *) *pStr, (const void *) strDefault, length);
result = NO_ERROR_RESULT_SET;
}
} while (0);
if((NO_ERROR_RESULT_SET != result) && (NOT_FOUND != result))
{
if(name)
{
log_error(TAG, "getStringDup failed [%s] %d", name, result);
}
else
{
log_error(TAG, "getStringDup failed %d", result);
}
}
return result;
}
int ConfigFileImpl::get_PZ_Int32Default(const char * const name, int & value, const int & Default)
{
int result = getInt32(name, value);
if(NOT_FOUND == result)
{
value = Default;
return 0;
}
else if(value < 0)
{
value = Default;
return 1;
}
return result;
}
int ConfigFileImpl::get_PNZ_Int32Default(const char * const name, int & value, const int & Default)
{
int result = getInt32(name, value);
if(NOT_FOUND == result)
{
value = Default;
return 0;
}
else if(value <= 0)
{
value = Default;
return 1;
}
return result;
}
int ConfigFileImpl::getInt32Default(const char * const name, int & value, const int & Default)
{
int result = getInt32(name, value);
if(NOT_FOUND == result)
{
value = Default;
return 0;
}
return result;
}
int ConfigFileImpl::getInt32(const char * const name, int & value)
{
int result = 1;
do
{
if(!m_loaded)
{
// if not loaded, return NOT_FOUND, so that other util functions invoking
// this function (eg:getInt32Default) can return back default value.
log_debug(TAG, "getInt32 m_loaded is false");
result = NOT_FOUND;
break;
}
BREAK_IF_ZERO(3, name);
result = NOT_FOUND;
for (PAIRS::Iterator it = m_config.begin(); it != m_config.end(); ++it)
{
ConfigPair & pair = (*it);
if(0 == strcmp(name, pair.name))
{
if(strlen(pair.value) < 1)
{
result = 101;
break;
}
errno = 0;
char * end_ptr = 0;
long temp = strtol(pair.value, &end_ptr, 0);
if((LONG_MAX == temp) || (LONG_MIN == temp))
{
result = 102;
}
else if(0 != errno)
{
// conversion error
log_error(TAG, "conversion error [%d] [%s]", errno, strerror(errno));
result = 103;
}
else if('\0' != *end_ptr)
{
// string not fully consumed
result = 104;
}
else if((temp > INT_MAX) || (temp < INT_MIN))
{
// beyond range for int32
result = 105;
}
else
{
// conversion okay
value = (int) temp;
result = 0;
}
break;
}
}
} while (0);
if((NO_ERROR_RESULT_SET != result) && (NOT_FOUND != result))
{
if(name)
{
log_error(TAG, "getInt32 failed [%s] %d", name, result);
}
else
{
log_error(TAG, "getInt32 failed %d", result);
}
}
return result;
}
int ConfigFileImpl::getDoubleDefault(const char * const name, double & value, const double & Default)
{
int result = getDouble(name, value);
if(NOT_FOUND == result)
{
value = Default;
return 0;
}
return result;
}
int ConfigFileImpl::getDouble(const char * const name, double & value)
{
int result = 1;
do
{
if(!m_loaded)
{
// if not loaded, return NOT_FOUND, so that other util functions invoking
// this function (eg:getDoubleDefault) can return back default value.
log_debug(TAG, "getDouble m_loaded is false");
result = NOT_FOUND;
break;
}
BREAK_IF_ZERO(3, name);
result = NOT_FOUND;
for (PAIRS::Iterator it = m_config.begin(); it != m_config.end(); ++it)
{
ConfigPair & pair = (*it);
if(0 == strcmp(name, pair.name))
{
if(strlen(pair.value) < 1)
{
result = 101;
break;
}
errno = 0;
char * end_ptr = 0;
double temp = strtod(pair.value, &end_ptr);
if(0 != errno)
{
// conversion error
log_error(TAG, "conversion error [%d] [%s]", errno, strerror(errno));
result = 102;
}
else if('\0' != *end_ptr)
{
// string not fully consumed
result = 103;
}
else
{
// conversion okay
value = temp;
result = 0;
}
break;
}
}
} while (0);
if((NO_ERROR_RESULT_SET != result) && (NOT_FOUND != result))
{
if(name)
{
log_error(TAG, "getDouble failed [%s] %d", name, result);
}
else
{
log_error(TAG, "getDouble failed %d", result);
}
}
return result;
}
ConfigFile * ConfigFile::createInstance(const char * const filename, const size_t max_line_length, const bool verbose)
{
return new (std::nothrow) ConfigFileImpl(filename, max_line_length, verbose);
}
} // namespace qc_loc_fw

View File

@@ -0,0 +1,524 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Log utility
GENERAL DESCRIPTION
This component provides logging service to all client side components
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <new>
//#include <base_util/log.h>
#include <base_util/sync.h>
#include <base_util/list.h>
#include <base_util/string_routines.h>
#include <base_util/time_routines.h>
#define DEFAULT_ERROR_OUTPUT EO_STDOUT
#if defined (USE_ANDROID_LOGGING) || defined (__ANDROID__)
// Android and LE targets with logcat support
#define LOG_NDEBUG 0
// these 2 symbols are needed on ICS for DEBUG- and INFO-level
// log messages to be processed. They are not neeeded on JB
#define LOG_NDEBUG 0
#define LOG_NIDEBUG 0
#define LOG_TAG NULL
#ifdef __ANDROID_NDK__
#include <android/log.h>
#define ANDROID_LOG __android_log_print
#define LOG_VERBOSE ANDROID_LOG_VERBOSE
#define LOG_DEBUG ANDROID_LOG_DEBUG
#define LOG_INFO ANDROID_LOG_INFO
#define LOG_WARN ANDROID_LOG_WARN
#define LOG_ERROR ANDROID_LOG_ERROR
#else // #ifdef __ANDROID_NDK__
#include <utils/Log.h>
#ifdef ALOG
#define ANDROID_LOG ALOG
#else // #ifdef ALOG
#define ANDROID_LOG LOG
#endif // #ifdef ALOG
#endif // #ifdef __ANDROID_NDK__
#undef DEFAULT_ERROR_OUTPUT
#define DEFAULT_ERROR_OUTPUT EO_ANDROID
#endif // #if defined (USE_ANDROID_LOGGING) || defined (__ANDROID__)
#define BREAK_IF_ZERO(ERR,X) if(0==(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO(ERR,X) if(0!=(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO_RC(ERR,RC,X) if(0!=(RC=(X))) {result = (ERR); break;}
namespace qc_loc_fw
{
class LocalLogLevelItem;
static char global_log_tag[64] = { 'Q', 'C', 'A', 'L', 'O', 'G', '\0' };
static ERROR_LEVEL global_log_level = EL_LOG_OFF;
static const char * const private_log_tag = "LOG_UTIL";
static Mutex * global_log_mutex = Mutex::createInstance();
static List<LocalLogLevelItem> * local_log_level_list =
new (std::nothrow) List<LocalLogLevelItem>();
class LocalLogLevelItem
{
private:
char * local_tag;
ERROR_LEVEL local_log_level;
ERROR_OUTPUT local_output;
void setTag(const char * const tag)
{
if(0 != tag)
{
local_tag = strdup(tag);
}
}
public:
const char * getTag() const
{
return local_tag;
}
void setLevel(const ERROR_LEVEL level)
{
local_log_level = level;
}
void setOutput(const ERROR_OUTPUT output)
{
local_output = output;
}
ERROR_LEVEL getLevel() const
{
return local_log_level;
}
ERROR_OUTPUT getOutput() const
{
return local_output;
}
LocalLogLevelItem(const char * const tag)
{
setTag(tag);
local_log_level = EL_LOG_ALL;
local_output = DEFAULT_ERROR_OUTPUT;
}
LocalLogLevelItem(const LocalLogLevelItem & rhs)
{
if(&rhs == this)
{
// no operation for assigning to self
return;
}
setTag(rhs.local_tag);
local_log_level = rhs.local_log_level;
local_output = rhs.local_output;
}
~LocalLogLevelItem()
{
if(0 != local_tag)
{
// we got this from strdup, which uses malloc.
free(local_tag);
local_tag = 0;
}
local_tag = 0;
}
bool equals(const char * const tag)
{
if((0 == tag) || (0 == local_tag))
{
return false;
}
if(0 == strcmp(tag, local_tag))
{
return true;
}
return false;
}
};
static LocalLogLevelItem * findLocalLevelItemLocked(const char * const tag)
{
LocalLogLevelItem * p_item = 0;
if(0 != local_log_level_list)
{
for (ListIterator<LocalLogLevelItem> it = local_log_level_list->begin(); it != local_log_level_list->end(); ++it)
{
if(it->equals(tag))
{
p_item = it.ptr();
break;
}
}
}
return p_item;
}
static bool is_log_enabled(const char * const local_log_tag, const ERROR_LEVEL log_level)
{
bool ok_to_log = false;
const LocalLogLevelItem * const pLogLevelRec = findLocalLevelItemLocked(local_log_tag);
if(0 != pLogLevelRec)
{
if(log_level <= pLogLevelRec->getLevel())
{
ok_to_log = true;
}
}
else
{
if(log_level <= global_log_level)
{
ok_to_log = true;
}
}
return ok_to_log;
}
bool is_log_verbose_enabled(const char * const local_log_tag)
{
return is_log_enabled(local_log_tag, EL_VERBOSE);
}
static void vlog(const char * const local_log_tag, const ERROR_LEVEL log_level, const char * const format, va_list args)
{
bool ok_to_log = false;
const LocalLogLevelItem * const pLogLevelRec = findLocalLevelItemLocked(local_log_tag);
ERROR_OUTPUT local_output = DEFAULT_ERROR_OUTPUT;
if(0 != pLogLevelRec)
{
if(log_level <= pLogLevelRec->getLevel())
{
ok_to_log = true;
}
local_output = pLogLevelRec->getOutput();
}
else
{
if(log_level <= global_log_level)
{
ok_to_log = true;
}
}
if(ok_to_log)
{
int format_result = -1;
char buffer1[512];
char buffer2[512];
format_result = vsnprintf(buffer1, sizeof(buffer1), format, args);
if (0 >= format_result)
{
strlcpy(buffer1, "log subsystem message format error", sizeof(buffer1));
}
#if defined (USE_ANDROID_LOGGING) || defined (__ANDROID__)
if (EO_ANDROID & local_output)
{
if (0 != local_log_tag)
{
format_result = snprintf(buffer2, sizeof(buffer2), "[%s] %s", local_log_tag, buffer1);
}
else
{
format_result = snprintf(buffer2, sizeof(buffer2), "%s", buffer1);
}
if (format_result > 0)
{
switch (log_level)
{
case EL_ERROR:
ANDROID_LOG(LOG_ERROR, global_log_tag, "%s", buffer2);
break;
case EL_WARNING:
ANDROID_LOG(LOG_WARN, global_log_tag, "%s", buffer2);
break;
case EL_INFO:
ANDROID_LOG(LOG_INFO, global_log_tag, "%s", buffer2);
break;
case EL_DEBUG:
ANDROID_LOG(LOG_DEBUG, global_log_tag, "%s", buffer2);
break;
case EL_VERBOSE:
ANDROID_LOG(LOG_VERBOSE, global_log_tag, "%s", buffer2);
break;
default:
ANDROID_LOG(LOG_ERROR, global_log_tag, "Internal error in log subsystem: unknown log level");
break;
}
}
else
{
ANDROID_LOG(LOG_ERROR, global_log_tag, "Internal error in log subsystem: format error");
}
}
#endif // #if defined (USE_ANDROID_LOGGING) || defined (__ANDROID__)
if (EO_STDOUT & local_output)
{
char time_string[40];
time_t now = time(NULL);
struct tm *curr_time = localtime(&now);
struct tm zero_time;
memset(&zero_time, 0, sizeof(zero_time));
if (nullptr == curr_time) {
curr_time = &zero_time;
}
// time format example: 11-11 11:06:02.725
strftime(time_string, sizeof(time_string)-1, "%m-%d %H:%M:%S.000", curr_time);
if (0 != local_log_tag)
{
format_result = snprintf(buffer2, sizeof(buffer2), "%s %s:[%s] %s",
time_string, global_log_tag, local_log_tag, buffer1);
}
else
{
format_result = snprintf(buffer2, sizeof(buffer2), "%s %s: %s",
time_string, global_log_tag, buffer1);
}
if (format_result > 0)
{
puts(buffer2);
}
else
{
puts("Internal error in log subsystem: format error");
}
}
}
}
int log_set_global_level(const ERROR_LEVEL level)
{
int result = 1;
do
{
BREAK_IF_ZERO(2, global_log_mutex);
AutoLock latch(global_log_mutex);
BREAK_IF_NON_ZERO(3, latch.ZeroIfLocked());
global_log_level = level;
result = 0;
} while (0);
if(0 != result)
{
log_error(private_log_tag, "log_set_global_level failed %d", result);
}
return result;
}
int log_set_global_tag(const char * const tag)
{
int result = 1;
do
{
BREAK_IF_ZERO(2, global_log_mutex);
AutoLock latch(global_log_mutex);
BREAK_IF_NON_ZERO(3, latch.ZeroIfLocked());
size_t copy_length = strlcpy(global_log_tag, tag, sizeof(global_log_tag));
if(copy_length >= sizeof(global_log_tag))
{
result = 4;
break;
}
result = 0;
} while (0);
if(0 != result)
{
log_error(private_log_tag, "log_set_global_tag failed %d", result);
}
return result;
}
int log_set_local_level_for_tag(const char *const tag, const ERROR_LEVEL level)
{
ERROR_OUTPUT output = DEFAULT_ERROR_OUTPUT;
return log_set_local_level_for_tag(tag, level, output);
}
int log_set_local_level_for_tag(const char * const tag, const ERROR_LEVEL level,
const ERROR_OUTPUT output)
{
int result = 1;
do
{
BREAK_IF_ZERO(2, tag);
BREAK_IF_ZERO(3, global_log_mutex);
BREAK_IF_ZERO(4, local_log_level_list);
AutoLock latch(global_log_mutex);
BREAK_IF_NON_ZERO(5, latch.ZeroIfLocked());
LocalLogLevelItem * const p_item = findLocalLevelItemLocked(tag);
if(0 != p_item)
{
p_item->setLevel(level);
p_item->setOutput(output);
}
else
{
LocalLogLevelItem item(tag);
item.setLevel(level);
item.setOutput(output);
BREAK_IF_ZERO(6, item.getTag());
BREAK_IF_NON_ZERO(7, local_log_level_list->add(item));
}
result = 0;
} while (0);
if(0 != result)
{
log_error(private_log_tag, "log_set_local_level_for_tag failed %d", result);
}
return result;
}
int log_flush_all_local_level()
{
return log_flush_local_level_for_tag(0);
}
int log_flush_local_level_for_tag(const char * const tag)
{
int result = 1;
do
{
BREAK_IF_ZERO(2, global_log_mutex);
BREAK_IF_ZERO(3, local_log_level_list)
AutoLock latch(global_log_mutex);
BREAK_IF_NON_ZERO(4, latch.ZeroIfLocked());
for (ListIterator<LocalLogLevelItem> it = local_log_level_list->begin(); it != local_log_level_list->end();)
{
if((0 == tag) || it->equals(tag))
{
it = local_log_level_list->erase(it);
}
else
{
++it;
}
}
result = 0;
} while (0);
if(0 != result)
{
log_error(private_log_tag, "log_flush_local_level_for_tag failed %d", result);
}
return result;
}
void log_error_no_lock(const char * const local_log_tag, const char * const format, ...)
{
// note there is NO AUTO LOCK for this function
// this function is designed to report WITHOUT any locks
va_list args;
va_start(args, format);
// don't lock the global mutex, for we are reporting a bug in threading code
vlog(local_log_tag, EL_ERROR, format, args);
va_end(args);
}
void log_error(const char * const local_log_tag, const char * const format, ...)
{
// ignore null checking for global_log_mutex. let it fail and continue
// there is something very wrong, but we still want to log message to be sent out
AutoLock latch(global_log_mutex);
va_list args;
va_start(args, format);
vlog(local_log_tag, EL_ERROR, format, args);
va_end(args);
}
void log_warning(const char * const local_log_tag, const char * const format, ...)
{
// ignore null checking for global_log_mutex. let it fail and continue
// there is something very wrong, but we still want to log message to be sent out
AutoLock latch(global_log_mutex);
va_list args;
va_start(args, format);
vlog(local_log_tag, EL_WARNING, format, args);
va_end(args);
}
void log_info(const char * const local_log_tag, const char * const format, ...)
{
// ignore null checking for global_log_mutex. let it fail and continue
// there is something very wrong, but we still want to log message to be sent out
AutoLock latch(global_log_mutex);
va_list args;
va_start(args, format);
vlog(local_log_tag, EL_INFO, format, args);
va_end(args);
}
void log_debug(const char * const local_log_tag, const char * const format, ...)
{
// ignore null checking for global_log_mutex. let it fail and continue
// there is something very wrong, but we still want to log message to be sent out
AutoLock latch(global_log_mutex);
va_list args;
va_start(args, format);
vlog(local_log_tag, EL_DEBUG, format, args);
va_end(args);
}
void log_verbose(const char * const local_log_tag, const char * const format, ...)
{
// ignore null checking for global_log_mutex. let it fail and continue
// there is something very wrong, but we still want to log message to be sent out
AutoLock latch(global_log_mutex);
va_list args;
va_start(args, format);
vlog(local_log_tag, EL_VERBOSE, format, args);
va_end(args);
}
} // namespace qc_loc_fw

View File

@@ -0,0 +1,366 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Memory stream
GENERAL DESCRIPTION
This component implements one input memory stream and one auto-expandable
output memory stream.
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#include <new>
#include <string.h>
#include <base_util/log.h>
#include <base_util/memorystream.h>
#define BREAK_IF_ZERO(ERR,X) if(0==(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO(ERR,X) if(0!=(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO_RC(ERR,RC,X) if(0!=(RC=(X))) {result = (ERR); break;}
namespace qc_loc_fw
{
static const char * const TAG = "MemoryStream";
MemoryStreamBase::~MemoryStreamBase()
{
// dummy destructor
}
OutMemoryStream::~OutMemoryStream()
{
// dummy destructor
}
InMemoryStream::~InMemoryStream()
{
// dummy destructor
}
class OutMemoryStreamImpl: public OutMemoryStream
{
public:
OutMemoryStreamImpl();
~OutMemoryStreamImpl();
size_t getSize() const
{
return getPutCursor();
}
BYTE * getBufferNonConst()
{
return m_pData;
}
const BYTE * getBuffer() const
{
return m_pData;
}
size_t getPutCursor() const
{
return m_put_cursor;
}
int append(const void * const pData, const size_t length);
void releaseBufferOwnership()
{
m_pData = 0;
m_put_cursor = 0;
m_capacity = 0;
}
private:
BYTE * m_pData;
size_t m_put_cursor;
size_t m_capacity;
static const size_t min_length = 64;
int expand(const size_t length);
};
OutMemoryStreamImpl::OutMemoryStreamImpl() :
m_pData(0), m_put_cursor(0), m_capacity(0)
{
}
OutMemoryStreamImpl::~OutMemoryStreamImpl()
{
if(0 != m_pData)
{
delete[] m_pData;
m_pData = 0;
}
m_put_cursor = 0;
m_capacity = 0;
}
int OutMemoryStreamImpl::expand(const size_t length)
{
int result = 1;
do
{
if(0 >= length)
{
result = 2;
break;
}
const size_t space_left = m_capacity - m_put_cursor;
if(length < space_left)
{
result = 0;
break;
}
size_t new_length = m_put_cursor + length;
if(new_length < min_length)
{
new_length = min_length;
}
else if(new_length < (m_capacity * 2))
{
new_length = m_capacity * 2;
}
BYTE * new_buffer = new (std::nothrow) BYTE[new_length];
if(0 == new_buffer)
{
result = 3;
break;
}
if(0 != m_pData)
{
memcpy(new_buffer, m_pData, m_put_cursor);
delete[] m_pData;
}
m_pData = new_buffer;
m_capacity = new_length;
// m_put_cursor is not changed
//log_verbose(TAG, "stream expanded to %u bytes, with length %u", (unsigned int)m_capacity, (unsigned int)m_put_cursor);
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "expand error %d", result);
}
return result;
}
int OutMemoryStreamImpl::append(const void * const pData, const size_t length)
{
int result = 1;
do
{
if(0 != expand(length))
{
result = 2;
break;
}
memcpy(m_pData + m_put_cursor, pData, length);
m_put_cursor += length;
//log_verbose(TAG, "current stream length %u", (unsigned int)m_put_cursor);
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "append error %d", result);
}
return result;
}
class InMemoryStreamImpl: public InMemoryStream
{
public:
InMemoryStreamImpl(OutMemoryStream * const os = 0);
~InMemoryStreamImpl();
size_t getSize() const
{
return getCapacity();
}
const BYTE * getBuffer() const
{
return m_pData;
}
int setBufferOwnership(const void ** const ppIn, const size_t length)
{
int result = 1;
do
{
BREAK_IF_ZERO(2, ppIn);
BREAK_IF_NON_ZERO(3, setBufferNoDup(*ppIn, length));
*ppIn = 0;
m_ownership = true;
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "setBufferOwnership failed %d", result);
}
return result;
}
int setBufferNoDup(const void * const pIn, const size_t length)
{
if(m_ownership)
{
delete[] m_pData;
m_ownership = false;
}
m_pData = reinterpret_cast<const BYTE*>(pIn);
m_capacity = length;
m_get_cursor = 0;
return 0;
}
int extract(void * const pData, const size_t length);
size_t getGetCursor() const
{
return m_get_cursor;
}
size_t getCapacity() const
{
return m_capacity;
}
int setGetCursor(const size_t cursor)
{
if(cursor <= m_capacity)
{
m_get_cursor = cursor;
return 0;
}
else
{
log_error(TAG, "setGetCursor range error");
return 1;
}
}
virtual InMemoryStream * clone() const;
private:
bool m_ownership;
const BYTE * m_pData;
size_t m_get_cursor;
size_t m_capacity;
};
InMemoryStreamImpl::InMemoryStreamImpl(OutMemoryStream * const os) :
m_ownership(false), m_pData(0), m_get_cursor(0), m_capacity(0)
{
if(os != 0)
{
m_ownership = true;
m_pData = os->getBuffer();
m_capacity = os->getSize();
static_cast<OutMemoryStreamImpl *>(os)->releaseBufferOwnership();
}
}
InMemoryStreamImpl::~InMemoryStreamImpl()
{
if(m_ownership)
{
delete[] m_pData;
}
m_pData = 0;
m_get_cursor = 0;
m_capacity = 0;
}
int InMemoryStreamImpl::extract(void * const pData, const size_t length)
{
int result = 1;
do
{
if(0 == length)
{
result = 3;
break;
}
if(0 == m_pData)
{
result = 4;
break;
}
const size_t data_left = m_capacity - m_get_cursor;
if(data_left < length)
{
result = 5;
break;
}
if(0 != pData)
{
memcpy(pData, m_pData + m_get_cursor, length);
}
m_get_cursor += length;
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "extract error %d", result);
}
return result;
}
OutMemoryStream * OutMemoryStream::createInstance()
{
return new (std::nothrow) OutMemoryStreamImpl();
}
InMemoryStream * InMemoryStream::createInstance()
{
return new (std::nothrow) InMemoryStreamImpl();
}
InMemoryStream * InMemoryStream::createInstance(OutMemoryStream * const os)
{
return new (std::nothrow) InMemoryStreamImpl(os);
}
InMemoryStream * InMemoryStreamImpl::clone() const
{
InMemoryStreamImpl *pNewIs = (InMemoryStreamImpl *)InMemoryStream::createInstance();
if (NULL != pNewIs) {
// do shallow copy first
*pNewIs = *this;
if (m_pData) {
pNewIs->m_pData = new BYTE[m_capacity];
if (pNewIs->m_pData) {
memcpy((void *)pNewIs->m_pData, (const void *)m_pData, m_capacity);
pNewIs->m_ownership = true;
} else {
delete pNewIs;
pNewIs = NULL;
}
}
}
return pNewIs;
}
} // namespace qc_loc_fw

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
String related routines
GENERAL DESCRIPTION
This component provides utilities used for string processing
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#include <string.h>
#include <base_util/log.h>
#ifndef IZAT_OFFLINE
#define HAS_STRLCPY 1
#endif // #ifndef IZAT_OFFLINE
#define BREAK_IF_ZERO(ERR,X) if(0==(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO(ERR,X) if(0!=(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO_RC(ERR,RC,X) if(0!=(RC=(X))) {result = (ERR); break;}
namespace qc_loc_fw
{
#if HAS_STRLCPY
#else // #if HAS_STRLCPY
size_t strlcpy(char *dest, const char *src, size_t dest_capacity)
{
// strlcpy is not available on standard linux glibc, so I have to
// implement this
// somehow Android has its own strlcpy
size_t src_length = strlen(src);
if(dest_capacity > 0)
{
size_t copy_length = 0;
if(src_length >= dest_capacity)
{
copy_length = dest_capacity - 1;
}
else
{
copy_length = src_length;
}
memcpy(dest, src, copy_length);
dest[copy_length] = '\0';
}
else
{
// weird error
src_length = 0;
}
return src_length;
}
size_t strlcat(char *dest, const char *src, size_t dest_capacity)
{
size_t dest_length = strlen(dest);
size_t src_length = strlen(src);
if (dest_capacity > 0)
{
size_t copy_length = 0;
if (dest_length + src_length >= dest_capacity)
{
copy_length = dest_capacity - dest_length - 1;
}
else
{
copy_length = src_length;
}
memcpy(dest + dest_length, src, copy_length);
dest_length += copy_length;
dest[dest_length] = '\0';
}
else
{
// weird error
dest_length = 0;
}
return dest_length;
}
#endif // #if HAS_STRLCPY
} // namespace qc_loc_fw

View File

@@ -0,0 +1,894 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Sync utilities
GENERAL DESCRIPTION
This component provides utilities used for synchronization among threads
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <new>
#include <base_util/queue.h>
#include <base_util/log.h>
#include <base_util/sync.h>
#define BREAK_IF_ZERO(ERR,X) if(0==(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO(ERR,X) if(0!=(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO_RC(ERR,RC,X) if(0!=(RC=(X))) {result = (ERR); break;}
namespace qc_loc_fw
{
// non-thread safe version, to be used only in threading related code
void log_error_no_lock(const char * const local_log_tag, const char * const format, ...);
static const char * const MUTEX_DEFAULT_TAG = "Mutex";
static const char * const AUTOLOCK_DEFAULT_TAG = "AutoLock";
static const char * const WAITABLE_BASE_DEFAULT_TAG = "WaitableBase";
static const char * const QUEUE_DEFAULT_TAG = "BlockingQueue";
static const char * const THREAD_DEFAULT_TAG = "AutoLock";
class MutexImpl: public Mutex
{
public:
MutexImpl(const char * const tag, const bool verboseLog);
virtual ~MutexImpl();
int lock();
int unlock();
pthread_mutex_t * getRawMutex()
{
return &m_mutex;
}
private:
// this variable is only set once, at creation
// after that, it can never change, for it is not protected by a mutex
const char * m_tag;
// this variable is only set once, at creation
// after that, it can never change, for it is not protected by a mutex
const bool m_flagEnableVerboseLog;
pthread_mutex_t m_mutex;
};
MutexImpl::MutexImpl(const char * const tag, const bool verboseLog) :
m_tag(tag),
m_flagEnableVerboseLog(verboseLog)
{
int result = 1;
pthread_mutexattr_t mutex_attr;
bool destroy_attr = false;
do
{
if(0 == m_tag)
{
m_tag = MUTEX_DEFAULT_TAG;
}
BREAK_IF_NON_ZERO(2, pthread_mutexattr_init(&mutex_attr));
destroy_attr = true;
BREAK_IF_NON_ZERO(3, pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK));
BREAK_IF_NON_ZERO(4, pthread_mutex_init(&m_mutex, &mutex_attr));
result = 0;
} while (0);
if (destroy_attr == true)
{
if (0 != pthread_mutexattr_destroy(&mutex_attr))
{
result = 5;
}
}
if(0 != result)
{
log_error_no_lock(m_tag, "MutexImpl: result: %d, error: %d, [%s]", result, errno, strerror(errno));
}
}
MutexImpl::~MutexImpl()
{
int rc = pthread_mutex_destroy(&m_mutex);
if(0 != rc)
{
log_error_no_lock(m_tag, "~MutexImpl: pthread_mutex_destroy rc: %d, [%s]", rc, strerror(rc));
}
}
int MutexImpl::lock()
{
if(m_flagEnableVerboseLog)
{
log_verbose(m_tag, "lock: about to lock");
}
int rc = pthread_mutex_lock(&m_mutex);
if(0 != rc)
{
log_error_no_lock(m_tag, "lock: pthread_mutex_lock return code: %d, [%s]", rc, strerror(rc));
return 1;
}
if(m_flagEnableVerboseLog)
{
log_verbose(m_tag, "lock: just acquired");
}
return 0;
}
int MutexImpl::unlock()
{
if(0 != pthread_mutex_unlock(&m_mutex))
{
log_error_no_lock(m_tag, "unlock: pthread_mutex_unlock error: %d, [%s]", errno, strerror(errno));
return 1;
}
if(m_flagEnableVerboseLog)
{
log_verbose(m_tag, "lock: just released");
}
return 0;
}
Mutex::~Mutex()
{
// dummy destructor
}
Mutex * Mutex::createInstance(const char * const tag, const bool verboseLog)
{
return new (std::nothrow) MutexImpl(tag, verboseLog);
}
AutoLock::AutoLock(Mutex * const pMutex, const char * log_tag) :
m_pMutex(pMutex),
m_tag(log_tag),
m_locked(false)
{
int result = 1;
do
{
if(0 == m_tag)
{
m_tag = AUTOLOCK_DEFAULT_TAG;
}
BREAK_IF_ZERO(2, m_pMutex);
BREAK_IF_NON_ZERO(3, m_pMutex->lock());
m_locked = true;
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "AutoLock: lock error: %d", result);
}
}
AutoLock::~AutoLock()
{
int result = 1;
do
{
BREAK_IF_ZERO(2, m_pMutex);
if (m_locked)
{
// Do not unlock the lock if we haven't acquired it.
BREAK_IF_NON_ZERO(3, m_pMutex->unlock());
}
m_locked = false;
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "AutoLock: unlock error: %d", result);
}
}
int AutoLock::ZeroIfLocked()
{
if(m_locked)
{
return 0;
}
return 1;
}
class WaitableBase
{
public:
virtual int lock_and_wait(const TimeDiff & timeout_diff);
virtual int unlock();
WaitableBase(const char * const name, const bool verboseLog);
virtual ~WaitableBase() = 0;
// the call flow for internal state modification should be
// 'lock' -> modify state -> 'signal_one_and_then_unlock'
virtual int lock();
virtual int signal_one_and_then_unlock();
virtual int signal_all_and_then_unlock();
// called by lock_and_wait to make sure we need to wait after
// locked but before the wait
virtual int ZeroIfShouldWaitAgain_locked() = 0;
private:
pthread_cond_t m_cond;
MutexImpl m_mutex;
const char * m_tag;
bool m_verboseLog;
};
WaitableBase::WaitableBase(const char * const name, const bool verboseLog) :
m_mutex(name, verboseLog),
m_tag(name),
m_verboseLog(verboseLog)
{
int result = 1;
pthread_condattr_t cond_attr;
bool destroy_cond = false;
do
{
if(0 == m_tag)
{
m_tag = WAITABLE_BASE_DEFAULT_TAG;
}
errno = 0;
BREAK_IF_NON_ZERO(2, pthread_condattr_init(&cond_attr));
destroy_cond = true;
BREAK_IF_NON_ZERO(3, pthread_condattr_setclock(&cond_attr, CLOCK_REALTIME));
BREAK_IF_NON_ZERO(4, pthread_cond_init(&m_cond, &cond_attr));
result = 0;
} while(0);
if (destroy_cond == true)
{
if (0 != pthread_condattr_destroy(&cond_attr))
{
result = 5;
}
}
if(0 != result)
{
log_error_no_lock(m_tag, "WaitableBase: pthread conditional variable error: %d, errno=%d, [%s]",
result, errno, strerror(errno));
}
}
WaitableBase::~WaitableBase()
{
if(0 != pthread_cond_destroy(&m_cond))
{
log_error_no_lock(m_tag, "~WaitableBase: pthread_cond_destroy error: %d, [%s]", errno, strerror(errno));
}
}
int WaitableBase::lock()
{
int result = 1;
do
{
if(m_verboseLog)
{
log_verbose(m_tag, "about to lock for state modification");
}
// if we're locked, we should not lock again
BREAK_IF_NON_ZERO(3, m_mutex.lock());
if(m_verboseLog)
{
log_verbose(m_tag, "just acquired lock for state modification");
}
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "lock : result %d", result);
}
return result;
}
int WaitableBase::unlock()
{
int result = 1;
do
{
// if we're not locked, we should not unlock again
if(m_verboseLog)
{
log_verbose(m_tag, "about to unlock");
}
BREAK_IF_NON_ZERO(3, m_mutex.unlock());
if(m_verboseLog)
{
log_verbose(m_tag, "unlocked");
}
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "unlock : result %d", result);
}
return result;
}
int WaitableBase::signal_one_and_then_unlock()
{
int result = 1;
do
{
// we should be already locked
if(m_verboseLog)
{
log_verbose(m_tag, "about to signal");
}
result = 100;
if(0 != pthread_cond_signal(&m_cond))
{
result = 101;
}
BREAK_IF_NON_ZERO(4, unlock());
if(100 != result)
{
break;
}
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "WaitableBase: signal_one_and_then_unlock result: %d, errno %d, [%s]", result, errno,
strerror(errno));
}
return result;
}
int WaitableBase::signal_all_and_then_unlock()
{
int result = 1;
do
{
// we should be already locked
if(m_verboseLog)
{
log_verbose(m_tag, "about to signal");
}
result = 100;
if(0 != pthread_cond_broadcast(&m_cond))
{
result = 101;
}
BREAK_IF_NON_ZERO(4, unlock());
if(100 != result)
{
break;
}
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "WaitableBase: signal_all_and_then_unlock result: %d, errno: %d, [%s]", result, errno,
strerror(errno));
}
return result;
}
int WaitableBase::lock_and_wait(const TimeDiff & timeout_diff)
{
int result = 1;
do
{
// we should not be already locked
if(m_verboseLog)
{
log_verbose(m_tag, "about to lock for wait");
}
BREAK_IF_NON_ZERO(2, m_mutex.lock());
bool flagTimeout = false;
result = 10;
// if this function returns non-zero, we return 0 immediately without waiting
while ((!flagTimeout) && (0 == ZeroIfShouldWaitAgain_locked()))
{
if(m_verboseLog)
{
log_verbose(m_tag, "about to wait");
}
int rc = 0;
if(!timeout_diff.is_valid())
{
// timeout is invalid, which means we are going to wait forever
rc = pthread_cond_wait(&m_cond, m_mutex.getRawMutex());
}
else
{
// same pthread_cond_timedwait, but now time should be absolute realtime time
const Timestamp now_realtime(CLOCK_REALTIME);
Timestamp timeout_realtime(now_realtime + timeout_diff);
if (!timeout_realtime.is_valid())
{
// this shall not happen
result = 12;
break;
}
if(timeout_diff.get_total_sec() > 0)
{
rc = pthread_cond_timedwait(&m_cond, m_mutex.getRawMutex(),
timeout_realtime.getTimestampPtr());
}
else
{
// removing the timeout parameter - essentially making value of zero
rc = pthread_cond_timedwait(&m_cond, m_mutex.getRawMutex(),
now_realtime.getTimestampPtr());
}
}
if(m_verboseLog)
{
log_verbose(m_tag, "just waken up from wait");
}
if(0 == rc)
{
// good
}
else if(ETIMEDOUT == rc)
{
// timeout_diff
flagTimeout = true;
}
else
{
// something is wrong
log_error_no_lock(m_tag, "lock_and_wait: pthread_cond_wait error: %d, [%s]", errno, strerror(errno));
result = 15;
}
if(10 != result)
{
break;
}
}
if(10 != result)
{
break;
}
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "WaitableBase: lock_and_wait error: %d", result);
}
return result;
}
BlockingQueue::~BlockingQueue()
{
// dummy destructor
}
class BlockingQueueImpl: public BlockingQueue, protected WaitableBase
{
public:
BlockingQueueImpl(const char * tag, const bool verboseLog);
~BlockingQueueImpl();
virtual int push(void * const ptr);
virtual int close();
virtual int pop(void ** const pptr, const timespec * const timeout_abs_realtime, bool * const p_is_queue_closed);
virtual int pop(void ** const pptr, const TimeDiff & timeout, bool * const p_is_queue_closed);
virtual int ZeroIfShouldWaitAgain_locked();
Queue<void *> m_queue;
const char * m_tag;
bool m_isClosed;
bool m_verboseLog;
};
BlockingQueueImpl::BlockingQueueImpl(const char * tag, const bool verboseLog) :
WaitableBase("BlockingQueue", verboseLog),
m_tag(tag),
m_isClosed(false),
m_verboseLog(verboseLog)
{
if(0 == m_tag)
{
m_tag = QUEUE_DEFAULT_TAG;
}
}
BlockingQueueImpl::~BlockingQueueImpl()
{
if(m_queue.getSize() > 0)
{
log_warning(m_tag, "~BlockingQueueImpl: memory leak");
}
}
int BlockingQueueImpl::ZeroIfShouldWaitAgain_locked()
{
if(m_isClosed)
{
return -1;
}
else
{
return m_queue.getSize();
}
}
int BlockingQueueImpl::push(void * const ptr)
{
int result = 1;
do
{
BREAK_IF_NON_ZERO(2, lock());
if(m_isClosed)
{
result = 3;
}
else
{
result = 100;
if(0 != m_queue.push(ptr))
{
// something is wrong, but we cannot leave just now
result = 101;
}
}
BREAK_IF_NON_ZERO(4, signal_one_and_then_unlock());
if(100 != result)
{
break;
}
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "push: error: %d", result);
}
return result;
}
int BlockingQueueImpl::close()
{
int result = 1;
do
{
BREAK_IF_NON_ZERO(2, lock());
m_isClosed = true;
// note we have to release ALL threads blocking on us
BREAK_IF_NON_ZERO(3, signal_all_and_then_unlock());
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "close: error: %d", result);
}
return result;
}
int BlockingQueueImpl::pop(void ** const pptr, const timespec * const timeout_abs_realtime, bool * const p_is_queue_closed)
{
int result = 1;
do
{
// warn the API user about deprecated feature
log_warning(m_tag, "pop 0: deprecated.");
BREAK_IF_ZERO(2, pptr);
*pptr = 0;
const Timestamp now_wallclock(CLOCK_REALTIME);
TimeDiff timeout_diff(false);
if(0 != timeout_abs_realtime)
{
const Timestamp timeout_wallclock(CLOCK_REALTIME, *timeout_abs_realtime);
if(timeout_wallclock >= now_wallclock)
{
timeout_diff = timeout_wallclock - now_wallclock;
}
else
{
// this is valid 0, which means we are not going to wait at all
timeout_diff.reset(true);
}
}
else
{
// timeout_diff is reset to invalid, which means we are going to wait forever
timeout_diff.reset(false);
}
BREAK_IF_NON_ZERO(10, pop(pptr, timeout_diff, p_is_queue_closed));
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "pop 0: error: %d", result);
}
return result;
}
int BlockingQueueImpl::pop(void ** const pptr, const TimeDiff & timeout, bool * const p_is_queue_closed)
{
int result = 1;
do
{
BREAK_IF_ZERO(2, pptr);
*pptr = 0;
if(0 != p_is_queue_closed)
{
*p_is_queue_closed = false;
}
BREAK_IF_NON_ZERO(4, lock_and_wait(timeout));
// note we're now locked, so it's okay to copy the members
if(0 != p_is_queue_closed)
{
*p_is_queue_closed = m_isClosed;
}
else
{
if(m_isClosed)
{
// warn to API user that he/she should provide p_is_queue_closed for us
// to notify this condition
log_warning(m_tag, "pop: queue is already closed");
}
else
{
// ignore
}
}
if(m_queue.getSize() > 0)
{
if(0 != m_queue.pop(pptr))
{
// something is wrong, but we cannot leave just now
result = 5;
}
}
else
{
// timeout or queue closed
}
BREAK_IF_NON_ZERO(5, unlock());
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "pop: error: %d", result);
}
return result;
}
BlockingQueue * BlockingQueue::createInstance(const char * tag, const bool verboseLog)
{
return new (std::nothrow) BlockingQueueImpl(tag, verboseLog);
}
Runnable::~Runnable()
{
// dummy destructor
}
Thread::~Thread()
{
// dummy destructor
}
class ThreadImpl: public Thread
{
public:
ThreadImpl(const char * tag, Runnable * const pRunnable, const bool delete_runnable_at_destruction);
virtual ~ThreadImpl();
virtual int launch();
virtual int join();
const char * m_tag;
Runnable * m_pRunnable;
pthread_t m_thread;
bool m_delete_runnable_at_destruction;
enum ThreadState
{
TS_NOT_CREATED_YET, TS_LAUNCHED_JOINABLE, TS_JOINED, TS_DETACHED,
};
ThreadState m_state;
static void * thread_func(void * ptr);
};
ThreadImpl::~ThreadImpl()
{
switch (m_state)
{
case TS_NOT_CREATED_YET:
case TS_JOINED:
case TS_DETACHED:
// we're okay to leave
if(m_delete_runnable_at_destruction)
{
delete m_pRunnable;
}
m_pRunnable = 0;
break;
default:
log_error_no_lock(m_tag, "~ThreadImpl: thread is probably still running");
break;
}
}
ThreadImpl::ThreadImpl(const char * tag, Runnable * const pRunnable, const bool delete_runnable_at_destruction) :
m_tag(tag),
m_pRunnable(pRunnable),
m_delete_runnable_at_destruction(delete_runnable_at_destruction),
m_state(TS_NOT_CREATED_YET)
{
// KlocWorks complains about m_thread not initialized
memset(&m_thread, 0, sizeof(m_thread));
int result = 1;
do
{
if(0 == m_tag)
{
m_tag = THREAD_DEFAULT_TAG;
}
BREAK_IF_ZERO(2, m_pRunnable);
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "ThreadImpl: result: %d", result);
}
}
int ThreadImpl::launch()
{
int result = 1;
pthread_attr_t thread_attr;
bool destroy_attr = false;
do
{
if(TS_NOT_CREATED_YET != m_state)
{
result = 2;
break;
}
BREAK_IF_NON_ZERO(3, pthread_attr_init(&thread_attr));
destroy_attr = true;
// this is actually the default setting
BREAK_IF_NON_ZERO(4, pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE));
BREAK_IF_NON_ZERO(5, pthread_create(&m_thread, &thread_attr, thread_func, this));
BREAK_IF_NON_ZERO(5, pthread_setname_np(m_thread, "loc-mq-thread"));
m_state = TS_LAUNCHED_JOINABLE;
result = 0;
} while (0);
if (destroy_attr == true)
{
if (0 != pthread_attr_destroy(&thread_attr))
{
result = 5;
}
}
if(0 != result)
{
log_error_no_lock(m_tag, "launch: result: %d, errno: %d, [%s]", result, errno, strerror(errno));
}
return result;
}
int ThreadImpl::join()
{
int result = 1;
do
{
if(TS_LAUNCHED_JOINABLE != m_state)
{
result = 2;
break;
}
// thread must have been created
// thread must be joinable, not detached, for this to work
void * ptr = 0;
BREAK_IF_NON_ZERO(3, pthread_join(m_thread, &ptr));
m_state = TS_JOINED;
result = 0;
} while (0);
if(0 != result)
{
log_error_no_lock(m_tag, "join: result: %d, errno: %d, [%s]", result, errno, strerror(errno));
}
return result;
}
void * ThreadImpl::thread_func(void * ptr)
{
ThreadImpl * obj = reinterpret_cast<ThreadImpl *>(ptr);
obj->m_pRunnable->run();
return 0;
}
Thread * Thread::createInstance(const char * tag, Runnable * const pRunnable, const bool delete_runnable_at_destruction)
{
return new (std::nothrow) ThreadImpl(tag, pRunnable, delete_runnable_at_destruction);
}
} // namespace qc_loc_fw

View File

@@ -0,0 +1,696 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Time related routines
GENERAL DESCRIPTION
This component provides utilities used for timestamp and time
difference processing
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#include <time.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/time.h>
#include <base_util/time_routines.h>
#include <base_util/log.h>
#define BREAK_IF_ZERO(ERR,X) if(0==(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO(ERR,X) if(0!=(X)) {result = (ERR); break;}
#define BREAK_IF_NON_ZERO_RC(ERR,RC,X) if(0!=(RC=(X))) {result = (ERR); break;}
#ifdef CLOCK_BOOTTIME
#define ENABLED_BOOTTIME_SUPPORT 1
#else
#define ENABLED_BOOTTIME_SUPPORT 0
#endif
#define TIME_RTC_MS_AS_OF_12_1_2014 (1417569370000)
const int NANO_PER_SEC = 1000000000;
namespace qc_loc_fw
{
const char * const TimeDiff::TAG = "TimerDiff";
const char * const Timestamp::TAG = "Timestamp";
TimeDiff::TimeDiff(const bool validity)
{
reset(validity);
}
void TimeDiff::reset(const bool validity)
{
m_is_valid = validity;
memset(&m_timediff, 0, sizeof(m_timediff));
}
bool TimeDiff::is_valid() const
{
return m_is_valid;
}
const timespec * TimeDiff::getTimeDiffPtr() const
{
if(!m_is_valid)
{
log_warning(TAG, "getTimeDiffPtr time diff is invalid");
}
return &m_timediff;
}
float TimeDiff::get_total_sec() const
{
float conv = -1;
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
break;
}
conv = m_timediff.tv_nsec / 1e9;
conv += m_timediff.tv_sec;
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "get_total_sec failed %d", result);
}
return conv;
}
float TimeDiff::get_total_msec() const
{
float conv = -1;
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
break;
}
conv = m_timediff.tv_nsec / 1e6f;
conv += (m_timediff.tv_sec) * 1000.0f;
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "get_total_msec failed %d", result);
}
return conv;
}
int TimeDiff::add_sec(const int sec)
{
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
break;
}
m_timediff.tv_sec += sec;
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "add_sec failed %d", result);
}
return result;
}
int TimeDiff::add_msec(const int msec)
{
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
break;
}
int sec = msec / 1000;
long long int msec_modified = msec - sec * 1000;
m_timediff.tv_nsec += msec_modified * 1000000;
while (m_timediff.tv_nsec >= NANO_PER_SEC)
{
++sec;
m_timediff.tv_nsec -= NANO_PER_SEC;
}
m_timediff.tv_sec += sec;
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "add_msec failed %d", result);
}
return result;
}
int TimeDiff::add_nsec(const int nsec)
{
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
break;
}
m_timediff.tv_nsec += nsec;
while (m_timediff.tv_nsec >= NANO_PER_SEC)
{
++m_timediff.tv_sec;
m_timediff.tv_nsec -= NANO_PER_SEC;
}
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "add_nsec failed %d", result);
}
return result;
}
Timestamp::Timestamp(bool set_to_default_clock)
{
invalidate();
if(set_to_default_clock)
{
(void) reset_to_default_clock();
}
}
Timestamp::Timestamp(const int clock_id, const timespec & src)
{
m_is_valid = true;
m_clock_id = clock_id;
memcpy(&m_timestamp, &src, sizeof(m_timestamp));
}
Timestamp::Timestamp(const Timestamp & rhs)
{
*this = rhs;
}
Timestamp::Timestamp(const int clock_id)
{
reset_to_clock_id(clock_id);
}
int Timestamp::get_clock_id() const
{
return m_clock_id;
}
bool Timestamp::is_valid() const
{
return m_is_valid;
}
bool Timestamp::is_valid_and_default() const
{
bool result = false;
if(is_valid())
{
#if ENABLED_BOOTTIME_SUPPORT
const int default_clock_id = CLOCK_BOOTTIME;
#else
const int default_clock_id = CLOCK_MONOTONIC;
#endif //#if ENABLED_BOOTTIME_SUPPORT
if(default_clock_id == m_clock_id)
{
result = true;
}
}
return result;
}
void Timestamp::invalidate()
{
m_is_valid = false;
m_clock_id = -1;
memset(&m_timestamp, 0, sizeof(m_timestamp));
}
timespec * Timestamp::getTimestampPtr()
{
const timespec * const ptr = static_cast<const Timestamp *>(this)->getTimestampPtr();
return const_cast<timespec *>(ptr);
}
const timespec * Timestamp::getTimestampPtr() const
{
if(!m_is_valid)
{
log_warning(TAG, "getTimestampPtr timestamp is invalid");
}
return &m_timestamp;
}
int Timestamp::reset_to_default_clock()
{
#if ENABLED_BOOTTIME_SUPPORT
return reset_to_boottime();
#else
return reset_to_monotonic();
#endif
}
int Timestamp::reset_to_monotonic()
{
return reset_to_clock_id(CLOCK_MONOTONIC);
}
int Timestamp::reset_to_boottime()
{
#if ENABLED_BOOTTIME_SUPPORT
return reset_to_clock_id(CLOCK_BOOTTIME);
#else
invalidate();
log_error(TAG, "reset_to_boottime not supported");
return 2;
#endif
}
int Timestamp::reset_to_realtime()
{
return reset_to_clock_id(CLOCK_REALTIME);
}
int Timestamp::reset_to_clock_id(const int clock_id)
{
invalidate();
if(0 == clock_gettime(clock_id, &m_timestamp))
{
m_clock_id = clock_id;
m_is_valid = true;
return 0;
}
log_error(TAG, "reset_to_clock_id failed: id(%d) errno(%d)(%s)", clock_id, errno, strerror(errno));
return 1;
}
Timestamp Timestamp::operator -(const TimeDiff & rhs) const
{
Timestamp past(false);
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
exit(-1);
}
if(!rhs.is_valid())
{
result = 3;
exit(-1);
}
const timespec * rhs_ptr = rhs.getTimeDiffPtr();
past.m_timestamp.tv_sec = m_timestamp.tv_sec - rhs_ptr->tv_sec;
past.m_timestamp.tv_nsec = m_timestamp.tv_nsec - rhs_ptr->tv_nsec;
while (past.m_timestamp.tv_nsec < 0)
{
--past.m_timestamp.tv_sec;
past.m_timestamp.tv_nsec += NANO_PER_SEC;
}
while (past.m_timestamp.tv_nsec >= NANO_PER_SEC)
{
++past.m_timestamp.tv_sec;
past.m_timestamp.tv_nsec -= NANO_PER_SEC;
}
if(past.m_timestamp.tv_sec < 0)
{
log_error(TAG, "diff is returning -ve value possible time rollover %d", past.m_timestamp.tv_sec);
}
past.m_is_valid = true;
past.m_clock_id = m_clock_id;
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "operator - diff failed %d", result);
}
return past;
}
Timestamp Timestamp::operator +(const TimeDiff & rhs) const
{
Timestamp sum(false);
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
exit(-1);
}
if(!rhs.is_valid())
{
result = 3;
exit(-1);
}
const timespec * rhs_ptr = rhs.getTimeDiffPtr();
sum.m_timestamp.tv_sec = m_timestamp.tv_sec + rhs_ptr->tv_sec;
sum.m_timestamp.tv_nsec = m_timestamp.tv_nsec + rhs_ptr->tv_nsec;
while (sum.m_timestamp.tv_nsec >= NANO_PER_SEC)
{
++sum.m_timestamp.tv_sec;
sum.m_timestamp.tv_nsec -= NANO_PER_SEC;
}
sum.m_is_valid = true;
sum.m_clock_id = m_clock_id;
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "operator + failed %d", result);
}
return sum;
}
TimeDiff Timestamp::operator -(const Timestamp & rhs) const
{
// reset to invalid
TimeDiff delta(false);
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
exit(-1);
}
if(!rhs.is_valid())
{
result = 3;
exit(-1);
}
if(m_clock_id != rhs.m_clock_id)
{
// must be the same clock !
result = 4;
log_error(TAG, "operator - ts: my clock id: %d, his clock id: %d", m_clock_id, rhs.m_clock_id);
exit(-1);
}
struct timespec time_delta = {};
time_delta.tv_sec = m_timestamp.tv_sec - rhs.m_timestamp.tv_sec;
time_delta.tv_nsec = m_timestamp.tv_nsec - rhs.m_timestamp.tv_nsec;
while (time_delta.tv_nsec < 0)
{
--time_delta.tv_sec;
time_delta.tv_nsec += NANO_PER_SEC;
}
while (time_delta.tv_nsec >= NANO_PER_SEC)
{
++time_delta.tv_sec;
time_delta.tv_nsec -= NANO_PER_SEC;
}
if(time_delta.tv_sec < 0)
{
log_error(TAG, "operator - ts returning -ve value probable time rollover: sec:%d/%d/%d, nsec:%d/%d/%d", (int) m_timestamp.tv_sec,
(int) rhs.m_timestamp.tv_sec, (int) time_delta.tv_sec, (int) m_timestamp.tv_nsec,
(int) rhs.m_timestamp.tv_nsec, (int) time_delta.tv_nsec);
}
// set the diff to valid now
delta.reset(true);
BREAK_IF_NON_ZERO(10, delta.add_sec(time_delta.tv_sec));
BREAK_IF_NON_ZERO(11, delta.add_nsec(time_delta.tv_nsec));
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "operator - ts failed %d", result);
}
return delta;
}
bool Timestamp::operator >=(const Timestamp & rhs) const
{
bool is_greater_then = false;
int result = 1;
do
{
if(!m_is_valid)
{
result = 2;
exit(-1);
}
if(!rhs.is_valid())
{
result = 3;
exit(-1);
}
if(m_clock_id != rhs.m_clock_id)
{
// must be the same clock !
result = 4;
log_error(TAG, "operator >=: my clock id: %d, his clock id: %d", m_clock_id, rhs.m_clock_id);
exit(-1);
}
struct timespec time_delta = {};
time_delta.tv_sec = m_timestamp.tv_sec - rhs.m_timestamp.tv_sec;
time_delta.tv_nsec = m_timestamp.tv_nsec - rhs.m_timestamp.tv_nsec;
while (time_delta.tv_nsec < 0)
{
--time_delta.tv_sec;
time_delta.tv_nsec += NANO_PER_SEC;
}
while (time_delta.tv_nsec >= NANO_PER_SEC)
{
++time_delta.tv_sec;
time_delta.tv_nsec -= NANO_PER_SEC;
}
if(time_delta.tv_sec < 0)
{
is_greater_then = false;
}
else
{
is_greater_then = true;
}
result = 0;
} while (0);
if(0 != result)
{
log_error(TAG, "operator >= failed %d", result);
}
return is_greater_then;
}
bool Timestamp::operator <(const Timestamp & rhs) const
{
return !operator >=(rhs);
}
Timestamp & Timestamp::operator =(const Timestamp & rhs)
{
m_is_valid = rhs.m_is_valid;
m_clock_id = rhs.m_clock_id;
m_timestamp = rhs.m_timestamp;
return *this;
}
int Timestamp::insert_into_postcard(OutPostcard * const dest_card, const char * const name_str)
{
OutPostcard * nest_card = 0;
int result = 1;
do
{
BREAK_IF_ZERO(2, name_str);
nest_card = OutPostcard::createInstance();
BREAK_IF_ZERO(3, nest_card);
if(!m_is_valid)
{
result = 4;
break;
}
BREAK_IF_NON_ZERO(10, nest_card->init());
// note that CLOCK_ID is system-specific. For example, you cannot find clock id concept in Java
// on Android, there is SystemClock.elapsedRealtimeNanos which seemingly returns CLOCK_BOOTTIME,
// but that is not really documented, so clock id becomes undefined in Java world anywhere
// so, timestamp doesn't really work if your message has any chance of being interpreted from
// the Java world (of Android)
BREAK_IF_NON_ZERO(11, nest_card->addInt32("CLOCK_ID", m_clock_id));
BREAK_IF_NON_ZERO(12, nest_card->addInt32("TS_SEC", (OutPostcard::INT32 )m_timestamp.tv_sec));
BREAK_IF_NON_ZERO(13, nest_card->addInt32("TS_NSEC", (OutPostcard::INT32 )m_timestamp.tv_nsec));
BREAK_IF_NON_ZERO(14, nest_card->finalize());
BREAK_IF_NON_ZERO(20, dest_card->addCard(name_str, nest_card));
result = 0;
} while (0);
delete nest_card;
nest_card = 0;
if(0 != result)
{
log_error(TAG, "insert_into_postcard failed %d", result);
}
return result;
}
int Timestamp::retrieve_from_postcard(InPostcard * const src_card, const char * const name_str)
{
InPostcard * nest_card = 0;
int result = 1;
do
{
invalidate();
BREAK_IF_ZERO(2, name_str);
BREAK_IF_ZERO(3, src_card);
BREAK_IF_NON_ZERO(10, src_card->getCard(name_str, &nest_card));
BREAK_IF_NON_ZERO(10, nest_card->getInt32("CLOCK_ID", m_clock_id));
int ts_sec = 0;
BREAK_IF_NON_ZERO(11, nest_card->getInt32("TS_SEC", ts_sec));
m_timestamp.tv_sec = ts_sec;
int ts_nsec = 0;
BREAK_IF_NON_ZERO(12, nest_card->getInt32("TS_NSEC", ts_nsec));
m_timestamp.tv_nsec = ts_nsec;
m_is_valid = true;
result = 0;
} while (0);
delete nest_card;
nest_card = 0;
if(0 != result)
{
log_error(TAG, "retrieve_from_postcard failed %d", result);
}
return result;
}
long long get_time_rtc_ms()
{
struct timeval present_time;
long long current_time_msec;
// present time: seconds, and microseconds
gettimeofday(&present_time, NULL);
// Calculate absolute expire time (to avoid data overflow)
current_time_msec = present_time.tv_sec;
current_time_msec *= 1000; // convert to milli-seconds
current_time_msec += (present_time.tv_usec + 500) / 1000;
return current_time_msec;
}
// Returns monotonic time
long long get_time_monotonic_ms()
{
#ifndef IZAT_OFFLINE
uint64_t current_time_msec = 0;
struct timespec tp = {};
clock_gettime(CLOCK_MONOTONIC, &tp);
current_time_msec = tp.tv_sec;
current_time_msec *= 1000; // convert to milli-seconds
current_time_msec += ((tp.tv_nsec + 500000) / 1000000);
return current_time_msec;
#else
return get_time_rtc_ms();
#endif
}
// Check if rtc time is valid or not
bool is_time_rtc_ms_valid(long long rtc_time_ms)
{
bool is_valid = false;
// Only if the timestamp is big enough, we consider it as valid
if (rtc_time_ms > TIME_RTC_MS_AS_OF_12_1_2014)
{
is_valid = true;
}
return is_valid;
}
// Returns monotonic time
long long get_time_boot_ms()
{
#ifdef CLOCK_BOOTTIME
uint64_t current_time_msec = 0;
struct timespec tp = {};
clock_gettime(CLOCK_BOOTTIME, &tp);
current_time_msec = tp.tv_sec;
current_time_msec *= 1000; // convert to milli-seconds
current_time_msec += ((tp.tv_nsec + 500000) / 1000000);
return current_time_msec;
#else
return get_time_rtc_ms();
#endif
}
} // namespace qc_loc_fw

View File

@@ -0,0 +1,29 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
String related routines
GENERAL DESCRIPTION
This component implements portable string related routines
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __QC_LOC_FW_STRING_H__
#define __QC_LOC_FW_STRING_H__
#include <base_util/log.h>
namespace qc_loc_fw
{
#ifdef IZAT_OFFLINE
// Android has its own strlcpy
size_t strlcpy(char *dest, const char *src, size_t dest_capacity);
// Android has its own strlcat
size_t strlcat(char *dest, const char *src, size_t dest_capacity);
#endif // #ifdef IZAT_OFFLINE
} // namespace qc_loc_fw
#endif //#ifndef __QC_LOC_FW_STRING_H__

View File

@@ -0,0 +1,87 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Sync utilities
GENERAL DESCRIPTION
This header declares utilities used for thread synchronization
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_SYNC_H__
#define __XTRAT_WIFI_SYNC_H__
#include <time.h>
#include <base_util/time_routines.h>
namespace qc_loc_fw
{
class Mutex
{
public:
virtual ~Mutex() = 0;
// name is only shallow copied (only the pointer is copied), so use constant string as the name!
static Mutex * createInstance(const char * const tag = 0, const bool verboseLog = false);
virtual int lock() = 0;
virtual int unlock() = 0;
};
class AutoLock
{
private:
Mutex * m_pMutex;
const char * m_tag;
bool m_locked;
public:
AutoLock(Mutex * const pMutex, const char * log_tag = 0);
~AutoLock();
int ZeroIfLocked();
};
class BlockingQueue
{
public:
virtual ~BlockingQueue() = 0;
static BlockingQueue * createInstance(const char * tag, const bool verboseLog = false);
virtual int push(void * const ptr) = 0;
virtual int close() = 0;
// deprecated, as realtime/wall clock is not a good design choice
// note the change in signature, that you have to explicitly specify timeout pointer to use this version
// if you don't, you'll be using the new version with TimeDiff(false)
virtual int pop(void ** const pptr, const timespec * const timeout_abs_realtime, bool * const p_is_queue_closed = 0) = 0;
// pass in TimeDiff(true) if you do not want to wait, which is valid time difference of 0
// pass in TimeDiff(false) if you want to wait forever, which is invalid time difference
// pass in some valid TimeDiff and we are going to wait for it
virtual int pop(void ** const pptr, const TimeDiff & timeout = TimeDiff(false), bool * const p_is_queue_closed = 0) = 0;
};
class Runnable
{
public:
// expect Runnable to be deleted within Thread, and other places
virtual ~Runnable() = 0;
virtual void run() = 0;
};
class Thread
{
public:
virtual ~Thread() = 0;
static Thread * createInstance(const char * tag, Runnable * const pRunnable, const bool delete_runnable_at_destruction = true);
// call 'launch' to start execution of this thread
virtual int launch() = 0;
// wait for it to complete
virtual int join() = 0;
};
} // namespace qc_loc_fw
#endif //#ifndef __XTRAT_WIFI_SYNC_H__

View File

@@ -0,0 +1,127 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Time related routines
GENERAL DESCRIPTION
This component implements portable time related routines
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __QC_LOC_FW_TIME_H__
#define __QC_LOC_FW_TIME_H__
#include <time.h>
#include <base_util/postcard.h>
namespace qc_loc_fw
{
class TimeDiff
{
public:
// validity: false to prevent any further operation unless it's reset with true
// or being copied/assigned with = to a valid object
explicit TimeDiff (const bool validity = true);
int add_sec(const int sec);
int add_msec(const int msec);
int add_nsec(const int nsec);
float get_total_sec() const;
float get_total_msec() const;
const timespec * getTimeDiffPtr() const;
bool is_valid() const;
void reset(const bool validity = false);
private:
static const char * const TAG;
bool m_is_valid;
timespec m_timediff;
};
class Timestamp
{
public:
// set to false if you want to use reset_to_XXX functions to initialize it to
// non-default clock, or you simply want to set it later, instead of at time of construction
explicit Timestamp (const bool set_to_default_clock = true);
// use this if you want to set it to some specific clock type using clock id (defined in time.h)
explicit Timestamp (const int clock_id);
// use this if you want to initialize it with pre-existing timespec acquired using some clock type
Timestamp (const int clock_id, const timespec & src);
// copy constructor
Timestamp (const Timestamp & rhs);
timespec * getTimestampPtr();
const timespec * getTimestampPtr() const;
// use this one for most cases, which uses BOOTTIME if available, otherwise MONOTONIC
int reset_to_default_clock();
// CLOCK_MONOTONIC, this might be subjected to NTP clock modulation, and might stop counting
// when the device is sleeping
int reset_to_monotonic();
// CLOCK_BOOTTIME, same as CLOCK_MONOTONIC, but should count sleeping time as well
// currently not supported
int reset_to_boottime();
// CLOCK_REALTIME. wall clock, subject to system time change. normally you don't want this
// if you're looking for timers
int reset_to_realtime();
int reset_to_clock_id(const int clock_id);
int get_clock_id() const;
bool is_valid() const;
bool is_valid_and_default() const;
void invalidate();
Timestamp operator + (const TimeDiff & rhs) const;
Timestamp operator - (const TimeDiff & rhs) const;
TimeDiff operator - (const Timestamp & rhs) const;
bool operator >= (const Timestamp & rhs) const;
bool operator < (const Timestamp & rhs) const;
Timestamp & operator = (const Timestamp & rhs);
// timestamp is highly system-specific and doesn't translate into Java world well
// so, please use these functions with caution
int insert_into_postcard(OutPostcard * const dest_card, const char * const name_str);
int retrieve_from_postcard(InPostcard * const src_card, const char * const name_str);
private:
static const char * const TAG;
bool m_is_valid;
int m_clock_id;
timespec m_timestamp;
};
#ifdef __cplusplus
extern "C"
{
#endif
// Function Name: get_time_rtc_ms
// Description: return rtc time in milliseconds
// represents time since the Epoch
long long get_time_rtc_ms();
// Function Name: is_time_rtc_ms_valid
// Description: Check if rtc time is valid or not
bool is_time_rtc_ms_valid(long long rtc_time_ms);
// Function Name: get_time_boot_ms
// Description: Returns monotonic time from boot
long long get_time_boot_ms();
// Function Name: get_time_monotonic_ms
// Description: Returns monotonic time
long long get_time_monotonic_ms();
#ifdef __cplusplus
}
#endif
} // namespace qc_loc_fw
#endif //#ifndef __QC_LOC_FW_TIME_H__

View File

@@ -0,0 +1,221 @@
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
Vector template
GENERAL DESCRIPTION
This component implements a vector of any type
Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
=============================================================================*/
#ifndef __XTRAT_WIFI_VECTOR_H__
#define __XTRAT_WIFI_VECTOR_H__
#include <base_util/log.h>
namespace qc_loc_fw
{
template<typename T>
class vector
{
private:
static const char * const TAG;
static const int DEFAULT_CAPACITY = 64;
public:
typedef T * Iterator;
vector() :
m_pArray(0), m_capacity(0), m_num_elements(0)
{
}
vector(const vector<T> & rhs) :
m_pArray(0), m_capacity(0), m_num_elements(0)
{
(void) operator =(rhs);
}
virtual ~vector()
{
flush();
}
void flush()
{
if(0 != m_pArray)
{
delete[] m_pArray;
m_pArray = 0;
}
m_capacity = 0;
m_num_elements = 0;
}
int push_back(const T & element)
{
int result = 0;
// Check if the Array has been allocated already.
if (0 == m_pArray)
{
// Inserting an element where as the Array is not yet allocated
// Allocate the array to default size
m_capacity = DEFAULT_CAPACITY;
m_pArray = new (std::nothrow) T[m_capacity];
if (0 == m_pArray)
{
result = -1;
}
}
else
{
// Memory is already allocated. Check if the Array is running on boundary
if (m_capacity == m_num_elements)
{
// We do not have space for more elements
// Double the size and copy over the elements in new array
unsigned int new_size = 2 * m_capacity;
T* pNewArray = new (std::nothrow) T[new_size];
if (0 != pNewArray)
{
for (unsigned int i = 0; i < m_capacity; ++i)
{
pNewArray[i] = m_pArray[i];
}
m_capacity = new_size;
delete [] m_pArray;
m_pArray = pNewArray;
}
else
{
result = -2;
}
}
}
if (0 == result)
{
// Store the new element
m_pArray [m_num_elements] = element;
++m_num_elements;
}
else
{
log_error(TAG, "insertion failed %d", result);
}
return result;
}
T & operator [](const unsigned int index)
{
if(index < m_num_elements)
{
return m_pArray[index];
}
else
{
log_error(TAG, "index out of range\n");
// could be null reference, but we're doomed anyway
return m_pArray[0];
}
}
const T & operator [](const unsigned int index) const
{
if(index < m_num_elements)
{
return m_pArray[index];
}
else
{
log_error(TAG, "index out of range\n");
// could be null reference, but we're doomed anyway
return m_pArray[0];
}
}
unsigned int getNumOfElements() const
{
return m_num_elements;
}
unsigned int getCapacity() const
{
return m_capacity;
}
const vector<T> & operator =(const vector<T> & rhs)
{
int result = 1;
if(&rhs == this)
{
// do nothing for self-assignment
return *this;
}
flush();
int new_size = rhs.getCapacity();
if(new_size > 0)
{
int elements = rhs.getNumOfElements();
T * pNewArray = new (std::nothrow) T[new_size];
if(0 != pNewArray)
{
for (int i = 0; i < elements; ++i)
{
pNewArray[i] = rhs.m_pArray[i];
}
m_capacity = new_size;
m_num_elements = elements;
if(0 != m_pArray)
{
delete[] m_pArray;
}
m_pArray = pNewArray;
result = 0;
}
else
{
result = 2;
}
}
else
{
// do nothing. it's okay to insert empty array into an array
result = 0;
}
if(0 != result)
{
log_error(TAG, "assignment failed %d", result);
}
return *this;
}
Iterator begin()
{
return Iterator(m_pArray);
}
Iterator end()
{
return Iterator(m_pArray + m_num_elements);
}
private:
T * m_pArray;
unsigned int m_capacity;
unsigned int m_num_elements;
};
template<typename T>
const char * const vector<T>::TAG = "vector";
} // namespace qc_loc_fw
#endif //#ifndef __XTRAT_WIFI_VECTOR_H__

View File

@@ -0,0 +1,37 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libloc_socket
LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib
LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils \
liblog \
libgps.utils
LOCAL_SRC_FILES := \
LocSocket.cpp
LOCAL_CFLAGS := \
-fno-short-enums \
-D_ANDROID_
LOCAL_HEADER_LIBRARIES := \
libqmi_common_headers \
libloc_core_headers \
libgps.utils_headers \
libloc_pla_headers \
liblocation_api_headers
LOCAL_CFLAGS += $(GNSS_CFLAGS)
ifeq ($(TARGET_KERNEL_VERSION),$(filter $(TARGET_KERNEL_VERSION),3.18 4.4 4.9))
LOCAL_CFLAGS += -DUSE_QSOCKET
LOCAL_HEADER_LIBRARIES += libqsocket_headers
LOCAL_SHARED_LIBRARIES += libqsocket
endif
include $(BUILD_SHARED_LIBRARY)

View File

@@ -0,0 +1,456 @@
/* Copyright (c) 2019 - 2021 The Linux Foundation. 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.
* * Neither the name of The Linux Foundation, nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the
disclaimer below) 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.
* Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
GRANTED BY THIS LICENSE. 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.
*/
#include <unistd.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#ifdef USE_QSOCKET
#include <sys/ioctl.h>
#include <poll.h>
#include <qsocket.h>
#include <qsocket_ipcr.h>
#else
#include <endian.h>
#include <linux/qrtr.h>
#endif
#include <log_util.h>
#include <LocIpc.h>
namespace loc_util {
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "LocSvc_Qrtr"
class ServiceInfo {
const int32_t mServiceId;
const int32_t mInstanceId;
const string mName;
public:
inline ServiceInfo(int32_t service, int32_t instance) :
mServiceId(service), mInstanceId(instance),
mName(to_string(service) + ":" + to_string(instance)) {}
inline const char* getName() const { return mName.data(); }
inline int32_t getServiceId() const { return mServiceId; }
inline int32_t getInstanceId() const { return mInstanceId; }
};
#ifdef USE_QSOCKET
class LocIpcQsockSender : public LocIpcSender {
protected:
shared_ptr<Sock> mSock;
const ServiceInfo mServiceInfo;
qsockaddr_ipcr mAddr;
mutable bool mLookupPending;
inline virtual bool isOperable() const override {
return mSock != nullptr && mSock->mSid != -1;
}
inline void serviceLookup() const {
if (mLookupPending && mSock->isValid()) {
ipcr_name_t ipcrName = {
.service = (uint32_t)mServiceInfo.getServiceId(),
.instance = (uint32_t)mServiceInfo.getInstanceId()
};
uint32_t numEntries = 1;
int rc = ipcr_find_name(mSock->mSid, &ipcrName,
(struct qsockaddr_ipcr*)&mAddr, NULL, &numEntries, 0);
LOC_LOGd("serviceLookup, rc = %d, numEntries = %d\n", rc, numEntries);
if (rc < 0 || 1 != numEntries) {
mSock->close();
}
mLookupPending = false;
}
}
inline virtual ssize_t send(const uint8_t data[], uint32_t length,
int32_t /* msgId */) const override {
serviceLookup();
return mSock->send(data, length, 0, (struct sockaddr*)&mAddr,
sizeof(mAddr));
}
public:
inline LocIpcQsockSender(const qsockaddr_ipcr& destAddr) :
LocIpcSender(),
mSock(make_shared<Sock>(::socket(AF_IPC_ROUTER, SOCK_DGRAM, 0))),
mServiceInfo(0, 0), mAddr(destAddr), mLookupPending(false) {
}
inline LocIpcQsockSender(int service, int instance) :
LocIpcSender(),
mSock(make_shared<Sock>(::socket(AF_IPC_ROUTER, SOCK_DGRAM, 0))),
mServiceInfo(service, instance), mAddr({}), mLookupPending(true) {
}
unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) override {
return make_unique<SockRecver>(listener, *this, mSock);
}
};
class LocIpcQsockRecver : public LocIpcQsockSender, public LocIpcRecver {
protected:
inline virtual ssize_t recv() const override {
socklen_t size = sizeof(mAddr);
return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size);
}
public:
inline LocIpcQsockRecver(const shared_ptr<ILocIpcListener>& listener,
int service, int instance) :
LocIpcQsockSender(service, instance),
LocIpcRecver(listener, *this) {
qsockaddr_ipcr addr = {
AF_IPC_ROUTER,
{
IPCR_ADDR_NAME,
{
(uint32_t)service,
(uint32_t)instance
}
},
0
};
if (mSock->isValid() &&
::bind(mSock->mSid, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
LOC_LOGe("bind socket error. sock fd: %d,reason: %s",
mSock->mSid, strerror(errno));
mSock->close();
}
}
inline virtual unique_ptr<LocIpcSender> getLastSender() const override {
return make_unique<LocIpcQsockSender>(mAddr);
}
inline virtual const char* getName() const override {
return mServiceInfo.getName();
}
inline virtual void abort() const override {
if (isSendable()) {
serviceLookup();
mSock->sendAbort(0, (struct sockaddr*)&mAddr, sizeof(mAddr));
}
}
};
shared_ptr<LocIpcSender> createLocIpcQrtrSender(int service, int instance) {
return make_shared<LocIpcQsockSender>(service, instance);
}
unique_ptr<LocIpcRecver> createLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
int service, int instance,
const shared_ptr<LocIpcQrtrWatcher>& qrtrWatcher) {
return make_unique<LocIpcQsockRecver>(listener, service, instance);
}
#else
#define SOCKET_SENDER_SEND_TIMEOUT_MSEC 100
static inline __le32 cpu_to_le32(uint32_t x) { return htole32(x); }
static inline uint32_t le32_to_cpu(__le32 x) { return le32toh(x); }
class LocIpcQrtrSender : public LocIpcSender {
protected:
const ServiceInfo mServiceInfo;
shared_ptr<Sock> mSock;
mutable sockaddr_qrtr mAddr;
mutable sockaddr_qrtr mCtrlPntAddr;
mutable struct qrtr_ctrl_pkt mCtrlPkt;
mutable bool mLookupPending;
bool ctrlCmdAndResponse(enum qrtr_pkt_type cmd) const {
LOC_LOGd("cmd: %d, sock valid %d, sock id %d, service id %d, instance id %d",
cmd, mSock->isValid(), mSock->mSid,
le32_to_cpu(mCtrlPkt.server.service),
le32_to_cpu(mCtrlPkt.server.instance));
if (mSock->isValid()) {
int rc = 0;
mCtrlPkt.cmd = cpu_to_le32(cmd);
if ((rc = ::sendto(mSock->mSid, &mCtrlPkt, sizeof(mCtrlPkt), 0,
(const struct sockaddr *)&mCtrlPntAddr, sizeof(mCtrlPntAddr))) < 0) {
LOC_LOGe("failed: sendto rc=%d reason=(%s)", rc, strerror(errno));
} else if (QRTR_TYPE_NEW_LOOKUP == cmd) {
int len = 0;
struct qrtr_ctrl_pkt pkt;
while ((len = ::recv(mSock->mSid, &pkt, sizeof(pkt), 0)) > 0) {
if (len >= (decltype(len))sizeof(pkt)) {
qrtr_pkt_type pktType = (qrtr_pkt_type) le32_to_cpu(pkt.cmd);
LOC_LOGd("qrtr new lookup received pkt type: %d, "
"pkt service id: %d, instance id: %d,"
"node %d, port %d",
pktType, le32_to_cpu(pkt.server.service),
le32_to_cpu(pkt.server.instance),
le32_to_cpu(pkt.server.node),
le32_to_cpu(pkt.server.port));
switch (pktType){
case QRTR_TYPE_NEW_SERVER:
if (le32_to_cpu(pkt.server.service) == 0 &&
le32_to_cpu(pkt.server.instance) == 0) {
return false;
} else if ((mCtrlPkt.server.service == pkt.server.service) &&
(mCtrlPkt.server.instance == pkt.server.instance)) {
mAddr.sq_node = le32_to_cpu(pkt.server.node);
mAddr.sq_port = le32_to_cpu(pkt.server.port);
return true;
}
break;
case QRTR_TYPE_DEL_SERVER:
if ((mCtrlPkt.server.service == pkt.server.service) &&
(mCtrlPkt.server.instance == pkt.server.instance)) {
// service of particular service id, instance id gets deleted
return false;
}
break;
default:
break;
}
}
}
}
}
LOC_LOGd("cmd: %d, return %d", cmd, mSock->isValid());
return mSock->isValid();
}
inline virtual bool isOperable() const override {
return mSock != nullptr && mSock->isValid() &&
(mAddr.sq_node != 0 || mAddr.sq_port != 0);
}
inline virtual ssize_t send(const uint8_t data[], uint32_t length,
int32_t /* msgId */) const override {
if (mLookupPending) {
if (ctrlCmdAndResponse(QRTR_TYPE_NEW_LOOKUP) == false) {
return 0;
}
mLookupPending = false;
}
int result = mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr));
return result;
}
public:
inline LocIpcQrtrSender(const sockaddr_qrtr& destAddr) :
LocIpcSender(), mServiceInfo(0, 0),
mSock(make_shared<Sock>(::socket(AF_QIPCRTR, SOCK_DGRAM, 0))),
mAddr(destAddr), mCtrlPkt({}), mLookupPending(false) {
}
inline LocIpcQrtrSender(int service, int instance) : LocIpcSender(),
mServiceInfo(service, instance),
mSock(make_shared<Sock>(::socket(AF_QIPCRTR, SOCK_DGRAM, 0))),
mAddr({AF_QIPCRTR, 0, 0}),
mCtrlPkt({}),
mLookupPending(true) {
// set timeout so if failed to send, call will return after SOCKET_TIMEOUT_MSEC
// otherwise, call may never return
timeval timeout;
timeout.tv_sec = SOCKET_SENDER_SEND_TIMEOUT_MSEC / 1000;
timeout.tv_usec = SOCKET_SENDER_SEND_TIMEOUT_MSEC % 1000 * 1000;
setsockopt(mSock->mSid, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
socklen_t sl = sizeof(mAddr);
int rc = 0;
if ((rc = getsockname(mSock->mSid, (struct sockaddr*)&mAddr, &sl)) ||
mAddr.sq_family != AF_QIPCRTR || sl != sizeof(mAddr)) {
LOC_LOGe("failed: getsockname rc=%d reason=(%s), mAddr.sq_family=%d",
rc, strerror(errno), mAddr.sq_family);
mSock->close();
} else {
mCtrlPkt.server.service = cpu_to_le32(service);
mCtrlPkt.server.instance = cpu_to_le32(instance);
mCtrlPkt.server.node = cpu_to_le32(mAddr.sq_node);
mCtrlPkt.server.port = cpu_to_le32(mAddr.sq_port);
mCtrlPntAddr = mAddr;
mCtrlPntAddr.sq_port = QRTR_PORT_CTRL;
}
}
unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) override {
return make_unique<SockRecver>(listener, *this, mSock);
}
inline virtual bool updateDestAddr(uint32_t nodeId, uint32_t portId)
{
if (mAddr.sq_node != nodeId || mAddr.sq_port != portId) {
sockaddr_qrtr addr = {AF_QIPCRTR, nodeId, portId};
mAddr = addr;
}
mLookupPending = false;
return true;
}
};
class LocIpcQrtrListener : public ILocIpcListener {
const shared_ptr<ILocIpcListener> mRealListener;
const shared_ptr<LocIpcQrtrWatcher> mQrtrWatcher;
inline bool handleQrtrCtrlMsg(const char* data, uint32_t len) {
const struct qrtr_ctrl_pkt* pkt = reinterpret_cast<const struct qrtr_ctrl_pkt*>(data);
bool handledAsQrtrCtrlMsg = false;
if (sizeof(*pkt) == len) {
const uint32_t cmd = le32_to_cpu(pkt->cmd);
if (cmd >= QRTR_TYPE_DATA && cmd <= QRTR_TYPE_DEL_LOOKUP) {
handledAsQrtrCtrlMsg = true;
int serviceId = le32_to_cpu(pkt->server.service);
int instanceId = le32_to_cpu(pkt->server.instance);
uint32_t serverNodeId = le32_to_cpu(pkt->server.node);
uint32_t serverPort = le32_to_cpu(pkt->server.port);
int clientNodeId = le32_to_cpu(pkt->client.node);
int clientPort = le32_to_cpu(pkt->client.port);
LOC_LOGv("qrtr control msg: cmd %d, server.service:instance-node:port %d:%d-%d:%d,"
" client node:port %d:%d", cmd, serviceId, instanceId, serverNodeId,
serverPort, clientNodeId, clientPort);
if (nullptr != mQrtrWatcher) {
if ((QRTR_TYPE_NEW_SERVER == cmd || QRTR_TYPE_DEL_SERVER == cmd) &&
mQrtrWatcher->isServiceInWatch(serviceId)) {
LocIpcQrtrWatcher::ServiceStatus status = (QRTR_TYPE_NEW_SERVER == cmd) ?
LocIpcQrtrWatcher::ServiceStatus::UP :
LocIpcQrtrWatcher::ServiceStatus::DOWN;
mQrtrWatcher->onServiceStatusChange(serviceId, instanceId, status,
serverNodeId, serverPort);
} else if ((QRTR_TYPE_DEL_CLIENT == cmd || QRTR_TYPE_BYE == cmd) &&
mQrtrWatcher->isClientInWatch(clientNodeId)) {
mQrtrWatcher->onClientGone(clientNodeId, clientPort);
}
}
}
}
return handledAsQrtrCtrlMsg;
}
public:
inline LocIpcQrtrListener(const shared_ptr<ILocIpcListener>& listener,
const shared_ptr<LocIpcQrtrWatcher>& qrtrWatcher) :
mRealListener(listener), mQrtrWatcher(qrtrWatcher) {}
inline virtual void onListenerReady() override {
if (nullptr != mRealListener) mRealListener->onListenerReady();
}
inline virtual void onReceive(const char* data, uint32_t len,
const LocIpcRecver* recver) override {
if ((!handleQrtrCtrlMsg(data, len)) && (nullptr != mRealListener)) {
mRealListener->onReceive(data, len, recver);
}
}
};
class LocIpcQrtrRecver : public LocIpcQrtrSender, public LocIpcRecver {
protected:
inline virtual ssize_t recv() const override {
socklen_t size = sizeof(mAddr);
return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size);
}
public:
inline LocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
int service, int instance,
const shared_ptr<LocIpcQrtrWatcher>& qrtrWatcher) :
LocIpcQrtrSender(service, instance),
LocIpcRecver(make_shared<LocIpcQrtrListener>(listener, qrtrWatcher), *this) {
ctrlCmdAndResponse(QRTR_TYPE_NEW_SERVER);
if (nullptr != qrtrWatcher) {
struct qrtr_ctrl_pkt pkt = {};
pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_LOOKUP);
int rc = 0;
for (int serviceId : qrtrWatcher->getServicesToWatch()) {
pkt.server.service = cpu_to_le32(serviceId);
LOC_LOGd("watch for service: %d", pkt.server.service);
if ((rc = ::sendto(mSock->mSid, &pkt, sizeof(pkt), 0,
(const struct sockaddr *)&mCtrlPntAddr,
sizeof(mCtrlPntAddr))) < 0) {
LOC_LOGe("failed: sendto rc=%d reason=(%s)\n", rc, strerror(errno));
}
}
}
}
inline ~LocIpcQrtrRecver() { ctrlCmdAndResponse(QRTR_TYPE_DEL_SERVER); }
inline virtual unique_ptr<LocIpcSender> getLastSender() const override {
return make_unique<LocIpcQrtrSender>(mAddr);
}
inline virtual const char* getName() const override {
return mServiceInfo.getName();
}
inline virtual void abort() const override {
if (isSendable()) {
mSock->sendAbort(0, (struct sockaddr*)&mAddr, sizeof(mAddr));
}
}
};
shared_ptr<LocIpcSender> createLocIpcQrtrSender(int service, int instance) {
return make_shared<LocIpcQrtrSender>(service, instance);
}
unique_ptr<LocIpcRecver> createLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
int service, int instance,
const shared_ptr<LocIpcQrtrWatcher>& qrtrWatcher) {
return make_unique<LocIpcQrtrRecver>(listener, service, instance, qrtrWatcher);
}
#endif
}

View File

@@ -0,0 +1,50 @@
AM_CFLAGS = \
-DDEBUG \
-I src/ \
-I inc/ \
$(QMIFW_CFLAGS) \
$(GPSUTILS_CFLAGS) \
-fpermissive
if USE_QSOCKET
AM_CFLAGS += -DUSE_QSOCKET
endif
ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = -std=c++14
requiredlibs = \
$(QMIFW_LIBS) \
$(GPSUTILS_LIBS)
c_sources = \
LocSocket.cpp
libloc_socket_la_SOURCES = \
$(c_sources)
######################
# Build loc_socket
######################
if USE_GLIB
libloc_socket_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
libloc_socket_la_LDFLAGS = -lstdc++ -g -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
libloc_socket_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
else
libloc_socket_la_CFLAGS = $(AM_CFLAGS)
libloc_socket_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread -shared -version-info 1:0:0
libloc_socket_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
endif
libloc_socket_la_LIBADD = $(requiredlibs) -lstdc++
#Create and Install libraries
library_include_HEADERS =
lib_LTLIBRARIES = libloc_socket.la
library_includedir = $(pkgincludedir)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = loc-socket.pc
EXTRA_DIST = $(pkgconfig_DATA)

View File

@@ -0,0 +1,117 @@
# configure.ac -- Autoconf script for gps location-utils
#
# Process this file with autoconf to produce a configure script
# Requires autoconf tool later than 2.61
AC_PREREQ(2.61)
# Initialize the loc_socket package version 1.0.0
AC_INIT([loc-socket],1.0.0)
# Does not strictly follow GNU Coding standards
AM_INIT_AUTOMAKE([foreign subdir-objects])
# Disables auto rebuilding of configure, Makefile.ins
AM_MAINTAINER_MODE
# Verifies the --srcdir is correct by checking for the path
AC_CONFIG_SRCDIR([Makefile.am])
# defines some macros variable to be included by source
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
# Checks for programs.
AC_PROG_LIBTOOL
AC_PROG_CXX
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_AWK
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
PKG_PROG_PKG_CONFIG
# Checks for libraries.
PKG_CHECK_MODULES([GPSUTILS], [qcom-gps-utils])
AC_SUBST([GPSUTILS_CFLAGS])
AC_SUBST([GPSUTILS_LIBS])
AC_ARG_WITH([external_ap],
AC_HELP_STRING([--with-external_ap=@<:@dir@:>@],
[Using External Application Processor]),
[],
with_external_ap=no)
if test "x$with_external_ap" != "xno"; then
CPPFLAGS="${CPPFLAGS} -DFEATURE_EXTERNAL_AP"
fi
AM_CONDITIONAL(USE_EXTERNAL_AP, test "x${with_external_ap}" = "xyes")
AC_ARG_WITH([qsocket],
AC_HELP_STRING([--with-qsocket], [kernel supports qsocket]))
AM_CONDITIONAL(USE_QSOCKET, test "x${with_qsocket}" = "xyes")
AM_COND_IF(USE_QSOCKET, [
PKG_CHECK_MODULES([QMIFW], [qmi-framework])
AC_SUBST([QMIFW_CFLAGS])
AC_SUBST([QMIFW_LIBS])
])
AC_ARG_WITH([external_ap],
AC_HELP_STRING([--with-external_ap=@<:@dir@:>@],
[Using External Application Processor]),
[],
with_external_ap=no)
if test "x$with_external_ap" != "xno"; then
CPPFLAGS="${CPPFLAGS} -DFEATURE_EXTERNAL_AP"
else
# Checks for libraries.
PKG_CHECK_MODULES([CUTILS], [libcutils])
AC_SUBST([CUTILS_CFLAGS])
AC_SUBST([CUTILS_LIBS])
fi
AC_ARG_WITH([glib],
AC_HELP_STRING([--with-glib],
[enable glib, building HLOS systems which use glib]))
if (test "x${with_glib}" = "xyes"); then
AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
AC_MSG_ERROR(GThread >= 2.16 is required))
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
AC_MSG_ERROR(GLib >= 2.16 is required))
GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
fi
AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
AC_ARG_WITH([core_includes],
AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
[Specify the location of the core headers]),
[core_incdir=$withval],
with_core_includes=no)
if test "x$with_core_includes" != "xno"; then
CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
fi
AC_ARG_WITH([locpla_includes],
AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
[specify the path to locpla-includes in loc-pla_git.bb]),
[locpla_incdir=$withval],
with_locpla_includes=no)
if test "x$with_locpla_includes" != "xno"; then
AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
fi
AC_CONFIG_FILES([ \
Makefile \
loc-socket.pc
])
AC_OUTPUT

View File

@@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: loc-socket
Description: location socket library
Version: @VERSION@
Libs: -L${libdir} -lloc_socket
Cflags: -I${includedir} -I${includedir}/loc-socket