diff options
author | Michael Bestas <mkbestas@gmail.com> | 2020-04-18 17:12:06 +0300 |
---|---|---|
committer | Michael Bestas <mkbestas@gmail.com> | 2020-04-18 17:12:39 +0300 |
commit | ddfa99dce7571688697e965b992a35b3f01c1aba (patch) | |
tree | 83e4f6b862bf4752c73e09d7d60496be95a1eda4 /gps/utils | |
parent | 570a57c7abc1a0f0e48698821e0061dd2e807dc5 (diff) | |
parent | ea8aefcf657335910a97e158e1c4752db9b0a880 (diff) |
sdm660-common: Import GPS HAL from LA.UM.8.2.r1-04300-sdm660.0
Change-Id: I5e93d71bc7df7bb46af8c4b9ff11e8302113cfa9
Diffstat (limited to 'gps/utils')
35 files changed, 13259 insertions, 0 deletions
diff --git a/gps/utils/Android.mk b/gps/utils/Android.mk new file mode 100644 index 0000000..3887696 --- /dev/null +++ b/gps/utils/Android.mk @@ -0,0 +1,65 @@ +ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),) +ifneq ($(BUILD_TINY_ANDROID),true) +#Compile this library only for builds with the latest modem image + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + + +## Libs +LOCAL_SHARED_LIBRARIES := \ + libdl \ + libutils \ + libcutils \ + liblog \ + libprocessgroup + +LOCAL_SRC_FILES += \ + loc_log.cpp \ + loc_cfg.cpp \ + msg_q.c \ + linked_list.c \ + loc_target.cpp \ + LocHeap.cpp \ + LocTimer.cpp \ + LocThread.cpp \ + MsgTask.cpp \ + loc_misc_utils.cpp \ + loc_nmea.cpp \ + LocIpc.cpp + +# Flag -std=c++11 is not accepted by compiler when LOCAL_CLANG is set to true +LOCAL_CFLAGS += \ + -fno-short-enums \ + -D_ANDROID_ + +ifeq ($(TARGET_BUILD_VARIANT),user) + LOCAL_CFLAGS += -DTARGET_BUILD_VARIANT_USER +endif + +LOCAL_LDFLAGS += -Wl,--export-dynamic + +## Includes +LOCAL_HEADER_LIBRARIES := \ + libutils_headers \ + libloc_pla_headers \ + liblocation_api_headers + +LOCAL_MODULE := libgps.utils +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional + +LOCAL_PRELINK_MODULE := false + +LOCAL_CFLAGS += $(GNSS_CFLAGS) + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := libgps.utils_headers +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +include $(BUILD_HEADER_LIBRARY) + +endif # not BUILD_TINY_ANDROID +endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE diff --git a/gps/utils/LocHeap.cpp b/gps/utils/LocHeap.cpp new file mode 100644 index 0000000..d667f14 --- /dev/null +++ b/gps/utils/LocHeap.cpp @@ -0,0 +1,354 @@ +/* Copyright (c) 2015, 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. + * + */ +#include <LocHeap.h> + +class LocHeapNode { + friend class LocHeap; + + // size of of the subtree, excluding self, 1 if no subtree + int mSize; + LocHeapNode* mLeft; + LocHeapNode* mRight; + LocRankable* mData; +public: + inline LocHeapNode(LocRankable& data) : + mSize(1), mLeft(NULL), mRight(NULL), mData(&data) {} + ~LocHeapNode(); + + // this only swaps the data of the two nodes, so no + // detach / re-attached is necessary + void swap(LocHeapNode& node); + + LocRankable* detachData(); + + // push a node into the tree stucture, keeping sorted by rank + void push(LocHeapNode& node); + + // pop the head node out of the tree stucture. keeping sorted by rank + static LocHeapNode* pop(LocHeapNode*& top); + + // remove a specific node from the tree + // returns the pointer to the node removed, which would be either the + // same as input (if successfully removed); or NULL (if failed). + static LocHeapNode* remove(LocHeapNode*& top, LocRankable& data); + + // convenience method to compare data ranking + inline bool outRanks(LocHeapNode& node) { return mData->outRanks(*node.mData); } + inline bool outRanks(LocRankable& data) { return mData->outRanks(data); } + + // checks if mSize is correct, AND this node is the highest ranking + // of the entire subtree + bool checkNodes(); + + inline int getSize() { return mSize; } +}; + +inline +LocHeapNode::~LocHeapNode() { + if (mLeft) { + delete mLeft; + mLeft = NULL; + } + if (mRight) { + delete mRight; + mRight = NULL; + } + if (mData) { + mData = NULL; + } +} + +inline +void LocHeapNode::swap(LocHeapNode& node) { + LocRankable* tmpData = node.mData; + node.mData = mData; + mData = tmpData; +} + +inline +LocRankable* LocHeapNode::detachData() { + LocRankable* data = mData; + mData = NULL; + return data; +} + +// push keeps the tree sorted by rank, it also tries to balance the +// tree by adding the new node to the smaller of the subtrees. +// The pointer to the tree and internal links never change. If the +// mData of tree top ranks lower than that of the incoming node, +// mData will be swapped with that of the incoming node to ensure +// ranking, no restructuring the container nodes. +void LocHeapNode::push(LocHeapNode& node) { + // ensure the current node ranks higher than in the incoming one + if (node.outRanks(*this)) { + swap(node); + } + + // now drop the new node (ensured lower than *this) into a subtree + if (NULL == mLeft) { + mLeft = &node; + } else if (NULL == mRight) { + mRight = &node; + } else if (mLeft->mSize <= mRight->mSize) { + mLeft->push(node); + } else { + mRight->push(node); + } + mSize++; +} + +// pop keeps the tree sorted by rank, but it does not try to balance +// the tree. It recursively swaps with the higher ranked top of the +// subtrees. +// The return is a popped out node from leaf level, that has the data +// swapped all the way down from the top. The pinter to the tree and +// internal links will not be changed or restructured, except for the +// node that is popped out. +// If the return pointer == this, this the last node in the tree. +LocHeapNode* LocHeapNode::pop(LocHeapNode*& top) { + // we know the top has the highest ranking at this point, else + // the tree is broken. This top will be popped out. But we need + // a node from the left or right child, whichever ranks higher, + // to replace the current top. This then will need to be done + // recursively to the leaf level. So we swap the mData of the + // current top node all the way down to the leaf level. + LocHeapNode* poppedNode = top; + // top is losing a node in its subtree + top->mSize--; + if (top->mLeft || top->mRight) { + // if mLeft is NULL, mRight for sure is NOT NULL, take that; + // else if mRight is NULL, mLeft for sure is NOT, take that; + // else we take the address of whatever has higher ranking mData + LocHeapNode*& subTop = (NULL == top->mLeft) ? top->mRight : + ((NULL == top->mRight) ? top->mLeft : + (top->mLeft->outRanks(*(top->mRight)) ? top->mLeft : top->mRight)); + // swap mData, the tree top gets updated with the new data. + top->swap(*subTop); + // pop out from the subtree + poppedNode = pop(subTop); + } else { + // if the top has only single node + // detach the poppedNode from the tree + // subTop is the reference of ether mLeft or mRight + // NOT a local stack pointer. so it MUST be NULL'ed here. + top = NULL; + } + + return poppedNode; +} + +// navigating through the tree and find the node that hass the input +// data. Since this is a heap, we do recursive linear search. +// returns the pointer to the node removed, which would be either the +// same as input (if successfully removed); or NULL (if failed). +LocHeapNode* LocHeapNode::remove(LocHeapNode*& top, LocRankable& data) { + LocHeapNode* removedNode = NULL; + // this is the node, by address + if (&data == (LocRankable*)(top->mData)) { + // pop this node out + removedNode = pop(top); + } else if (!data.outRanks(*top->mData)) { + // subtrees might have this node + if (top->mLeft) { + removedNode = remove(top->mLeft, data); + } + // if we did not find in mLeft, and mRight is not empty + if (!removedNode && top->mRight) { + removedNode = remove(top->mRight, data); + } + + // top lost a node in its subtree + if (removedNode) { + top->mSize--; + } + } + + return removedNode; +} + +// checks if mSize is correct, AND this node is the highest ranking +// of the entire subtree +bool LocHeapNode::checkNodes() { + // size of the current subtree + int totalSize = mSize; + if (mLeft) { + // check the consistency of left subtree + if (mLeft->outRanks(*this) || !mLeft->checkNodes()) { + return false; + } + // subtract the size of left subtree (with subtree head) + totalSize -= mLeft->mSize; + } + + if (mRight) { + // check the consistency of right subtree + if (mRight->outRanks(*this) || !mRight->checkNodes()) { + return false; + } + // subtract the size of right subtree (with subtree head) + totalSize -= mRight->mSize; + } + + // for the tree nodes to consistent, totalSize must be 1 now + return totalSize == 1; +} + +LocHeap::~LocHeap() { + if (mTree) { + delete mTree; + } +} + +void LocHeap::push(LocRankable& node) { + LocHeapNode* heapNode = new LocHeapNode(node); + if (!mTree) { + mTree = heapNode; + } else { + mTree->push(*heapNode); + } +} + +LocRankable* LocHeap::peek() { + LocRankable* top = NULL; + if (mTree) { + top = mTree->mData; + } + return top; +} + +LocRankable* LocHeap::pop() { + LocRankable* locNode = NULL; + if (mTree) { + // mTree may become NULL after this call + LocHeapNode* heapNode = LocHeapNode::pop(mTree); + locNode = heapNode->detachData(); + delete heapNode; + } + return locNode; +} + +LocRankable* LocHeap::remove(LocRankable& rankable) { + LocRankable* locNode = NULL; + if (mTree) { + // mTree may become NULL after this call + LocHeapNode* heapNode = LocHeapNode::remove(mTree, rankable); + if (heapNode) { + locNode = heapNode->detachData(); + delete heapNode; + } + } + return locNode; +} + +#ifdef __LOC_UNIT_TEST__ +bool LocHeap::checkTree() { + return ((NULL == mTree) || mTree->checkNodes()); +} +uint32_t LocHeap::getTreeSize() { + return (NULL == mTree) ? 0 : mTree->getSize(); +} +#endif + +#ifdef __LOC_DEBUG__ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +class LocHeapDebug : public LocHeap { +public: + bool checkTree() { + return ((NULL == mTree) || mTree->checkNodes()); + } + + uint32_t getTreeSize() { + return (NULL == mTree) ? 0 : (mTree->getSize()); + } +}; + +class LocHeapDebugData : public LocRankable { + const int mID; +public: + LocHeapDebugData(int id) : mID(id) {} + inline virtual int ranks(LocRankable& rankable) { + LocHeapDebugData* testData = dynamic_cast<LocHeapDebugData*>(&rankable); + return testData->mID - mID; + } +}; + +// For Linux command line testing: +// compilation: g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../vendor/qcom/proprietary/gps-internal/unit-tests/fakes_for_host -I../../../../system/core/include LocHeap.cpp +// test: valgrind --leak-check=full ./a.out 100 +int main(int argc, char** argv) { + srand(time(NULL)); + int tries = atoi(argv[1]); + int checks = tries >> 3; + LocHeapDebug heap; + int treeSize = 0; + + for (int i = 0; i < tries; i++) { + if (i % checks == 0 && !heap.checkTree()) { + printf("tree check failed before %dth op\n", i); + } + int r = rand(); + + if (r & 1) { + LocHeapDebugData* data = new LocHeapDebugData(r >> 1); + heap.push(dynamic_cast<LocRankable&>(*data)); + treeSize++; + } else { + LocRankable* rankable = heap.pop(); + if (rankable) { + delete rankable; + } + treeSize ? treeSize-- : 0; + } + + printf("%s: %d == %d\n", (r&1)?"push":"pop", treeSize, heap.getTreeSize()); + if (treeSize != heap.getTreeSize()) { + printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + tries = i+1; + break; + } + } + + if (!heap.checkTree()) { + printf("!!!!!!!!!!tree check failed at the end after %d ops!!!!!!!\n", tries); + } else { + printf("success!\n"); + } + + for (LocRankable* data = heap.pop(); NULL != data; data = heap.pop()) { + delete data; + } + + return 0; +} + +#endif diff --git a/gps/utils/LocHeap.h b/gps/utils/LocHeap.h new file mode 100644 index 0000000..b491948 --- /dev/null +++ b/gps/utils/LocHeap.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2015, 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. + * + */ +#ifndef __LOC_HEAP__ +#define __LOC_HEAP__ + +#include <stddef.h> +#include <string.h> + +// abstract class to be implemented by client to provide a rankable class +class LocRankable { +public: + virtual inline ~LocRankable() {} + + // method to rank objects of such type for sorting purposes. + // The pointer of the input node would be stored in the heap. + // >0 if ranks higher than the input; + // ==0 if equally ranks with the input; + // <0 if ranks lower than the input + virtual int ranks(LocRankable& rankable) = 0; + + // convenient method to rank objects of such type for sorting purposes. + inline bool outRanks(LocRankable& rankable) { return ranks(rankable) > 0; } +}; + +// opaque class to provide service implementation. +class LocHeapNode; + +// a heap whose left and right children are not sorted. It is sorted only vertically, +// i.e. parent always ranks higher than children, if they exist. Ranking algorithm is +// implemented in Rankable. The reason that there is no sort between children is to +// help beter balance the tree with lower cost. When a node is pushed to the tree, +// it is guaranteed that the subtree that is smaller gets to have the new node. +class LocHeap { +protected: + LocHeapNode* mTree; +public: + inline LocHeap() : mTree(NULL) {} + ~LocHeap(); + + // push keeps the tree sorted by rank, it also tries to balance the + // tree by adding the new node to the smaller of the subtrees. + // node is reference to an obj that is managed by client, that client + // creates and destroyes. The destroy should happen after the + // node is popped out from the heap. + void push(LocRankable& node); + + // Peeks the node data on tree top, which has currently the highest ranking + // There is no change the tree structure with this operation + // Returns NULL if the tree is empty, otherwise pointer to the node data of + // the tree top. + LocRankable* peek(); + + // pop keeps the tree sorted by rank, but it does not try to balance + // the tree. + // Return - pointer to the node popped out, or NULL if heap is already empty + LocRankable* pop(); + + // navigating through the tree and find the node that ranks the same + // as the input data, then remove it from the tree. Rank is implemented + // by rankable obj. + // returns the pointer to the node removed; or NULL (if failed). + LocRankable* remove(LocRankable& rankable); + +#ifdef __LOC_UNIT_TEST__ + bool checkTree(); + uint32_t getTreeSize(); +#endif +}; + +#endif //__LOC_HEAP__ diff --git a/gps/utils/LocIpc.cpp b/gps/utils/LocIpc.cpp new file mode 100644 index 0000000..e9dbe9d --- /dev/null +++ b/gps/utils/LocIpc.cpp @@ -0,0 +1,414 @@ +/* Copyright (c) 2017-2018 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. + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <netinet/in.h> +#include <netdb.h> +#include <loc_misc_utils.h> +#include <log_util.h> +#include <LocIpc.h> +#include <algorithm> + +using namespace std; + +namespace loc_util { + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "LocSvc_LocIpc" + +#define SOCK_OP_AND_LOG(buf, length, opable, rtv, exe) \ + if (nullptr == (buf) || 0 == (length)) { \ + LOC_LOGe("Invalid inputs: buf - %p, length - %u", (buf), (length)); \ + } else if (!(opable)) { \ + LOC_LOGe("Invalid object: operable - %d", (opable)); \ + } else { \ + rtv = (exe); \ + if (-1 == rtv) { \ + LOC_LOGw("failed reason: %s", strerror(errno)); \ + } \ + } + +const char Sock::MSG_ABORT[] = "LocIpc::Sock::ABORT"; +const char Sock::LOC_IPC_HEAD[] = "$MSGLEN$"; +ssize_t Sock::send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr, + socklen_t addrlen) const { + ssize_t rtv = -1; + SOCK_OP_AND_LOG(buf, len, isValid(), rtv, sendto(buf, len, flags, destAddr, addrlen)); + return rtv; +} +ssize_t Sock::recv(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, int flags, + struct sockaddr *srcAddr, socklen_t *addrlen, int sid) const { + ssize_t rtv = -1; + if (-1 == sid) { + sid = mSid; + } // else it sid would be connection based socket id for recv + SOCK_OP_AND_LOG(dataCb.get(), mMaxTxSize, isValid(), rtv, + recvfrom(recver, dataCb, sid, flags, srcAddr, addrlen)); + return rtv; +} +ssize_t Sock::sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr, + socklen_t addrlen) const { + ssize_t rtv = -1; + if (len <= mMaxTxSize) { + rtv = ::sendto(mSid, buf, len, flags, destAddr, addrlen); + } else { + std::string head(LOC_IPC_HEAD + to_string(len)); + rtv = ::sendto(mSid, head.c_str(), head.length(), flags, destAddr, addrlen); + if (rtv > 0) { + for (size_t offset = 0; offset < len && rtv > 0; offset += rtv) { + rtv = ::sendto(mSid, (char*)buf + offset, min(len - offset, (size_t)mMaxTxSize), + flags, destAddr, addrlen); + } + rtv = (rtv > 0) ? (head.length() + len) : -1; + } + } + return rtv; +} +ssize_t Sock::recvfrom(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, + int sid, int flags, struct sockaddr *srcAddr, socklen_t *addrlen) const { + std::string msg(mMaxTxSize, 0); + ssize_t nBytes = ::recvfrom(sid, (void*)msg.data(), msg.size(), flags, srcAddr, addrlen); + if (nBytes > 0) { + if (strncmp(msg.data(), MSG_ABORT, sizeof(MSG_ABORT)) == 0) { + LOC_LOGi("recvd abort msg.data %s", msg.data()); + nBytes = 0; + } else if (strncmp(msg.data(), LOC_IPC_HEAD, sizeof(LOC_IPC_HEAD) - 1)) { + // short message + msg.resize(nBytes); + dataCb->onReceive(msg.data(), nBytes, &recver); + } else { + // long message + size_t msgLen = 0; + sscanf(msg.data() + sizeof(LOC_IPC_HEAD) - 1, "%zu", &msgLen); + msg.resize(msgLen); + for (size_t msgLenReceived = 0; (msgLenReceived < msgLen) && (nBytes > 0); + msgLenReceived += nBytes) { + nBytes = ::recvfrom(sid, &(msg[msgLenReceived]), msg.size() - msgLenReceived, + flags, srcAddr, addrlen); + } + if (nBytes > 0) { + nBytes = msgLen; + dataCb->onReceive(msg.data(), nBytes, &recver); + } + } + } + + return nBytes; +} +ssize_t Sock::sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen) { + return send(MSG_ABORT, sizeof(MSG_ABORT), flags, destAddr, addrlen); +} + +class LocIpcLocalSender : public LocIpcSender { +protected: + shared_ptr<Sock> mSock; + struct sockaddr_un mAddr; + inline virtual bool isOperable() const override { return mSock != nullptr && mSock->isValid(); } + inline virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const { + return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr)); + } +public: + inline LocIpcLocalSender(const char* name) : LocIpcSender(), + mSock(make_shared<Sock>((nullptr == name) ? -1 : (::socket(AF_UNIX, SOCK_DGRAM, 0)))), + mAddr({.sun_family = AF_UNIX, {}}) { + if (mSock != nullptr && mSock->isValid()) { + snprintf(mAddr.sun_path, sizeof(mAddr.sun_path), "%s", name); + } + } +}; + +class LocIpcLocalRecver : public LocIpcLocalSender, 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 LocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener, const char* name) : + LocIpcLocalSender(name), LocIpcRecver(listener, *this) { + + if ((unlink(mAddr.sun_path) < 0) && (errno != ENOENT)) { + LOC_LOGw("unlink socket error. reason:%s", strerror(errno)); + } + + umask(0157); + if (mSock->isValid() && ::bind(mSock->mSid, (struct sockaddr*)&mAddr, sizeof(mAddr)) < 0) { + LOC_LOGe("bind socket error. sock fd: %d: %s, reason: %s", mSock->mSid, + mAddr.sun_path, strerror(errno)); + mSock->close(); + } + } + inline virtual ~LocIpcLocalRecver() { unlink(mAddr.sun_path); } + inline virtual const char* getName() const override { return mAddr.sun_path; }; + inline virtual void abort() const override { + if (isSendable()) { + mSock->sendAbort(0, (struct sockaddr*)&mAddr, sizeof(mAddr)); + } + } +}; + +class LocIpcInetSender : public LocIpcSender { +protected: + int mSockType; + shared_ptr<Sock> mSock; + const string mName; + sockaddr_in mAddr; + inline virtual bool isOperable() const override { return mSock != nullptr && mSock->isValid(); } + virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const { + return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr)); + } +public: + inline LocIpcInetSender(const LocIpcInetSender& sender) : + mSockType(sender.mSockType), mSock(sender.mSock), + mName(sender.mName), mAddr(sender.mAddr) { + } + inline LocIpcInetSender(const char* name, int32_t port, int sockType) : LocIpcSender(), + mSockType(sockType), + mSock(make_shared<Sock>((nullptr == name) ? -1 : (::socket(AF_INET, mSockType, 0)))), + mName((nullptr == name) ? "" : name), + mAddr({.sin_family = AF_INET, .sin_port = htons(port), + .sin_addr = {htonl(INADDR_ANY)}}) { + if (mSock != nullptr && mSock->isValid() && nullptr != name) { + struct hostent* hp = gethostbyname(name); + if (nullptr != hp) { + memcpy((char*)&(mAddr.sin_addr.s_addr), hp->h_addr_list[0], hp->h_length); + } + } + } + + unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) override { + return make_unique<SockRecver>(listener, *this, mSock); + } +}; + +class LocIpcInetTcpSender : public LocIpcInetSender { +protected: + mutable bool mFirstTime; + + virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const { + if (mFirstTime) { + mFirstTime = false; + ::connect(mSock->mSid, (const struct sockaddr*)&mAddr, sizeof(mAddr)); + } + return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr)); + } + +public: + inline LocIpcInetTcpSender(const char* name, int32_t port) : + LocIpcInetSender(name, port, SOCK_STREAM), + mFirstTime(true) {} +}; + +class LocIpcInetRecver : public LocIpcInetSender, public LocIpcRecver { + int32_t mPort; +protected: + virtual ssize_t recv() const = 0; +public: + inline LocIpcInetRecver(const shared_ptr<ILocIpcListener>& listener, const char* name, + int32_t port, int sockType) : + LocIpcInetSender(name, port, sockType), LocIpcRecver(listener, *this), + mPort(port) { + if (mSock->isValid() && ::bind(mSock->mSid, (struct sockaddr*)&mAddr, sizeof(mAddr)) < 0) { + LOC_LOGe("bind socket error. sock fd: %d, reason: %s", mSock->mSid, strerror(errno)); + mSock->close(); + } + } + inline virtual ~LocIpcInetRecver() {} + inline virtual const char* getName() const override { return mName.data(); }; + inline virtual void abort() const override { + if (isSendable()) { + sockaddr_in loopBackAddr = {.sin_family = AF_INET, .sin_port = htons(mPort), + .sin_addr = {htonl(INADDR_LOOPBACK)}}; + mSock->sendAbort(0, (struct sockaddr*)&loopBackAddr, sizeof(loopBackAddr)); + } + } + inline virtual unique_ptr<LocIpcSender> getLastSender() const override { + return make_unique<LocIpcInetSender>(static_cast<const LocIpcInetSender&>(*this)); + } +}; + +class LocIpcInetTcpRecver : public LocIpcInetRecver { + mutable int32_t mConnFd; +protected: + inline virtual ssize_t recv() const override { + socklen_t size = sizeof(mAddr); + if (-1 == mConnFd && mSock->isValid()) { + if (::listen(mSock->mSid, 3) < 0 || + (mConnFd = accept(mSock->mSid, (struct sockaddr*)&mAddr, &size)) < 0) { + mSock->close(); + mConnFd = -1; + } + } + return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size, mConnFd); + } +public: + inline LocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener, const char* name, + int32_t port) : + LocIpcInetRecver(listener, name, port, SOCK_STREAM), mConnFd(-1) {} + inline virtual ~LocIpcInetTcpRecver() { if (-1 != mConnFd) ::close(mConnFd);} +}; + +class LocIpcInetUdpRecver : public LocIpcInetRecver { +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 LocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener, const char* name, + int32_t port) : + LocIpcInetRecver(listener, name, port, SOCK_DGRAM) {} + + inline virtual ~LocIpcInetUdpRecver() {} +}; + +class LocIpcRunnable : public LocRunnable { + bool mAbortCalled; + LocIpc& mLocIpc; + unique_ptr<LocIpcRecver> mIpcRecver; +public: + inline LocIpcRunnable(LocIpc& locIpc, unique_ptr<LocIpcRecver>& ipcRecver) : + mAbortCalled(false), + mLocIpc(locIpc), + mIpcRecver(move(ipcRecver)) {} + inline bool run() override { + if (mIpcRecver != nullptr) { + mLocIpc.startBlockingListening(*(mIpcRecver.get())); + if (!mAbortCalled) { + LOC_LOGw("startListeningBlocking() returned w/o stopBlockingListening() called"); + } + } + // return false so the calling thread exits while loop + return false; + } + inline void abort() { + mAbortCalled = true; + if (mIpcRecver != nullptr) { + mIpcRecver->abort(); + } + } +}; + +bool LocIpc::startNonBlockingListening(unique_ptr<LocIpcRecver>& ipcRecver) { + if (ipcRecver != nullptr && ipcRecver->isRecvable()) { + std::string threadName("LocIpc-"); + threadName.append(ipcRecver->getName()); + mRunnable = new LocIpcRunnable(*this, ipcRecver); + return mThread.start(threadName.c_str(), mRunnable); + } else { + LOC_LOGe("ipcRecver is null OR ipcRecver->recvable() is fasle"); + return false; + } +} + +bool LocIpc::startBlockingListening(LocIpcRecver& ipcRecver) { + if (ipcRecver.isRecvable()) { + // inform that the socket is ready to receive message + ipcRecver.onListenerReady(); + while (ipcRecver.recvData()); + return true; + } else { + LOC_LOGe("ipcRecver is null OR ipcRecver->recvable() is fasle"); + return false; + } +} + +void LocIpc::stopNonBlockingListening() { + if (mRunnable) { + mRunnable->abort(); + mRunnable = nullptr; + } +} + +void LocIpc::stopBlockingListening(LocIpcRecver& ipcRecver) { + if (ipcRecver.isRecvable()) { + ipcRecver.abort(); + } +} + +bool LocIpc::send(LocIpcSender& sender, const uint8_t data[], uint32_t length, int32_t msgId) { + return sender.sendData(data, length, msgId); +} + +shared_ptr<LocIpcSender> LocIpc::getLocIpcLocalSender(const char* localSockName) { + return make_shared<LocIpcLocalSender>(localSockName); +} +unique_ptr<LocIpcRecver> LocIpc::getLocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener, + const char* localSockName) { + return make_unique<LocIpcLocalRecver>(listener, localSockName); +} +static void* sLibQrtrHandle = nullptr; +static const char* sLibQrtrName = "libloc_socket.so"; +shared_ptr<LocIpcSender> LocIpc::getLocIpcQrtrSender(int service, int instance) { + typedef shared_ptr<LocIpcSender> (*creator_t) (int, int); + static creator_t creator = (creator_t)dlGetSymFromLib(sLibQrtrHandle, sLibQrtrName, + "_ZN8loc_util22createLocIpcQrtrSenderEii"); + return (nullptr == creator) ? nullptr : creator(service, instance); +} +unique_ptr<LocIpcRecver> LocIpc::getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener, + int service, int instance) { + typedef unique_ptr<LocIpcRecver> (*creator_t)(const shared_ptr<ILocIpcListener>&, int, int); + static creator_t creator = (creator_t)dlGetSymFromLib(sLibQrtrHandle, sLibQrtrName, +#ifdef USE_GLIB + "_ZN8loc_util22createLocIpcQrtrRecverERKSt10shared_ptrINS_15ILocIpcListenerEEii"); +#else + "_ZN8loc_util22createLocIpcQrtrRecverERKNSt3__110shared_ptrINS_15ILocIpcListenerEEEii"); +#endif + return (nullptr == creator) ? nullptr : creator(listener, service, instance); +} +shared_ptr<LocIpcSender> LocIpc::getLocIpcInetTcpSender(const char* serverName, int32_t port) { + return make_shared<LocIpcInetTcpSender>(serverName, port); +} +unique_ptr<LocIpcRecver> LocIpc::getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener, + const char* serverName, int32_t port) { + return make_unique<LocIpcInetTcpRecver>(listener, serverName, port); +} +shared_ptr<LocIpcSender> LocIpc::getLocIpcInetUdpSender(const char* serverName, int32_t port) { + return make_shared<LocIpcInetSender>(serverName, port, SOCK_DGRAM); +} +unique_ptr<LocIpcRecver> LocIpc::getLocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener, + const char* serverName, int32_t port) { + return make_unique<LocIpcInetUdpRecver>(listener, serverName, port); +} +pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>> + LocIpc::getLocIpcQmiLocServiceSenderRecverPair(const shared_ptr<ILocIpcListener>& listener, int instance) { + typedef pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>> (*creator_t)(const shared_ptr<ILocIpcListener>&, int); + static void* sLibEmuHandle = nullptr; + static creator_t creator = (creator_t)dlGetSymFromLib(sLibEmuHandle, "libloc_emu.so", + "_ZN13QmiLocService41createLocIpcQmiLocServiceSenderRecverPairERKNSt3__110shared_ptrIN8loc_util15ILocIpcListenerEEEi"); + return (nullptr == creator) ? + make_pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>>(nullptr, nullptr) : + creator(listener, instance); +} + +} diff --git a/gps/utils/LocIpc.h b/gps/utils/LocIpc.h new file mode 100644 index 0000000..d6f8d1d --- /dev/null +++ b/gps/utils/LocIpc.h @@ -0,0 +1,206 @@ +/* Copyright (c) 2017-2018 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. + * + */ + +#ifndef __LOC_IPC__ +#define __LOC_IPC__ + +#include <string> +#include <memory> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <LocThread.h> + +using namespace std; + +namespace loc_util { + + +class LocIpcRecver; +class LocIpcSender; +class LocIpcRunnable; + +class ILocIpcListener { +protected: + inline virtual ~ILocIpcListener() {} +public: + // LocIpc client can overwrite this function to get notification + // when the socket for LocIpc is ready to receive messages. + inline virtual void onListenerReady() {} + virtual void onReceive(const char* data, uint32_t len, const LocIpcRecver* recver) = 0; +}; + + +class LocIpc { +public: + inline LocIpc() : mRunnable(nullptr) {} + inline virtual ~LocIpc() { + stopNonBlockingListening(); + } + + static shared_ptr<LocIpcSender> + getLocIpcLocalSender(const char* localSockName); + static shared_ptr<LocIpcSender> + getLocIpcInetUdpSender(const char* serverName, int32_t port); + static shared_ptr<LocIpcSender> + getLocIpcInetTcpSender(const char* serverName, int32_t port); + static shared_ptr<LocIpcSender> + getLocIpcQrtrSender(int service, int instance); + + static unique_ptr<LocIpcRecver> + getLocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener, + const char* localSockName); + static unique_ptr<LocIpcRecver> + getLocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener, + const char* serverName, int32_t port); + static unique_ptr<LocIpcRecver> + getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener, + const char* serverName, int32_t port); + static unique_ptr<LocIpcRecver> + getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener, + int service, int instance); + + static pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>> + getLocIpcQmiLocServiceSenderRecverPair(const shared_ptr<ILocIpcListener>& listener, + int instance); + + // Listen for new messages in current thread. Calling this funciton will + // block current thread. + // The listening can be stopped by calling stopBlockingListening() passing + // in the same ipcRecver obj handle. + static bool startBlockingListening(LocIpcRecver& ipcRecver); + static void stopBlockingListening(LocIpcRecver& ipcRecver); + + // Create a new LocThread and listen for new messages in it. + // Calling this function will return immediately and won't block current thread. + // The listening can be stopped by calling stopNonBlockingListening(). + bool startNonBlockingListening(unique_ptr<LocIpcRecver>& ipcRecver); + void stopNonBlockingListening(); + + // Send out a message. + // Call this function to send a message in argument data to socket in argument name. + // + // Argument name contains the name of the target unix socket. data contains the + // message to be sent out. Convert your message to a string before calling this function. + // The function will return true on success, and false on failure. + static bool send(LocIpcSender& sender, const uint8_t data[], + uint32_t length, int32_t msgId = -1); + +private: + LocThread mThread; + LocIpcRunnable *mRunnable; +}; + +/* this is only when client needs to implement Sender / Recver that are not already provided by + the factor methods prvoided by LocIpc. */ + +class LocIpcSender { +protected: + LocIpcSender() = default; + virtual bool isOperable() const = 0; + virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t msgId) const = 0; +public: + virtual ~LocIpcSender() = default; + virtual void informRecverRestarted() {} + inline bool isSendable() const { return isOperable(); } + inline bool sendData(const uint8_t data[], uint32_t length, int32_t msgId) const { + return isSendable() && (send(data, length, msgId) > 0); + } + virtual unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) { + return nullptr; + } +}; + +class LocIpcRecver { + LocIpcSender& mIpcSender; +protected: + const shared_ptr<ILocIpcListener> mDataCb; + inline LocIpcRecver(const shared_ptr<ILocIpcListener>& listener, LocIpcSender& sender) : + mIpcSender(sender), mDataCb(listener) {} + LocIpcRecver(LocIpcRecver const& recver) = delete; + LocIpcRecver& operator=(LocIpcRecver const& recver) = delete; + virtual ssize_t recv() const = 0; +public: + virtual ~LocIpcRecver() = default; + inline bool recvData() const { return isRecvable() && (recv() > 0); } + inline bool isRecvable() const { return mDataCb != nullptr && mIpcSender.isSendable(); } + virtual void onListenerReady() { if (mDataCb != nullptr) mDataCb->onListenerReady(); } + inline virtual unique_ptr<LocIpcSender> getLastSender() const { + return nullptr; + } + virtual void abort() const = 0; + virtual const char* getName() const = 0; +}; + +class Sock { + static const char MSG_ABORT[]; + static const char LOC_IPC_HEAD[]; + const uint32_t mMaxTxSize; + ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr, + socklen_t addrlen) const; + ssize_t recvfrom(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, + int sid, int flags, struct sockaddr *srcAddr, socklen_t *addrlen) const; +public: + int mSid; + inline Sock(int sid, const uint32_t maxTxSize = 8192) : mMaxTxSize(maxTxSize), mSid(sid) {} + inline ~Sock() { close(); } + inline bool isValid() const { return -1 != mSid; } + ssize_t send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr, + socklen_t addrlen) const; + ssize_t recv(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, int flags, + struct sockaddr *srcAddr, socklen_t *addrlen, int sid = -1) const; + ssize_t sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen); + inline void close() { + if (isValid()) { + ::close(mSid); + mSid = -1; + } + } +}; + +class SockRecver : public LocIpcRecver { + shared_ptr<Sock> mSock; +protected: + inline virtual ssize_t recv() const override { + return mSock->recv(*this, mDataCb, 0, nullptr, nullptr); + } +public: + inline SockRecver(const shared_ptr<ILocIpcListener>& listener, + LocIpcSender& sender, shared_ptr<Sock> sock) : + LocIpcRecver(listener, sender), mSock(sock) { + } + inline virtual const char* getName() const override { + return "SockRecver"; + } + inline virtual void abort() const override {} +}; + +} + +#endif //__LOC_IPC__ diff --git a/gps/utils/LocSharedLock.h b/gps/utils/LocSharedLock.h new file mode 100644 index 0000000..a7af35e --- /dev/null +++ b/gps/utils/LocSharedLock.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2015, 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. + * + */ +#ifndef __LOC_SHARED_LOCK__ +#define __LOC_SHARED_LOCK__ + +#include <stddef.h> +#ifndef FEATURE_EXTERNAL_AP +#include <cutils/atomic.h> +#endif /* FEATURE_EXTERNAL_AP */ +#include <pthread.h> + +#ifdef FEATURE_EXTERNAL_AP +#include <atomic> + +inline int32_t android_atomic_inc(volatile int32_t *addr) +{ + volatile std::atomic_int_least32_t* a = (volatile std::atomic_int_least32_t*)addr; + return std::atomic_fetch_add_explicit(a, 1, std::memory_order_release); +} + +inline int32_t android_atomic_dec(volatile int32_t *addr) +{ + volatile std::atomic_int_least32_t* a = (volatile std::atomic_int_least32_t*)addr; + return std::atomic_fetch_sub_explicit(a, 1, std::memory_order_release); +} + +#endif /* FEATURE_EXTERNAL_AP */ + // This is a utility created for use cases such that there are more than +// one client who need to share the same lock, but it is not predictable +// which of these clients is to last to go away. This shared lock deletes +// itself when the last client calls its drop() method. To add a cient, +// this share lock's share() method has to be called, so that the obj +// can maintain an accurate client count. +class LocSharedLock { + volatile int32_t mRef; + pthread_mutex_t mMutex; + inline ~LocSharedLock() { pthread_mutex_destroy(&mMutex); } +public: + // first client to create this LockSharedLock + inline LocSharedLock() : mRef(1) { pthread_mutex_init(&mMutex, NULL); } + // following client(s) are to *share()* this lock created by the first client + inline LocSharedLock* share() { android_atomic_inc(&mRef); return this; } + // whe a client no longer needs this shared lock, drop() shall be called. + inline void drop() { if (1 == android_atomic_dec(&mRef)) delete this; } + // locking the lock to enter critical section + inline void lock() { pthread_mutex_lock(&mMutex); } + // unlocking the lock to leave the critical section + inline void unlock() { pthread_mutex_unlock(&mMutex); } +}; + +#endif //__LOC_SHARED_LOCK__ diff --git a/gps/utils/LocThread.cpp b/gps/utils/LocThread.cpp new file mode 100644 index 0000000..568a6bb --- /dev/null +++ b/gps/utils/LocThread.cpp @@ -0,0 +1,266 @@ +/* Copyright (c) 2015, 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. + * + */ +#include <LocThread.h> +#include <string.h> +#include <pthread.h> +#include <loc_pla.h> + +class LocThreadDelegate { + LocRunnable* mRunnable; + bool mJoinable; + pthread_t mThandle; + pthread_mutex_t mMutex; + int mRefCount; + ~LocThreadDelegate(); + LocThreadDelegate(LocThread::tCreate creator, const char* threadName, + LocRunnable* runnable, bool joinable); + void destroy(); +public: + static LocThreadDelegate* create(LocThread::tCreate creator, + const char* threadName, LocRunnable* runnable, bool joinable); + void stop(); + // bye() is for the parent thread to go away. if joinable, + // parent must stop the spawned thread, join, and then + // destroy(); if detached, the parent can go straight + // ahead to destroy() + inline void bye() { mJoinable ? stop() : destroy(); } + inline bool isRunning() { return (NULL != mRunnable); } + static void* threadMain(void* arg); +}; + +// it is important to note that internal members must be +// initialized to values as if pthread_create succeeds. +// This is to avoid the race condition between the threads, +// once the thread is created, some of these values will +// be check in the spawned thread, and must set correctly +// then and there. +// However, upon pthread_create failure, the data members +// must be set to indicate failure, e.g. mRunnable, and +// threashold approprietly for destroy(), e.g. mRefCount. +LocThreadDelegate::LocThreadDelegate(LocThread::tCreate creator, + const char* threadName, LocRunnable* runnable, bool joinable) : + mRunnable(runnable), mJoinable(joinable), mThandle((pthread_t)NULL), + mMutex(PTHREAD_MUTEX_INITIALIZER), mRefCount(2) { + + // set up thread name, if nothing is passed in + if (!threadName) { + threadName = "LocThread"; + } + + // create the thread here, then if successful + // and a name is given, we set the thread name + if (creator) { + mThandle = creator(threadName, threadMain, this); + } else if (pthread_create(&mThandle, NULL, threadMain, this)) { + // pthread_create() failed + mThandle = (pthread_t)NULL; + } + + if (mThandle) { + // set thread name + char lname[16]; + int len = (sizeof(lname) > (strlen(threadName) + 1)) ? + (strlen(threadName)):(sizeof(lname) - 1); + memcpy(lname, threadName, len); + lname[len] = 0; + // set the thread name here + pthread_setname_np(mThandle, lname); + + // detach, if not joinable + if (!joinable) { + pthread_detach(mThandle); + } + } else { + // must set these values upon failure + mRunnable = NULL; + mJoinable = false; + mRefCount = 1; + } +} + +inline +LocThreadDelegate::~LocThreadDelegate() { + // at this point nothing should need done any more +} + +// factory method so that we could return NULL upon failure +LocThreadDelegate* LocThreadDelegate::create(LocThread::tCreate creator, + const char* threadName, LocRunnable* runnable, bool joinable) { + LocThreadDelegate* thread = NULL; + if (runnable) { + thread = new LocThreadDelegate(creator, threadName, runnable, joinable); + if (thread && !thread->isRunning()) { + thread->destroy(); + thread = NULL; + } + } + + return thread; +} + +// The order is importang +// NULLing mRunnalbe stops the while loop in threadMain() +// join() if mJoinble must come before destroy() call, as +// the obj must remain alive at this time so that mThandle +// remains valud. +void LocThreadDelegate::stop() { + // mRunnable and mJoinable are reset on different triggers. + // mRunnable may get nulled on the spawned thread's way out; + // or here. + // mJouinable (if ever been true) gets falsed when client + // thread triggers stop, with either a stop() + // call or the client releases thread obj handle. + if (mRunnable) { + mRunnable = NULL; + } + if (mJoinable) { + mJoinable = false; + pthread_join(mThandle, NULL); + } + // call destroy() to possibly delete the obj + destroy(); +} + +// method for clients to call to release the obj +// when it is a detached thread, the client thread +// and the spawned thread can both try to destroy() +// asynchronously. And we delete this obj when +// mRefCount becomes 0. +void LocThreadDelegate::destroy() { + // else case shouldn't happen, unless there is a + // leaking obj. But only our code here has such + // obj, so if we test our code well, else case + // will never happen + if (mRefCount > 0) { + // we need a flag on the stack + bool callDelete = false; + + // critical section between threads + pthread_mutex_lock(&mMutex); + // last destroy() call + callDelete = (1 == mRefCount--); + pthread_mutex_unlock(&mMutex); + + // upon last destroy() call we delete this obj + if (callDelete) { + delete this; + } + } +} + +void* LocThreadDelegate::threadMain(void* arg) { + LocThreadDelegate* locThread = (LocThreadDelegate*)(arg); + + if (locThread) { + LocRunnable* runnable = locThread->mRunnable; + + if (runnable) { + if (locThread->isRunning()) { + runnable->prerun(); + } + + while (locThread->isRunning() && runnable->run()); + + if (locThread->isRunning()) { + runnable->postrun(); + } + + // at this time, locThread->mRunnable may or may not be NULL + // NULL it just to be safe and clean, as we want the field + // in the released memory slot to be NULL. + locThread->mRunnable = NULL; + delete runnable; + } + locThread->destroy(); + } + + return NULL; +} + +LocThread::~LocThread() { + if (mThread) { + mThread->bye(); + mThread = NULL; + } +} + +bool LocThread::start(tCreate creator, const char* threadName, LocRunnable* runnable, bool joinable) { + bool success = false; + if (!mThread) { + mThread = LocThreadDelegate::create(creator, threadName, runnable, joinable); + // true only if thread is created successfully + success = (NULL != mThread); + } + return success; +} + +void LocThread::stop() { + if (mThread) { + mThread->stop(); + mThread = NULL; + } +} + +#ifdef __LOC_DEBUG__ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +class LocRunnableTest1 : public LocRunnable { + int mID; +public: + LocRunnableTest1(int id) : LocRunnable(), mID(id) {} + virtual bool run() { + printf("LocRunnableTest1: %d\n", mID++); + sleep(1); + return true; + } +}; + +// on linux command line: +// compile: g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -std=c++0x -I. -I../../../../vendor/qcom/proprietary/gps-internal/unit-tests/fakes_for_host -I../../../../system/core/include -lpthread LocThread.cpp +// test detached thread: valgrind ./a.out 0 +// test joinable thread: valgrind ./a.out 1 +int main(int argc, char** argv) { + LocRunnableTest1 test(10); + + LocThread thread; + thread.start("LocThreadTest", test, atoi(argv[1])); + + sleep(10); + + thread.stop(); + + sleep(5); + + return 0; +} + +#endif diff --git a/gps/utils/LocThread.h b/gps/utils/LocThread.h new file mode 100644 index 0000000..2a65d8f --- /dev/null +++ b/gps/utils/LocThread.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2015, 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. + * + */ +#ifndef __LOC_THREAD__ +#define __LOC_THREAD__ + +#include <stddef.h> +#include <pthread.h> + +// abstract class to be implemented by client to provide a runnable class +// which gets scheduled by LocThread +class LocRunnable { +public: + inline LocRunnable() {} + inline virtual ~LocRunnable() {} + + // The method to be implemented by thread clients + // and be scheduled by LocThread + // This method will be repeated called until it returns false; or + // until thread is stopped. + virtual bool run() = 0; + + // The method to be run before thread loop (conditionally repeatedly) + // calls run() + inline virtual void prerun() {} + + // The method to be run after thread loop (conditionally repeatedly) + // calls run() + inline virtual void postrun() {} +}; + +// opaque class to provide service implementation. +class LocThreadDelegate; + +// A utility class to create a thread and run LocRunnable +// caller passes in. +class LocThread { + LocThreadDelegate* mThread; +public: + inline LocThread() : mThread(NULL) {} + virtual ~LocThread(); + + typedef pthread_t (*tCreate)(const char* name, void* (*start)(void*), void* arg); + // client starts thread with a runnable, which implements + // the logics to fun in the created thread context. + // The thread could be either joinable or detached. + // runnable is an obj managed by client. Client creates and + // frees it (but must be after stop() is called, or + // this LocThread obj is deleted). + // The obj will be deleted by LocThread if start() + // returns true. Else it is client's responsibility + // to delete the object + // Returns 0 if success; false if failure. + bool start(tCreate creator, const char* threadName, LocRunnable* runnable, bool joinable = true); + inline bool start(const char* threadName, LocRunnable* runnable, bool joinable = true) { + return start(NULL, threadName, runnable, joinable); + } + + // NOTE: if this is a joinable thread, this stop may block + // for a while until the thread is joined. + void stop(); + + // thread status check + inline bool isRunning() { return NULL != mThread; } +}; + +#endif //__LOC_THREAD__ diff --git a/gps/utils/LocTimer.cpp b/gps/utils/LocTimer.cpp new file mode 100644 index 0000000..93775d0 --- /dev/null +++ b/gps/utils/LocTimer.cpp @@ -0,0 +1,753 @@ +/* Copyright (c) 2015, 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. + * + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <errno.h> +#include <sys/timerfd.h> +#include <sys/epoll.h> +#include <log_util.h> +#include <loc_timer.h> +#include <LocTimer.h> +#include <LocHeap.h> +#include <LocThread.h> +#include <LocSharedLock.h> +#include <MsgTask.h> + +#ifdef __HOST_UNIT_TEST__ +#define EPOLLWAKEUP 0 +#define CLOCK_BOOTTIME CLOCK_MONOTONIC +#define CLOCK_BOOTTIME_ALARM CLOCK_MONOTONIC +#endif + +/* +There are implementations of 5 classes in this file: +LocTimer, LocTimerDelegate, LocTimerContainer, LocTimerPollTask, LocTimerWrapper + +LocTimer - client front end, interface for client to start / stop timers, also + to provide a callback. +LocTimerDelegate - an internal timer entity, which also is a LocRankable obj. + Its life cycle is different than that of LocTimer. It gets + created when LocTimer::start() is called, and gets deleted + when it expires or clients calls the hosting LocTimer obj's + stop() method. When a LocTimerDelegate obj is ticking, it + stays in the corresponding LocTimerContainer. When expired + or stopped, the obj is removed from the container. Since it + is also a LocRankable obj, and LocTimerContainer also is a + heap, its ranks() implementation decides where it is placed + in the heap. +LocTimerContainer - core of the timer service. It is a container (derived from + LocHeap) for LocTimerDelegate (implements LocRankable) objs. + There are 2 of such containers, one for sw timers (or Linux + timers) one for hw timers (or Linux alarms). It adds one of + each (those that expire the soonest) to kernel via services + provided by LocTimerPollTask. All the heap management on the + LocTimerDelegate objs are done in the MsgTask context, such + that synchronization is ensured. +LocTimerPollTask - is a class that wraps timerfd and epoll POXIS APIs. It also + both implements LocRunnalbe with epoll_wait() in the run() + method. It is also a LocThread client, so as to loop the run + method. +LocTimerWrapper - a LocTimer client itself, to implement the existing C API with + APIs, loc_timer_start() and loc_timer_stop(). + +*/ + +class LocTimerPollTask; + +// This is a multi-functaional class that: +// * extends the LocHeap class for the detection of head update upon add / remove +// events. When that happens, soonest time out changes, so timerfd needs update. +// * contains the timers, and add / remove them into the heap +// * provides and maps 2 of such containers, one for timers (or mSwTimers), one +// for alarms (or mHwTimers); +// * provides a polling thread; +// * provides a MsgTask thread for synchronized add / remove / timer client callback. +class LocTimerContainer : public LocHeap { + // mutex to synchronize getters of static members + static pthread_mutex_t mMutex; + // Container of timers + static LocTimerContainer* mSwTimers; + // Container of alarms + static LocTimerContainer* mHwTimers; + // Msg task to provider msg Q, sender and reader. + static MsgTask* mMsgTask; + // Poll task to provide epoll call and threading to poll. + static LocTimerPollTask* mPollTask; + // timer / alarm fd + int mDevFd; + // ctor + LocTimerContainer(bool wakeOnExpire); + // dtor + ~LocTimerContainer(); + static MsgTask* getMsgTaskLocked(); + static LocTimerPollTask* getPollTaskLocked(); + // extend LocHeap and pop if the top outRanks input + LocTimerDelegate* popIfOutRanks(LocTimerDelegate& timer); + // update the timer POSIX calls with updated soonest timer spec + void updateSoonestTime(LocTimerDelegate* priorTop); + +public: + // factory method to control the creation of mSwTimers / mHwTimers + static LocTimerContainer* get(bool wakeOnExpire); + + LocTimerDelegate* getSoonestTimer(); + int getTimerFd(); + // add a timer / alarm obj into the container + void add(LocTimerDelegate& timer); + // remove a timer / alarm obj from the container + void remove(LocTimerDelegate& timer); + // handling of timer / alarm expiration + void expire(); +}; + +// This class implements the polling thread that epolls imer / alarm fds. +// The LocRunnable::run() contains the actual polling. The other methods +// will be run in the caller's thread context to add / remove timer / alarm +// fds the kernel, while the polling is blocked on epoll_wait() call. +// Since the design is that we have maximally 2 polls, one for all the +// timers; one for all the alarms, we will poll at most on 2 fds. But it +// is possile that all we have are only timers or alarms at one time, so we +// allow dynamically add / remove fds we poll on. The design decision of +// having 1 fd per container of timer / alarm is such that, we may not need +// to make a system call each time a timer / alarm is added / removed, unless +// that changes the "soonest" time out of that of all the timers / alarms. +class LocTimerPollTask : public LocRunnable { + // the epoll fd + const int mFd; + // the thread that calls run() method + LocThread* mThread; + friend class LocThreadDelegate; + // dtor + ~LocTimerPollTask(); +public: + // ctor + LocTimerPollTask(); + // this obj will be deleted once thread is deleted + void destroy(); + // add a container of timers. Each contain has a unique device fd, i.e. + // either timer or alarm fd, and a heap of timers / alarms. It is expected + // that container would have written to the device fd with the soonest + // time out value in the heap at the time of calling this method. So all + // this method does is to add the fd of the input container to the poll + // and also add the pointer of the container to the event data ptr, such + // when poll_wait wakes up on events, we know who is the owner of the fd. + void addPoll(LocTimerContainer& timerContainer); + // remove a fd that is assciated with a container. The expectation is that + // the atual timer would have been removed from the container. + void removePoll(LocTimerContainer& timerContainer); + // The polling thread context will call this method. This is where + // epoll_wait() is blocking and waiting for events.. + virtual bool run(); +}; + +// Internal class of timer obj. It gets born when client calls LocTimer::start(); +// and gets deleted when client calls LocTimer::stop() or when the it expire()'s. +// This class implements LocRankable::ranks() so that when an obj is added into +// the container (of LocHeap), it gets placed in sorted order. +class LocTimerDelegate : public LocRankable { + friend class LocTimerContainer; + friend class LocTimer; + LocTimer* mClient; + LocSharedLock* mLock; + struct timespec mFutureTime; + LocTimerContainer* mContainer; + // not a complete obj, just ctor for LocRankable comparisons + inline LocTimerDelegate(struct timespec& delay) + : mClient(NULL), mLock(NULL), mFutureTime(delay), mContainer(NULL) {} + inline ~LocTimerDelegate() { if (mLock) { mLock->drop(); mLock = NULL; } } +public: + LocTimerDelegate(LocTimer& client, struct timespec& futureTime, LocTimerContainer* container); + void destroyLocked(); + // LocRankable virtual method + virtual int ranks(LocRankable& rankable); + void expire(); + inline struct timespec getFutureTime() { return mFutureTime; } +}; + +/***************************LocTimerContainer methods***************************/ + +// Most of these static recources are created on demand. They however are never +// destoyed. The theory is that there are processes that link to this util lib +// but never use timer, then these resources would never need to be created. +// For those processes that do use timer, it will likely also need to every +// once in a while. It might be cheaper keeping them around. +pthread_mutex_t LocTimerContainer::mMutex = PTHREAD_MUTEX_INITIALIZER; +LocTimerContainer* LocTimerContainer::mSwTimers = NULL; +LocTimerContainer* LocTimerContainer::mHwTimers = NULL; +MsgTask* LocTimerContainer::mMsgTask = NULL; +LocTimerPollTask* LocTimerContainer::mPollTask = NULL; + +// ctor - initialize timer heaps +// A container for swTimer (timer) is created, when wakeOnExpire is true; or +// HwTimer (alarm), when wakeOnExpire is false. +LocTimerContainer::LocTimerContainer(bool wakeOnExpire) : + mDevFd(timerfd_create(wakeOnExpire ? CLOCK_BOOTTIME_ALARM : CLOCK_BOOTTIME, 0)) { + + if ((-1 == mDevFd) && (errno == EINVAL)) { + LOC_LOGW("%s: timerfd_create failure, fallback to CLOCK_MONOTONIC - %s", + __FUNCTION__, strerror(errno)); + mDevFd = timerfd_create(CLOCK_MONOTONIC, 0); + } + + if (-1 != mDevFd) { + // ensure we have the necessary resources created + LocTimerContainer::getPollTaskLocked(); + LocTimerContainer::getMsgTaskLocked(); + } else { + LOC_LOGE("%s: timerfd_create failure - %s", __FUNCTION__, strerror(errno)); + } +} + +// dtor +// we do not ever destroy the static resources. +inline +LocTimerContainer::~LocTimerContainer() { + close(mDevFd); +} + +LocTimerContainer* LocTimerContainer::get(bool wakeOnExpire) { + // get the reference of either mHwTimer or mSwTimers per wakeOnExpire + LocTimerContainer*& container = wakeOnExpire ? mHwTimers : mSwTimers; + // it is cheap to check pointer first than locking mutext unconditionally + if (!container) { + pthread_mutex_lock(&mMutex); + // let's check one more time to be safe + if (!container) { + container = new LocTimerContainer(wakeOnExpire); + // timerfd_create failure + if (-1 == container->getTimerFd()) { + delete container; + container = NULL; + } + } + pthread_mutex_unlock(&mMutex); + } + return container; +} + +MsgTask* LocTimerContainer::getMsgTaskLocked() { + // it is cheap to check pointer first than locking mutext unconditionally + if (!mMsgTask) { + mMsgTask = new MsgTask("LocTimerMsgTask", false); + } + return mMsgTask; +} + +LocTimerPollTask* LocTimerContainer::getPollTaskLocked() { + // it is cheap to check pointer first than locking mutext unconditionally + if (!mPollTask) { + mPollTask = new LocTimerPollTask(); + } + return mPollTask; +} + +inline +LocTimerDelegate* LocTimerContainer::getSoonestTimer() { + return (LocTimerDelegate*)(peek()); +} + +inline +int LocTimerContainer::getTimerFd() { + return mDevFd; +} + +void LocTimerContainer::updateSoonestTime(LocTimerDelegate* priorTop) { + LocTimerDelegate* curTop = getSoonestTimer(); + + // check if top has changed + if (curTop != priorTop) { + struct itimerspec delay; + memset(&delay, 0, sizeof(struct itimerspec)); + bool toSetTime = false; + // if tree is empty now, we remove poll and disarm timer + if (!curTop) { + mPollTask->removePoll(*this); + // setting the values to disarm timer + delay.it_value.tv_sec = 0; + delay.it_value.tv_nsec = 0; + toSetTime = true; + } else if (!priorTop || curTop->outRanks(*priorTop)) { + // do this first to avoid race condition, in case settime is called + // with too small an interval + mPollTask->addPoll(*this); + delay.it_value = curTop->getFutureTime(); + toSetTime = true; + } + if (toSetTime) { + timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL); + } + } +} + +// all the heap management is done in the MsgTask context. +inline +void LocTimerContainer::add(LocTimerDelegate& timer) { + struct MsgTimerPush : public LocMsg { + LocTimerContainer* mTimerContainer; + LocHeapNode* mTree; + LocTimerDelegate* mTimer; + inline MsgTimerPush(LocTimerContainer& container, LocTimerDelegate& timer) : + LocMsg(), mTimerContainer(&container), mTimer(&timer) {} + inline virtual void proc() const { + LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer(); + mTimerContainer->push((LocRankable&)(*mTimer)); + mTimerContainer->updateSoonestTime(priorTop); + } + }; + + mMsgTask->sendMsg(new MsgTimerPush(*this, timer)); +} + +// all the heap management is done in the MsgTask context. +void LocTimerContainer::remove(LocTimerDelegate& timer) { + struct MsgTimerRemove : public LocMsg { + LocTimerContainer* mTimerContainer; + LocTimerDelegate* mTimer; + inline MsgTimerRemove(LocTimerContainer& container, LocTimerDelegate& timer) : + LocMsg(), mTimerContainer(&container), mTimer(&timer) {} + inline virtual void proc() const { + LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer(); + + // update soonest timer only if mTimer is actually removed from + // mTimerContainer AND mTimer is not priorTop. + if (priorTop == ((LocHeap*)mTimerContainer)->remove((LocRankable&)*mTimer)) { + // if passing in NULL, we tell updateSoonestTime to update + // kernel with the current top timer interval. + mTimerContainer->updateSoonestTime(NULL); + } + // all timers are deleted here, and only here. + delete mTimer; + } + }; + + mMsgTask->sendMsg(new MsgTimerRemove(*this, timer)); +} + +// all the heap management is done in the MsgTask context. +// Upon expire, we check and continuously pop the heap until +// the top node's timeout is in the future. +void LocTimerContainer::expire() { + struct MsgTimerExpire : public LocMsg { + LocTimerContainer* mTimerContainer; + inline MsgTimerExpire(LocTimerContainer& container) : + LocMsg(), mTimerContainer(&container) {} + inline virtual void proc() const { + struct timespec now; + // get time spec of now + clock_gettime(CLOCK_BOOTTIME, &now); + LocTimerDelegate timerOfNow(now); + // pop everything in the heap that outRanks now, i.e. has time older than now + // and then call expire() on that timer. + for (LocTimerDelegate* timer = (LocTimerDelegate*)mTimerContainer->pop(); + NULL != timer; + timer = mTimerContainer->popIfOutRanks(timerOfNow)) { + // the timer delegate obj will be deleted before the return of this call + timer->expire(); + } + mTimerContainer->updateSoonestTime(NULL); + } + }; + + struct itimerspec delay; + memset(&delay, 0, sizeof(struct itimerspec)); + timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL); + mPollTask->removePoll(*this); + mMsgTask->sendMsg(new MsgTimerExpire(*this)); +} + +LocTimerDelegate* LocTimerContainer::popIfOutRanks(LocTimerDelegate& timer) { + LocTimerDelegate* poppedNode = NULL; + if (mTree && !timer.outRanks(*peek())) { + poppedNode = (LocTimerDelegate*)(pop()); + } + + return poppedNode; +} + + +/***************************LocTimerPollTask methods***************************/ + +inline +LocTimerPollTask::LocTimerPollTask() + : mFd(epoll_create(2)), mThread(new LocThread()) { + // before a next call returens, a thread will be created. The run() method + // could already be running in parallel. Also, since each of the objs + // creates a thread, the container will make sure that there will be only + // one of such obj for our timer implementation. + if (!mThread->start("LocTimerPollTask", this)) { + delete mThread; + mThread = NULL; + } +} + +inline +LocTimerPollTask::~LocTimerPollTask() { + // when fs is closed, epoll_wait() should fail run() should return false + // and the spawned thread should exit. + close(mFd); +} + +void LocTimerPollTask::destroy() { + if (mThread) { + LocThread* thread = mThread; + mThread = NULL; + delete thread; + } else { + delete this; + } +} + +void LocTimerPollTask::addPoll(LocTimerContainer& timerContainer) { + struct epoll_event ev; + memset(&ev, 0, sizeof(ev)); + + ev.events = EPOLLIN | EPOLLWAKEUP; + ev.data.fd = timerContainer.getTimerFd(); + // it is important that we set this context pointer with the input + // timer container this is how we know which container should handle + // which expiration. + ev.data.ptr = &timerContainer; + + epoll_ctl(mFd, EPOLL_CTL_ADD, timerContainer.getTimerFd(), &ev); +} + +inline +void LocTimerPollTask::removePoll(LocTimerContainer& timerContainer) { + epoll_ctl(mFd, EPOLL_CTL_DEL, timerContainer.getTimerFd(), NULL); +} + +// The polling thread context will call this method. If run() method needs to +// be repetitvely called, it must return true from the previous call. +bool LocTimerPollTask::run() { + struct epoll_event ev[2]; + + // we have max 2 descriptors to poll from + int fds = epoll_wait(mFd, ev, 2, -1); + + // we pretty much want to continually poll until the fd is closed + bool rerun = (fds > 0) || (errno == EINTR); + + if (fds > 0) { + // we may have 2 events + for (int i = 0; i < fds; i++) { + // each fd has a context pointer associated with the right timer container + LocTimerContainer* container = (LocTimerContainer*)(ev[i].data.ptr); + if (container) { + container->expire(); + } else { + epoll_ctl(mFd, EPOLL_CTL_DEL, ev[i].data.fd, NULL); + } + } + } + + // if rerun is true, we are requesting to be scheduled again + return rerun; +} + +/***************************LocTimerDelegate methods***************************/ + +inline +LocTimerDelegate::LocTimerDelegate(LocTimer& client, + struct timespec& futureTime, + LocTimerContainer* container) + : mClient(&client), + mLock(mClient->mLock->share()), + mFutureTime(futureTime), + mContainer(container) { + // adding the timer into the container + mContainer->add(*this); +} + +inline +void LocTimerDelegate::destroyLocked() { + // client handle will likely be deleted soon after this + // method returns. Nulling this handle so that expire() + // won't call the callback on the dead handle any more. + mClient = NULL; + + if (mContainer) { + LocTimerContainer* container = mContainer; + mContainer = NULL; + if (container) { + container->remove(*this); + } + } // else we do not do anything. No such *this* can be + // created and reached here with mContainer ever been + // a non NULL. So *this* must have reached the if clause + // once, and we want it reach there only once. +} + +int LocTimerDelegate::ranks(LocRankable& rankable) { + int rank = -1; + LocTimerDelegate* timer = (LocTimerDelegate*)(&rankable); + if (timer) { + // larger time ranks lower!!! + // IOW, if input obj has bigger tv_sec/tv_nsec, this obj outRanks higher + rank = timer->mFutureTime.tv_sec - mFutureTime.tv_sec; + if(0 == rank) + { + //rank against tv_nsec for msec accuracy + rank = (int)(timer->mFutureTime.tv_nsec - mFutureTime.tv_nsec); + } + } + return rank; +} + +inline +void LocTimerDelegate::expire() { + // keeping a copy of client pointer to be safe + // when timeOutCallback() is called at the end of this + // method, *this* obj may be already deleted. + LocTimer* client = mClient; + // force a stop, which will lead to delete of this obj + if (client && client->stop()) { + // calling client callback with a pointer save on the stack + // only if stop() returns true, i.e. it hasn't been stopped + // already. + client->timeOutCallback(); + } +} + + +/***************************LocTimer methods***************************/ +LocTimer::LocTimer() : mTimer(NULL), mLock(new LocSharedLock()) { +} + +LocTimer::~LocTimer() { + stop(); + if (mLock) { + mLock->drop(); + mLock = NULL; + } +} + +bool LocTimer::start(unsigned int timeOutInMs, bool wakeOnExpire) { + bool success = false; + mLock->lock(); + if (!mTimer) { + struct timespec futureTime; + clock_gettime(CLOCK_BOOTTIME, &futureTime); + futureTime.tv_sec += timeOutInMs / 1000; + futureTime.tv_nsec += (timeOutInMs % 1000) * 1000000; + if (futureTime.tv_nsec >= 1000000000) { + futureTime.tv_sec += futureTime.tv_nsec / 1000000000; + futureTime.tv_nsec %= 1000000000; + } + + LocTimerContainer* container; + container = LocTimerContainer::get(wakeOnExpire); + if (NULL != container) { + mTimer = new LocTimerDelegate(*this, futureTime, container); + // if mTimer is non 0, success should be 0; or vice versa + } + success = (NULL != mTimer); + } + mLock->unlock(); + return success; +} + +bool LocTimer::stop() { + bool success = false; + mLock->lock(); + if (mTimer) { + LocTimerDelegate* timer = mTimer; + mTimer = NULL; + if (timer) { + timer->destroyLocked(); + success = true; + } + } + mLock->unlock(); + return success; +} + +/***************************LocTimerWrapper methods***************************/ +////////////////////////////////////////////////////////////////////////// +// This section below wraps for the C style APIs +////////////////////////////////////////////////////////////////////////// +class LocTimerWrapper : public LocTimer { + loc_timer_callback mCb; + void* mCallerData; + LocTimerWrapper* mMe; + static pthread_mutex_t mMutex; + inline ~LocTimerWrapper() { mCb = NULL; mMe = NULL; } +public: + inline LocTimerWrapper(loc_timer_callback cb, void* callerData) : + mCb(cb), mCallerData(callerData), mMe(this) { + } + void destroy() { + pthread_mutex_lock(&mMutex); + if (NULL != mCb && this == mMe) { + delete this; + } + pthread_mutex_unlock(&mMutex); + } + virtual void timeOutCallback() { + loc_timer_callback cb = mCb; + void* callerData = mCallerData; + if (cb) { + cb(callerData, 0); + } + destroy(); + } +}; + +pthread_mutex_t LocTimerWrapper::mMutex = PTHREAD_MUTEX_INITIALIZER; + +void* loc_timer_start(uint64_t msec, loc_timer_callback cb_func, + void *caller_data, bool wake_on_expire) +{ + LocTimerWrapper* locTimerWrapper = NULL; + + if (cb_func) { + locTimerWrapper = new LocTimerWrapper(cb_func, caller_data); + + if (locTimerWrapper) { + locTimerWrapper->start(msec, wake_on_expire); + } + } + + return locTimerWrapper; +} + +void loc_timer_stop(void*& handle) +{ + if (handle) { + LocTimerWrapper* locTimerWrapper = (LocTimerWrapper*)(handle); + locTimerWrapper->destroy(); + handle = NULL; + } +} + +////////////////////////////////////////////////////////////////////////// +// This section above wraps for the C style APIs +////////////////////////////////////////////////////////////////////////// + +#ifdef __LOC_DEBUG__ + +double getDeltaSeconds(struct timespec from, struct timespec to) { + return (double)to.tv_sec + (double)to.tv_nsec / 1000000000 + - from.tv_sec - (double)from.tv_nsec / 1000000000; +} + +struct timespec getNow() { + struct timespec now; + clock_gettime(CLOCK_BOOTTIME, &now); + return now; +} + +class LocTimerTest : public LocTimer, public LocRankable { + int mTimeOut; + const struct timespec mTimeOfBirth; + inline struct timespec getTimerWrapper(int timeout) { + struct timespec now; + clock_gettime(CLOCK_BOOTTIME, &now); + now.tv_sec += timeout; + return now; + } +public: + inline LocTimerTest(int timeout) : LocTimer(), LocRankable(), + mTimeOut(timeout), mTimeOfBirth(getTimerWrapper(0)) {} + inline virtual int ranks(LocRankable& rankable) { + LocTimerTest* timer = dynamic_cast<LocTimerTest*>(&rankable); + return timer->mTimeOut - mTimeOut; + } + inline virtual void timeOutCallback() { + printf("timeOutCallback() - "); + deviation(); + } + double deviation() { + struct timespec now = getTimerWrapper(0); + double delta = getDeltaSeconds(mTimeOfBirth, now); + printf("%lf: %lf\n", delta, delta * 100 / mTimeOut); + return delta / mTimeOut; + } +}; + +// For Linux command line testing: +// compilation: +// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../system/core/include -o LocHeap.o LocHeap.cpp +// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -std=c++0x -I. -I../../../../system/core/include -lpthread -o LocThread.o LocThread.cpp +// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../system/core/include -o LocTimer.o LocTimer.cpp +int main(int argc, char** argv) { + struct timespec timeOfStart=getNow(); + srand(time(NULL)); + int tries = atoi(argv[1]); + int checks = tries >> 3; + LocTimerTest** timerArray = new LocTimerTest*[tries]; + memset(timerArray, NULL, tries); + + for (int i = 0; i < tries; i++) { + int r = rand() % tries; + LocTimerTest* timer = new LocTimerTest(r); + if (timerArray[r]) { + if (!timer->stop()) { + printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); + printf("ERRER: %dth timer, id %d, not running when it should be\n", i, r); + exit(0); + } else { + printf("stop() - %d\n", r); + delete timer; + timerArray[r] = NULL; + } + } else { + if (!timer->start(r, false)) { + printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); + printf("ERRER: %dth timer, id %d, running when it should not be\n", i, r); + exit(0); + } else { + printf("stop() - %d\n", r); + timerArray[r] = timer; + } + } + } + + for (int i = 0; i < tries; i++) { + if (timerArray[i]) { + if (!timerArray[i]->stop()) { + printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow())); + printf("ERRER: %dth timer, not running when it should be\n", i); + exit(0); + } else { + printf("stop() - %d\n", i); + delete timerArray[i]; + timerArray[i] = NULL; + } + } + } + + delete[] timerArray; + + return 0; +} + +#endif diff --git a/gps/utils/LocTimer.h b/gps/utils/LocTimer.h new file mode 100644 index 0000000..abc7f64 --- /dev/null +++ b/gps/utils/LocTimer.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2015, 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. + * + */ + +#ifndef __LOC_TIMER_CPP_H__ +#define __LOC_TIMER_CPP_H__ + +#include <stddef.h> +#include <loc_pla.h> + +// opaque class to provide service implementation. +class LocTimerDelegate; +class LocSharedLock; + +// LocTimer client must extend this class and implementthe callback. +// start() / stop() methods are to arm / disarm timer. +class LocTimer +{ + LocTimerDelegate* mTimer; + LocSharedLock* mLock; + // don't really want mLock to be manipulated by clients, yet LocTimer + // has to have a reference to the lock so that the delete of LocTimer + // and LocTimerDelegate can work together on their share resources. + friend class LocTimerDelegate; + +public: + LocTimer(); + virtual ~LocTimer(); + + // timeOutInMs: timeout delay in ms + // wakeOnExpire: true if to wake up CPU (if sleeping) upon timer + // expiration and notify the client. + // false if to wait until next time CPU wakes up (if + // sleeping) and then notify the client. + // return: true on success; + // false on failure, e.g. timer is already running. + bool start(uint32_t timeOutInMs, bool wakeOnExpire); + + // return: true on success; + // false on failure, e.g. timer is not running. + bool stop(); + + // LocTimer client Should implement this method. + // This method is used for timeout calling back to client. This method + // should be short enough (eg: send a message to your own thread). + virtual void timeOutCallback() = 0; +}; + +#endif //__LOC_DELAY_H__ diff --git a/gps/utils/LocUnorderedSetMap.h b/gps/utils/LocUnorderedSetMap.h new file mode 100644 index 0000000..8748134 --- /dev/null +++ b/gps/utils/LocUnorderedSetMap.h @@ -0,0 +1,192 @@ +/* Copyright (c) 2015, 2017 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. + * + */ +#ifndef __LOC_UNORDERDED_SETMAP_H__ +#define __LOC_UNORDERDED_SETMAP_H__ + +#include <algorithm> +#include <unordered_set> +#include <unordered_map> + +using std::unordered_set; +using std::unordered_map; + +namespace loc_util { + +// Trim from *fromSet* any elements that also exist in *rVals*. +// The optional *goneVals*, if not null, will be populated with removed elements. +template <typename T> +inline static void trimSet(unordered_set<T>& fromSet, const unordered_set<T>& rVals, + unordered_set<T>* goneVals) { + for (auto val : rVals) { + if (fromSet.erase(val) > 0 && nullptr != goneVals) { + goneVals->insert(val); + } + } +} + +// this method is destructive to the input unordered_sets. +// the return set is the interset extracted out from the two input sets, *s1* and *s2*. +// *s1* and *s2* will be left with the intersect removed from them. +template <typename T> +static unordered_set<T> removeAndReturnInterset(unordered_set<T>& s1, unordered_set<T>& s2) { + unordered_set<T> common(0); + for (auto b = s2.begin(); b != s2.end(); b++) { + auto a = find(s1.begin(), s1.end(), *b); + if (a != s1.end()) { + // this is a common item of both l1 and l2, remove from both + // but after we add to common + common.insert(*a); + s1.erase(a); + s2.erase(b); + } + } + return common; +} + +template <typename KEY, typename VAL> +class LocUnorderedSetMap { + unordered_map<KEY, unordered_set<VAL>> mMap; + + + // Trim the VALs pointed to by *iter*, with everything that also exist in *rVals*. + // If the set becomes empty, remove the map entry. *goneVals*, if not null, records + // the trimmed VALs. + bool trimOrRemove(typename unordered_map<KEY, unordered_set<VAL>>::iterator iter, + const unordered_set<VAL>& rVals, unordered_set<VAL>* goneVals) { + trimSet<VAL>(iter->second, rVals, goneVals); + bool removeEntry = (iter->second.empty()); + if (removeEntry) { + mMap.erase(iter); + } + return removeEntry; + } + +public: + inline LocUnorderedSetMap() {} + inline LocUnorderedSetMap(size_t size) : mMap(size) {} + + inline bool empty() { return mMap.empty(); } + + // This gets the raw pointer to the VALs pointed to by *key* + // If the entry is not in the map, nullptr will be returned. + inline unordered_set<VAL>* getValSetPtr(const KEY& key) { + auto entry = mMap.find(key); + return (entry != mMap.end()) ? &(entry->second) : nullptr; + } + + // This gets a copy of VALs pointed to by *key* + // If the entry is not in the map, an empty set will be returned. + inline unordered_set<VAL> getValSet(const KEY& key) { + auto entry = mMap.find(key); + return (entry != mMap.end()) ? entry->second : unordered_set<VAL>(0); + } + + // This gets all the KEYs from the map + inline unordered_set<KEY> getKeys() { + unordered_set<KEY> keys(0); + for (auto entry : mMap) { + keys.insert(entry.first); + } + return keys; + } + + inline bool remove(const KEY& key) { + return mMap.erase(key) > 0; + } + + // This looks into all the entries keyed by *keys*. Remove any VALs from the entries + // that also exist in *rVals*. If the entry is left with an empty set, the entry will + // be removed. The optional parameters *goneKeys* and *goneVals* will record the KEYs + // (or entries) and the collapsed VALs removed from the map, respectively. + inline void trimOrRemove(unordered_set<KEY>&& keys, const unordered_set<VAL>& rVals, + unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) { + trimOrRemove(keys, rVals, goneKeys, goneVals); + } + inline void trimOrRemove(unordered_set<KEY>& keys, const unordered_set<VAL>& rVals, + unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) { + for (auto key : keys) { + auto iter = mMap.find(key); + if (iter != mMap.end() && trimOrRemove(iter, rVals, goneVals) && nullptr != goneKeys) { + goneKeys->insert(iter->first); + } + } + } + + // This adds all VALs from *newVals* to the map entry keyed by *key*. Or if it + // doesn't exist yet, add the set to the map. + bool add(const KEY& key, const unordered_set<VAL>& newVals) { + bool newEntryAdded = false; + if (!newVals.empty()) { + auto iter = mMap.find(key); + if (iter != mMap.end()) { + iter->second.insert(newVals.begin(), newVals.end()); + } else { + mMap[key] = newVals; + newEntryAdded = true; + } + } + return newEntryAdded; + } + + // This adds to each of entries in the map keyed by *keys* with the VALs in the + // *enwVals*. If there new entries added (new key in *keys*), *newKeys*, if not + // null, would be populated with those keys. + inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>&& newVals, + unordered_set<KEY>* newKeys) { + add(keys, newVals, newKeys); + } + inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>& newVals, + unordered_set<KEY>* newKeys) { + for (auto key : keys) { + if (add(key, newVals) && nullptr != newKeys) { + newKeys->insert(key); + } + } + } + + // This puts *newVals* into the map keyed by *key*, and returns the VALs that are + // in effect removed from the keyed VAL set in the map entry. + // This call would also remove those same VALs from *newVals*. + inline unordered_set<VAL> update(const KEY& key, unordered_set<VAL>& newVals) { + unordered_set<VAL> goneVals(0); + + if (newVals.empty()) { + mMap.erase(key); + } else { + auto curVals = mMap[key]; + mMap[key] = newVals; + goneVals = removeAndReturnInterset(curVals, newVals); + } + return goneVals; + } +}; + +} // namespace loc_util + +#endif // #ifndef __LOC_UNORDERDED_SETMAP_H__ diff --git a/gps/utils/Makefile.am b/gps/utils/Makefile.am new file mode 100644 index 0000000..9a9c67e --- /dev/null +++ b/gps/utils/Makefile.am @@ -0,0 +1,72 @@ +ACLOCAL_AMFLAGS = -I m4 + +AM_CFLAGS = -Wundef \ + -MD \ + -Wno-trigraphs \ + -g -O0 \ + -fno-inline \ + -fno-short-enums \ + -fpic \ + -I./ \ + -std=c++14 \ + $(LOCPLA_CFLAGS) + +libgps_utils_la_h_sources = \ + msg_q.h \ + linked_list.h \ + loc_cfg.h \ + loc_log.h \ + loc_target.h \ + loc_timer.h \ + MsgTask.h \ + LocHeap.h \ + LocThread.h \ + LocTimer.h \ + LocIpc.h \ + loc_misc_utils.h \ + loc_nmea.h \ + gps_extended_c.h \ + gps_extended.h \ + loc_gps.h \ + log_util.h \ + LocSharedLock.h \ + LocUnorderedSetMap.h + +libgps_utils_la_c_sources = \ + linked_list.c \ + msg_q.c \ + loc_cfg.cpp \ + loc_log.cpp \ + loc_target.cpp \ + LocHeap.cpp \ + LocTimer.cpp \ + LocThread.cpp \ + LocIpc.cpp \ + MsgTask.cpp \ + loc_misc_utils.cpp \ + loc_nmea.cpp + +library_includedir = $(pkgincludedir) + +library_include_HEADERS = $(libgps_utils_la_h_sources) + +libgps_utils_la_SOURCES = $(libgps_utils_la_c_sources) + +if USE_GLIB +libgps_utils_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@ +libgps_utils_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0 +libgps_utils_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@ +else +libgps_utils_la_CFLAGS = $(AM_CFLAGS) +libgps_utils_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0 +libgps_utils_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS) +endif + +libgps_utils_la_LIBADD = $(CUTILS_LIBS) -ldl + +#Create and Install libraries +lib_LTLIBRARIES = libgps_utils.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gps-utils.pc +EXTRA_DIST = $(pkgconfig_DATA) diff --git a/gps/utils/MsgTask.cpp b/gps/utils/MsgTask.cpp new file mode 100644 index 0000000..73a77fd --- /dev/null +++ b/gps/utils/MsgTask.cpp @@ -0,0 +1,108 @@ +/* Copyright (c) 2011-2013, 2015, 2017The 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. + * + */ +#define LOG_NDEBUG 0 +#define LOG_TAG "LocSvc_MsgTask" + +#include <unistd.h> +#include <MsgTask.h> +#include <msg_q.h> +#include <log_util.h> +#include <loc_log.h> +#include <loc_pla.h> + +static void LocMsgDestroy(void* msg) { + delete (LocMsg*)msg; +} + +MsgTask::MsgTask(LocThread::tCreate tCreator, + const char* threadName, bool joinable) : + mQ(msg_q_init2()), mThread(new LocThread()) { + if (!mThread->start(tCreator, threadName, this, joinable)) { + delete mThread; + mThread = NULL; + } +} + +MsgTask::MsgTask(const char* threadName, bool joinable) : + mQ(msg_q_init2()), mThread(new LocThread()) { + if (!mThread->start(threadName, this, joinable)) { + delete mThread; + mThread = NULL; + } +} + +MsgTask::~MsgTask() { + msg_q_flush((void*)mQ); + msg_q_destroy((void**)&mQ); +} + +void MsgTask::destroy() { + LocThread* thread = mThread; + msg_q_unblock((void*)mQ); + if (thread) { + mThread = NULL; + delete thread; + } else { + delete this; + } +} + +void MsgTask::sendMsg(const LocMsg* msg) const { + if (msg && this) { + msg_q_snd((void*)mQ, (void*)msg, LocMsgDestroy); + } else { + LOC_LOGE("%s: msg is %p and this is %p", + __func__, msg, this); + } +} + +void MsgTask::prerun() { +#ifndef FEATURE_EXTERNAL_AP + // make sure we do not run in background scheduling group + set_sched_policy(gettid(), SP_FOREGROUND); +#endif /* FEATURE_EXTERNAL_AP */ +} + +bool MsgTask::run() { + LocMsg* msg; + msq_q_err_type result = msg_q_rcv((void*)mQ, (void **)&msg); + if (eMSG_Q_SUCCESS != result) { + LOC_LOGE("%s:%d] fail receiving msg: %s\n", __func__, __LINE__, + loc_get_msg_q_status(result)); + return false; + } + + msg->log(); + // there is where each individual msg handling is invoked + msg->proc(); + + delete msg; + + return true; +} diff --git a/gps/utils/MsgTask.h b/gps/utils/MsgTask.h new file mode 100644 index 0000000..9eb1f56 --- /dev/null +++ b/gps/utils/MsgTask.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2011-2013,2015 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. + * + */ +#ifndef __MSG_TASK__ +#define __MSG_TASK__ + +#include <LocThread.h> + +struct LocMsg { + inline LocMsg() {} + inline virtual ~LocMsg() {} + virtual void proc() const = 0; + inline virtual void log() const {} +}; + +class MsgTask : public LocRunnable { + const void* mQ; + LocThread* mThread; + friend class LocThreadDelegate; +protected: + virtual ~MsgTask(); +public: + MsgTask(LocThread::tCreate tCreator, const char* threadName = NULL, bool joinable = true); + MsgTask(const char* threadName = NULL, bool joinable = true); + // this obj will be deleted once thread is deleted + void destroy(); + void sendMsg(const LocMsg* msg) const; + // Overrides of LocRunnable methods + // This method will be repeated called until it returns false; or + // until thread is stopped. + virtual bool run(); + + // The method to be run before thread loop (conditionally repeatedly) + // calls run() + virtual void prerun(); + + // The method to be run after thread loop (conditionally repeatedly) + // calls run() + inline virtual void postrun() {} +}; + +#endif //__MSG_TASK__ diff --git a/gps/utils/configure.ac b/gps/utils/configure.ac new file mode 100644 index 0000000..fd16494 --- /dev/null +++ b/gps/utils/configure.ac @@ -0,0 +1,92 @@ +# configure.ac -- Autoconf script for gps gps-utils +# +# Process this file with autoconf to produce a configure script + +# Requires autoconf tool later than 2.61 +AC_PREREQ(2.61) +# Initialize the gps gps-utils package version 1.0.0 +AC_INIT([gps-utils],1.0.0) +# Does not strictly follow GNU Coding standards +AM_INIT_AUTOMAKE([foreign]) +# 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 + +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([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_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 \ + gps-utils.pc + ]) + +AC_OUTPUT diff --git a/gps/utils/gps-utils.pc.in b/gps/utils/gps-utils.pc.in new file mode 100644 index 0000000..a988731 --- /dev/null +++ b/gps/utils/gps-utils.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: gps-utils +Description: QTI GPS Location utils +Version: @VERSION +Libs: -L${libdir} -lgps_utils +Cflags: -I${includedir}/gps-utils diff --git a/gps/utils/gps_extended.h b/gps/utils/gps_extended.h new file mode 100644 index 0000000..2455629 --- /dev/null +++ b/gps/utils/gps_extended.h @@ -0,0 +1,114 @@ +/* Copyright (c) 2013-2017 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. + */ + +#ifndef GPS_EXTENDED_H +#define GPS_EXTENDED_H + +/** + * @file + * @brief C++ declarations for GPS types + */ + +#include <gps_extended_c.h> +#if defined(USE_GLIB) || defined(OFF_TARGET) +#include <string.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +struct LocPosMode +{ + LocPositionMode mode; + LocGpsPositionRecurrence recurrence; + uint32_t min_interval; + uint32_t preferred_accuracy; + uint32_t preferred_time; + bool share_position; + char credentials[14]; + char provider[8]; + GnssPowerMode powerMode; + uint32_t timeBetweenMeasurements; + LocPosMode(LocPositionMode m, LocGpsPositionRecurrence recr, + uint32_t gap, uint32_t accu, uint32_t time, + bool sp, const char* cred, const char* prov, + GnssPowerMode pMode = GNSS_POWER_MODE_INVALID, + uint32_t tbm = 0) : + mode(m), recurrence(recr), + min_interval(gap < GPS_MIN_POSSIBLE_FIX_INTERVAL_MS ? + GPS_MIN_POSSIBLE_FIX_INTERVAL_MS : gap), + preferred_accuracy(accu), preferred_time(time), + share_position(sp), powerMode(pMode), + timeBetweenMeasurements(tbm) { + memset(credentials, 0, sizeof(credentials)); + memset(provider, 0, sizeof(provider)); + if (NULL != cred) { + memcpy(credentials, cred, sizeof(credentials)-1); + } + if (NULL != prov) { + memcpy(provider, prov, sizeof(provider)-1); + } + } + + inline LocPosMode() : + mode(LOC_POSITION_MODE_MS_BASED), + recurrence(LOC_GPS_POSITION_RECURRENCE_PERIODIC), + min_interval(GPS_DEFAULT_FIX_INTERVAL_MS), + preferred_accuracy(50), preferred_time(120000), + share_position(true), powerMode(GNSS_POWER_MODE_INVALID), + timeBetweenMeasurements(GPS_DEFAULT_FIX_INTERVAL_MS) { + memset(credentials, 0, sizeof(credentials)); + memset(provider, 0, sizeof(provider)); + } + + inline bool equals(const LocPosMode &anotherMode) const + { + return anotherMode.mode == mode && + anotherMode.recurrence == recurrence && + anotherMode.min_interval == min_interval && + anotherMode.preferred_accuracy == preferred_accuracy && + anotherMode.preferred_time == preferred_time && + anotherMode.powerMode == powerMode && + anotherMode.timeBetweenMeasurements == timeBetweenMeasurements && + !strncmp(anotherMode.credentials, credentials, sizeof(credentials)-1) && + !strncmp(anotherMode.provider, provider, sizeof(provider)-1); + } + + void logv() const; +}; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* GPS_EXTENDED_H */ + diff --git a/gps/utils/gps_extended_c.h b/gps/utils/gps_extended_c.h new file mode 100644 index 0000000..69a659e --- /dev/null +++ b/gps/utils/gps_extended_c.h @@ -0,0 +1,2290 @@ +/* Copyright (c) 2013-2019 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. + */ + +#ifndef GPS_EXTENDED_C_H +#define GPS_EXTENDED_C_H + +#include <ctype.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <loc_gps.h> +#include <LocationAPI.h> + +struct timespec32_t { + uint32_t tv_sec; /* seconds */ + uint32_t tv_nsec; /* and nanoseconds */ +}; + + +/** + * @file + * @brief C++ declarations for GPS types + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Location has valid source information. */ +#define LOCATION_HAS_SOURCE_INFO 0x0020 +/** LocGpsLocation has valid "is indoor?" flag */ +#define LOC_GPS_LOCATION_HAS_IS_INDOOR 0x0040 +/** LocGpsLocation has valid floor number */ +#define LOC_GPS_LOCATION_HAS_FLOOR_NUMBER 0x0080 +/** LocGpsLocation has valid map URL*/ +#define LOC_GPS_LOCATION_HAS_MAP_URL 0x0100 +/** LocGpsLocation has valid map index */ +#define LOC_GPS_LOCATION_HAS_MAP_INDEX 0x0200 + +#define GNSS_INVALID_JAMMER_IND 0x7FFFFFFF + +/** Sizes for indoor fields */ +#define GPS_LOCATION_MAP_URL_SIZE 400 +#define GPS_LOCATION_MAP_INDEX_SIZE 16 + +/** Position source is ULP */ +#define ULP_LOCATION_IS_FROM_HYBRID 0x0001 +/** Position source is GNSS only */ +#define ULP_LOCATION_IS_FROM_GNSS 0x0002 +/** Position is from a Geofence Breach Event */ +#define ULP_LOCATION_IS_FROM_GEOFENCE 0X0004 +/** Position is from Hardware FLP */ +#define ULP_LOCATION_IS_FROM_HW_FLP 0x0008 +/** Position is from NLP */ +#define ULP_LOCATION_IS_FROM_NLP 0x0010 +/** Position is from external DR solution*/ +#define ULP_LOCATION_IS_FROM_EXT_DR 0X0020 +/** Raw GNSS position fixes */ +#define ULP_LOCATION_IS_FROM_GNSS_RAW 0X0040 + +typedef uint32_t LocSvInfoSource; +/** SVinfo source is GNSS/DR */ +#define ULP_SVINFO_IS_FROM_GNSS ((LocSvInfoSource)0x0001) +/** Raw SVinfo from GNSS */ +#define ULP_SVINFO_IS_FROM_DR ((LocSvInfoSource)0x0002) + +#define ULP_MIN_INTERVAL_INVALID 0xffffffff +#define ULP_MAX_NMEA_STRING_SIZE 201 + +/*Emergency SUPL*/ +#define LOC_GPS_NI_TYPE_EMERGENCY_SUPL 4 + +#define LOC_AGPS_CERTIFICATE_MAX_LENGTH 2000 +#define LOC_AGPS_CERTIFICATE_MAX_SLOTS 10 + +/* TBM Threshold for tracking in background power mode : in millis */ +#define TRACKING_TBM_THRESHOLD_MILLIS 480000 + +/** Maximum number of satellites in an ephemeris report. */ +#define GNSS_EPHEMERIS_LIST_MAX_SIZE_V02 32 + +typedef uint32_t LocPosTechMask; +#define LOC_POS_TECH_MASK_DEFAULT ((LocPosTechMask)0x00000000) +#define LOC_POS_TECH_MASK_SATELLITE ((LocPosTechMask)0x00000001) +#define LOC_POS_TECH_MASK_CELLID ((LocPosTechMask)0x00000002) +#define LOC_POS_TECH_MASK_WIFI ((LocPosTechMask)0x00000004) +#define LOC_POS_TECH_MASK_SENSORS ((LocPosTechMask)0x00000008) +#define LOC_POS_TECH_MASK_REFERENCE_LOCATION ((LocPosTechMask)0x00000010) +#define LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION ((LocPosTechMask)0x00000020) +#define LOC_POS_TECH_MASK_AFLT ((LocPosTechMask)0x00000040) +#define LOC_POS_TECH_MASK_HYBRID ((LocPosTechMask)0x00000080) +#define LOC_POS_TECH_MASK_PPE ((LocPosTechMask)0x00000100) + +enum loc_registration_mask_status { + LOC_REGISTRATION_MASK_ENABLED, + LOC_REGISTRATION_MASK_DISABLED, + LOC_REGISTRATION_MASK_SET +}; + +typedef enum { + LOC_SUPPORTED_FEATURE_ODCPI_2_V02 = 0, /**< Support ODCPI version 2 feature */ + LOC_SUPPORTED_FEATURE_WIFI_AP_DATA_INJECT_2_V02, /**< Support Wifi AP data inject version 2 feature */ + LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02, /**< Support debug NMEA feature */ + LOC_SUPPORTED_FEATURE_GNSS_ONLY_POSITION_REPORT, /**< Support GNSS Only position reports */ + LOC_SUPPORTED_FEATURE_FDCL, /**< Support FDCL */ + LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02, /**< Support constellation enablement */ + LOC_SUPPORTED_FEATURE_AGPM_V02, /**< Support AGPM feature */ + LOC_SUPPORTED_FEATURE_XTRA_INTEGRITY, /**< Support XTRA integrity */ + LOC_SUPPORTED_FEATURE_FDCL_2, /**< Support FDCL V2 */ + LOC_SUPPORTED_FEATURE_LOCATION_PRIVACY /**< Support location privacy */ +} loc_supported_feature_enum; + +typedef struct { + /** set to sizeof(UlpLocation) */ + uint32_t size; + LocGpsLocation gpsLocation; + /* Provider indicator for HYBRID or GPS */ + uint16_t position_source; + LocPosTechMask tech_mask; + bool unpropagatedPosition; +} UlpLocation; + +typedef struct { + /** set to sizeof(UlpNmea) */ + uint32_t size; + char nmea_str[ULP_MAX_NMEA_STRING_SIZE]; + unsigned int len; +} UlpNmea; + + +/** AGPS type */ +typedef int8_t AGpsExtType; +#define LOC_AGPS_TYPE_INVALID -1 +#define LOC_AGPS_TYPE_ANY 0 +#define LOC_AGPS_TYPE_SUPL 1 +#define LOC_AGPS_TYPE_C2K 2 +#define LOC_AGPS_TYPE_WWAN_ANY 3 +#define LOC_AGPS_TYPE_WIFI 4 +#define LOC_AGPS_TYPE_SUPL_ES 5 + +/** SSID length */ +#define SSID_BUF_SIZE (32+1) + +typedef int16_t AGpsBearerType; +#define AGPS_APN_BEARER_INVALID 0 +#define AGPS_APN_BEARER_IPV4 1 +#define AGPS_APN_BEARER_IPV6 2 +#define AGPS_APN_BEARER_IPV4V6 3 + +typedef uint32_t LocApnTypeMask; +/**< Denotes APN type for Default/Internet traffic */ +#define LOC_APN_TYPE_MASK_DEFAULT ((LocApnTypeMask)0x00000001) +/**< Denotes APN type for IP Multimedia Subsystem */ +#define LOC_APN_TYPE_MASK_IMS ((LocApnTypeMask)0x00000002) +/**< Denotes APN type for Multimedia Messaging Service */ +#define LOC_APN_TYPE_MASK_MMS ((LocApnTypeMask)0x00000004) +/**< Denotes APN type for Dial Up Network */ +#define LOC_APN_TYPE_MASK_DUN ((LocApnTypeMask)0x00000008) +/**< Denotes APN type for Secure User Plane Location */ +#define LOC_APN_TYPE_MASK_SUPL ((LocApnTypeMask)0x00000010) +/**< Denotes APN type for High Priority Mobile Data */ +#define LOC_APN_TYPE_MASK_HIPRI ((LocApnTypeMask)0x00000020) +/**< Denotes APN type for over the air administration */ +#define LOC_APN_TYPE_MASK_FOTA ((LocApnTypeMask)0x00000040) +/**< Denotes APN type for Carrier Branded Services */ +#define LOC_APN_TYPE_MASK_CBS ((LocApnTypeMask)0x00000080) +/**< Denotes APN type for Initial Attach */ +#define LOC_APN_TYPE_MASK_IA ((LocApnTypeMask)0x00000100) +/**< Denotes APN type for emergency */ +#define LOC_APN_TYPE_MASK_EMERGENCY ((LocApnTypeMask)0x00000200) + +typedef uint32_t AGpsTypeMask; +#define AGPS_ATL_TYPE_SUPL ((AGpsTypeMask)0x00000001) +#define AGPS_ATL_TYPE_SUPL_ES ((AGpsTypeMask)0x00000002) +#define AGPS_ATL_TYPE_WWAN ((AGpsTypeMask)0x00000004) + +typedef struct { + void* statusV4Cb; + AGpsTypeMask atlType; +} AgpsCbInfo; + +typedef struct { + void* visibilityControlCb; + void* isInEmergencySession; +} NfwCbInfo; + +/** GPS extended callback structure. */ +typedef struct { + /** set to sizeof(LocGpsCallbacks) */ + uint32_t size; + loc_gps_set_capabilities set_capabilities_cb; + loc_gps_acquire_wakelock acquire_wakelock_cb; + loc_gps_release_wakelock release_wakelock_cb; + loc_gps_create_thread create_thread_cb; + loc_gps_request_utc_time request_utc_time_cb; +} GpsExtCallbacks; + +/** Callback to report the xtra server url to the client. + * The client should use this url when downloading xtra unless overwritten + * in the gps.conf file + */ +typedef void (* report_xtra_server)(const char*, const char*, const char*); + +/** Callback structure for the XTRA interface. */ +typedef struct { + loc_gps_xtra_download_request download_request_cb; + loc_gps_create_thread create_thread_cb; + report_xtra_server report_xtra_server_cb; +} GpsXtraExtCallbacks; + +/** Represents the status of AGPS. */ +typedef struct { + /** set to sizeof(AGpsExtStatus) */ + uint32_t size; + + AGpsExtType type; + LocAGpsStatusValue status; + uint32_t ipv4_addr; + struct sockaddr_storage addr; + char ssid[SSID_BUF_SIZE]; + char password[SSID_BUF_SIZE]; +} AGpsExtStatus; + +/** Callback with AGPS status information. + * Can only be called from a thread created by create_thread_cb. + */ +typedef void (* agps_status_extended)(AGpsExtStatus* status); + +/** Callback structure for the AGPS interface. */ +typedef struct { + agps_status_extended status_cb; + loc_gps_create_thread create_thread_cb; +} AGpsExtCallbacks; + + +typedef void (*loc_ni_notify_callback)(LocGpsNiNotification *notification, bool esEnalbed); +/** GPS NI callback structure. */ +typedef struct +{ + /** + * Sends the notification request from HAL to GPSLocationProvider. + */ + loc_ni_notify_callback notify_cb; +} GpsNiExtCallbacks; + +typedef enum loc_server_type { + LOC_AGPS_CDMA_PDE_SERVER, + LOC_AGPS_CUSTOM_PDE_SERVER, + LOC_AGPS_MPC_SERVER, + LOC_AGPS_SUPL_SERVER, + LOC_AGPS_MO_SUPL_SERVER +} LocServerType; + +typedef enum loc_position_mode_type { + LOC_POSITION_MODE_INVALID = -1, + LOC_POSITION_MODE_STANDALONE = 0, + LOC_POSITION_MODE_MS_BASED, + LOC_POSITION_MODE_MS_ASSISTED, + LOC_POSITION_MODE_RESERVED_1, + LOC_POSITION_MODE_RESERVED_2, + LOC_POSITION_MODE_RESERVED_3, + LOC_POSITION_MODE_RESERVED_4, + LOC_POSITION_MODE_RESERVED_5 + +} LocPositionMode; + +/** + * @brief Minimum allowed value for fix interval. + * + * This value is a sanity limit in GPS framework. The hardware has own internal + * limits that may not match this value + * + * @sa GPS_DEFAULT_FIX_INTERVAL_MS + */ + +#define GPS_MIN_POSSIBLE_FIX_INTERVAL_MS 100 +/** + * @brief Default value for fix interval. + * + * This value is used by default whenever appropriate. + * + * @sa GPS_MIN_POSSIBLE_FIX_INTERVAL_MS + */ +#define GPS_DEFAULT_FIX_INTERVAL_MS 1000 + +/** Flags to indicate which values are valid in a GpsLocationExtended. */ +typedef uint64_t GpsLocationExtendedFlags; +/** GpsLocationExtended has valid pdop, hdop, vdop. */ +#define GPS_LOCATION_EXTENDED_HAS_DOP 0x0001 +/** GpsLocationExtended has valid altitude mean sea level. */ +#define GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL 0x0002 +/** UlpLocation has valid magnetic deviation. */ +#define GPS_LOCATION_EXTENDED_HAS_MAG_DEV 0x0004 +/** UlpLocation has valid mode indicator. */ +#define GPS_LOCATION_EXTENDED_HAS_MODE_IND 0x0008 +/** GpsLocationExtended has valid vertical uncertainty */ +#define GPS_LOCATION_EXTENDED_HAS_VERT_UNC 0x0010 +/** GpsLocationExtended has valid speed uncertainty */ +#define GPS_LOCATION_EXTENDED_HAS_SPEED_UNC 0x0020 +/** GpsLocationExtended has valid heading uncertainty */ +#define GPS_LOCATION_EXTENDED_HAS_BEARING_UNC 0x0040 +/** GpsLocationExtended has valid horizontal reliability */ +#define GPS_LOCATION_EXTENDED_HAS_HOR_RELIABILITY 0x0080 +/** GpsLocationExtended has valid vertical reliability */ +#define GPS_LOCATION_EXTENDED_HAS_VERT_RELIABILITY 0x0100 +/** GpsLocationExtended has valid Horizontal Elliptical Uncertainty (Semi-Major Axis) */ +#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MAJOR 0x0200 +/** GpsLocationExtended has valid Horizontal Elliptical Uncertainty (Semi-Minor Axis) */ +#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MINOR 0x0400 +/** GpsLocationExtended has valid Elliptical Horizontal Uncertainty Azimuth */ +#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_AZIMUTH 0x0800 +/** GpsLocationExtended has valid gnss sv used in position data */ +#define GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA 0x1000 +/** GpsLocationExtended has valid navSolutionMask */ +#define GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK 0x2000 +/** GpsLocationExtended has valid LocPosTechMask */ +#define GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK 0x4000 +/** GpsLocationExtended has valid LocSvInfoSource */ +#define GPS_LOCATION_EXTENDED_HAS_SV_SOURCE_INFO 0x8000 +/** GpsLocationExtended has valid position dynamics data */ +#define GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA 0x10000 +/** GpsLocationExtended has GPS Time */ +#define GPS_LOCATION_EXTENDED_HAS_GPS_TIME 0x20000 +/** GpsLocationExtended has Extended Dilution of Precision */ +#define GPS_LOCATION_EXTENDED_HAS_EXT_DOP 0x40000 +/** GpsLocationExtended has North standard deviation */ +#define GPS_LOCATION_EXTENDED_HAS_NORTH_STD_DEV 0x80000 +/** GpsLocationExtended has East standard deviation*/ +#define GPS_LOCATION_EXTENDED_HAS_EAST_STD_DEV 0x100000 +/** GpsLocationExtended has North Velocity */ +#define GPS_LOCATION_EXTENDED_HAS_NORTH_VEL 0x200000 +/** GpsLocationExtended has East Velocity */ +#define GPS_LOCATION_EXTENDED_HAS_EAST_VEL 0x400000 +/** GpsLocationExtended has up Velocity */ +#define GPS_LOCATION_EXTENDED_HAS_UP_VEL 0x800000 +/** GpsLocationExtended has North Velocity Uncertainty */ +#define GPS_LOCATION_EXTENDED_HAS_NORTH_VEL_UNC 0x1000000 +/** GpsLocationExtended has East Velocity Uncertainty */ +#define GPS_LOCATION_EXTENDED_HAS_EAST_VEL_UNC 0x2000000 +/** GpsLocationExtended has up Velocity Uncertainty */ +#define GPS_LOCATION_EXTENDED_HAS_UP_VEL_UNC 0x4000000 +/** GpsLocationExtended has Clock Bias */ +#define GPS_LOCATION_EXTENDED_HAS_CLOCK_BIAS 0x8000000 +/** GpsLocationExtended has Clock Bias std deviation*/ +#define GPS_LOCATION_EXTENDED_HAS_CLOCK_BIAS_STD_DEV 0x10000000 +/** GpsLocationExtended has Clock drift*/ +#define GPS_LOCATION_EXTENDED_HAS_CLOCK_DRIFT 0x20000000 +/** GpsLocationExtended has Clock drift std deviation**/ +#define GPS_LOCATION_EXTENDED_HAS_CLOCK_DRIFT_STD_DEV 0x40000000 +/** GpsLocationExtended has leap seconds **/ +#define GPS_LOCATION_EXTENDED_HAS_LEAP_SECONDS 0x80000000 +/** GpsLocationExtended has time uncertainty **/ +#define GPS_LOCATION_EXTENDED_HAS_TIME_UNC 0x100000000 +/** GpsLocationExtended has heading rate **/ +#define GPS_LOCATION_EXTENDED_HAS_HEADING_RATE 0x200000000 +/** GpsLocationExtended has multiband signals **/ +#define GPS_LOCATION_EXTENDED_HAS_MULTIBAND 0x400000000 +/** GpsLocationExtended has sensor calibration confidence */ +#define GPS_LOCATION_EXTENDED_HAS_CALIBRATION_CONFIDENCE 0x800000000 +/** GpsLocationExtended has sensor calibration status */ +#define GPS_LOCATION_EXTENDED_HAS_CALIBRATION_STATUS 0x1000000000 +/** GpsLocationExtended has the engine type that produced this + * position, the bit mask will only be set when there are two + * or more position engines running in the system */ +#define GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE 0x2000000000 + /** GpsLocationExtended has the engine mask that indicates the + * set of engines contribute to the fix. */ +#define GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_MASK 0x4000000000 + +typedef uint32_t LocNavSolutionMask; +/* Bitmask to specify whether SBAS ionospheric correction is used */ +#define LOC_NAV_MASK_SBAS_CORRECTION_IONO ((LocNavSolutionMask)0x0001) +/* Bitmask to specify whether SBAS fast correction is used */ +#define LOC_NAV_MASK_SBAS_CORRECTION_FAST ((LocNavSolutionMask)0x0002) +/**< Bitmask to specify whether SBAS long-tem correction is used */ +#define LOC_NAV_MASK_SBAS_CORRECTION_LONG ((LocNavSolutionMask)0x0004) +/**< Bitmask to specify whether SBAS integrity information is used */ +#define LOC_NAV_MASK_SBAS_INTEGRITY ((LocNavSolutionMask)0x0008) +/**< Bitmask to specify whether Position Report is DGNSS corrected */ +#define LOC_NAV_MASK_DGNSS_CORRECTION ((LocNavSolutionMask)0x0010) +/**< Bitmask to specify whether Position Report is RTK corrected */ +#define LOC_NAV_MASK_RTK_CORRECTION ((LocNavSolutionMask)0x0020) +/**< Bitmask to specify whether Position Report is PPP corrected */ +#define LOC_NAV_MASK_PPP_CORRECTION ((LocNavSolutionMask)0x0040) +/**< Bitmask to specify whether Position Report is RTK fixed corrected */ +#define LOC_NAV_MASK_RTK_FIXED_CORRECTION ((LocNavSolutionMask)0x0080) + +typedef uint32_t LocPosDataMask; +/* Bitmask to specify whether Navigation data has Forward Acceleration */ +#define LOC_NAV_DATA_HAS_LONG_ACCEL ((LocPosDataMask)0x0001) +/* Bitmask to specify whether Navigation data has Sideward Acceleration */ +#define LOC_NAV_DATA_HAS_LAT_ACCEL ((LocPosDataMask)0x0002) +/* Bitmask to specify whether Navigation data has Vertical Acceleration */ +#define LOC_NAV_DATA_HAS_VERT_ACCEL ((LocPosDataMask)0x0004) +/* Bitmask to specify whether Navigation data has Heading Rate */ +#define LOC_NAV_DATA_HAS_YAW_RATE ((LocPosDataMask)0x0008) +/* Bitmask to specify whether Navigation data has Body pitch */ +#define LOC_NAV_DATA_HAS_PITCH ((LocPosDataMask)0x0010) +/* Bitmask to specify whether Navigation data has Forward Acceleration Unc */ +#define LOC_NAV_DATA_HAS_LONG_ACCEL_UNC ((LocPosDataMask)0x0020) +/* Bitmask to specify whether Navigation data has Sideward Acceleration Unc*/ +#define LOC_NAV_DATA_HAS_LAT_ACCEL_UNC ((LocPosDataMask)0x0040) +/* Bitmask to specify whether Navigation data has Vertical Acceleration Unc*/ +#define LOC_NAV_DATA_HAS_VERT_ACCEL_UNC ((LocPosDataMask)0x0080) +/* Bitmask to specify whether Navigation data has Heading Rate Unc*/ +#define LOC_NAV_DATA_HAS_YAW_RATE_UNC ((LocPosDataMask)0x0100) +/* Bitmask to specify whether Navigation data has Body pitch Unc*/ +#define LOC_NAV_DATA_HAS_PITCH_UNC ((LocPosDataMask)0x0200) + +typedef uint32_t GnssAdditionalSystemInfoMask; +/* Bitmask to specify whether Tauc is valid */ +#define GNSS_ADDITIONAL_SYSTEMINFO_HAS_TAUC ((GnssAdditionalSystemInfoMask)0x0001) +/* Bitmask to specify whether leapSec is valid */ +#define GNSS_ADDITIONAL_SYSTEMINFO_HAS_LEAP_SEC ((GnssAdditionalSystemInfoMask)0x0002) + + +/** GPS PRN Range */ +#define GPS_SV_PRN_MIN 1 +#define GPS_SV_PRN_MAX 32 +#define SBAS_SV_PRN_MIN 33 +#define SBAS_SV_PRN_MAX 64 +#define GLO_SV_PRN_MIN 65 +#define GLO_SV_PRN_MAX 96 +#define QZSS_SV_PRN_MIN 193 +#define QZSS_SV_PRN_MAX 197 +#define BDS_SV_PRN_MIN 201 +#define BDS_SV_PRN_MAX 235 +#define GAL_SV_PRN_MIN 301 +#define GAL_SV_PRN_MAX 336 +#define NAVIC_SV_PRN_MIN 401 +#define NAVIC_SV_PRN_MAX 414 + +typedef enum { + LOC_RELIABILITY_NOT_SET = 0, + LOC_RELIABILITY_VERY_LOW = 1, + LOC_RELIABILITY_LOW = 2, + LOC_RELIABILITY_MEDIUM = 3, + LOC_RELIABILITY_HIGH = 4 +}LocReliability; + +typedef enum { + LOC_IN_EMERGENCY_UNKNOWN = 0, + LOC_IN_EMERGENCY_SET = 1, + LOC_IN_EMERGENCY_NOT_SET = 2 +}LocInEmergency; + +typedef struct { + struct timespec32_t apTimeStamp; + /*boottime received from pps-ktimer*/ + float apTimeStampUncertaintyMs; + /* timestamp uncertainty in milli seconds */ +}Gnss_ApTimeStampStructType; + +typedef struct { + uint64_t gps_sv_used_ids_mask; + uint64_t glo_sv_used_ids_mask; + uint64_t gal_sv_used_ids_mask; + uint64_t bds_sv_used_ids_mask; + uint64_t qzss_sv_used_ids_mask; + uint64_t navic_sv_used_ids_mask; +} GnssSvUsedInPosition; + +typedef struct { + uint64_t gps_l1ca_sv_used_ids_mask; // GPS L1CA + uint64_t gps_l1c_sv_used_ids_mask; // GPS L1C + uint64_t gps_l2_sv_used_ids_mask; // GPS L2 + uint64_t gps_l5_sv_used_ids_mask; // GPS L5 + uint64_t glo_g1_sv_used_ids_mask; // GLO G1 + uint64_t glo_g2_sv_used_ids_mask; // GLO G2 + uint64_t gal_e1_sv_used_ids_mask; // GAL E1 + uint64_t gal_e5a_sv_used_ids_mask; // GAL E5A + uint64_t gal_e5b_sv_used_ids_mask; // GAL E5B + uint64_t bds_b1i_sv_used_ids_mask; // BDS B1I + uint64_t bds_b1c_sv_used_ids_mask; // BDS B1C + uint64_t bds_b2i_sv_used_ids_mask; // BDS B2I + uint64_t bds_b2ai_sv_used_ids_mask; // BDS B2AI + uint64_t qzss_l1ca_sv_used_ids_mask; // QZSS L1CA + uint64_t qzss_l1s_sv_used_ids_mask; // QZSS L1S + uint64_t qzss_l2_sv_used_ids_mask; // QZSS L2 + uint64_t qzss_l5_sv_used_ids_mask; // QZSS L5 + uint64_t sbas_l1_sv_used_ids_mask; // SBAS L1 + uint64_t bds_b2aq_sv_used_ids_mask; // BDS B2AQ +} GnssSvMbUsedInPosition; + +/* Body Frame parameters */ +typedef struct { + /** Contains Body frame LocPosDataMask bits. */ + uint32_t bodyFrameDatamask; + /* Forward Acceleration in body frame (m/s2)*/ + float longAccel; + /** Uncertainty of Forward Acceleration in body frame */ + float longAccelUnc; + /* Sideward Acceleration in body frame (m/s2)*/ + float latAccel; + /** Uncertainty of Side-ward Acceleration in body frame */ + float latAccelUnc; + /* Vertical Acceleration in body frame (m/s2)*/ + float vertAccel; + /** Uncertainty of Vertical Acceleration in body frame */ + float vertAccelUnc; + /* Heading Rate (Radians/second) */ + float yawRate; + /** Uncertainty of Heading Rate */ + float yawRateUnc; + /* Body pitch (Radians) */ + float pitch; + /** Uncertainty of Body pitch */ + float pitchRadUnc; +}LocPositionDynamics; + +typedef struct { + + /** Position dilution of precision. + Range: 1 (highest accuracy) to 50 (lowest accuracy) */ + float PDOP; + + /** Horizontal dilution of precision. + Range: 1 (highest accuracy) to 50 (lowest accuracy) */ + float HDOP; + + /** Vertical dilution of precision. + Range: 1 (highest accuracy) to 50 (lowest accuracy) */ + float VDOP; + + /** geometric dilution of precision. + Range: 1 (highest accuracy) to 50 (lowest accuracy) */ + float GDOP; + + /** time dilution of precision. + Range: 1 (highest accuracy) to 50 (lowest accuracy) */ + float TDOP; +}LocExtDOP; + +/* GPS Time structure */ +typedef struct { + + /**< Current GPS week as calculated from midnight, Jan. 6, 1980. \n + - Units: Weeks */ + uint16_t gpsWeek; + + /**< Amount of time into the current GPS week. \n + - Units: Milliseconds */ + uint32_t gpsTimeOfWeekMs; +}GPSTimeStruct; + +typedef uint8_t CarrierPhaseAmbiguityType; +#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_NONE ((CarrierPhaseAmbiguityType)0) +#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_FLOAT ((CarrierPhaseAmbiguityType)1) +#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_FIXED ((CarrierPhaseAmbiguityType)2) + +/** GNSS Signal Type and RF Band */ +typedef uint32_t GnssSignalTypeMask; +/** GPS L1CA Signal */ +#define GNSS_SIGNAL_GPS_L1CA ((GnssSignalTypeMask)0x00000001ul) +/** GPS L1C Signal */ +#define GNSS_SIGNAL_GPS_L1C ((GnssSignalTypeMask)0x00000002ul) +/** GPS L2 RF Band */ +#define GNSS_SIGNAL_GPS_L2 ((GnssSignalTypeMask)0x00000004ul) +/** GPS L5 RF Band */ +#define GNSS_SIGNAL_GPS_L5 ((GnssSignalTypeMask)0x00000008ul) +/** GLONASS G1 (L1OF) RF Band */ +#define GNSS_SIGNAL_GLONASS_G1 ((GnssSignalTypeMask)0x00000010ul) +/** GLONASS G2 (L2OF) RF Band */ +#define GNSS_SIGNAL_GLONASS_G2 ((GnssSignalTypeMask)0x00000020ul) +/** GALILEO E1 RF Band */ +#define GNSS_SIGNAL_GALILEO_E1 ((GnssSignalTypeMask)0x00000040ul) +/** GALILEO E5A RF Band */ +#define GNSS_SIGNAL_GALILEO_E5A ((GnssSignalTypeMask)0x00000080ul) +/** GALILEO E5B RF Band */ +#define GNSS_SIGNAL_GALILIEO_E5B ((GnssSignalTypeMask)0x00000100ul) +/** BEIDOU B1_I RF Band */ +#define GNSS_SIGNAL_BEIDOU_B1I ((GnssSignalTypeMask)0x00000200ul) +/** BEIDOU B1C RF Band */ +#define GNSS_SIGNAL_BEIDOU_B1C ((GnssSignalTypeMask)0x00000400ul) +/** BEIDOU B2_I RF Band */ +#define GNSS_SIGNAL_BEIDOU_B2I ((GnssSignalTypeMask)0x00000800ul) +/** BEIDOU B2A_I RF Band */ +#define GNSS_SIGNAL_BEIDOU_B2AI ((GnssSignalTypeMask)0x00001000ul) +/** QZSS L1CA RF Band */ +#define GNSS_SIGNAL_QZSS_L1CA ((GnssSignalTypeMask)0x00002000ul) +/** QZSS L1S RF Band */ +#define GNSS_SIGNAL_QZSS_L1S ((GnssSignalTypeMask)0x00004000ul) +/** QZSS L2 RF Band */ +#define GNSS_SIGNAL_QZSS_L2 ((GnssSignalTypeMask)0x00008000ul) +/** QZSS L5 RF Band */ +#define GNSS_SIGNAL_QZSS_L5 ((GnssSignalTypeMask)0x00010000ul) +/** SBAS L1 RF Band */ +#define GNSS_SIGNAL_SBAS_L1 ((GnssSignalTypeMask)0x00020000ul) +/** NAVIC L5 RF Band */ +#define GNSS_SIGNAL_NAVIC_L5 ((GnssSignalTypeMask)0x00040000ul) +/** BEIDOU B2A_Q RF Band */ +#define GNSS_SIGNAL_BEIDOU_B2AQ ((GnssSignalTypeMask)0x00080000ul) + +typedef uint16_t GnssMeasUsageStatusBitMask; +/** Used in fix */ +#define GNSS_MEAS_USED_IN_PVT ((GnssMeasUsageStatusBitMask)0x00000001ul) +/** Measurement is Bad */ +#define GNSS_MEAS_USAGE_STATUS_BAD_MEAS ((GnssMeasUsageStatusBitMask)0x00000002ul) +/** Measurement has too low C/N */ +#define GNSS_MEAS_USAGE_STATUS_CNO_TOO_LOW ((GnssMeasUsageStatusBitMask)0x00000004ul) +/** Measurement has too low elevation */ +#define GNSS_MEAS_USAGE_STATUS_ELEVATION_TOO_LOW ((GnssMeasUsageStatusBitMask)0x00000008ul) +/** No ephemeris available for this measurement */ +#define GNSS_MEAS_USAGE_STATUS_NO_EPHEMERIS ((GnssMeasUsageStatusBitMask)0x00000010ul) +/** No corrections available for the measurement */ +#define GNSS_MEAS_USAGE_STATUS_NO_CORRECTIONS ((GnssMeasUsageStatusBitMask)0x00000020ul) +/** Corrections has timed out for the measurement */ +#define GNSS_MEAS_USAGE_STATUS_CORRECTION_TIMEOUT ((GnssMeasUsageStatusBitMask)0x00000040ul) +/** Measurement is unhealthy */ +#define GNSS_MEAS_USAGE_STATUS_UNHEALTHY ((GnssMeasUsageStatusBitMask)0x00000080ul) +/** Configuration is disabled for this measurement */ +#define GNSS_MEAS_USAGE_STATUS_CONFIG_DISABLED ((GnssMeasUsageStatusBitMask)0x00000100ul) +/** Measurement not used for other reasons */ +#define GNSS_MEAS_USAGE_STATUS_OTHER ((GnssMeasUsageStatusBitMask)0x00000200ul) + +/** Flags to indicate valid fields in epMeasUsageInfo */ +typedef uint16_t GnssMeasUsageInfoValidityMask; +#define GNSS_PSEUDO_RANGE_RESIDUAL_VALID ((GnssMeasUsageInfoValidityMask)0x00000001ul) +#define GNSS_DOPPLER_RESIDUAL_VALID ((GnssMeasUsageInfoValidityMask)0x00000002ul) +#define GNSS_CARRIER_PHASE_RESIDUAL_VALID ((GnssMeasUsageInfoValidityMask)0x00000004ul) +#define GNSS_CARRIER_PHASE_AMBIGUITY_TYPE_VALID ((GnssMeasUsageInfoValidityMask)0x00000008ul) + +typedef uint16_t GnssSvPolyStatusMask; +#define GNSS_SV_POLY_SRC_ALM_CORR_V02 ((GnssSvPolyStatusMask)0x01) +#define GNSS_SV_POLY_GLO_STR4_V02 ((GnssSvPolyStatusMask)0x02) +#define GNSS_SV_POLY_DELETE_V02 ((GnssSvPolyStatusMask)0x04) +#define GNSS_SV_POLY_SRC_GAL_FNAV_OR_INAV_V02 ((GnssSvPolyStatusMask)0x08) +typedef uint16_t GnssSvPolyStatusMaskValidity; +#define GNSS_SV_POLY_SRC_ALM_CORR_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x01) +#define GNSS_SV_POLY_GLO_STR4_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x02) +#define GNSS_SV_POLY_DELETE_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x04) +#define GNSS_SV_POLY_SRC_GAL_FNAV_OR_INAV_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x08) + + +typedef struct { + /** Specifies GNSS signal type + Mandatory Field*/ + GnssSignalTypeMask gnssSignalType; + /** Specifies GNSS Constellation Type + Mandatory Field*/ + Gnss_LocSvSystemEnumType gnssConstellation; + /** GNSS SV ID. + For GPS: 1 to 32 + For GLONASS: 65 to 96. When slot-number to SV ID mapping is unknown, set as 255. + For SBAS: 120 to 151 + For QZSS-L1CA:193 to 197 + For BDS: 201 to 237 + For GAL: 301 to 336 */ + uint16_t gnssSvId; + /** GLONASS frequency number + 7. + Valid only for a GLONASS system and + is to be ignored for all other systems. + Range: 1 to 14 */ + uint8_t gloFrequency; + /** Carrier phase ambiguity type. */ + CarrierPhaseAmbiguityType carrierPhaseAmbiguityType; + /** Validity mask */ + GnssMeasUsageStatusBitMask measUsageStatusMask; + /** Specifies measurement usage status + Mandatory Field*/ + GnssMeasUsageInfoValidityMask validityMask; + /** Computed pseudorange residual. + Unit: Meters */ + float pseudorangeResidual; + /** Computed doppler residual. + Unit: Meters/sec*/ + float dopplerResidual; + /** Computed carrier phase residual. + Unit: Cycles*/ + float carrierPhaseResidual; + /** Carrier phase ambiguity value. + Unit: Cycles*/ + float carrierPhasAmbiguity; +} GpsMeasUsageInfo; + + +/** Represents gps location extended. */ +typedef struct { + /** set to sizeof(GpsLocationExtended) */ + uint32_t size; + /** Contains GpsLocationExtendedFlags bits. */ + uint64_t flags; + /** Contains the Altitude wrt mean sea level */ + float altitudeMeanSeaLevel; + /** Contains Position Dilusion of Precision. */ + float pdop; + /** Contains Horizontal Dilusion of Precision. */ + float hdop; + /** Contains Vertical Dilusion of Precision. */ + float vdop; + /** Contains Magnetic Deviation. */ + float magneticDeviation; + /** vertical uncertainty in meters */ + float vert_unc; + /** speed uncertainty in m/s */ + float speed_unc; + /** heading uncertainty in degrees (0 to 359.999) */ + float bearing_unc; + /** horizontal reliability. */ + LocReliability horizontal_reliability; + /** vertical reliability. */ + LocReliability vertical_reliability; + /* Horizontal Elliptical Uncertainty (Semi-Major Axis) */ + float horUncEllipseSemiMajor; + /* Horizontal Elliptical Uncertainty (Semi-Minor Axis) */ + float horUncEllipseSemiMinor; + /* Elliptical Horizontal Uncertainty Azimuth */ + float horUncEllipseOrientAzimuth; + + Gnss_ApTimeStampStructType timeStamp; + /** Gnss sv used in position data */ + GnssSvUsedInPosition gnss_sv_used_ids; + /** Gnss sv used in position data for multiband */ + GnssSvMbUsedInPosition gnss_mb_sv_used_ids; + /** Nav solution mask to indicate sbas corrections */ + LocNavSolutionMask navSolutionMask; + /** Position technology used in computing this fix */ + LocPosTechMask tech_mask; + /** SV Info source used in computing this fix */ + LocSvInfoSource sv_source; + /** Body Frame Dynamics: 4wayAcceleration and pitch set with validity */ + GnssLocationPositionDynamics bodyFrameData; + /** GPS Time */ + GPSTimeStruct gpsTime; + GnssSystemTime gnssSystemTime; + /** Dilution of precision associated with this position*/ + LocExtDOP extDOP; + /** North standard deviation. + Unit: Meters */ + float northStdDeviation; + /** East standard deviation. + Unit: Meters */ + float eastStdDeviation; + /** North Velocity. + Unit: Meters/sec */ + float northVelocity; + /** East Velocity. + Unit: Meters/sec */ + float eastVelocity; + /** Up Velocity. + Unit: Meters/sec */ + float upVelocity; + /** North Velocity standard deviation. + Unit: Meters/sec */ + float northVelocityStdDeviation; + /** East Velocity standard deviation. + Unit: Meters/sec */ + float eastVelocityStdDeviation; + /** Up Velocity standard deviation + Unit: Meters/sec */ + float upVelocityStdDeviation; + /** Estimated clock bias. Unit: Nano seconds */ + float clockbiasMeter; + /** Estimated clock bias std deviation. Unit: Nano seconds */ + float clockBiasStdDeviationMeter; + /** Estimated clock drift. Unit: Meters/sec */ + float clockDrift; + /** Estimated clock drift std deviation. Unit: Meters/sec */ + float clockDriftStdDeviation; + /** Number of valid reference stations. Range:[0-4] */ + uint8_t numValidRefStations; + /** Reference station(s) number */ + uint16_t referenceStation[4]; + /** Number of measurements received for use in fix. + Shall be used as maximum index in-to svUsageInfo[]. + Set to 0, if svUsageInfo reporting is not supported. + Range: 0-EP_GNSS_MAX_MEAS */ + uint8_t numOfMeasReceived; + /** Measurement Usage Information */ + GpsMeasUsageInfo measUsageInfo[GNSS_SV_MAX]; + /** Leap Seconds */ + uint8_t leapSeconds; + /** Time uncertainty in milliseconds */ + float timeUncMs; + /** Heading Rate is in NED frame. + Range: 0 to 359.999. 946 + Unit: Degrees per Seconds */ + float headingRateDeg; + /** Sensor calibration confidence percent. Range: 0 - 100 */ + uint8_t calibrationConfidence; + DrCalibrationStatusMask calibrationStatus; + /* location engine type. When the fix. when the type is set to + LOC_ENGINE_SRC_FUSED, the fix is the propagated/aggregated + reports from all engines running on the system (e.g.: + DR/SPE/PPE). To check which location engine contributes to + the fused output, check for locOutputEngMask. */ + LocOutputEngineType locOutputEngType; + /* when loc output eng type is set to fused, this field + indicates the set of engines contribute to the fix. */ + PositioningEngineMask locOutputEngMask; +} GpsLocationExtended; + +enum loc_sess_status { + LOC_SESS_SUCCESS, + LOC_SESS_INTERMEDIATE, + LOC_SESS_FAILURE +}; + +// struct that contains complete position info from engine +typedef struct { + UlpLocation location; + GpsLocationExtended locationExtended; + enum loc_sess_status sessionStatus; +} EngineLocationInfo; + +// Nmea sentence types mask +typedef uint32_t NmeaSentenceTypesMask; +#define LOC_NMEA_MASK_GGA_V02 ((NmeaSentenceTypesMask)0x00000001) /**< Enable GGA type */ +#define LOC_NMEA_MASK_RMC_V02 ((NmeaSentenceTypesMask)0x00000002) /**< Enable RMC type */ +#define LOC_NMEA_MASK_GSV_V02 ((NmeaSentenceTypesMask)0x00000004) /**< Enable GSV type */ +#define LOC_NMEA_MASK_GSA_V02 ((NmeaSentenceTypesMask)0x00000008) /**< Enable GSA type */ +#define LOC_NMEA_MASK_VTG_V02 ((NmeaSentenceTypesMask)0x00000010) /**< Enable VTG type */ +#define LOC_NMEA_MASK_PQXFI_V02 ((NmeaSentenceTypesMask)0x00000020) /**< Enable PQXFI type */ +#define LOC_NMEA_MASK_PSTIS_V02 ((NmeaSentenceTypesMask)0x00000040) /**< Enable PSTIS type */ +#define LOC_NMEA_MASK_GLGSV_V02 ((NmeaSentenceTypesMask)0x00000080) /**< Enable GLGSV type */ +#define LOC_NMEA_MASK_GNGSA_V02 ((NmeaSentenceTypesMask)0x00000100) /**< Enable GNGSA type */ +#define LOC_NMEA_MASK_GNGNS_V02 ((NmeaSentenceTypesMask)0x00000200) /**< Enable GNGNS type */ +#define LOC_NMEA_MASK_GARMC_V02 ((NmeaSentenceTypesMask)0x00000400) /**< Enable GARMC type */ +#define LOC_NMEA_MASK_GAGSV_V02 ((NmeaSentenceTypesMask)0x00000800) /**< Enable GAGSV type */ +#define LOC_NMEA_MASK_GAGSA_V02 ((NmeaSentenceTypesMask)0x00001000) /**< Enable GAGSA type */ +#define LOC_NMEA_MASK_GAVTG_V02 ((NmeaSentenceTypesMask)0x00002000) /**< Enable GAVTG type */ +#define LOC_NMEA_MASK_GAGGA_V02 ((NmeaSentenceTypesMask)0x00004000) /**< Enable GAGGA type */ +#define LOC_NMEA_MASK_PQGSA_V02 ((NmeaSentenceTypesMask)0x00008000) /**< Enable PQGSA type */ +#define LOC_NMEA_MASK_PQGSV_V02 ((NmeaSentenceTypesMask)0x00010000) /**< Enable PQGSV type */ +#define LOC_NMEA_MASK_DEBUG_V02 ((NmeaSentenceTypesMask)0x00020000) /**< Enable DEBUG type */ +#define LOC_NMEA_MASK_GPDTM_V02 ((NmeaSentenceTypesMask)0x00040000) /**< Enable GPDTM type */ +#define LOC_NMEA_MASK_GNGGA_V02 ((NmeaSentenceTypesMask)0x00080000) /**< Enable GNGGA type */ +#define LOC_NMEA_MASK_GNRMC_V02 ((NmeaSentenceTypesMask)0x00100000) /**< Enable GNRMC type */ +#define LOC_NMEA_MASK_GNVTG_V02 ((NmeaSentenceTypesMask)0x00200000) /**< Enable GNVTG type */ +#define LOC_NMEA_MASK_GAGNS_V02 ((NmeaSentenceTypesMask)0x00400000) /**< Enable GAGNS type */ +#define LOC_NMEA_MASK_GBGGA_V02 ((NmeaSentenceTypesMask)0x00800000) /**< Enable GBGGA type */ +#define LOC_NMEA_MASK_GBGSA_V02 ((NmeaSentenceTypesMask)0x01000000) /**< Enable GBGSA type */ +#define LOC_NMEA_MASK_GBGSV_V02 ((NmeaSentenceTypesMask)0x02000000) /**< Enable GBGSV type */ +#define LOC_NMEA_MASK_GBRMC_V02 ((NmeaSentenceTypesMask)0x04000000) /**< Enable GBRMC type */ +#define LOC_NMEA_MASK_GBVTG_V02 ((NmeaSentenceTypesMask)0x08000000) /**< Enable GBVTG type */ +#define LOC_NMEA_MASK_GQGSV_V02 ((NmeaSentenceTypesMask)0x10000000) /**< Enable GQGSV type */ +#define LOC_NMEA_MASK_GIGSV_V02 ((NmeaSentenceTypesMask)0x20000000) /**< Enable GIGSV type */ +#define LOC_NMEA_MASK_GNDTM_V02 ((NmeaSentenceTypesMask)0x40000000) /**< Enable GNDTM type */ + + +// all bitmasks of general supported NMEA sentenses - debug is not part of this +#define LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK (LOC_NMEA_MASK_GGA_V02 | LOC_NMEA_MASK_RMC_V02 | \ + LOC_NMEA_MASK_GSV_V02 | LOC_NMEA_MASK_GSA_V02 | LOC_NMEA_MASK_VTG_V02 | \ + LOC_NMEA_MASK_PQXFI_V02 | LOC_NMEA_MASK_PSTIS_V02 | LOC_NMEA_MASK_GLGSV_V02 | \ + LOC_NMEA_MASK_GNGSA_V02 | LOC_NMEA_MASK_GNGNS_V02 | LOC_NMEA_MASK_GARMC_V02 | \ + LOC_NMEA_MASK_GAGSV_V02 | LOC_NMEA_MASK_GAGSA_V02 | LOC_NMEA_MASK_GAVTG_V02 | \ + LOC_NMEA_MASK_GAGGA_V02 | LOC_NMEA_MASK_PQGSA_V02 | LOC_NMEA_MASK_PQGSV_V02 | \ + LOC_NMEA_MASK_GPDTM_V02 | LOC_NMEA_MASK_GNGGA_V02 | LOC_NMEA_MASK_GNRMC_V02 | \ + LOC_NMEA_MASK_GNVTG_V02 | LOC_NMEA_MASK_GAGNS_V02 | LOC_NMEA_MASK_GBGGA_V02 | \ + LOC_NMEA_MASK_GBGSA_V02 | LOC_NMEA_MASK_GBGSV_V02 | LOC_NMEA_MASK_GBRMC_V02 | \ + LOC_NMEA_MASK_GBVTG_V02 | LOC_NMEA_MASK_GQGSV_V02 | LOC_NMEA_MASK_GIGSV_V02 | \ + LOC_NMEA_MASK_GNDTM_V02) + +typedef enum { + LOC_ENG_IF_REQUEST_SENDER_ID_QUIPC = 0, + LOC_ENG_IF_REQUEST_SENDER_ID_MSAPM, + LOC_ENG_IF_REQUEST_SENDER_ID_MSAPU, + LOC_ENG_IF_REQUEST_SENDER_ID_GPSONE_DAEMON, + LOC_ENG_IF_REQUEST_SENDER_ID_MODEM, + LOC_ENG_IF_REQUEST_SENDER_ID_UNKNOWN +} loc_if_req_sender_id_e_type; + + +#define smaller_of(a, b) (((a) > (b)) ? (b) : (a)) +#define MAX_APN_LEN 100 + +// This will be overridden by the individual adapters +// if necessary. +#define DEFAULT_IMPL(rtv) \ +{ \ + LOC_LOGD("%s: default implementation invoked", __func__); \ + return rtv; \ +} + +enum loc_api_adapter_err { + LOC_API_ADAPTER_ERR_SUCCESS = 0, + LOC_API_ADAPTER_ERR_GENERAL_FAILURE = 1, + LOC_API_ADAPTER_ERR_UNSUPPORTED = 2, + LOC_API_ADAPTER_ERR_INVALID_HANDLE = 4, + LOC_API_ADAPTER_ERR_INVALID_PARAMETER = 5, + LOC_API_ADAPTER_ERR_ENGINE_BUSY = 6, + LOC_API_ADAPTER_ERR_PHONE_OFFLINE = 7, + LOC_API_ADAPTER_ERR_TIMEOUT = 8, + LOC_API_ADAPTER_ERR_SERVICE_NOT_PRESENT = 9, + LOC_API_ADAPTER_ERR_INTERNAL = 10, + + /* equating engine down to phone offline, as they are the same errror */ + LOC_API_ADAPTER_ERR_ENGINE_DOWN = LOC_API_ADAPTER_ERR_PHONE_OFFLINE, + LOC_API_ADAPTER_ERR_FAILURE = 101, + LOC_API_ADAPTER_ERR_UNKNOWN +}; + +enum loc_api_adapter_event_index { + LOC_API_ADAPTER_REPORT_POSITION = 0, // Position report comes in loc_parsed_position_s_type + LOC_API_ADAPTER_REPORT_SATELLITE, // Satellite in view report + LOC_API_ADAPTER_REPORT_NMEA_1HZ, // NMEA report at 1HZ rate + LOC_API_ADAPTER_REPORT_NMEA_POSITION, // NMEA report at position report rate + LOC_API_ADAPTER_REQUEST_NI_NOTIFY_VERIFY, // NI notification/verification request + LOC_API_ADAPTER_REQUEST_ASSISTANCE_DATA, // Assistance data, eg: time, predicted orbits request + LOC_API_ADAPTER_REQUEST_LOCATION_SERVER, // Request for location server + LOC_API_ADAPTER_REPORT_IOCTL, // Callback report for loc_ioctl + LOC_API_ADAPTER_REPORT_STATUS, // Misc status report: eg, engine state + LOC_API_ADAPTER_REQUEST_WIFI, // + LOC_API_ADAPTER_SENSOR_STATUS, // + LOC_API_ADAPTER_REQUEST_TIME_SYNC, // + LOC_API_ADAPTER_REPORT_SPI, // + LOC_API_ADAPTER_REPORT_NI_GEOFENCE, // + LOC_API_ADAPTER_GEOFENCE_GEN_ALERT, // + LOC_API_ADAPTER_REPORT_GENFENCE_BREACH, // + LOC_API_ADAPTER_PEDOMETER_CTRL, // + LOC_API_ADAPTER_MOTION_CTRL, // + LOC_API_ADAPTER_REQUEST_WIFI_AP_DATA, // Wifi ap data + LOC_API_ADAPTER_BATCH_FULL, // Batching on full + LOC_API_ADAPTER_BATCHED_POSITION_REPORT, // Batching on fix + LOC_API_ADAPTER_BATCHED_GENFENCE_BREACH_REPORT, // + LOC_API_ADAPTER_GNSS_MEASUREMENT_REPORT, // GNSS Measurement Report + LOC_API_ADAPTER_GNSS_SV_POLYNOMIAL_REPORT, // GNSS SV Polynomial Report + LOC_API_ADAPTER_GDT_UPLOAD_BEGIN_REQ, // GDT upload start request + LOC_API_ADAPTER_GDT_UPLOAD_END_REQ, // GDT upload end request + LOC_API_ADAPTER_GNSS_MEASUREMENT, // GNSS Measurement report + LOC_API_ADAPTER_REQUEST_TIMEZONE, // Timezone injection request + LOC_API_ADAPTER_REPORT_GENFENCE_DWELL_REPORT, // Geofence dwell report + LOC_API_ADAPTER_REQUEST_SRN_DATA, // request srn data from AP + LOC_API_ADAPTER_REQUEST_POSITION_INJECTION, // Position injection request + LOC_API_ADAPTER_BATCH_STATUS, // batch status + LOC_API_ADAPTER_FDCL_SERVICE_REQ, // FDCL service request + LOC_API_ADAPTER_REPORT_UNPROPAGATED_POSITION, // Unpropagated Position report + LOC_API_ADAPTER_BS_OBS_DATA_SERVICE_REQ, // BS observation data request + LOC_API_ADAPTER_GNSS_SV_EPHEMERIS_REPORT, // GNSS SV Ephemeris Report + LOC_API_ADAPTER_LOC_SYSTEM_INFO, // Location system info event + LOC_API_ADAPTER_GNSS_NHZ_MEASUREMENT_REPORT, // GNSS SV nHz measurement report + LOC_API_ADAPTER_EVENT_REPORT_INFO, // Event report info + LOC_API_ADAPTER_EVENT_MAX +}; + +#define LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT (1<<LOC_API_ADAPTER_REPORT_POSITION) +#define LOC_API_ADAPTER_BIT_SATELLITE_REPORT (1<<LOC_API_ADAPTER_REPORT_SATELLITE) +#define LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT (1<<LOC_API_ADAPTER_REPORT_NMEA_1HZ) +#define LOC_API_ADAPTER_BIT_NMEA_POSITION_REPORT (1<<LOC_API_ADAPTER_REPORT_NMEA_POSITION) +#define LOC_API_ADAPTER_BIT_NI_NOTIFY_VERIFY_REQUEST (1<<LOC_API_ADAPTER_REQUEST_NI_NOTIFY_VERIFY) +#define LOC_API_ADAPTER_BIT_ASSISTANCE_DATA_REQUEST (1<<LOC_API_ADAPTER_REQUEST_ASSISTANCE_DATA) +#define LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST (1<<LOC_API_ADAPTER_REQUEST_LOCATION_SERVER) +#define LOC_API_ADAPTER_BIT_IOCTL_REPORT (1<<LOC_API_ADAPTER_REPORT_IOCTL) +#define LOC_API_ADAPTER_BIT_STATUS_REPORT (1<<LOC_API_ADAPTER_REPORT_STATUS) +#define LOC_API_ADAPTER_BIT_REQUEST_WIFI (1<<LOC_API_ADAPTER_REQUEST_WIFI) +#define LOC_API_ADAPTER_BIT_SENSOR_STATUS (1<<LOC_API_ADAPTER_SENSOR_STATUS) +#define LOC_API_ADAPTER_BIT_REQUEST_TIME_SYNC (1<<LOC_API_ADAPTER_REQUEST_TIME_SYNC) +#define LOC_API_ADAPTER_BIT_REPORT_SPI (1<<LOC_API_ADAPTER_REPORT_SPI) +#define LOC_API_ADAPTER_BIT_REPORT_NI_GEOFENCE (1<<LOC_API_ADAPTER_REPORT_NI_GEOFENCE) +#define LOC_API_ADAPTER_BIT_GEOFENCE_GEN_ALERT (1<<LOC_API_ADAPTER_GEOFENCE_GEN_ALERT) +#define LOC_API_ADAPTER_BIT_REPORT_GENFENCE_BREACH (1<<LOC_API_ADAPTER_REPORT_GENFENCE_BREACH) +#define LOC_API_ADAPTER_BIT_BATCHED_GENFENCE_BREACH_REPORT (1<<LOC_API_ADAPTER_BATCHED_GENFENCE_BREACH_REPORT) +#define LOC_API_ADAPTER_BIT_PEDOMETER_CTRL (1<<LOC_API_ADAPTER_PEDOMETER_CTRL) +#define LOC_API_ADAPTER_BIT_MOTION_CTRL (1<<LOC_API_ADAPTER_MOTION_CTRL) +#define LOC_API_ADAPTER_BIT_REQUEST_WIFI_AP_DATA (1<<LOC_API_ADAPTER_REQUEST_WIFI_AP_DATA) +#define LOC_API_ADAPTER_BIT_BATCH_FULL (1<<LOC_API_ADAPTER_BATCH_FULL) +#define LOC_API_ADAPTER_BIT_BATCHED_POSITION_REPORT (1<<LOC_API_ADAPTER_BATCHED_POSITION_REPORT) +#define LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT_REPORT (1<<LOC_API_ADAPTER_GNSS_MEASUREMENT_REPORT) +#define LOC_API_ADAPTER_BIT_GNSS_SV_POLYNOMIAL_REPORT (1<<LOC_API_ADAPTER_GNSS_SV_POLYNOMIAL_REPORT) +#define LOC_API_ADAPTER_BIT_GDT_UPLOAD_BEGIN_REQ (1<<LOC_API_ADAPTER_GDT_UPLOAD_BEGIN_REQ) +#define LOC_API_ADAPTER_BIT_GDT_UPLOAD_END_REQ (1<<LOC_API_ADAPTER_GDT_UPLOAD_END_REQ) +#define LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT (1<<LOC_API_ADAPTER_GNSS_MEASUREMENT) +#define LOC_API_ADAPTER_BIT_REQUEST_TIMEZONE (1<<LOC_API_ADAPTER_REQUEST_TIMEZONE) +#define LOC_API_ADAPTER_BIT_REPORT_GENFENCE_DWELL (1<<LOC_API_ADAPTER_REPORT_GENFENCE_DWELL_REPORT) +#define LOC_API_ADAPTER_BIT_REQUEST_SRN_DATA (1<<LOC_API_ADAPTER_REQUEST_SRN_DATA) +#define LOC_API_ADAPTER_BIT_POSITION_INJECTION_REQUEST (1<<LOC_API_ADAPTER_REQUEST_POSITION_INJECTION) +#define LOC_API_ADAPTER_BIT_BATCH_STATUS (1<<LOC_API_ADAPTER_BATCH_STATUS) +#define LOC_API_ADAPTER_BIT_FDCL_SERVICE_REQ (1ULL<<LOC_API_ADAPTER_FDCL_SERVICE_REQ) +#define LOC_API_ADAPTER_BIT_PARSED_UNPROPAGATED_POSITION_REPORT (1ULL<<LOC_API_ADAPTER_REPORT_UNPROPAGATED_POSITION) +#define LOC_API_ADAPTER_BIT_BS_OBS_DATA_SERVICE_REQ (1ULL<<LOC_API_ADAPTER_BS_OBS_DATA_SERVICE_REQ) +#define LOC_API_ADAPTER_BIT_GNSS_SV_EPHEMERIS_REPORT (1ULL<<LOC_API_ADAPTER_GNSS_SV_EPHEMERIS_REPORT) +#define LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO (1ULL<<LOC_API_ADAPTER_LOC_SYSTEM_INFO) +#define LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT (1ULL<<LOC_API_ADAPTER_GNSS_NHZ_MEASUREMENT_REPORT) +#define LOC_API_ADAPTER_BIT_EVENT_REPORT_INFO (1ULL<<LOC_API_ADAPTER_EVENT_REPORT_INFO) + +typedef uint64_t LOC_API_ADAPTER_EVENT_MASK_T; + +typedef enum loc_api_adapter_msg_to_check_supported { + LOC_API_ADAPTER_MESSAGE_LOCATION_BATCHING, // Batching 1.0 + LOC_API_ADAPTER_MESSAGE_BATCHED_GENFENCE_BREACH, // Geofence Batched Breach + LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING, // DBT 2.0 + LOC_API_ADAPTER_MESSAGE_ADAPTIVE_LOCATION_BATCHING, // Batching 1.5 + LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING, // Batching 2.0 + LOC_API_ADAPTER_MESSAGE_UPDATE_TBF_ON_THE_FLY, // Updating Tracking TBF On The Fly + LOC_API_ADAPTER_MESSAGE_OUTDOOR_TRIP_BATCHING, // Outdoor Trip Batching + + LOC_API_ADAPTER_MESSAGE_MAX +} LocCheckingMessagesID; + +typedef int IzatDevId_t; + +typedef uint32_t LOC_GPS_LOCK_MASK; +#define isGpsLockNone(lock) ((lock) == 0) +#define isGpsLockMO(lock) ((lock) & ((LOC_GPS_LOCK_MASK)1)) +#define isGpsLockMT(lock) ((lock) & ((LOC_GPS_LOCK_MASK)2)) +#define isGpsLockAll(lock) (((lock) & ((LOC_GPS_LOCK_MASK)3)) == 3) + +/*++ *********************************************** +** Satellite Measurement and Satellite Polynomial +** Structure definitions +** *********************************************** +--*/ +#define GNSS_SV_POLY_VELOCITY_COEF_MAX_SIZE 12 +#define GNSS_SV_POLY_XYZ_0_TH_ORDER_COEFF_MAX_SIZE 3 +#define GNSS_SV_POLY_XYZ_N_TH_ORDER_COEFF_MAX_SIZE 9 +#define GNSS_SV_POLY_SV_CLKBIAS_COEFF_MAX_SIZE 4 +/** Max number of GNSS SV measurement */ +#define GNSS_LOC_SV_MEAS_LIST_MAX_SIZE 128 + +enum ulp_gnss_sv_measurement_valid_flags{ + + ULP_GNSS_SV_MEAS_GPS_TIME = 0, + ULP_GNSS_SV_MEAS_PSUEDO_RANGE, + ULP_GNSS_SV_MEAS_MS_IN_WEEK, + ULP_GNSS_SV_MEAS_SUB_MSEC, + ULP_GNSS_SV_MEAS_CARRIER_PHASE, + ULP_GNSS_SV_MEAS_DOPPLER_SHIFT, + ULP_GNSS_SV_MEAS_CNO, + ULP_GNSS_SV_MEAS_LOSS_OF_LOCK, + + ULP_GNSS_SV_MEAS_MAX_VALID_FLAGS +}; + +#define ULP_GNSS_SV_MEAS_BIT_GPS_TIME (1<<ULP_GNSS_SV_MEAS_GPS_TIME) +#define ULP_GNSS_SV_MEAS_BIT_PSUEDO_RANGE (1<<ULP_GNSS_SV_MEAS_PSUEDO_RANGE) +#define ULP_GNSS_SV_MEAS_BIT_MS_IN_WEEK (1<<ULP_GNSS_SV_MEAS_MS_IN_WEEK) +#define ULP_GNSS_SV_MEAS_BIT_SUB_MSEC (1<<ULP_GNSS_SV_MEAS_SUB_MSEC) +#define ULP_GNSS_SV_MEAS_BIT_CARRIER_PHASE (1<<ULP_GNSS_SV_MEAS_CARRIER_PHASE) +#define ULP_GNSS_SV_MEAS_BIT_DOPPLER_SHIFT (1<<ULP_GNSS_SV_MEAS_DOPPLER_SHIFT) +#define ULP_GNSS_SV_MEAS_BIT_CNO (1<<ULP_GNSS_SV_MEAS_CNO) +#define ULP_GNSS_SV_MEAS_BIT_LOSS_OF_LOCK (1<<ULP_GNSS_SV_MEAS_LOSS_OF_LOCK) + +enum ulp_gnss_sv_poly_valid_flags{ + + ULP_GNSS_SV_POLY_GLO_FREQ = 0, + ULP_GNSS_SV_POLY_T0, + ULP_GNSS_SV_POLY_IODE, + ULP_GNSS_SV_POLY_FLAG, + ULP_GNSS_SV_POLY_POLYCOEFF_XYZ0, + ULP_GNSS_SV_POLY_POLYCOEFF_XYZN, + ULP_GNSS_SV_POLY_POLYCOEFF_OTHER, + ULP_GNSS_SV_POLY_SV_POSUNC, + ULP_GNSS_SV_POLY_IONODELAY, + ULP_GNSS_SV_POLY_IONODOT, + ULP_GNSS_SV_POLY_SBAS_IONODELAY, + ULP_GNSS_SV_POLY_SBAS_IONODOT, + ULP_GNSS_SV_POLY_TROPODELAY, + ULP_GNSS_SV_POLY_ELEVATION, + ULP_GNSS_SV_POLY_ELEVATIONDOT, + ULP_GNSS_SV_POLY_ELEVATIONUNC, + ULP_GNSS_SV_POLY_VELO_COEFF, + ULP_GNSS_SV_POLY_ENHANCED_IOD, + ULP_GNSS_SV_POLY_GPS_ISC_L1CA, + ULP_GNSS_SV_POLY_GPS_ISC_L2C, + ULP_GNSS_SV_POLY_GPS_ISC_L5I5, + ULP_GNSS_SV_POLY_GPS_ISC_L5Q5, + ULP_GNSS_SV_POLY_GPS_TGD, + ULP_GNSS_SV_POLY_GLO_TGD_G1G2, + ULP_GNSS_SV_POLY_BDS_TGD_B1, + ULP_GNSS_SV_POLY_BDS_TGD_B2, + ULP_GNSS_SV_POLY_BDS_TGD_B2A, + ULP_GNSS_SV_POLY_BDS_ISC_B2A, + ULP_GNSS_SV_POLY_GAL_BGD_E1E5A, + ULP_GNSS_SV_POLY_GAL_BGD_E1E5B, + ULP_GNSS_SV_POLY_NAVIC_TGD_L5 +}; + +#define ULP_GNSS_SV_POLY_BIT_GLO_FREQ (1<<ULP_GNSS_SV_POLY_GLO_FREQ) +#define ULP_GNSS_SV_POLY_BIT_T0 (1<<ULP_GNSS_SV_POLY_T0) +#define ULP_GNSS_SV_POLY_BIT_IODE (1<<ULP_GNSS_SV_POLY_IODE) +#define ULP_GNSS_SV_POLY_BIT_FLAG (1<<ULP_GNSS_SV_POLY_FLAG) +#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_XYZ0 (1<<ULP_GNSS_SV_POLY_POLYCOEFF_XYZ0) +#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_XYZN (1<<ULP_GNSS_SV_POLY_POLYCOEFF_XYZN) +#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_OTHER (1<<ULP_GNSS_SV_POLY_POLYCOEFF_OTHER) +#define ULP_GNSS_SV_POLY_BIT_SV_POSUNC (1<<ULP_GNSS_SV_POLY_SV_POSUNC) +#define ULP_GNSS_SV_POLY_BIT_IONODELAY (1<<ULP_GNSS_SV_POLY_IONODELAY) +#define ULP_GNSS_SV_POLY_BIT_IONODOT (1<<ULP_GNSS_SV_POLY_IONODOT) +#define ULP_GNSS_SV_POLY_BIT_SBAS_IONODELAY (1<<ULP_GNSS_SV_POLY_SBAS_IONODELAY) +#define ULP_GNSS_SV_POLY_BIT_SBAS_IONODOT (1<<ULP_GNSS_SV_POLY_SBAS_IONODOT) +#define ULP_GNSS_SV_POLY_BIT_TROPODELAY (1<<ULP_GNSS_SV_POLY_TROPODELAY) +#define ULP_GNSS_SV_POLY_BIT_ELEVATION (1<<ULP_GNSS_SV_POLY_ELEVATION) +#define ULP_GNSS_SV_POLY_BIT_ELEVATIONDOT (1<<ULP_GNSS_SV_POLY_ELEVATIONDOT) +#define ULP_GNSS_SV_POLY_BIT_ELEVATIONUNC (1<<ULP_GNSS_SV_POLY_ELEVATIONUNC) +#define ULP_GNSS_SV_POLY_BIT_VELO_COEFF (1<<ULP_GNSS_SV_POLY_VELO_COEFF) +#define ULP_GNSS_SV_POLY_BIT_ENHANCED_IOD (1<<ULP_GNSS_SV_POLY_ENHANCED_IOD) +#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L1CA (1<<ULP_GNSS_SV_POLY_GPS_ISC_L1CA) +#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L2C (1<<ULP_GNSS_SV_POLY_GPS_ISC_L2C) +#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L5I5 (1<<ULP_GNSS_SV_POLY_GPS_ISC_L5I5) +#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L5Q5 (1<<ULP_GNSS_SV_POLY_GPS_ISC_L5Q5) +#define ULP_GNSS_SV_POLY_BIT_GPS_TGD (1<<ULP_GNSS_SV_POLY_GPS_TGD) +#define ULP_GNSS_SV_POLY_BIT_GLO_TGD_G1G2 (1<<ULP_GNSS_SV_POLY_GLO_TGD_G1G2) +#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B1 (1<<ULP_GNSS_SV_POLY_BDS_TGD_B1) +#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B2 (1<<ULP_GNSS_SV_POLY_BDS_TGD_B2) +#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B2A (1<<ULP_GNSS_SV_POLY_BDS_TGD_B2A) +#define ULP_GNSS_SV_POLY_BIT_BDS_ISC_B2A (1<<ULP_GNSS_SV_POLY_BDS_ISC_B2A) +#define ULP_GNSS_SV_POLY_BIT_GAL_BGD_E1E5A (1<<ULP_GNSS_SV_POLY_GAL_BGD_E1E5A) +#define ULP_GNSS_SV_POLY_BIT_GAL_BGD_E1E5B (1<<ULP_GNSS_SV_POLY_GAL_BGD_E1E5B) +#define ULP_GNSS_SV_POLY_BIT_NAVIC_TGD_L5 (1<<ULP_GNSS_SV_POLY_NAVIC_TGD_L5) + +typedef enum +{ + GNSS_LOC_FREQ_SOURCE_INVALID = 0, + /**< Source of the frequency is invalid */ + GNSS_LOC_FREQ_SOURCE_EXTERNAL = 1, + /**< Source of the frequency is from external injection */ + GNSS_LOC_FREQ_SOURCE_PE_CLK_REPORT = 2, + /**< Source of the frequency is from Navigation engine */ + GNSS_LOC_FREQ_SOURCE_UNKNOWN = 3 + /**< Source of the frequency is unknown */ +} Gnss_LocSourceofFreqEnumType; + +typedef struct +{ + uint32_t size; + float clockDrift; + /**< Receiver clock Drift \n + - Units: meter per sec \n + */ + float clockDriftUnc; + /**< Receiver clock Drift uncertainty \n + - Units: meter per sec \n + */ + Gnss_LocSourceofFreqEnumType sourceOfFreq; +}Gnss_LocRcvrClockFrequencyInfoStructType; + +typedef struct +{ + uint32_t size; + uint8_t leapSec; + /**< GPS time leap second delta to UTC time \n + - Units: sec \n + */ + uint8_t leapSecUnc; + /**< Uncertainty for GPS leap second \n + - Units: sec \n + */ +}Gnss_LeapSecondInfoStructType; + +typedef enum +{ + GNSS_LOC_SYS_TIME_BIAS_VALID = 0x01, + /**< System time bias valid */ + GNSS_LOC_SYS_TIME_BIAS_UNC_VALID = 0x02, + /**< System time bias uncertainty valid */ +}Gnss_LocInterSystemBiasValidMaskType; + +typedef struct +{ + uint32_t size; + uint32_t validMask; + /* Validity mask as per Gnss_LocInterSystemBiasValidMaskType */ + + float timeBias; + /**< System-1 to System-2 Time Bias \n + - Units: msec \n + */ + float timeBiasUnc; + /**< System-1 to System-2 Time Bias uncertainty \n + - Units: msec \n + */ +} Gnss_InterSystemBiasStructType; + + +typedef struct { + + uint32_t size; + + uint8_t systemRtc_valid; + /**< Validity indicator for System RTC */ + + uint64_t systemRtcMs; + /**< Platform system RTC value \n + - Units: msec \n + */ + +}Gnss_LocGnssTimeExtStructType; + +typedef enum +{ + GNSS_LOC_MEAS_STATUS_NULL = 0x00000000, + /**< No information state */ + GNSS_LOC_MEAS_STATUS_SM_VALID = 0x00000001, + /**< Code phase is known */ + GNSS_LOC_MEAS_STATUS_SB_VALID = 0x00000002, + /**< Sub-bit time is known */ + GNSS_LOC_MEAS_STATUS_MS_VALID = 0x00000004, + /**< Satellite time is known */ + GNSS_LOC_MEAS_STATUS_BE_CONFIRM = 0x00000008, + /**< Bit edge is confirmed from signal */ + GNSS_LOC_MEAS_STATUS_VELOCITY_VALID = 0x00000010, + /**< Satellite Doppler measured */ + GNSS_LOC_MEAS_STATUS_VELOCITY_FINE = 0x00000020, + /**< TRUE: Fine Doppler measured, FALSE: Coarse Doppler measured */ + GNSS_LOC_MEAS_STATUS_FROM_RNG_DIFF = 0x00000200, + /**< Range update from Satellite differences */ + GNSS_LOC_MEAS_STATUS_FROM_VE_DIFF = 0x00000400, + /**< Doppler update from Satellite differences */ + GNSS_LOC_MEAS_STATUS_DONT_USE_X = 0x00000800, + /**< Don't use measurement if bit is set */ + GNSS_LOC_MEAS_STATUS_DONT_USE_M = 0x000001000, + /**< Don't use measurement if bit is set */ + GNSS_LOC_MEAS_STATUS_DONT_USE_D = 0x000002000, + /**< Don't use measurement if bit is set */ + GNSS_LOC_MEAS_STATUS_DONT_USE_S = 0x000004000, + /**< Don't use measurement if bit is set */ + GNSS_LOC_MEAS_STATUS_DONT_USE_P = 0x000008000 + /**< Don't use measurement if bit is set */ +}Gnss_LocSvMeasStatusMaskType; + +typedef struct +{ + uint32_t size; + uint32_t svMs; + /**< Satellite time milisecond.\n + For GPS, BDS, GAL range of 0 thru (604800000-1) \n + For GLONASS range of 0 thru (86400000-1) \n + Valid when PD_LOC_MEAS_STATUS_MS_VALID bit is set in measurement status \n + Note: All SV times in the current measurement block are alredy propagated to common reference time epoch. \n + - Units: msec \n + */ + float svSubMs; + /**<Satellite time sub-millisecond. \n + Total SV Time = svMs + svSubMs \n + - Units: msec \n + */ + float svTimeUncMs; + /**< Satellite Time uncertainty \n + - Units: msec \n + */ + float dopplerShift; + /**< Satellite Doppler \n + - Units: meter per sec \n + */ + float dopplerShiftUnc; + /**< Satellite Doppler uncertainty\n + - Units: meter per sec \n + */ +}Gnss_LocSVTimeSpeedStructType; + +typedef enum +{ + GNSS_SV_STATE_IDLE = 0, + GNSS_SV_STATE_SEARCH = 1, + GNSS_SV_STATE_SEARCH_VERIFY = 2, + GNSS_SV_STATE_BIT_EDGE = 3, + GNSS_SV_STATE_VERIFY_TRACK = 4, + GNSS_SV_STATE_TRACK = 5, + GNSS_SV_STATE_RESTART = 6, + GNSS_SV_STATE_DPO_TRACK = 7 +} Gnss_LocSVStateEnumType; + +typedef enum +{ + GNSS_LOC_SVINFO_MASK_HAS_EPHEMERIS = 0x01, + /**< Ephemeris is available for this SV */ + GNSS_LOC_SVINFO_MASK_HAS_ALMANAC = 0x02 + /**< Almanac is available for this SV */ +}Gnss_LocSvInfoMaskT; + +typedef enum +{ + GNSS_LOC_SV_SRCH_STATUS_IDLE = 1, + /**< SV is not being actively processed */ + GNSS_LOC_SV_SRCH_STATUS_SEARCH = 2, + /**< The system is searching for this SV */ + GNSS_LOC_SV_SRCH_STATUS_TRACK = 3 + /**< SV is being tracked */ +}Gnss_LocSvSearchStatusEnumT; + +typedef struct +{ + uint32_t size; + Gnss_LocSvSystemEnumType gnssSystem; + // 0 signal type mask indicates invalid value + GnssSignalTypeMask gnssSignalTypeMask; + uint16_t gnssSvId; + /**< GNSS SV ID. + \begin{itemize1} + \item Range: \begin{itemize1} + \item For GPS: 1 to 32 + \item For GLONASS: 1 to 32 + \item For SBAS: 120 to 151 + \item For BDS: 201 to 237 + \end{itemize1} \end{itemize1} + The GPS and GLONASS SVs can be disambiguated using the system field. + */ + uint8_t gloFrequency; + /**< GLONASS frequency number + 7 \n + Valid only for GLONASS System \n + Shall be ignored for all other systems \n + - Range: 1 to 14 \n + */ + Gnss_LocSvSearchStatusEnumT svStatus; + /**< Satellite search state \n + @ENUM() + */ + bool healthStatus_valid; + /**< SV Health Status validity flag\n + - 0: Not valid \n + - 1: Valid \n + */ + uint8_t healthStatus; + /**< Health status. + \begin{itemize1} + \item Range: 0 to 1; 0 = unhealthy, \n 1 = healthy, 2 = unknown + \vspace{-0.18in} \end{itemize1} + */ + Gnss_LocSvInfoMaskT svInfoMask; + /**< Indicates whether almanac and ephemeris information is available. \n + @MASK() + */ + uint64_t measurementStatus; + /**< Bitmask indicating SV measurement status. + Valid bitmasks: \n + If any MSB bit in 0xFFC0000000000000 DONT_USE is set, the measurement + must not be used by the client. + @MASK() + */ + uint16_t CNo; + /**< Carrier to Noise ratio \n + - Units: 0.1 dBHz \n + */ + uint16_t gloRfLoss; + /**< GLONASS Rf loss reference to Antenna. \n + - Units: dB, Scale: 0.1 \n + */ + bool lossOfLock; + /**< Loss of signal lock indicator \n + - 0: Signal in continuous track \n + - 1: Signal not in track \n + */ + int16_t measLatency; + /**< Age of the measurement. Positive value means measurement precedes ref time. \n + - Units: msec \n + */ + Gnss_LocSVTimeSpeedStructType svTimeSpeed; + /**< Unfiltered SV Time and Speed information + */ + float dopplerAccel; + /**< Satellite Doppler Accelertion\n + - Units: Hz/s \n + */ + bool multipathEstValid; + /**< Multipath estimate validity flag\n + - 0: Multipath estimate not valid \n + - 1: Multipath estimate valid \n + */ + float multipathEstimate; + /**< Estimate of multipath in measurement\n + - Units: Meters \n + */ + bool fineSpeedValid; + /**< Fine speed validity flag\n + - 0: Fine speed not valid \n + - 1: Fine speed valid \n + */ + float fineSpeed; + /**< Carrier phase derived speed \n + - Units: m/s \n + */ + bool fineSpeedUncValid; + /**< Fine speed uncertainty validity flag\n + - 0: Fine speed uncertainty not valid \n + - 1: Fine speed uncertainty valid \n + */ + float fineSpeedUnc; + /**< Carrier phase derived speed \n + - Units: m/s \n + */ + bool carrierPhaseValid; + /**< Carrier Phase measurement validity flag\n + - 0: Carrier Phase not valid \n + - 1: Carrier Phase valid \n + */ + double carrierPhase; + /**< Carrier phase measurement [L1 cycles] \n + */ + bool cycleSlipCountValid; + /**< Cycle slup count validity flag\n + - 0: Not valid \n + - 1: Valid \n + */ + uint8_t cycleSlipCount; + /**< Increments when a CSlip is detected */ + + bool svDirectionValid; + /**< Validity flag for SV direction */ + + float svAzimuth; + /**< Satellite Azimuth + - Units: radians \n + */ + float svElevation; + /**< Satellite Elevation + - Units: radians \n + */ + uint64_t validMeasStatusMask; + /**< Bitmask indicating SV measurement status Validity. + Valid bitmasks: \n + If any MSB bit in 0xFFC0000000000000 DONT_USE is set, the measurement + must not be used by the client. + @MASK() + */ + bool carrierPhaseUncValid; + /**< Validity flag for SV direction */ + + float carrierPhaseUnc; + + +} Gnss_SVMeasurementStructType; + + +typedef uint64_t GpsSvMeasHeaderFlags; +#define GNSS_SV_MEAS_HEADER_HAS_LEAP_SECOND 0x00000001 +#define GNSS_SV_MEAS_HEADER_HAS_CLOCK_FREQ 0x00000002 +#define GNSS_SV_MEAS_HEADER_HAS_AP_TIMESTAMP 0x00000004 +#define GNSS_SV_MEAS_HEADER_HAS_GPS_GLO_INTER_SYSTEM_BIAS 0x00000008 +#define GNSS_SV_MEAS_HEADER_HAS_GPS_BDS_INTER_SYSTEM_BIAS 0x00000010 +#define GNSS_SV_MEAS_HEADER_HAS_GPS_GAL_INTER_SYSTEM_BIAS 0x00000020 +#define GNSS_SV_MEAS_HEADER_HAS_BDS_GLO_INTER_SYSTEM_BIAS 0x00000040 +#define GNSS_SV_MEAS_HEADER_HAS_GAL_GLO_INTER_SYSTEM_BIAS 0x00000080 +#define GNSS_SV_MEAS_HEADER_HAS_GAL_BDS_INTER_SYSTEM_BIAS 0x00000100 +#define GNSS_SV_MEAS_HEADER_HAS_GPS_SYSTEM_TIME 0x00000200 +#define GNSS_SV_MEAS_HEADER_HAS_GAL_SYSTEM_TIME 0x00000400 +#define GNSS_SV_MEAS_HEADER_HAS_BDS_SYSTEM_TIME 0x00000800 +#define GNSS_SV_MEAS_HEADER_HAS_QZSS_SYSTEM_TIME 0x00001000 +#define GNSS_SV_MEAS_HEADER_HAS_GLO_SYSTEM_TIME 0x00002000 +#define GNSS_SV_MEAS_HEADER_HAS_GPS_SYSTEM_TIME_EXT 0x00004000 +#define GNSS_SV_MEAS_HEADER_HAS_GAL_SYSTEM_TIME_EXT 0x00008000 +#define GNSS_SV_MEAS_HEADER_HAS_BDS_SYSTEM_TIME_EXT 0x00010000 +#define GNSS_SV_MEAS_HEADER_HAS_QZSS_SYSTEM_TIME_EXT 0x00020000 +#define GNSS_SV_MEAS_HEADER_HAS_GLO_SYSTEM_TIME_EXT 0x00040000 +#define GNSS_SV_MEAS_HEADER_HAS_GPSL1L5_TIME_BIAS 0x00080000 +#define GNSS_SV_MEAS_HEADER_HAS_GALE1E5A_TIME_BIAS 0x00100000 +#define GNSS_SV_MEAS_HEADER_HAS_GPS_NAVIC_INTER_SYSTEM_BIAS 0x00200000 +#define GNSS_SV_MEAS_HEADER_HAS_GAL_NAVIC_INTER_SYSTEM_BIAS 0x00400000 +#define GNSS_SV_MEAS_HEADER_HAS_GLO_NAVIC_INTER_SYSTEM_BIAS 0x00800000 +#define GNSS_SV_MEAS_HEADER_HAS_BDS_NAVIC_INTER_SYSTEM_BIAS 0x01000000 +#define GNSS_SV_MEAS_HEADER_HAS_NAVIC_SYSTEM_TIME 0x02000000 +#define GNSS_SV_MEAS_HEADER_HAS_NAVIC_SYSTEM_TIME_EXT 0x04000000 + +typedef struct +{ + uint32_t size; + // see defines in GNSS_SV_MEAS_HEADER_HAS_XXX_XXX + uint64_t flags; + + Gnss_LeapSecondInfoStructType leapSec; + + Gnss_LocRcvrClockFrequencyInfoStructType clockFreq; /* Freq */ + + Gnss_ApTimeStampStructType apBootTimeStamp; + + Gnss_InterSystemBiasStructType gpsGloInterSystemBias; + Gnss_InterSystemBiasStructType gpsBdsInterSystemBias; + Gnss_InterSystemBiasStructType gpsGalInterSystemBias; + Gnss_InterSystemBiasStructType bdsGloInterSystemBias; + Gnss_InterSystemBiasStructType galGloInterSystemBias; + Gnss_InterSystemBiasStructType galBdsInterSystemBias; + Gnss_InterSystemBiasStructType gpsNavicInterSystemBias; + Gnss_InterSystemBiasStructType galNavicInterSystemBias; + Gnss_InterSystemBiasStructType gloNavicInterSystemBias; + Gnss_InterSystemBiasStructType bdsNavicInterSystemBias; + Gnss_InterSystemBiasStructType gpsL1L5TimeBias; + Gnss_InterSystemBiasStructType galE1E5aTimeBias; + + GnssSystemTimeStructType gpsSystemTime; + GnssSystemTimeStructType galSystemTime; + GnssSystemTimeStructType bdsSystemTime; + GnssSystemTimeStructType qzssSystemTime; + GnssSystemTimeStructType navicSystemTime; + GnssGloTimeStructType gloSystemTime; + + /** GPS system RTC time information. */ + Gnss_LocGnssTimeExtStructType gpsSystemTimeExt; + /** GAL system RTC time information. */ + Gnss_LocGnssTimeExtStructType galSystemTimeExt; + /** BDS system RTC time information. */ + Gnss_LocGnssTimeExtStructType bdsSystemTimeExt; + /** QZSS system RTC time information. */ + Gnss_LocGnssTimeExtStructType qzssSystemTimeExt; + /** GLONASS system RTC time information. */ + Gnss_LocGnssTimeExtStructType gloSystemTimeExt; + /** NAVIC system RTC time information. */ + Gnss_LocGnssTimeExtStructType navicSystemTimeExt; +} GnssSvMeasurementHeader; + +typedef struct { + uint32_t size; + bool isNhz; + GnssSvMeasurementHeader svMeasSetHeader; + uint32_t svMeasCount; + Gnss_SVMeasurementStructType svMeas[GNSS_LOC_SV_MEAS_LIST_MAX_SIZE]; + +} GnssSvMeasurementSet; + +typedef struct { + uint32_t size; // set to sizeof(GnssMeasurements) + GnssSvMeasurementSet gnssSvMeasurementSet; + GnssMeasurementsNotification gnssMeasNotification; +} GnssMeasurements; + +typedef enum +{ + GNSS_SV_POLY_COEFF_VALID = 0x01, + /**< SV position in orbit coefficients are valid */ + GNSS_SV_POLY_IONO_VALID = 0x02, + /**< Iono estimates are valid */ + + GNSS_SV_POLY_TROPO_VALID = 0x04, + /**< Tropo estimates are valid */ + + GNSS_SV_POLY_ELEV_VALID = 0x08, + /**< Elevation, rate, uncertainty are valid */ + + GNSS_SV_POLY_SRC_ALM_CORR = 0x10, + /**< Polynomials based on XTRA */ + + GNSS_SV_POLY_SBAS_IONO_VALID = 0x20, + /**< SBAS IONO and rate are valid */ + + GNSS_SV_POLY_GLO_STR4 = 0x40 + /**< GLONASS String 4 has been received */ +}Gnss_SvPolyStatusMaskType; + + +typedef struct +{ + uint32_t size; + uint16_t gnssSvId; + /* GPS: 1-32, GLO: 65-96, 0: Invalid, + SBAS: 120-151, BDS:201-237,GAL:301 to 336 + All others are reserved + */ + int8_t freqNum; + /* Freq index, only valid if u_SysInd is GLO */ + + GnssSvPolyStatusMaskValidity svPolyStatusMaskValidity; + GnssSvPolyStatusMask svPolyStatusMask; + + uint32_t is_valid; + + uint16_t iode; + /* Ephemeris reference time + GPS:Issue of Data Ephemeris used [unitless]. + GLO: Tb 7-bit, refer to ICD02 + */ + double T0; + /* Reference time for polynominal calculations + GPS: Secs in week. + GLO: Full secs since Jan/01/96 + */ + double polyCoeffXYZ0[GNSS_SV_POLY_XYZ_0_TH_ORDER_COEFF_MAX_SIZE]; + /* C0X, C0Y, C0Z */ + double polyCoefXYZN[GNSS_SV_POLY_XYZ_N_TH_ORDER_COEFF_MAX_SIZE]; + /* C1X, C2X ... C2Z, C3Z */ + float polyCoefOther[GNSS_SV_POLY_SV_CLKBIAS_COEFF_MAX_SIZE]; + /* C0T, C1T, C2T, C3T */ + float svPosUnc; /* SV position uncertainty [m]. */ + float ionoDelay; /* Ionospheric delay at d_T0 [m]. */ + float ionoDot; /* Iono delay rate [m/s]. */ + float sbasIonoDelay;/* SBAS Ionospheric delay at d_T0 [m]. */ + float sbasIonoDot; /* SBAS Iono delay rate [m/s]. */ + float tropoDelay; /* Tropospheric delay [m]. */ + float elevation; /* Elevation [rad] at d_T0 */ + float elevationDot; /* Elevation rate [rad/s] */ + float elevationUnc; /* SV elevation [rad] uncertainty */ + double velCoef[GNSS_SV_POLY_VELOCITY_COEF_MAX_SIZE]; + /* Coefficients of velocity poly */ + uint32_t enhancedIOD; /* Enhanced Reference Time */ + float gpsIscL1ca; + float gpsIscL2c; + float gpsIscL5I5; + float gpsIscL5Q5; + float gpsTgd; + float gloTgdG1G2; + float bdsTgdB1; + float bdsTgdB2; + float bdsTgdB2a; + float bdsIscB2a; + float galBgdE1E5a; + float galBgdE1E5b; + float navicTgdL5; +} GnssSvPolynomial; + +typedef enum { + GNSS_EPH_ACTION_UPDATE_SRC_UNKNOWN_V02 = 0, /**<Update ephemeris. Source of ephemeris is unknown */ + GNSS_EPH_ACTION_UPDATE_SRC_OTA_V02 = 1, /**<Update ephemeris. Source of ephemeris is OTA */ + GNSS_EPH_ACTION_UPDATE_SRC_NETWORK_V02 = 2, /**<Update ephemeris. Source of ephemeris is Network */ + GNSS_EPH_ACTION_UPDATE_MAX_V02 = 999, /**<Max value for update ephemeris action. DO NOT USE */ + GNSS_EPH_ACTION_DELETE_SRC_UNKNOWN_V02 = 1000, /**<Delete previous ephemeris from unknown source */ + GNSS_EPH_ACTION_DELETE_SRC_NETWORK_V02 = 1001, /**<Delete previous ephemeris from network */ + GNSS_EPH_ACTION_DELETE_SRC_OTA_V02 = 1002, /**<Delete previous ephemeris from OTA */ + GNSS_EPH_ACTION_DELETE_MAX_V02 = 1999, /**<Max value for delete ephemeris action. DO NOT USE */ +} GnssEphAction; + +typedef enum { + GAL_EPH_SIGNAL_SRC_UNKNOWN_V02 = 0, /**< GALILEO signal is unknown */ + GAL_EPH_SIGNAL_SRC_E1B_V02 = 1, /**< GALILEO signal is E1B */ + GAL_EPH_SIGNAL_SRC_E5A_V02 = 2, /**< GALILEO signal is E5A */ + GAL_EPH_SIGNAL_SRC_E5B_V02 = 3, /**< GALILEO signal is E5B */ +} GalEphSignalSource; + +typedef struct { + uint16_t gnssSvId; + /**< GNSS SV ID. + - Type: uint16 + \begin{itemize1} + \item Range: \begin{itemize1} + \item For GPS: 1 to 32 + \item For QZSS: 193 to 197 + \item For BDS: 201 to 237 + \item For GAL: 301 to 336 + \vspace{-0.18in} \end{itemize1} \end{itemize1} */ + + GnssEphAction updateAction; + /**< Specifies the action and source of ephemeris. \n + - Type: int32 enum */ + + uint16_t IODE; + /**< Issue of data ephemeris used (unit-less). \n + GPS: IODE 8 bits.\n + BDS: AODE 5 bits. \n + GAL: SIS IOD 10 bits. \n + - Type: uint16 + - Units: Unit-less */ + + double aSqrt; + /**< Square root of semi-major axis. \n + - Type: double + - Units: Square Root of Meters */ + + double deltaN; + /**< Mean motion difference from computed value. \n + - Type: double + - Units: Radians/Second */ + + double m0; + /**< Mean anomaly at reference time. \n + - Type: double + - Units: Radians */ + + double eccentricity; + /**< Eccentricity . \n + - Type: double + - Units: Unit-less */ + + double omega0; + /**< Longitude of ascending node of orbital plane at the weekly epoch. \n + - Type: double + - Units: Radians */ + + double i0; + /**< Inclination angle at reference time. \n + - Type: double + - Units: Radians */ + + double omega; + /**< Argument of Perigee. \n + - Type: double + - Units: Radians */ + + double omegaDot; + /**< Rate of change of right ascension. \n + - Type: double + - Units: Radians/Second */ + + double iDot; + /**< Rate of change of inclination angle. \n + - Type: double + - Units: Radians/Second */ + + double cUc; + /**< Amplitude of the cosine harmonic correction term to the argument of latitude. \n + - Type: double + - Units: Radians */ + + double cUs; + /**< Amplitude of the sine harmonic correction term to the argument of latitude. \n + - Type: double + - Units: Radians */ + + double cRc; + /**< Amplitude of the cosine harmonic correction term to the orbit radius. \n + - Type: double + - Units: Meters */ + + double cRs; + /**< Amplitude of the sine harmonic correction term to the orbit radius. \n + - Type: double + - Units: Meters */ + + double cIc; + /**< Amplitude of the cosine harmonic correction term to the angle of inclination. \n + - Type: double + - Units: Radians */ + + double cIs; + /**< Amplitude of the sine harmonic correction term to the angle of inclination. \n + - Type: double + - Units: Radians */ + + uint32_t toe; + /**< Reference time of ephemeris. \n + - Type: uint32 + - Units: Seconds */ + + uint32_t toc; + /**< Clock data reference time of week. \n + - Type: uint32 + - Units: Seconds */ + + double af0; + /**< Clock bias correction coefficient. \n + - Type: double + - Units: Seconds */ + + double af1; + /**< Clock drift coefficient. \n + - Type: double + - Units: Seconds/Second */ + + double af2; + /**< Clock drift rate correction coefficient. \n + - Type: double + - Units: Seconds/Seconds^2 */ + +} GnssEphCommon; + +/* GPS Navigation Model Info */ +typedef struct { + GnssEphCommon commonEphemerisData; + /**< Common ephemeris data. */ + + uint8_t signalHealth; + /**< Signal health. \n + Bit 0 : L5 Signal Health. \n + Bit 1 : L2 Signal Health. \n + Bit 2 : L1 Signal Health. \n + - Type: uint8 + - Values: 3 bit mask of signal health, where set bit indicates unhealthy signal */ + + uint8_t URAI; + /**< User Range Accuracy Index. \n + - Type: uint8 + - Units: Unit-less */ + + uint8_t codeL2; + /**< Indicates which codes are commanded ON for the L2 channel (2-bits). \n + - Type: uint8 + Valid Values: \n + - 00 : Reserved + - 01 : P code ON + - 10 : C/A code ON */ + + uint8_t dataFlagL2P; + /**< L2 P-code indication flag. \n + - Type: uint8 + - Value 1 indicates that the Nav data stream was commanded OFF on the P-code of the L2 channel. */ + + double tgd; + /**< Time of group delay. \n + - Type: double + - Units: Seconds */ + + uint8_t fitInterval; + /**< Indicates the curve-fit interval used by the CS. \n + - Type: uint8 + Valid Values: + - 0 : Four hours + - 1 : Greater than four hours */ + + uint16_t IODC; + /**< Issue of Data, Clock. \n + - Type: uint16 + - Units: Unit-less */ +} GpsEphemeris; + +/* GLONASS Navigation Model Info */ +typedef struct { + + uint16_t gnssSvId; + /**< GNSS SV ID. + - Type: uint16 + - Range: 65 to 96 if known. When the slot number to SV ID mapping is unknown, set to 255 */ + + GnssEphAction updateAction; + /**< Specifies the action and source of ephemeris. \n + - Type: int32 enum */ + + uint8_t bnHealth; + /**< SV health flags. \n + - Type: uint8 + Valid Values: \n + - 0 : Healthy + - 1 : Unhealthy */ + + uint8_t lnHealth; + /**< Ln SV health flags. GLONASS-M. \n + - Type: uint8 + Valid Values: \n + - 0 : Healthy + - 1 : Unhealthy */ + + uint8_t tb; + /**< Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. \n + - Type: uint8 + - Units: Unit-less */ + + uint8_t ft; + /**< SV accuracy index. \n + - Type: uint8 + - Units: Unit-less */ + + uint8_t gloM; + /**< GLONASS-M flag. \n + - Type: uint8 + Valid Values: \n + - 0 : GLONASS + - 1 : GLONASS-M */ + + uint8_t enAge; + /**< Characterizes "Age" of current information. \n + - Type: uint8 + - Units: Days */ + + uint8_t gloFrequency; + /**< GLONASS frequency number + 8. \n + - Type: uint8 + - Range: 1 to 14 + */ + + uint8_t p1; + /**< Time interval between two adjacent values of tb parameter. \n + - Type: uint8 + - Units: Minutes */ + + uint8_t p2; + /**< Flag of oddness ("1") or evenness ("0") of the value of tb \n + for intervals 30 or 60 minutes. \n + - Type: uint8 */ + + float deltaTau; + /**< Time difference between navigation RF signal transmitted in L2 sub-band \n + and aviation RF signal transmitted in L1 sub-band. \n + - Type: floating point + - Units: Seconds */ + + double position[3]; + /**< Satellite XYZ position. \n + - Type: array of doubles + - Units: Meters */ + + double velocity[3]; + /**< Satellite XYZ velocity. \n + - Type: array of doubles + - Units: Meters/Second */ + + double acceleration[3]; + /**< Satellite XYZ sola-luni acceleration. \n + - Type: array of doubles + - Units: Meters/Second^2 */ + + float tauN; + /**< Satellite clock correction relative to GLONASS time. \n + - Type: floating point + - Units: Seconds */ + + float gamma; + /**< Relative deviation of predicted carrier frequency value \n + from nominal value at the instant tb. \n + - Type: floating point + - Units: Unit-less */ + + double toe; + /**< Complete ephemeris time, including N4, NT and Tb. \n + [(N4-1)*1461 + (NT-1)]*86400 + tb*900 \n + - Type: double + - Units: Seconds */ + + uint16_t nt; + /**< Current date, calendar number of day within four-year interval. \n + Starting from the 1-st of January in a leap year. \n + - Type: uint16 + - Units: Days */ +} GlonassEphemeris; + +/* BDS Navigation Model Info */ +typedef struct { + + GnssEphCommon commonEphemerisData; + /**< Common ephemeris data. */ + + uint8_t svHealth; + /**< Satellite health information applied to both B1 and B2 (SatH1). \n + - Type: uint8 + Valid Values: \n + - 0 : Healthy + - 1 : Unhealthy */ + + uint8_t AODC; + /**< Age of data clock. \n + - Type: uint8 + - Units: Hours */ + + double tgd1; + /**< Equipment group delay differential on B1 signal. \n + - Type: double + - Units: Nano-Seconds */ + + double tgd2; + /**< Equipment group delay differential on B2 signal. \n + - Type: double + - Units: Nano-Seconds */ + + uint8_t URAI; + /**< User range accuracy index (4-bits). \n + - Type: uint8 + - Units: Unit-less */ +} BdsEphemeris; + +/* GALIELO Navigation Model Info */ +typedef struct { + + GnssEphCommon commonEphemerisData; + /**< Common ephemeris data. */ + + GalEphSignalSource dataSourceSignal; + /**< Galileo Signal Source. \n + Valid Values: \n + - GAL_EPH_SIGNAL_SRC_UNKNOWN (0) -- GALILEO signal is unknown + - GAL_EPH_SIGNAL_SRC_E1B (1) -- GALILEO signal is E1B + - GAL_EPH_SIGNAL_SRC_E5A (2) -- GALILEO signal is E5A + - GAL_EPH_SIGNAL_SRC_E5B (3) -- GALILEO signal is E5B */ + + uint8_t sisIndex; + /**< Signal-in-space index for dual frequency E1-E5b/E5a depending on dataSignalSource. \n + - Type: uint8 + - Units: Unit-less */ + + double bgdE1E5a; + /**< E1-E5a Broadcast group delay from F/Nav (E5A). \n + - Type: double + - Units: Seconds */ + + double bgdE1E5b; + /**< E1-E5b Broadcast group delay from I/Nav (E1B or E5B). \n + For E1B or E5B signal, both bgdE1E5a and bgdE1E5b are valid. \n + For E5A signal, only bgdE1E5a is valid. \n + Signal source identified using dataSignalSource. \n + - Type: double + - Units: Seconds */ + + uint8_t svHealth; + /**< SV health status of signal identified by dataSourceSignal. \n + - Type: uint8 + Valid Values: \n + - 0 : Healthy + - 1 : Unhealthy */ +} GalileoEphemeris; + +/** GPS Navigation model for each SV */ +typedef struct { + uint16_t numOfEphemeris; + GpsEphemeris gpsEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02]; +} GpsEphemerisResponse; + +/** GLONASS Navigation model for each SV */ +typedef struct { + uint16_t numOfEphemeris; + GlonassEphemeris gloEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02]; +} GlonassEphemerisResponse; + +/** BDS Navigation model for each SV */ +typedef struct { + uint16_t numOfEphemeris; + BdsEphemeris bdsEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02]; +} BdsEphemerisResponse; + +/** GALILEO Navigation model for each SV */ +typedef struct { + uint16_t numOfEphemeris; + GalileoEphemeris galEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02]; +} GalileoEphemerisResponse; + +/** QZSS Navigation model for each SV */ +typedef struct { + uint16_t numOfEphemeris; + GpsEphemeris qzssEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02]; +} QzssEphemerisResponse; + + +typedef struct { + /** Indicates GNSS Constellation Type + Mandatory field */ + Gnss_LocSvSystemEnumType gnssConstellation; + + /** GPS System Time of the ephemeris report */ + bool isSystemTimeValid; + GnssSystemTimeStructType systemTime; + + union { + /** GPS Ephemeris */ + GpsEphemerisResponse gpsEphemeris; + /** GLONASS Ephemeris */ + GlonassEphemerisResponse glonassEphemeris; + /** BDS Ephemeris */ + BdsEphemerisResponse bdsEphemeris; + /** GALILEO Ephemeris */ + GalileoEphemerisResponse galileoEphemeris; + /** QZSS Ephemeris */ + QzssEphemerisResponse qzssEphemeris; + } ephInfo; +} GnssSvEphemerisReport; + +typedef struct { + /** GPS System Time of the iono model report */ + bool isSystemTimeValid; + GnssSystemTimeStructType systemTime; + + /** Indicates GNSS Constellation Type */ + Gnss_LocSvSystemEnumType gnssConstellation; + + float alpha0; + /**< Klobuchar Model Parameter Alpha 0. + - Type: float + - Unit: Seconds + */ + + float alpha1; + /**< Klobuchar Model Parameter Alpha 1. + - Type: float + - Unit: Seconds / Semi-Circle + */ + + float alpha2; + /**< Klobuchar Model Parameter Alpha 2. + - Type: float + - Unit: Seconds / Semi-Circle^2 + */ + + float alpha3; + /**< Klobuchar Model Parameter Alpha 3. + - Type: float + - Unit: Seconds / Semi-Circle^3 + */ + + float beta0; + /**< Klobuchar Model Parameter Beta 0. + - Type: float + - Unit: Seconds + */ + + float beta1; + /**< Klobuchar Model Parameter Beta 1. + - Type: float + - Unit: Seconds / Semi-Circle + */ + + float beta2; + /**< Klobuchar Model Parameter Beta 2. + - Type: float + - Unit: Seconds / Semi-Circle^2 + */ + + float beta3; + /**< Klobuchar Model Parameter Beta 3. + - Type: float + - Unit: Seconds / Semi-Circle^3 + */ +} GnssKlobucharIonoModel; + +typedef struct { + /** GPS System Time of the report */ + bool isSystemTimeValid; + GnssSystemTimeStructType systemTime; + + GnssAdditionalSystemInfoMask validityMask; + double tauC; + int8_t leapSec; +} GnssAdditionalSystemInfo; + +/* Various Short Range Node Technology type*/ +typedef enum { + SRN_AP_DATA_TECH_TYPE_NONE, + SRN_AP_DATA_TECH_TYPE_BT, + SRN_AP_DATA_TECH_TYPE_BTLE, + SRN_AP_DATA_TECH_TYPE_NFC, + SRN_AP_DATA_TECH_TYPE_MOBILE_CODE, + SRN_AP_DATA_TECH_TYPE_OTHER +} Gnss_SrnTech; + +/* Mac Address type requested by modem */ +typedef enum { + SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_INVALID, /* No valid mac address type send */ + SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_PUBLIC, /* SRN AP MAC Address type PUBLIC */ + SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_PRIVATE, /* SRN AP MAC Address type PRIVATE */ + SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_OTHER, /* SRN AP MAC Address type OTHER */ +}Gnss_Srn_MacAddr_Type; + +typedef struct +{ + uint32_t size; + Gnss_SrnTech srnTechType; /* SRN Technology type in request */ + bool srnRequest; /* scan - start(true) or stop(false) */ + bool e911Mode; /* If in E911 emergency */ + Gnss_Srn_MacAddr_Type macAddrType; /* SRN AP MAC Address type */ +} GnssSrnDataReq; + +/* Mask indicating enabled or disabled constellations */ +typedef uint64_t GnssSvTypesMask; +typedef enum { + GNSS_SV_TYPES_MASK_GLO_BIT = (1<<0), + GNSS_SV_TYPES_MASK_BDS_BIT = (1<<1), + GNSS_SV_TYPES_MASK_QZSS_BIT = (1<<2), + GNSS_SV_TYPES_MASK_GAL_BIT = (1<<3), + GNSS_SV_TYPES_MASK_NAVIC_BIT = (1<<4), +} GnssSvTypesMaskBits; + +/* This SV Type config is injected directly to GNSS Adapter + * bypassing Location API */ +typedef struct { + uint32_t size; // set to sizeof(GnssSvTypeConfig) + // Enabled Constellations + GnssSvTypesMask enabledSvTypesMask; + // Disabled Constellations + GnssSvTypesMask blacklistedSvTypesMask; +} GnssSvTypeConfig; + +/* Provides the current GNSS SV Type configuration to the client. + * This is fetched via direct call to GNSS Adapter bypassing + * Location API */ +typedef std::function<void( + const GnssSvTypeConfig& config +)> GnssSvTypeConfigCallback; + +/* + * Represents the status of AGNSS augmented to support IPv4. + */ +struct AGnssExtStatusIpV4 { + AGpsExtType type; + LocApnTypeMask apnTypeMask; + LocAGpsStatusValue status; + /* + * 32-bit IPv4 address. + */ + uint32_t ipV4Addr; +}; + +/* + * Represents the status of AGNSS augmented to support IPv6. + */ +struct AGnssExtStatusIpV6 { + AGpsExtType type; + LocApnTypeMask apnTypeMask; + LocAGpsStatusValue status; + /* + * 128-bit IPv6 address. + */ + uint8_t ipV6Addr[16]; +}; + +/* +* Represents the the Nfw Notification structure +*/ +#define GNSS_MAX_NFW_APP_STRING_LEN 64 +#define GNSS_MAX_NFW_STRING_LEN 20 + +typedef enum { + GNSS_NFW_CTRL_PLANE = 0, + GNSS_NFW_SUPL = 1, + GNSS_NFW_IMS = 10, + GNSS_NFW_SIM = 11, + GNSS_NFW_OTHER_PROTOCOL_STACK = 100 +} GnssNfwProtocolStack; + +typedef enum { + GNSS_NFW_CARRIER = 0, + GNSS_NFW_OEM = 10, + GNSS_NFW_MODEM_CHIPSET_VENDOR = 11, + GNSS_NFW_GNSS_CHIPSET_VENDOR = 12, + GNSS_NFW_OTHER_CHIPSET_VENDOR = 13, + GNSS_NFW_AUTOMOBILE_CLIENT = 20, + GNSS_NFW_OTHER_REQUESTOR = 100 +} GnssNfwRequestor; + +typedef enum { + GNSS_NFW_REJECTED = 0, + GNSS_NFW_ACCEPTED_NO_LOCATION_PROVIDED = 1, + GNSS_NFW_ACCEPTED_LOCATION_PROVIDED = 2, +} GnssNfwResponseType; + +typedef struct { + char proxyAppPackageName[GNSS_MAX_NFW_APP_STRING_LEN]; + GnssNfwProtocolStack protocolStack; + char otherProtocolStackName[GNSS_MAX_NFW_STRING_LEN]; + GnssNfwRequestor requestor; + char requestorId[GNSS_MAX_NFW_STRING_LEN]; + GnssNfwResponseType responseType; + bool inEmergencyMode; + bool isCachedLocation; +} GnssNfwNotification; + +/* ODCPI Request Info */ +enum OdcpiRequestType { + ODCPI_REQUEST_TYPE_START, + ODCPI_REQUEST_TYPE_STOP +}; +struct OdcpiRequestInfo { + uint32_t size; + OdcpiRequestType type; + uint32_t tbfMillis; + bool isEmergencyMode; +}; +/* Callback to send ODCPI request to framework */ +typedef std::function<void(const OdcpiRequestInfo& request)> OdcpiRequestCallback; + +/* + * Callback with AGNSS(IpV4) status information. + * + * @param status Will be of type AGnssExtStatusIpV4. + */ +typedef void (*AgnssStatusIpV4Cb)(AGnssExtStatusIpV4 status); + +/* +* Callback with NFW information. +*/ +typedef void(*NfwStatusCb)(GnssNfwNotification notification); +typedef bool(*IsInEmergencySession)(void); + +/* + * Callback with AGNSS(IpV6) status information. + * + * @param status Will be of type AGnssExtStatusIpV6. + */ +typedef void (*AgnssStatusIpV6Cb)(AGnssExtStatusIpV6 status); + +/* Constructs for interaction with loc_net_iface library */ +typedef void (*LocAgpsOpenResultCb)(bool isSuccess, AGpsExtType agpsType, const char* apn, + AGpsBearerType bearerType, void* userDataPtr); + +typedef void (*LocAgpsCloseResultCb)(bool isSuccess, AGpsExtType agpsType, void* userDataPtr); + +/* Shared resources of LocIpc */ +#define LOC_IPC_HAL "/dev/socket/location/socket_hal" +#define LOC_IPC_XTRA "/dev/socket/location/xtra/socket_xtra" + +#define SOCKET_DIR_LOCATION "/dev/socket/location/" +#define SOCKET_DIR_EHUB "/dev/socket/location/ehub/" +#define SOCKET_TO_LOCATION_HAL_DAEMON "/dev/socket/loc_client/hal_daemon" + +#define SOCKET_LOC_CLIENT_DIR "/dev/socket/loc_client/" +#define EAP_LOC_CLIENT_DIR "/data/vendor/location/extap_locclient/" + +#define LOC_CLIENT_NAME_PREFIX "toclient" + +typedef uint64_t NetworkHandle; +#define NETWORK_HANDLE_UNKNOWN ~0 +#define MAX_NETWORK_HANDLES 10 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* GPS_EXTENDED_C_H */ diff --git a/gps/utils/linked_list.c b/gps/utils/linked_list.c new file mode 100644 index 0000000..02e1463 --- /dev/null +++ b/gps/utils/linked_list.c @@ -0,0 +1,325 @@ +/* Copyright (c) 2011, 2014, 2017 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. + */ + +#define LOG_TAG "LocSvc_utils_ll" + +#include "linked_list.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <loc_pla.h> +#include <log_util.h> + +typedef struct list_element { + struct list_element* next; + struct list_element* prev; + void* data_ptr; + void (*dealloc_func)(void*); +}list_element; + +typedef struct list_state { + list_element* p_head; + list_element* p_tail; +} list_state; + +/* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */ + +/*=========================================================================== + + FUNCTION: linked_list_init + + ===========================================================================*/ +linked_list_err_type linked_list_init(void** list_data) +{ + if( list_data == NULL ) + { + LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__); + return eLINKED_LIST_INVALID_PARAMETER; + } + + list_state* tmp_list; + tmp_list = (list_state*)calloc(1, sizeof(list_state)); + if( tmp_list == NULL ) + { + LOC_LOGE("%s: Unable to allocate space for list!\n", __FUNCTION__); + return eLINKED_LIST_FAILURE_GENERAL; + } + + tmp_list->p_head = NULL; + tmp_list->p_tail = NULL; + + *list_data = tmp_list; + + return eLINKED_LIST_SUCCESS; +} + +/*=========================================================================== + + FUNCTION: linked_list_destroy + + ===========================================================================*/ +linked_list_err_type linked_list_destroy(void** list_data) +{ + if( list_data == NULL ) + { + LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__); + return eLINKED_LIST_INVALID_HANDLE; + } + + list_state* p_list = (list_state*)*list_data; + + linked_list_flush(p_list); + + free(*list_data); + *list_data = NULL; + + return eLINKED_LIST_SUCCESS; +} + +/*=========================================================================== + + FUNCTION: linked_list_add + + ===========================================================================*/ +linked_list_err_type linked_list_add(void* list_data, void *data_obj, void (*dealloc)(void*)) +{ + if( list_data == NULL ) + { + LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__); + return eLINKED_LIST_INVALID_HANDLE; + } + + if( data_obj == NULL ) + { + LOC_LOGE("%s: Invalid input parameter!\n", __FUNCTION__); + return eLINKED_LIST_INVALID_PARAMETER; + } + + list_state* p_list = (list_state*)list_data; + list_element* elem = (list_element*)malloc(sizeof(list_element)); + if( elem == NULL ) + { + LOC_LOGE("%s: Memory allocation failed\n", __FUNCTION__); + return eLINKED_LIST_FAILURE_GENERAL; + } + + /* Copy data to newly created element */ + elem->data_ptr = data_obj; + elem->next = NULL; + elem->prev = NULL; + elem->dealloc_func = dealloc; + + /* Replace head element */ + list_element* tmp = p_list->p_head; + p_list->p_head = elem; + /* Point next to the previous head element */ + p_list->p_head->next = tmp; + + if( tmp != NULL ) + { + tmp->prev = p_list->p_head; + } + else + { + p_list->p_tail = p_list->p_head; + } + + return eLINKED_LIST_SUCCESS; +} + +/*=========================================================================== + + FUNCTION: linked_list_remove + + ===========================================================================*/ +linked_list_err_type linked_list_remove(void* list_data, void **data_obj) +{ + if( list_data == NULL ) + { + LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__); + return eLINKED_LIST_INVALID_HANDLE; + } + + if( data_obj == NULL ) + { + LOC_LOGE("%s: Invalid input parameter!\n", __FUNCTION__); + return eLINKED_LIST_INVALID_PARAMETER; + } + + list_state* p_list = (list_state*)list_data; + if( p_list->p_tail == NULL ) + { + return eLINKED_LIST_UNAVAILABLE_RESOURCE; + } + + list_element* tmp = p_list->p_tail; + + /* Replace tail element */ + p_list->p_tail = tmp->prev; + + if( p_list->p_tail != NULL ) + { + p_list->p_tail->next = NULL; + } + else + { + p_list->p_head = p_list->p_tail; + } + + /* Copy data to output param */ + *data_obj = tmp->data_ptr; + + /* Free allocated list element */ + free(tmp); + + return eLINKED_LIST_SUCCESS; +} + +/*=========================================================================== + + FUNCTION: linked_list_empty + + ===========================================================================*/ +int linked_list_empty(void* list_data) +{ + if( list_data == NULL ) + { + LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__); + return (int)eLINKED_LIST_INVALID_HANDLE; + } + else + { + list_state* p_list = (list_state*)list_data; + return p_list->p_head == NULL ? 1 : 0; + } +} + +/*=========================================================================== + + FUNCTION: linked_list_flush + + ===========================================================================*/ +linked_list_err_type linked_list_flush(void* list_data) +{ + if( list_data == NULL ) + { + LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__); + return eLINKED_LIST_INVALID_HANDLE; + } + + list_state* p_list = (list_state*)list_data; + + /* Remove all dynamically allocated elements */ + while( p_list->p_head != NULL ) + { + list_element* tmp = p_list->p_head->next; + + /* Free data pointer if told to do so. */ + if( p_list->p_head->dealloc_func != NULL ) + { + p_list->p_head->dealloc_func(p_list->p_head->data_ptr); + } + + /* Free list element */ + free(p_list->p_head); + + p_list->p_head = tmp; + } + + p_list->p_tail = NULL; + + return eLINKED_LIST_SUCCESS; +} + +/*=========================================================================== + + FUNCTION: linked_list_search + + ===========================================================================*/ +linked_list_err_type linked_list_search(void* list_data, void **data_p, + bool (*equal)(void* data_0, void* data), + void* data_0, bool rm_if_found) +{ + if( list_data == NULL || NULL == equal ) + { + LOC_LOGE("%s: Invalid list parameter! list_data %p equal %p\n", + __FUNCTION__, list_data, equal); + return eLINKED_LIST_INVALID_HANDLE; + } + + list_state* p_list = (list_state*)list_data; + if( p_list->p_tail == NULL ) + { + return eLINKED_LIST_UNAVAILABLE_RESOURCE; + } + + list_element* tmp = p_list->p_head; + + if (NULL != data_p) { + *data_p = NULL; + } + + while (NULL != tmp) { + if ((*equal)(data_0, tmp->data_ptr)) { + if (NULL != data_p) { + *data_p = tmp->data_ptr; + } + + if (rm_if_found) { + if (NULL == tmp->prev) { + p_list->p_head = tmp->next; + } else { + tmp->prev->next = tmp->next; + } + + if (NULL == tmp->next) { + p_list->p_tail = tmp->prev; + } else { + tmp->next->prev = tmp->prev; + } + + tmp->prev = tmp->next = NULL; + + // dealloc data if it is not copied out && caller + // has given us a dealloc function pointer. + if (NULL == data_p && NULL != tmp->dealloc_func) { + tmp->dealloc_func(tmp->data_ptr); + } + free(tmp); + } + + tmp = NULL; + } else { + tmp = tmp->next; + } + } + + return eLINKED_LIST_SUCCESS; +} + diff --git a/gps/utils/linked_list.h b/gps/utils/linked_list.h new file mode 100644 index 0000000..0b33ecb --- /dev/null +++ b/gps/utils/linked_list.h @@ -0,0 +1,219 @@ +/* Copyright (c) 2011, 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. + */ +#ifndef __LINKED_LIST_H__ +#define __LINKED_LIST_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <stdbool.h> +#include <stdlib.h> + +/** Linked List Return Codes */ +typedef enum +{ + eLINKED_LIST_SUCCESS = 0, + /**< Request was successful. */ + eLINKED_LIST_FAILURE_GENERAL = -1, + /**< Failed because of a general failure. */ + eLINKED_LIST_INVALID_PARAMETER = -2, + /**< Failed because the request contained invalid parameters. */ + eLINKED_LIST_INVALID_HANDLE = -3, + /**< Failed because an invalid handle was specified. */ + eLINKED_LIST_UNAVAILABLE_RESOURCE = -4, + /**< Failed because an there were not enough resources. */ + eLINKED_LIST_INSUFFICIENT_BUFFER = -5, + /**< Failed because an the supplied buffer was too small. */ + eLINKED_LIST_EMPTY = -6 + /**< Failed because list is empty. */ +}linked_list_err_type; + +/*=========================================================================== +FUNCTION linked_list_init + +DESCRIPTION + Initializes internal structures for linked list. + + list_data: State of list to be initialized. + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +linked_list_err_type linked_list_init(void** list_data); + +/*=========================================================================== +FUNCTION linked_list_destroy + +DESCRIPTION + Destroys internal structures for linked list. + + p_list_data: State of list to be destroyed. + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +linked_list_err_type linked_list_destroy(void** list_data); + +/*=========================================================================== +FUNCTION linked_list_add + +DESCRIPTION + Adds an element to the head of the linked list. The passed in data pointer + is not modified or freed. Passed in data_obj is expected to live throughout + the use of the linked_list (i.e. data is not allocated internally) + + p_list_data: List to add data to the head of. + data_obj: Pointer to data to add into list + dealloc: Function used to deallocate memory for this element. Pass NULL + if you do not want data deallocated during a flush operation + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +linked_list_err_type linked_list_add(void* list_data, void *data_obj, void (*dealloc)(void*)); + +/*=========================================================================== +FUNCTION linked_list_remove + +DESCRIPTION + Retrieves data from the list tail. data_obj is the tail element from the list + passed in by linked_list_add. + + p_list_data: List to remove the tail from. + data_obj: Pointer to data removed from list + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +linked_list_err_type linked_list_remove(void* list_data, void **data_obj); + +/*=========================================================================== +FUNCTION linked_list_empty + +DESCRIPTION + Tells whether the list currently contains any elements + + p_list_data: List to check if empty. + +DEPENDENCIES + N/A + +RETURN VALUE + 0/FALSE : List contains elements + 1/TRUE : List is Empty + Otherwise look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +int linked_list_empty(void* list_data); + +/*=========================================================================== +FUNCTION linked_list_flush + +DESCRIPTION + Removes all elements from the list and deallocates them using the provided + dealloc function while adding elements. + + p_list_data: List to remove all elements from. + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +linked_list_err_type linked_list_flush(void* list_data); + +/*=========================================================================== +FUNCTION linked_list_search + +DESCRIPTION + Searches for an element in the linked list. + + p_list_data: List handle. + data_p: to be stored with the data found; NUll if no match. + if data_p passed in as NULL, then no write to it. + equal: Function ptr takes in a list element, and returns + indication if this the one looking for. + data_0: The data being compared against. + rm_if_found: Should data be removed if found? + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +linked_list_err_type linked_list_search(void* list_data, void **data_p, + bool (*equal)(void* data_0, void* data), + void* data_0, bool rm_if_found); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __LINKED_LIST_H__ */ diff --git a/gps/utils/loc_cfg.cpp b/gps/utils/loc_cfg.cpp new file mode 100644 index 0000000..9c1f0b3 --- /dev/null +++ b/gps/utils/loc_cfg.cpp @@ -0,0 +1,1067 @@ +/* Copyright (c) 2011-2015, 2018 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. + * + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "LocSvc_utils_cfg" + +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <time.h> +#include <grp.h> +#include <errno.h> +#include <loc_cfg.h> +#include <loc_pla.h> +#include <loc_target.h> +#include <loc_misc_utils.h> +#ifdef USE_GLIB +#include <glib.h> +#endif +#include "log_util.h" + +/*============================================================================= + * + * GLOBAL DATA DECLARATION + * + *============================================================================*/ + +/* Parameter data */ +static uint32_t DEBUG_LEVEL = 0xff; +static uint32_t TIMESTAMP = 0; +static uint32_t DATUM_TYPE = 0; +static bool sVendorEnhanced = true; + +/* Parameter spec table */ +static const loc_param_s_type loc_param_table[] = +{ + {"DEBUG_LEVEL", &DEBUG_LEVEL, NULL, 'n'}, + {"TIMESTAMP", &TIMESTAMP, NULL, 'n'}, + {"DATUM_TYPE", &DATUM_TYPE, NULL, 'n'}, +}; +static const int loc_param_num = sizeof(loc_param_table) / sizeof(loc_param_s_type); + +typedef struct loc_param_v_type +{ + char* param_name; + char* param_str_value; + int param_int_value; + double param_double_value; +}loc_param_v_type; + +// Reference below arrays wherever needed to avoid duplicating +// same conf path string over and again in location code. +const char LOC_PATH_GPS_CONF[] = LOC_PATH_GPS_CONF_STR; +const char LOC_PATH_IZAT_CONF[] = LOC_PATH_IZAT_CONF_STR; +const char LOC_PATH_FLP_CONF[] = LOC_PATH_FLP_CONF_STR; +const char LOC_PATH_LOWI_CONF[] = LOC_PATH_LOWI_CONF_STR; +const char LOC_PATH_SAP_CONF[] = LOC_PATH_SAP_CONF_STR; +const char LOC_PATH_APDR_CONF[] = LOC_PATH_APDR_CONF_STR; +const char LOC_PATH_XTWIFI_CONF[] = LOC_PATH_XTWIFI_CONF_STR; +const char LOC_PATH_QUIPC_CONF[] = LOC_PATH_QUIPC_CONF_STR; + +bool isVendorEnhanced() { + return sVendorEnhanced; +} +void setVendorEnhanced(bool vendorEnhanced) { + sVendorEnhanced = vendorEnhanced; +} + +/*=========================================================================== +FUNCTION loc_get_datum_type + +DESCRIPTION + get datum type + +PARAMETERS: + N/A + +DEPENDENCIES + N/A + +RETURN VALUE + DATUM TYPE + +SIDE EFFECTS + N/A +===========================================================================*/ +int loc_get_datum_type() +{ + return DATUM_TYPE; +} + +/*=========================================================================== +FUNCTION loc_set_config_entry + +DESCRIPTION + Potentially sets a given configuration table entry based on the passed in + configuration value. This is done by using a string comparison of the + parameter names and those found in the configuration file. + +PARAMETERS: + config_entry: configuration entry in the table to possibly set + config_value: value to store in the entry if the parameter names match + +DEPENDENCIES + N/A + +RETURN VALUE + None + +SIDE EFFECTS + N/A +===========================================================================*/ +int loc_set_config_entry(const loc_param_s_type* config_entry, loc_param_v_type* config_value) +{ + int ret=-1; + if(NULL == config_entry || NULL == config_value) + { + LOC_LOGE("%s: INVALID config entry or parameter", __FUNCTION__); + return ret; + } + + if (strcmp(config_entry->param_name, config_value->param_name) == 0 && + config_entry->param_ptr) + { + switch (config_entry->param_type) + { + case 's': + if (strcmp(config_value->param_str_value, "NULL") == 0) + { + *((char*)config_entry->param_ptr) = '\0'; + } + else { + strlcpy((char*) config_entry->param_ptr, + config_value->param_str_value, + LOC_MAX_PARAM_STRING); + } + /* Log INI values */ + LOC_LOGD("%s: PARAM %s = %s", __FUNCTION__, + config_entry->param_name, (char*)config_entry->param_ptr); + + if(NULL != config_entry->param_set) + { + *(config_entry->param_set) = 1; + } + ret = 0; + break; + case 'n': + *((int *)config_entry->param_ptr) = config_value->param_int_value; + /* Log INI values */ + LOC_LOGD("%s: PARAM %s = %d", __FUNCTION__, + config_entry->param_name, config_value->param_int_value); + + if(NULL != config_entry->param_set) + { + *(config_entry->param_set) = 1; + } + ret = 0; + break; + case 'f': + *((double *)config_entry->param_ptr) = config_value->param_double_value; + /* Log INI values */ + LOC_LOGD("%s: PARAM %s = %f", __FUNCTION__, + config_entry->param_name, config_value->param_double_value); + + if(NULL != config_entry->param_set) + { + *(config_entry->param_set) = 1; + } + ret = 0; + break; + default: + LOC_LOGE("%s: PARAM %s parameter type must be n, f, or s", + __FUNCTION__, config_entry->param_name); + } + } + return ret; +} + +/*=========================================================================== +FUNCTION loc_fill_conf_item + +DESCRIPTION + Takes a line of configuration item and sets defined values based on + the passed in configuration table. This table maps strings to values to + set along with the type of each of these values. + +PARAMETERS: + input_buf : buffer contanis config item + config_table: table definition of strings to places to store information + table_length: length of the configuration table + +DEPENDENCIES + N/A + +RETURN VALUE + 0: Number of records in the config_table filled with input_buf + +SIDE EFFECTS + N/A +===========================================================================*/ +int loc_fill_conf_item(char* input_buf, + const loc_param_s_type* config_table, uint32_t table_length) +{ + int ret = 0; + + if (input_buf && config_table) { + char *lasts; + loc_param_v_type config_value; + memset(&config_value, 0, sizeof(config_value)); + + /* Separate variable and value */ + config_value.param_name = strtok_r(input_buf, "=", &lasts); + /* skip lines that do not contain "=" */ + if (config_value.param_name) { + config_value.param_str_value = strtok_r(NULL, "=", &lasts); + + /* skip lines that do not contain two operands */ + if (config_value.param_str_value) { + /* Trim leading and trailing spaces */ + loc_util_trim_space(config_value.param_name); + loc_util_trim_space(config_value.param_str_value); + + /* Parse numerical value */ + if ((strlen(config_value.param_str_value) >=3) && + (config_value.param_str_value[0] == '0') && + (tolower(config_value.param_str_value[1]) == 'x')) + { + /* hex */ + config_value.param_int_value = (int) strtol(&config_value.param_str_value[2], + (char**) NULL, 16); + } + else { + config_value.param_double_value = (double) atof(config_value.param_str_value); /* float */ + config_value.param_int_value = atoi(config_value.param_str_value); /* dec */ + } + + for(uint32_t i = 0; NULL != config_table && i < table_length; i++) + { + if(!loc_set_config_entry(&config_table[i], &config_value)) { + ret += 1; + } + } + } + } + } + + return ret; +} + +/*=========================================================================== +FUNCTION loc_read_conf_r (repetitive) + +DESCRIPTION + Reads the specified configuration file and sets defined values based on + the passed in configuration table. This table maps strings to values to + set along with the type of each of these values. + The difference between this and loc_read_conf is that this function returns + the file pointer position at the end of filling a config table. Also, it + reads a fixed number of parameters at a time which is equal to the length + of the configuration table. This functionality enables the caller to + repeatedly call the function to read data from the same file. + +PARAMETERS: + conf_fp : file pointer + config_table: table definition of strings to places to store information + table_length: length of the configuration table + +DEPENDENCIES + N/A + +RETURN VALUE + 0: Table filled successfully + 1: No more parameters to read + -1: Error filling table + +SIDE EFFECTS + N/A +===========================================================================*/ +int loc_read_conf_r(FILE *conf_fp, const loc_param_s_type* config_table, uint32_t table_length) +{ + int ret=0; + + unsigned int num_params=table_length; + if(conf_fp == NULL) { + LOC_LOGE("%s:%d]: ERROR: File pointer is NULL\n", __func__, __LINE__); + ret = -1; + goto err; + } + + /* Clear all validity bits */ + for(uint32_t i = 0; NULL != config_table && i < table_length; i++) + { + if(NULL != config_table[i].param_set) + { + *(config_table[i].param_set) = 0; + } + } + + char input_buf[LOC_MAX_PARAM_LINE]; /* declare a char array */ + + LOC_LOGD("%s:%d]: num_params: %d\n", __func__, __LINE__, num_params); + while(num_params) + { + if(!fgets(input_buf, LOC_MAX_PARAM_LINE, conf_fp)) { + LOC_LOGD("%s:%d]: fgets returned NULL\n", __func__, __LINE__); + break; + } + + num_params -= loc_fill_conf_item(input_buf, config_table, table_length); + } + +err: + return ret; +} + +/*=========================================================================== +FUNCTION loc_udpate_conf + +DESCRIPTION + Parses the passed in buffer for configuration items, and update the table + that is also passed in. + +Reads the specified configuration file and sets defined values based on + the passed in configuration table. This table maps strings to values to + set along with the type of each of these values. + +PARAMETERS: + conf_data: configuration items in bufferas a string + length: strlen(conf_data) + config_table: table definition of strings to places to store information + table_length: length of the configuration table + +DEPENDENCIES + N/A + +RETURN VALUE + number of the records in the table that is updated at time of return. + +SIDE EFFECTS + N/A +===========================================================================*/ +int loc_update_conf(const char* conf_data, int32_t length, + const loc_param_s_type* config_table, uint32_t table_length) +{ + int ret = -1; + + if (conf_data && length && config_table && table_length) { + // make a copy, so we do not tokenize the original data + char* conf_copy = (char*)malloc(length+1); + + if (conf_copy != NULL) + { + memcpy(conf_copy, conf_data, length); + // we hard NULL the end of string to be safe + conf_copy[length] = 0; + + // start with one record off + uint32_t num_params = table_length - 1; + char* saveptr = NULL; + char* input_buf = strtok_r(conf_copy, "\n", &saveptr); + ret = 0; + + LOC_LOGD("%s:%d]: num_params: %d\n", __func__, __LINE__, num_params); + while(num_params && input_buf) { + ret++; + num_params -= loc_fill_conf_item(input_buf, config_table, table_length); + input_buf = strtok_r(NULL, "\n", &saveptr); + } + free(conf_copy); + } + } + + return ret; +} + +/*=========================================================================== +FUNCTION loc_read_conf + +DESCRIPTION + Reads the specified configuration file and sets defined values based on + the passed in configuration table. This table maps strings to values to + set along with the type of each of these values. + +PARAMETERS: + conf_file_name: configuration file to read + config_table: table definition of strings to places to store information + table_length: length of the configuration table + +DEPENDENCIES + N/A + +RETURN VALUE + None + +SIDE EFFECTS + N/A +===========================================================================*/ +void loc_read_conf(const char* conf_file_name, const loc_param_s_type* config_table, + uint32_t table_length) +{ + FILE *conf_fp = NULL; + + if((conf_fp = fopen(conf_file_name, "r")) != NULL) + { + LOC_LOGD("%s: using %s", __FUNCTION__, conf_file_name); + if(table_length && config_table) { + loc_read_conf_r(conf_fp, config_table, table_length); + rewind(conf_fp); + } + loc_read_conf_r(conf_fp, loc_param_table, loc_param_num); + fclose(conf_fp); + } + /* Initialize logging mechanism with parsed data */ + loc_logger_init(DEBUG_LEVEL, TIMESTAMP); +} + +/*============================================================================= + * + * Define and Structures for Parsing Location Process Configuration File + * + *============================================================================*/ +#define MAX_NUM_STRINGS 20 + +//We can have 8 masks for now +#define CONFIG_MASK_TARGET_ALL 0X01 +#define CONFIG_MASK_TARGET_FOUND 0X02 +#define CONFIG_MASK_TARGET_CHECK 0X03 +#define CONFIG_MASK_BASEBAND_ALL 0X04 +#define CONFIG_MASK_BASEBAND_FOUND 0X08 +#define CONFIG_MASK_BASEBAND_CHECK 0x0c +#define CONFIG_MASK_AUTOPLATFORM_ALL 0x10 +#define CONFIG_MASK_AUTOPLATFORM_FOUND 0x20 +#define CONFIG_MASK_AUTOPLATFORM_CHECK 0x30 + +#define LOC_FEATURE_MASK_GTP_WIFI_BASIC 0x01 +#define LOC_FEATURE_MASK_GTP_WIFI_PREMIUM 0X02 +#define LOC_FEATURE_MASK_GTP_CELL_BASIC 0X04 +#define LOC_FEATURE_MASK_GTP_CELL_PREMIUM 0X08 +#define LOC_FEATURE_MASK_SAP_BASIC 0x40 +#define LOC_FEATURE_MASK_SAP_PREMIUM 0X80 +#define LOC_FEATURE_MASK_GTP_WAA_BASIC 0X100 +#define LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC 0X400 +#define LOC_FEATURE_MASK_ODCPI 0x1000 +#define LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT 0x2000 +#define LOC_FEATURE_MASK_SUPL_WIFI 0x4000 +#define LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO 0x8000 + +typedef struct { + char proc_name[LOC_MAX_PARAM_STRING]; + char proc_argument[LOC_MAX_PARAM_STRING]; + char proc_status[LOC_MAX_PARAM_STRING]; + char group_list[LOC_MAX_PARAM_STRING]; + unsigned int premium_feature; + unsigned int loc_feature_mask; + char platform_list[LOC_MAX_PARAM_STRING]; + char baseband[LOC_MAX_PARAM_STRING]; + unsigned int sglte_target; + char feature_gtp_mode[LOC_MAX_PARAM_STRING]; + char feature_gtp_waa[LOC_MAX_PARAM_STRING]; + char feature_sap[LOC_MAX_PARAM_STRING]; + char feature_odcpi[LOC_MAX_PARAM_STRING]; + char feature_free_wifi_scan_inject[LOC_MAX_PARAM_STRING]; + char feature_supl_wifi[LOC_MAX_PARAM_STRING]; + char feature_wifi_supplicant_info[LOC_MAX_PARAM_STRING]; + char auto_platform[LOC_MAX_PARAM_STRING]; + unsigned int vendor_enhanced_process; +} loc_launcher_conf; + +/* process configuration parameters */ +static loc_launcher_conf conf; + +/* gps.conf Parameter spec table */ +static const loc_param_s_type gps_conf_parameter_table[] = { + {"SGLTE_TARGET", &conf.sglte_target, NULL, 'n'}, +}; + +/* location feature conf, e.g.: izat.conf feature mode table*/ +static const loc_param_s_type loc_feature_conf_table[] = { + {"GTP_MODE", &conf.feature_gtp_mode, NULL, 's'}, + {"GTP_WAA", &conf.feature_gtp_waa, NULL, 's'}, + {"SAP", &conf.feature_sap, NULL, 's'}, + {"ODCPI", &conf.feature_odcpi, NULL, 's'}, + {"FREE_WIFI_SCAN_INJECT", &conf.feature_free_wifi_scan_inject, NULL, 's'}, + {"SUPL_WIFI", &conf.feature_supl_wifi, NULL, 's'}, + {"WIFI_SUPPLICANT_INFO", &conf.feature_wifi_supplicant_info, NULL, 's'}, +}; + +/* location process conf, e.g.: izat.conf Parameter spec table */ +static const loc_param_s_type loc_process_conf_parameter_table[] = { + {"PROCESS_NAME", &conf.proc_name, NULL, 's'}, + {"PROCESS_ARGUMENT", &conf.proc_argument, NULL, 's'}, + {"PROCESS_STATE", &conf.proc_status, NULL, 's'}, + {"PROCESS_GROUPS", &conf.group_list, NULL, 's'}, + {"PREMIUM_FEATURE", &conf.premium_feature, NULL, 'n'}, + {"IZAT_FEATURE_MASK", &conf.loc_feature_mask, NULL, 'n'}, + {"PLATFORMS", &conf.platform_list, NULL, 's'}, + {"BASEBAND", &conf.baseband, NULL, 's'}, + {"HARDWARE_TYPE", &conf.auto_platform, NULL, 's'}, + {"VENDOR_ENHANCED_PROCESS", &conf.vendor_enhanced_process, NULL, 'n'}, +}; + +/*=========================================================================== +FUNCTION loc_read_process_conf + +DESCRIPTION + Parse the specified conf file and return info for the processes defined. + The format of the file should conform with izat.conf. + +PARAMETERS: + conf_file_name: configuration file to read + process_count_ptr: pointer to store number of processes defined in the conf file. + process_info_table_ptr: pointer to store the process info table. + +DEPENDENCIES + The file must be in izat.conf format. + +RETURN VALUE + 0: success + none-zero: failure + +SIDE EFFECTS + N/A + +NOTES: + On success, memory pointed by (*process_info_table_ptr) must be freed. +===========================================================================*/ +int loc_read_process_conf(const char* conf_file_name, uint32_t * process_count_ptr, + loc_process_info_s_type** process_info_table_ptr) { + loc_process_info_s_type *child_proc = nullptr; + volatile int i=0; + unsigned int j=0; + gid_t gid_list[LOC_PROCESS_MAX_NUM_GROUPS]; + char *split_strings[MAX_NUM_STRINGS]; + int name_length=0, group_list_length=0, platform_length=0, baseband_length=0, ngroups=0, ret=0; + int auto_platform_length = 0; + int group_index=0, nstrings=0, status_length=0; + FILE* conf_fp = nullptr; + char platform_name[PROPERTY_VALUE_MAX], baseband_name[PROPERTY_VALUE_MAX]; + char autoplatform_name[PROPERTY_VALUE_MAX]; + unsigned int loc_service_mask=0; + char config_mask = 0; + unsigned char proc_list_length=0; + int gtp_cell_ap_enabled = 0; + char arg_gtp_waa[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--"; + char arg_gtp_modem_cell[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--"; + char arg_gtp_wifi[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--"; + char arg_sap[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--"; + char arg_disabled[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_DISABLED; + char arg_basic[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_BASIC; + char arg_premium[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_PREMIUM; + + if (process_count_ptr == NULL || process_info_table_ptr == NULL) { + return -1; + } + + //Read gps.conf and fill parameter table + UTIL_READ_CONF(LOC_PATH_GPS_CONF, gps_conf_parameter_table); + + //Form argument strings + strlcat(arg_gtp_waa, LOC_FEATURE_GTP_WAA, LOC_PROCESS_MAX_ARG_STR_LENGTH-3); + strlcat(arg_gtp_modem_cell, LOC_FEATURE_GTP_MODEM_CELL, LOC_PROCESS_MAX_ARG_STR_LENGTH-3); + strlcat(arg_gtp_wifi, LOC_FEATURE_GTP_WIFI, LOC_PROCESS_MAX_ARG_STR_LENGTH-3); + strlcat(arg_sap, LOC_FEATURE_SAP, LOC_PROCESS_MAX_ARG_STR_LENGTH-3); + + //Get platform name from ro.board.platform property + loc_get_platform_name(platform_name, sizeof(platform_name)); + //Get baseband name from ro.baseband property + loc_get_target_baseband(baseband_name, sizeof(baseband_name)); + //Identify if this is an automotive platform + loc_get_auto_platform_name(autoplatform_name,sizeof(autoplatform_name)); + + UTIL_READ_CONF(conf_file_name, loc_feature_conf_table); + + //Set service mask for GTP_MODE + if(strcmp(conf.feature_gtp_mode, "DISABLED") == 0) { + LOC_LOGD("%s:%d]: GTP MODE DISABLED", __func__, __LINE__); + } + else if(strcmp(conf.feature_gtp_mode, "LEGACY_WWAN") == 0) { + LOC_LOGD("%s:%d]: Setting GTP MODE to mode: LEGACY_WWAN", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC; + } + else if(strcmp(conf.feature_gtp_mode, "SDK") == 0) { + LOC_LOGD("%s:%d]: Setting GTP MODE to mode: SDK", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_GTP_WIFI_BASIC; + } + //conf file has a garbage value + else { + LOC_LOGE("%s:%d]: Unrecognized value for GTP MODE Mode."\ + " Setting GTP WIFI to default mode: DISABLED", __func__, __LINE__); + } + //Set service mask for GTP_WAA + if(strcmp(conf.feature_gtp_waa, "BASIC") == 0) { + LOC_LOGD("%s:%d]: Setting GTP WAA to mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_GTP_WAA_BASIC; + } + else if(strcmp(conf.feature_gtp_waa, "DISABLED") == 0) { + LOC_LOGD("%s:%d]: GTP WAA DISABLED", __func__, __LINE__); + } + //conf file has a garbage value + else { + LOC_LOGE("%s:%d]: Unrecognized value for GTP WAA Mode."\ + " Setting GTP WAA to default mode: DISABLED", __func__, __LINE__); + } + + //Set service mask for SAP + if(strcmp(conf.feature_sap, "PREMIUM") == 0) { + LOC_LOGD("%s:%d]: Setting SAP to mode: PREMIUM", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_SAP_PREMIUM; + } + else if(strcmp(conf.feature_sap, "BASIC") == 0) { + LOC_LOGD("%s:%d]: Setting SAP to mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_SAP_BASIC; + } + else if(strcmp(conf.feature_sap, "MODEM_DEFAULT") == 0) { + LOC_LOGD("%s:%d]: Setting SAP to mode: MODEM_DEFAULT", __func__, __LINE__); + } + else if(strcmp(conf.feature_sap, "DISABLED") == 0) { + LOC_LOGD("%s:%d]: Setting SAP to mode: DISABLED", __func__, __LINE__); + } + else { + LOC_LOGE("%s:%d]: Unrecognized value for SAP Mode."\ + " Setting SAP to default mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_SAP_BASIC; + } + + // Set service mask for ODCPI + if(strcmp(conf.feature_odcpi, "BASIC") == 0) { + LOC_LOGD("%s:%d]: Setting ODCPI to mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_ODCPI; + } + else if(strcmp(conf.feature_odcpi, "DISABLED") == 0) { + LOC_LOGD("%s:%d]: Setting ODCPI to mode: DISABLED", __func__, __LINE__); + } + else if(strcmp(conf.feature_odcpi, "PREMIUM") == 0) { + LOC_LOGD("%s:%d]: Unrecognized value for ODCPI mode."\ + "Setting ODCPI to default mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_ODCPI; + } + + // Set service mask for FREE_WIFI_SCAN_INJECT + if(strcmp(conf.feature_free_wifi_scan_inject, "BASIC") == 0) { + LOC_LOGD("%s:%d]: Setting FREE_WIFI_SCAN_INJECT to mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT; + } + else if(strcmp(conf.feature_free_wifi_scan_inject, "DISABLED") == 0) { + LOC_LOGD("%s:%d]: Setting FREE_WIFI_SCAN_INJECT to mode: DISABLED", __func__, __LINE__); + } + else if(strcmp(conf.feature_free_wifi_scan_inject, "PREMIUM") == 0) { + LOC_LOGD("%s:%d]: Unrecognized value for FREE_WIFI_SCAN_INJECT mode."\ + "Setting FREE_WIFI_SCAN_INJECT to default mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT; + } + + // Set service mask for SUPL_WIFI + if(strcmp(conf.feature_supl_wifi, "BASIC") == 0) { + LOC_LOGD("%s:%d]: Setting SUPL_WIFI to mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_SUPL_WIFI; + } + else if(strcmp(conf.feature_supl_wifi, "DISABLED") == 0) { + LOC_LOGD("%s:%d]: Setting SUPL_WIFI to mode: DISABLED", __func__, __LINE__); + } + else if(strcmp(conf.feature_supl_wifi, "PREMIUM") == 0) { + LOC_LOGD("%s:%d]: Unrecognized value for SUPL_WIFI mode."\ + "Setting SUPL_WIFI to default mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_SUPL_WIFI; + } + + // Set service mask for WIFI_SUPPLICANT_INFO + if(strcmp(conf.feature_wifi_supplicant_info, "BASIC") == 0) { + LOC_LOGD("%s:%d]: Setting WIFI_SUPPLICANT_INFO to mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO; + } + else if(strcmp(conf.feature_wifi_supplicant_info, "DISABLED") == 0) { + LOC_LOGD("%s:%d]: Setting WIFI_SUPPLICANT_INFO to mode: DISABLED", __func__, __LINE__); + } + else if(strcmp(conf.feature_wifi_supplicant_info, "PREMIUM") == 0) { + LOC_LOGD("%s:%d]: Unrecognized value for WIFI_SUPPLICANT_INFO mode."\ + "Setting LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO to default mode: BASIC", __func__, __LINE__); + loc_service_mask |= LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO; + } + + LOC_LOGD("%s:%d]: loc_service_mask: %x\n", __func__, __LINE__, loc_service_mask); + + if((conf_fp = fopen(conf_file_name, "r")) == NULL) { + LOC_LOGE("%s:%d]: Error opening %s %s\n", __func__, + __LINE__, conf_file_name, strerror(errno)); + ret = -1; + goto err; + } + + //Parse through the file to find out how many processes are to be launched + proc_list_length = 0; + do { + conf.proc_name[0] = 0; + //Here note that the 3rd parameter is passed as 1. + //This is so that only the first parameter in the table which is "PROCESS_NAME" + //is read. We do not want to read the entire block of parameters at this time + //since we are only counting the number of processes to launch. + //Therefore, only counting the occurrences of PROCESS_NAME parameter + //should suffice + if(loc_read_conf_r(conf_fp, loc_process_conf_parameter_table, 1)) { + LOC_LOGE("%s:%d]: Unable to read conf file. Failing\n", __func__, __LINE__); + ret = -1; + goto err; + } + name_length=(int)strlen(conf.proc_name); + if(name_length) { + proc_list_length++; + LOC_LOGD("Process name:%s", conf.proc_name); + } + } while(name_length); + LOC_LOGD("Process cnt = %d", proc_list_length); + + child_proc = (loc_process_info_s_type *)calloc(proc_list_length, sizeof(loc_process_info_s_type)); + if(child_proc == NULL) { + LOC_LOGE("%s:%d]: ERROR: Malloc returned NULL\n", __func__, __LINE__); + ret = -1; + goto err; + } + + //Move file descriptor to the beginning of the file + //so that the parameters can be read + rewind(conf_fp); + + for(j=0; j<proc_list_length; j++) { + //Set defaults for all the child process structs + child_proc[j].proc_status = DISABLED; + memset(child_proc[j].group_list, 0, sizeof(child_proc[j].group_list)); + config_mask=0; + if(loc_read_conf_r(conf_fp, loc_process_conf_parameter_table, + sizeof(loc_process_conf_parameter_table)/sizeof(loc_process_conf_parameter_table[0]))) { + LOC_LOGE("%s:%d]: Unable to read conf file. Failing\n", __func__, __LINE__); + ret = -1; + goto err; + } + + name_length=(int)strlen(conf.proc_name); + group_list_length=(int)strlen(conf.group_list); + platform_length = (int)strlen(conf.platform_list); + baseband_length = (int)strlen(conf.baseband); + status_length = (int)strlen(conf.proc_status); + auto_platform_length = (int)strlen(conf.auto_platform); + + if(!name_length || !group_list_length || !platform_length || + !baseband_length || !status_length || !auto_platform_length) { + LOC_LOGE("%s:%d]: Error: i: %d; One of the parameters not specified in conf file", + __func__, __LINE__, i); + continue; + } + + if (!isVendorEnhanced() && (conf.vendor_enhanced_process != 0)) { + LOC_LOGD("%s:%d]: Process %s is disabled via vendor enhanced process check", + __func__, __LINE__, conf.proc_name); + child_proc[j].proc_status = DISABLED_VIA_VENDOR_ENHANCED_CHECK; + continue; + } + + if(strcmp(conf.proc_status, "DISABLED") == 0) { + LOC_LOGD("%s:%d]: Process %s is disabled in conf file", + __func__, __LINE__, conf.proc_name); + child_proc[j].proc_status = DISABLED_FROM_CONF; + continue; + } + else if(strcmp(conf.proc_status, "ENABLED") == 0) { + LOC_LOGD("%s:%d]: Process %s is enabled in conf file", + __func__, __LINE__, conf.proc_name); + } + + //Since strlcpy copies length-1 characters, we add 1 to name_length + if((name_length+1) > LOC_MAX_PARAM_STRING) { + LOC_LOGE("%s:%d]: i: %d; Length of name parameter too long. Max length: %d", + __func__, __LINE__, i, LOC_MAX_PARAM_STRING); + continue; + } + strlcpy(child_proc[j].name[0], conf.proc_name, sizeof (child_proc[j].name[0])); + + child_proc[j].num_groups = 0; + ngroups = loc_util_split_string(conf.group_list, split_strings, MAX_NUM_STRINGS, ' '); + for(i=0; i<ngroups; i++) { + struct group* grp = getgrnam(split_strings[i]); + if (grp) { + child_proc[j].group_list[child_proc[j].num_groups] = grp->gr_gid; + child_proc[j].num_groups++; + LOC_LOGd("Group %s = %d", split_strings[i], grp->gr_gid); + } + } + + nstrings = loc_util_split_string(conf.platform_list, split_strings, MAX_NUM_STRINGS, ' '); + if(strcmp("all", split_strings[0]) == 0) { + if (nstrings == 1 || (nstrings == 2 && (strcmp("exclude", split_strings[1]) == 0))) { + LOC_LOGD("%s:%d]: Enabled for all targets\n", __func__, __LINE__); + config_mask |= CONFIG_MASK_TARGET_ALL; + } + else if (nstrings > 2 && (strcmp("exclude", split_strings[1]) == 0)) { + config_mask |= CONFIG_MASK_TARGET_FOUND; + for (i=2; i<nstrings; i++) { + if(strcmp(platform_name, split_strings[i]) == 0) { + LOC_LOGD("%s:%d]: Disabled platform %s\n", __func__, __LINE__, platform_name); + config_mask &= ~CONFIG_MASK_TARGET_FOUND; + break; + } + } + } + } + else { + for(i=0; i<nstrings; i++) { + if(strcmp(platform_name, split_strings[i]) == 0) { + LOC_LOGD("%s:%d]: Matched platform: %s\n", + __func__, __LINE__, split_strings[i]); + config_mask |= CONFIG_MASK_TARGET_FOUND; + break; + } + } + } + + nstrings = loc_util_split_string(conf.baseband, split_strings, MAX_NUM_STRINGS, ' '); + if(strcmp("all", split_strings[0]) == 0) { + if (nstrings == 1 || (nstrings == 2 && (strcmp("exclude", split_strings[1]) == 0))) { + LOC_LOGD("%s:%d]: Enabled for all basebands\n", __func__, __LINE__); + config_mask |= CONFIG_MASK_BASEBAND_ALL; + } + else if (nstrings > 2 && (strcmp("exclude", split_strings[1]) == 0)) { + config_mask |= CONFIG_MASK_BASEBAND_FOUND; + for (i=2; i<nstrings; i++) { + if(strcmp(baseband_name, split_strings[i]) == 0) { + LOC_LOGD("%s:%d]: Disabled band %s\n", __func__, __LINE__, baseband_name); + config_mask &= ~CONFIG_MASK_BASEBAND_FOUND; + break; + } + } + } + } + else { + for(i=0; i<nstrings; i++) { + if(strcmp(baseband_name, split_strings[i]) == 0) { + LOC_LOGD("%s:%d]: Matched baseband: %s\n", + __func__, __LINE__, split_strings[i]); + config_mask |= CONFIG_MASK_BASEBAND_FOUND; + break; + } + //Since ro.baseband is not a reliable source for detecting sglte + //the alternative is to read the SGLTE_TARGET parameter from gps.conf + //this parameter is read into conf_sglte_target + else if((strcmp("sglte", split_strings[i]) == 0 ) && conf.sglte_target) { + LOC_LOGD("%s:%d]: Matched baseband SGLTE\n", __func__, __LINE__); + config_mask |= CONFIG_MASK_BASEBAND_FOUND; + break; + } + } + } + + nstrings = loc_util_split_string(conf.auto_platform, split_strings, MAX_NUM_STRINGS, ' '); + if(strcmp("all", split_strings[0]) == 0) { + LOC_LOGD("%s:%d]: Enabled for all auto platforms\n", __func__, __LINE__); + config_mask |= CONFIG_MASK_AUTOPLATFORM_ALL; + } + else { + for(i=0; i<nstrings; i++) { + if(strcmp(autoplatform_name, split_strings[i]) == 0) { + LOC_LOGD("%s:%d]: Matched auto platform: %s\n", + __func__, __LINE__, split_strings[i]); + config_mask |= CONFIG_MASK_AUTOPLATFORM_FOUND; + break; + } + } + } + + if((config_mask & CONFIG_MASK_TARGET_CHECK) && + (config_mask & CONFIG_MASK_BASEBAND_CHECK) && + (config_mask & CONFIG_MASK_AUTOPLATFORM_CHECK) && + (child_proc[j].proc_status != DISABLED_FROM_CONF) && + (child_proc[j].proc_status != DISABLED_VIA_VENDOR_ENHANCED_CHECK)) { + + //Set args + //The first argument passed through argv is usually the name of the + //binary when started from commandline. + //getopt() seems to ignore this first argument and hence we assign it + //to the process name for consistency with command line args + i = 0; + char* temp_arg = ('/' == child_proc[j].name[0][0]) ? + (strrchr(child_proc[j].name[0], '/') + 1) : child_proc[j].name[0]; + strlcpy (child_proc[j].args[i++], temp_arg, sizeof (child_proc[j].args[i++])); + + if(conf.premium_feature) { + if(conf.loc_feature_mask & loc_service_mask) { + LOC_LOGD("%s:%d]: Enabled. %s has service mask: %x\n", + __func__, __LINE__, child_proc[j].name[0], conf.loc_feature_mask); + child_proc[j].proc_status = ENABLED; + + if(conf.loc_feature_mask & + (LOC_FEATURE_MASK_GTP_WIFI_BASIC | LOC_FEATURE_MASK_GTP_WIFI_PREMIUM)) { + if(loc_service_mask & LOC_FEATURE_MASK_GTP_WIFI_BASIC) { + strlcpy(child_proc[j].args[i++], arg_gtp_wifi, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_basic, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + else if(loc_service_mask & LOC_FEATURE_MASK_GTP_WIFI_PREMIUM) { + strlcpy(child_proc[j].args[i++], arg_gtp_wifi, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_premium, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + else + { + strlcpy(child_proc[j].args[i++], arg_gtp_wifi, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_disabled, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + } + if(conf.loc_feature_mask & + (LOC_FEATURE_MASK_GTP_CELL_BASIC | LOC_FEATURE_MASK_GTP_CELL_PREMIUM )) { + if(loc_service_mask & LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC) { + strlcpy(child_proc[j].args[i++], arg_gtp_modem_cell, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_basic, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + else { + strlcpy(child_proc[j].args[i++], arg_gtp_modem_cell, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_disabled, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + } + if(conf.loc_feature_mask & + (LOC_FEATURE_MASK_SAP_BASIC | LOC_FEATURE_MASK_SAP_PREMIUM)) { + if(loc_service_mask & LOC_FEATURE_MASK_SAP_BASIC) { + strlcpy(child_proc[j].args[i++], arg_sap, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_basic, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + else if(loc_service_mask & LOC_FEATURE_MASK_SAP_PREMIUM) { + strlcpy(child_proc[j].args[i++], arg_sap, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_premium, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + else + { + strlcpy(child_proc[j].args[i++], arg_sap, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_disabled, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + } + + if(conf.loc_feature_mask & LOC_FEATURE_MASK_GTP_WAA_BASIC) { + if(loc_service_mask & LOC_FEATURE_MASK_GTP_WAA_BASIC) { + strlcpy(child_proc[j].args[i++], arg_gtp_waa, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_basic, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + else + { + strlcpy(child_proc[j].args[i++], arg_gtp_waa, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + strlcpy(child_proc[j].args[i++], arg_disabled, + LOC_PROCESS_MAX_ARG_STR_LENGTH); + } + } + IF_LOC_LOGD { + LOC_LOGD("%s:%d]: %s args\n", __func__, __LINE__, child_proc[j].name[0]); + for(unsigned int k=0; k<LOC_PROCESS_MAX_NUM_ARGS; k++) { + if(child_proc[j].args[k][0] != '\0') { + LOC_LOGD("%s:%d]: k: %d, %s\n", __func__, __LINE__, k, + child_proc[j].args[k]); + } + } + LOC_LOGD("%s:%d]: \n", __func__, __LINE__); + } + } + else { + LOC_LOGD("%s:%d]: Disabled. %s has service mask: %x \n", + __func__, __LINE__, child_proc[j].name[0], conf.loc_feature_mask); + } + } + else { + LOC_LOGD("%s:%d]: %s not a premium feature. Enabled\n", + __func__, __LINE__, child_proc[j].name[0]); + child_proc[j].proc_status = ENABLED; + } + + /*Fill up the remaining arguments from configuration file*/ + LOC_LOGD("%s] Parsing Process_Arguments from Configuration: %s \n", + __func__, conf.proc_argument); + if(0 != conf.proc_argument[0]) + { + /************************************** + ** conf_proc_argument is shared by all the programs getting launched, + ** hence copy to process specific argument string and parse the same. + ***************************************/ + strlcpy(child_proc[j].argumentString, conf.proc_argument, + sizeof(child_proc[j].argumentString)); + char *temp_args[LOC_PROCESS_MAX_NUM_ARGS]; + memset (temp_args, 0, sizeof (temp_args)); + loc_util_split_string(child_proc[j].argumentString, &temp_args[i], + (LOC_PROCESS_MAX_NUM_ARGS - i), ' '); + // copy argument from the pointer to the memory + for (unsigned int index = i; index < LOC_PROCESS_MAX_NUM_ARGS; index++) { + if (temp_args[index] == NULL) { + break; + } + strlcpy (child_proc[j].args[index], temp_args[index], + sizeof (child_proc[j].args[index])); + } + } + } + else { + LOC_LOGD("%s:%d]: Process %s is disabled\n", + __func__, __LINE__, child_proc[j].name[0]); + } + } + +err: + if (conf_fp) { + fclose(conf_fp); + } + if (ret != 0) { + LOC_LOGE("%s:%d]: ret: %d", __func__, __LINE__, ret); + if (child_proc) { + free (child_proc); + child_proc = nullptr; + } + *process_count_ptr = 0; + *process_info_table_ptr = nullptr; + + } + else { + *process_count_ptr = proc_list_length; + *process_info_table_ptr = child_proc; + } + + return ret; +} diff --git a/gps/utils/loc_cfg.h b/gps/utils/loc_cfg.h new file mode 100644 index 0000000..5c77dc6 --- /dev/null +++ b/gps/utils/loc_cfg.h @@ -0,0 +1,143 @@ +/* Copyright (c) 2011-2015, 2018 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. + * + */ + +#ifndef LOC_CFG_H +#define LOC_CFG_H + +#include <stdio.h> +#include <stdint.h> +#include <sys/types.h> +#include <unistd.h> +#include <grp.h> + +#define LOC_MAX_PARAM_NAME 80 +#define LOC_MAX_PARAM_STRING 172 +#define LOC_MAX_PARAM_LINE (LOC_MAX_PARAM_NAME + LOC_MAX_PARAM_STRING) + +#define LOC_FEATURE_MODE_DISABLED "DISABLED" +#define LOC_FEATURE_MODE_BASIC "BASIC" +#define LOC_FEATURE_MODE_PREMIUM "PREMIUM" + +#define LOC_FEATURE_GTP_AP_CELL "gtp-ap-cell" +#define LOC_FEATURE_GTP_MODEM_CELL "gtp-modem-cell" +#define LOC_FEATURE_GTP_CELL_ENH "gtp-cell-enh" +#define LOC_FEATURE_GTP_WIFI "gtp-wifi" +#define LOC_FEATURE_GTP_WAA "gtp-waa" +#define LOC_FEATURE_SAP "sap" + +#define LOC_PROCESS_MAX_NUM_GROUPS 20 +#define LOC_PROCESS_MAX_NUM_ARGS 25 +#define LOC_PROCESS_MAX_ARG_STR_LENGTH 32 + +#define UTIL_UPDATE_CONF(conf_data, len, config_table) \ + loc_update_conf((conf_data), (len), (config_table), \ + sizeof(config_table) / sizeof(config_table[0])) + +#define UTIL_READ_CONF_DEFAULT(filename) \ + loc_read_conf((filename), NULL, 0); + +#define UTIL_READ_CONF(filename, config_table) \ + loc_read_conf((filename), (config_table), sizeof(config_table) / sizeof(config_table[0])) + +/*============================================================================= + * + * MODULE TYPE DECLARATION + * + *============================================================================*/ +typedef struct +{ + const char *param_name; + void *param_ptr; /* for string type, buf size need to be LOC_MAX_PARAM_STRING */ + uint8_t *param_set; /* indicate value set by config file */ + char param_type; /* 'n' for number, + 's' for string, NOTE: buf size need to be LOC_MAX_PARAM_STRING + 'f' for double */ +} loc_param_s_type; + +typedef enum { + ENABLED, + RUNNING, + DISABLED, + DISABLED_FROM_CONF, + DISABLED_VIA_VENDOR_ENHANCED_CHECK +} loc_process_e_status; + +typedef struct { + loc_process_e_status proc_status; + pid_t proc_id; + char name[2][LOC_MAX_PARAM_STRING]; + gid_t group_list[LOC_PROCESS_MAX_NUM_GROUPS]; + unsigned char num_groups; + char args[LOC_PROCESS_MAX_NUM_ARGS][LOC_PROCESS_MAX_ARG_STR_LENGTH]; + char argumentString[LOC_MAX_PARAM_STRING]; +} loc_process_info_s_type; + +/*============================================================================= + * + * MODULE EXTERNAL DATA + * + *============================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================= + * + * MODULE EXPORTED FUNCTIONS + * + *============================================================================*/ +bool isVendorEnhanced(); +void setVendorEnhanced(bool vendorEnhanced); +void loc_read_conf(const char* conf_file_name, + const loc_param_s_type* config_table, + uint32_t table_length); +int loc_read_conf_r(FILE *conf_fp, const loc_param_s_type* config_table, + uint32_t table_length); +int loc_update_conf(const char* conf_data, int32_t length, + const loc_param_s_type* config_table, uint32_t table_length); + +// Below are the location conf file paths +extern const char LOC_PATH_GPS_CONF[]; +extern const char LOC_PATH_IZAT_CONF[]; +extern const char LOC_PATH_FLP_CONF[]; +extern const char LOC_PATH_LOWI_CONF[]; +extern const char LOC_PATH_SAP_CONF[]; +extern const char LOC_PATH_APDR_CONF[]; +extern const char LOC_PATH_XTWIFI_CONF[]; +extern const char LOC_PATH_QUIPC_CONF[]; + +int loc_read_process_conf(const char* conf_file_name, uint32_t * process_count_ptr, + loc_process_info_s_type** process_info_table_ptr); +int loc_get_datum_type(); +#ifdef __cplusplus +} +#endif + +#endif /* LOC_CFG_H */ diff --git a/gps/utils/loc_gps.h b/gps/utils/loc_gps.h new file mode 100644 index 0000000..eae7383 --- /dev/null +++ b/gps/utils/loc_gps.h @@ -0,0 +1,2229 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOC_GPS_H +#define LOC_GPS_H + +#include <stdint.h> +#include <sys/cdefs.h> +#include <sys/types.h> +#include <pthread.h> +#include <sys/socket.h> +#include <stdbool.h> + +__BEGIN_DECLS + +#define LOC_FLP_STATUS_LOCATION_AVAILABLE 0 +#define LOC_FLP_STATUS_LOCATION_UNAVAILABLE 1 +#define LOC_CAPABILITY_GNSS (1U<<0) +#define LOC_CAPABILITY_WIFI (1U<<1) +#define LOC_CAPABILITY_CELL (1U<<3) + +/** Milliseconds since January 1, 1970 */ +typedef int64_t LocGpsUtcTime; + +/** Maximum number of SVs for loc_gps_sv_status_callback(). */ +#define LOC_GPS_MAX_SVS 32 +/** Maximum number of SVs for loc_gps_sv_status_callback(). */ +#define LOC_GNSS_MAX_SVS 64 + +/** Maximum number of Measurements in loc_gps_measurement_callback(). */ +#define LOC_GPS_MAX_MEASUREMENT 32 + +/** Maximum number of Measurements in loc_gnss_measurement_callback(). */ +#define LOC_GNSS_MAX_MEASUREMENT 64 + +/** Requested operational mode for GPS operation. */ +typedef uint32_t LocGpsPositionMode; +/* IMPORTANT: Note that the following values must match + * constants in GpsLocationProvider.java. */ +/** Mode for running GPS standalone (no assistance). */ +#define LOC_GPS_POSITION_MODE_STANDALONE 0 +/** AGPS MS-Based mode. */ +#define LOC_GPS_POSITION_MODE_MS_BASED 1 +/** + * AGPS MS-Assisted mode. This mode is not maintained by the platform anymore. + * It is strongly recommended to use LOC_GPS_POSITION_MODE_MS_BASED instead. + */ +#define LOC_GPS_POSITION_MODE_MS_ASSISTED 2 + +/** Requested recurrence mode for GPS operation. */ +typedef uint32_t LocGpsPositionRecurrence; +/* IMPORTANT: Note that the following values must match + * constants in GpsLocationProvider.java. */ +/** Receive GPS fixes on a recurring basis at a specified period. */ +#define LOC_GPS_POSITION_RECURRENCE_PERIODIC 0 +/** Request a single shot GPS fix. */ +#define LOC_GPS_POSITION_RECURRENCE_SINGLE 1 + +/** GPS status event values. */ +typedef uint16_t LocGpsStatusValue; +/* IMPORTANT: Note that the following values must match + * constants in GpsLocationProvider.java. */ +/** GPS status unknown. */ +#define LOC_GPS_STATUS_NONE 0 +/** GPS has begun navigating. */ +#define LOC_GPS_STATUS_SESSION_BEGIN 1 +/** GPS has stopped navigating. */ +#define LOC_GPS_STATUS_SESSION_END 2 +/** GPS has powered on but is not navigating. */ +#define LOC_GPS_STATUS_ENGINE_ON 3 +/** GPS is powered off. */ +#define LOC_GPS_STATUS_ENGINE_OFF 4 + +/** Flags to indicate which values are valid in a LocGpsLocation. */ +typedef uint16_t LocGpsLocationFlags; +/* IMPORTANT: Note that the following values must match + * constants in GpsLocationProvider.java. */ +/** LocGpsLocation has valid latitude and longitude. */ +#define LOC_GPS_LOCATION_HAS_LAT_LONG 0x0001 +/** LocGpsLocation has valid altitude. */ +#define LOC_GPS_LOCATION_HAS_ALTITUDE 0x0002 +/** LocGpsLocation has valid speed. */ +#define LOC_GPS_LOCATION_HAS_SPEED 0x0004 +/** LocGpsLocation has valid bearing. */ +#define LOC_GPS_LOCATION_HAS_BEARING 0x0008 +/** LocGpsLocation has valid accuracy. */ +#define LOC_GPS_LOCATION_HAS_ACCURACY 0x0010 +/** LocGpsLocation has valid vertical uncertainity */ +#define LOC_GPS_LOCATION_HAS_VERT_UNCERTAINITY 0x0040 +/** LocGpsLocation has valid spoof mask */ +#define LOC_GPS_LOCATION_HAS_SPOOF_MASK 0x0080 +/** LocGpsLocation has valid speed accuracy */ +#define LOC_GPS_LOCATION_HAS_SPEED_ACCURACY 0x0100 +/** LocGpsLocation has valid bearing accuracy */ +#define LOC_GPS_LOCATION_HAS_BEARING_ACCURACY 0x0200 + +/** Spoof mask in LocGpsLocation */ +typedef uint32_t LocGpsSpoofMask; +#define LOC_GPS_LOCATION_NONE_SPOOFED 0x0000 +#define LOC_GPS_LOCATION_POSITION_SPOOFED 0x0001 +#define LOC_GPS_LOCATION_TIME_SPOOFED 0x0002 +#define LOC_GPS_LOCATION_NAVIGATION_DATA_SPOOFED 0x0004 + +/** Flags for the loc_gps_set_capabilities callback. */ + +/** + * GPS HAL schedules fixes for LOC_GPS_POSITION_RECURRENCE_PERIODIC mode. If this is + * not set, then the framework will use 1000ms for min_interval and will start + * and call start() and stop() to schedule the GPS. + */ +#define LOC_GPS_CAPABILITY_SCHEDULING (1 << 0) +/** GPS supports MS-Based AGPS mode */ +#define LOC_GPS_CAPABILITY_MSB (1 << 1) +/** GPS supports MS-Assisted AGPS mode */ +#define LOC_GPS_CAPABILITY_MSA (1 << 2) +/** GPS supports single-shot fixes */ +#define LOC_GPS_CAPABILITY_SINGLE_SHOT (1 << 3) +/** GPS supports on demand time injection */ +#define LOC_GPS_CAPABILITY_ON_DEMAND_TIME (1 << 4) +/** GPS supports Geofencing */ +#define LOC_GPS_CAPABILITY_GEOFENCING (1 << 5) +/** GPS supports Measurements. */ +#define LOC_GPS_CAPABILITY_MEASUREMENTS (1 << 6) +/** GPS supports Navigation Messages */ +#define LOC_GPS_CAPABILITY_NAV_MESSAGES (1 << 7) + +/** + * Flags used to specify which aiding data to delete when calling + * delete_aiding_data(). + */ +typedef uint16_t LocGpsAidingData; +/* IMPORTANT: Note that the following values must match + * constants in GpsLocationProvider.java. */ +#define LOC_GPS_DELETE_EPHEMERIS 0x0001 +#define LOC_GPS_DELETE_ALMANAC 0x0002 +#define LOC_GPS_DELETE_POSITION 0x0004 +#define LOC_GPS_DELETE_TIME 0x0008 +#define LOC_GPS_DELETE_IONO 0x0010 +#define LOC_GPS_DELETE_UTC 0x0020 +#define LOC_GPS_DELETE_HEALTH 0x0040 +#define LOC_GPS_DELETE_SVDIR 0x0080 +#define LOC_GPS_DELETE_SVSTEER 0x0100 +#define LOC_GPS_DELETE_SADATA 0x0200 +#define LOC_GPS_DELETE_RTI 0x0400 +#define LOC_GPS_DELETE_MB_DATA 0x0800 +#define LOC_GPS_DELETE_CELLDB_INFO 0x8000 +#define LOC_GPS_DELETE_ALL 0xFFFF + +/** AGPS type */ +typedef uint16_t LocAGpsType; +#define LOC_AGPS_TYPE_ANY 0 +#define LOC_AGPS_TYPE_SUPL 1 +#define LOC_AGPS_TYPE_C2K 2 +#define LOC_AGPS_TYPE_WWAN_ANY 3 +#define LOC_AGPS_TYPE_WIFI 4 +#define LOC_AGPS_TYPE_SUPL_ES 5 + +typedef uint16_t LocAGpsSetIDType; +#define LOC_AGPS_SETID_TYPE_NONE 0 +#define LOC_AGPS_SETID_TYPE_IMSI 1 +#define LOC_AGPS_SETID_TYPE_MSISDN 2 + +typedef uint16_t LocApnIpType; +#define LOC_APN_IP_INVALID 0 +#define LOC_APN_IP_IPV4 1 +#define LOC_APN_IP_IPV6 2 +#define LOC_APN_IP_IPV4V6 3 + +/** + * String length constants + */ +#define LOC_GPS_NI_SHORT_STRING_MAXLEN 256 +#define LOC_GPS_NI_LONG_STRING_MAXLEN 2048 + +/** + * LocGpsNiType constants + */ +typedef uint32_t LocGpsNiType; +#define LOC_GPS_NI_TYPE_VOICE 1 +#define LOC_GPS_NI_TYPE_UMTS_SUPL 2 +#define LOC_GPS_NI_TYPE_UMTS_CTRL_PLANE 3 +/*Emergency SUPL*/ +#define LOC_GPS_NI_TYPE_EMERGENCY_SUPL 4 + +/** + * LocGpsNiNotifyFlags constants + */ +typedef uint32_t LocGpsNiNotifyFlags; +/** NI requires notification */ +#define LOC_GPS_NI_NEED_NOTIFY 0x0001 +/** NI requires verification */ +#define LOC_GPS_NI_NEED_VERIFY 0x0002 +/** NI requires privacy override, no notification/minimal trace */ +#define LOC_GPS_NI_PRIVACY_OVERRIDE 0x0004 + +/** + * GPS NI responses, used to define the response in + * NI structures + */ +typedef int LocGpsUserResponseType; +#define LOC_GPS_NI_RESPONSE_ACCEPT 1 +#define LOC_GPS_NI_RESPONSE_DENY 2 +#define LOC_GPS_NI_RESPONSE_NORESP 3 + +/** + * NI data encoding scheme + */ +typedef int LocGpsNiEncodingType; +#define LOC_GPS_ENC_NONE 0 +#define LOC_GPS_ENC_SUPL_GSM_DEFAULT 1 +#define LOC_GPS_ENC_SUPL_UTF8 2 +#define LOC_GPS_ENC_SUPL_UCS2 3 +#define LOC_GPS_ENC_UNKNOWN -1 + +/** AGPS status event values. */ +typedef uint8_t LocAGpsStatusValue; +/** GPS requests data connection for AGPS. */ +#define LOC_GPS_REQUEST_AGPS_DATA_CONN 1 +/** GPS releases the AGPS data connection. */ +#define LOC_GPS_RELEASE_AGPS_DATA_CONN 2 +/** AGPS data connection initiated */ +#define LOC_GPS_AGPS_DATA_CONNECTED 3 +/** AGPS data connection completed */ +#define LOC_GPS_AGPS_DATA_CONN_DONE 4 +/** AGPS data connection failed */ +#define LOC_GPS_AGPS_DATA_CONN_FAILED 5 + +typedef uint16_t LocAGpsRefLocationType; +#define LOC_AGPS_REF_LOCATION_TYPE_GSM_CELLID 1 +#define LOC_AGPS_REF_LOCATION_TYPE_UMTS_CELLID 2 +#define LOC_AGPS_REF_LOCATION_TYPE_MAC 3 +#define LOC_AGPS_REF_LOCATION_TYPE_LTE_CELLID 4 + +/* Deprecated, to be removed in the next Android release. */ +#define LOC_AGPS_REG_LOCATION_TYPE_MAC 3 + +/** Network types for update_network_state "type" parameter */ +#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE 0 +#define LOC_AGPS_RIL_NETWORK_TYPE_WIFI 1 +#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE_MMS 2 +#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE_SUPL 3 +#define LOC_AGPS_RIL_NETWORK_TTYPE_MOBILE_DUN 4 +#define LOC_AGPS_RIL_NETWORK_TTYPE_MOBILE_HIPRI 5 +#define LOC_AGPS_RIL_NETWORK_TTYPE_WIMAX 6 + +/* The following typedef together with its constants below are deprecated, and + * will be removed in the next release. */ +typedef uint16_t LocGpsClockFlags; +#define LOC_GPS_CLOCK_HAS_LEAP_SECOND (1<<0) +#define LOC_GPS_CLOCK_HAS_TIME_UNCERTAINTY (1<<1) +#define LOC_GPS_CLOCK_HAS_FULL_BIAS (1<<2) +#define LOC_GPS_CLOCK_HAS_BIAS (1<<3) +#define LOC_GPS_CLOCK_HAS_BIAS_UNCERTAINTY (1<<4) +#define LOC_GPS_CLOCK_HAS_DRIFT (1<<5) +#define LOC_GPS_CLOCK_HAS_DRIFT_UNCERTAINTY (1<<6) + +/** + * Flags to indicate what fields in LocGnssClock are valid. + */ +typedef uint16_t LocGnssClockFlags; +/** A valid 'leap second' is stored in the data structure. */ +#define LOC_GNSS_CLOCK_HAS_LEAP_SECOND (1<<0) +/** A valid 'time uncertainty' is stored in the data structure. */ +#define LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY (1<<1) +/** A valid 'full bias' is stored in the data structure. */ +#define LOC_GNSS_CLOCK_HAS_FULL_BIAS (1<<2) +/** A valid 'bias' is stored in the data structure. */ +#define LOC_GNSS_CLOCK_HAS_BIAS (1<<3) +/** A valid 'bias uncertainty' is stored in the data structure. */ +#define LOC_GNSS_CLOCK_HAS_BIAS_UNCERTAINTY (1<<4) +/** A valid 'drift' is stored in the data structure. */ +#define LOC_GNSS_CLOCK_HAS_DRIFT (1<<5) +/** A valid 'drift uncertainty' is stored in the data structure. */ +#define LOC_GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY (1<<6) + +/* The following typedef together with its constants below are deprecated, and + * will be removed in the next release. */ +typedef uint8_t LocGpsClockType; +#define LOC_GPS_CLOCK_TYPE_UNKNOWN 0 +#define LOC_GPS_CLOCK_TYPE_LOCAL_HW_TIME 1 +#define LOC_GPS_CLOCK_TYPE_GPS_TIME 2 + +/* The following typedef together with its constants below are deprecated, and + * will be removed in the next release. */ +typedef uint32_t LocGpsMeasurementFlags; +#define LOC_GPS_MEASUREMENT_HAS_SNR (1<<0) +#define LOC_GPS_MEASUREMENT_HAS_ELEVATION (1<<1) +#define LOC_GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY (1<<2) +#define LOC_GPS_MEASUREMENT_HAS_AZIMUTH (1<<3) +#define LOC_GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY (1<<4) +#define LOC_GPS_MEASUREMENT_HAS_PSEUDORANGE (1<<5) +#define LOC_GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY (1<<6) +#define LOC_GPS_MEASUREMENT_HAS_CODE_PHASE (1<<7) +#define LOC_GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY (1<<8) +#define LOC_GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY (1<<9) +#define LOC_GPS_MEASUREMENT_HAS_CARRIER_CYCLES (1<<10) +#define LOC_GPS_MEASUREMENT_HAS_CARRIER_PHASE (1<<11) +#define LOC_GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY (1<<12) +#define LOC_GPS_MEASUREMENT_HAS_BIT_NUMBER (1<<13) +#define LOC_GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT (1<<14) +#define LOC_GPS_MEASUREMENT_HAS_DOPPLER_SHIFT (1<<15) +#define LOC_GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY (1<<16) +#define LOC_GPS_MEASUREMENT_HAS_USED_IN_FIX (1<<17) +#define LOC_GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE (1<<18) + +/** + * Flags to indicate what fields in LocGnssMeasurement are valid. + */ +typedef uint32_t LocGnssMeasurementFlags; +/** A valid 'snr' is stored in the data structure. */ +#define LOC_GNSS_MEASUREMENT_HAS_SNR (1<<0) +/** A valid 'carrier frequency' is stored in the data structure. */ +#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY (1<<9) +/** A valid 'carrier cycles' is stored in the data structure. */ +#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_CYCLES (1<<10) +/** A valid 'carrier phase' is stored in the data structure. */ +#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE (1<<11) +/** A valid 'carrier phase uncertainty' is stored in the data structure. */ +#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY (1<<12) + +/* The following typedef together with its constants below are deprecated, and + * will be removed in the next release. */ +typedef uint8_t LocGpsLossOfLock; +#define LOC_GPS_LOSS_OF_LOCK_UNKNOWN 0 +#define LOC_GPS_LOSS_OF_LOCK_OK 1 +#define LOC_GPS_LOSS_OF_LOCK_CYCLE_SLIP 2 + +/* The following typedef together with its constants below are deprecated, and + * will be removed in the next release. Use LocGnssMultipathIndicator instead. + */ +typedef uint8_t LocGpsMultipathIndicator; +#define LOC_GPS_MULTIPATH_INDICATOR_UNKNOWN 0 +#define LOC_GPS_MULTIPATH_INDICATOR_DETECTED 1 +#define LOC_GPS_MULTIPATH_INDICATOR_NOT_USED 2 + +/** + * Enumeration of available values for the GNSS Measurement's multipath + * indicator. + */ +typedef uint8_t LocGnssMultipathIndicator; +/** The indicator is not available or unknown. */ +#define LOC_GNSS_MULTIPATH_INDICATOR_UNKNOWN 0 +/** The measurement is indicated to be affected by multipath. */ +#define LOC_GNSS_MULTIPATH_INDICATOR_PRESENT 1 +/** The measurement is indicated to be not affected by multipath. */ +#define LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT 2 + +/* The following typedef together with its constants below are deprecated, and + * will be removed in the next release. */ +typedef uint16_t LocGpsMeasurementState; +#define LOC_GPS_MEASUREMENT_STATE_UNKNOWN 0 +#define LOC_GPS_MEASUREMENT_STATE_CODE_LOCK (1<<0) +#define LOC_GPS_MEASUREMENT_STATE_BIT_SYNC (1<<1) +#define LOC_GPS_MEASUREMENT_STATE_SUBFRAME_SYNC (1<<2) +#define LOC_GPS_MEASUREMENT_STATE_TOW_DECODED (1<<3) +#define LOC_GPS_MEASUREMENT_STATE_MSEC_AMBIGUOUS (1<<4) + +/** + * Flags indicating the GNSS measurement state. + * + * The expected behavior here is for GPS HAL to set all the flags that applies. + * For example, if the state for a satellite is only C/A code locked and bit + * synchronized, and there is still millisecond ambiguity, the state should be + * set as: + * + * LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK | LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC | + * LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS + * + * If GNSS is still searching for a satellite, the corresponding state should be + * set to LOC_GNSS_MEASUREMENT_STATE_UNKNOWN(0). + */ +typedef uint32_t LocGnssMeasurementState; +#define LOC_GNSS_MEASUREMENT_STATE_UNKNOWN 0 +#define LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK (1<<0) +#define LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC (1<<1) +#define LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC (1<<2) +#define LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED (1<<3) +#define LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS (1<<4) +#define LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC (1<<5) +#define LOC_GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC (1<<6) +#define LOC_GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED (1<<7) +#define LOC_GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC (1<<8) +#define LOC_GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC (1<<9) +#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK (1<<10) +#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK (1<<11) +#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC (1<<12) +#define LOC_GNSS_MEASUREMENT_STATE_SBAS_SYNC (1<<13) + +/* The following typedef together with its constants below are deprecated, and + * will be removed in the next release. */ +typedef uint16_t LocGpsAccumulatedDeltaRangeState; +#define LOC_GPS_ADR_STATE_UNKNOWN 0 +#define LOC_GPS_ADR_STATE_VALID (1<<0) +#define LOC_GPS_ADR_STATE_RESET (1<<1) +#define LOC_GPS_ADR_STATE_CYCLE_SLIP (1<<2) + +/** + * Flags indicating the Accumulated Delta Range's states. + */ +typedef uint16_t LocGnssAccumulatedDeltaRangeState; +#define LOC_GNSS_ADR_STATE_UNKNOWN 0 +#define LOC_GNSS_ADR_STATE_VALID (1<<0) +#define LOC_GNSS_ADR_STATE_RESET (1<<1) +#define LOC_GNSS_ADR_STATE_CYCLE_SLIP (1<<2) + +#if 0 +/* The following typedef together with its constants below are deprecated, and + * will be removed in the next release. */ +typedef uint8_t GpsNavigationMessageType; +#define GPS_NAVIGATION_MESSAGE_TYPE_UNKNOWN 0 +#define GPS_NAVIGATION_MESSAGE_TYPE_L1CA 1 +#define GPS_NAVIGATION_MESSAGE_TYPE_L2CNAV 2 +#define GPS_NAVIGATION_MESSAGE_TYPE_L5CNAV 3 +#define GPS_NAVIGATION_MESSAGE_TYPE_CNAV2 4 + +/** + * Enumeration of available values to indicate the GNSS Navigation message + * types. + * + * For convenience, first byte is the LocGnssConstellationType on which that signal + * is typically transmitted + */ +typedef int16_t GnssNavigationMessageType; + +#define GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN 0 +/** GPS L1 C/A message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L1CA 0x0101 +/** GPS L2-CNAV message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L2CNAV 0x0102 +/** GPS L5-CNAV message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L5CNAV 0x0103 +/** GPS CNAV-2 message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_CNAV2 0x0104 +/** Glonass L1 CA message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_GLO_L1CA 0x0301 +/** Beidou D1 message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_BDS_D1 0x0501 +/** Beidou D2 message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_BDS_D2 0x0502 +/** Galileo I/NAV message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_GAL_I 0x0601 +/** Galileo F/NAV message contained in the structure. */ +#define GNSS_NAVIGATION_MESSAGE_TYPE_GAL_F 0x0602 + +/** + * Status of Navigation Message + * When a message is received properly without any parity error in its navigation words, the + * status should be set to NAV_MESSAGE_STATUS_PARITY_PASSED. But if a message is received + * with words that failed parity check, but GPS is able to correct those words, the status + * should be set to NAV_MESSAGE_STATUS_PARITY_REBUILT. + * No need to send any navigation message that contains words with parity error and cannot be + * corrected. + */ +typedef uint16_t NavigationMessageStatus; +#define NAV_MESSAGE_STATUS_UNKNOWN 0 +#define NAV_MESSAGE_STATUS_PARITY_PASSED (1<<0) +#define NAV_MESSAGE_STATUS_PARITY_REBUILT (1<<1) + +/* This constant is deprecated, and will be removed in the next release. */ +#define NAV_MESSAGE_STATUS_UNKONW 0 +#endif + +/** + * Flags that indicate information about the satellite + */ +typedef uint8_t LocGnssSvFlags; +#define LOC_GNSS_SV_FLAGS_NONE 0 +#define LOC_GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA (1 << 0) +#define LOC_GNSS_SV_FLAGS_HAS_ALMANAC_DATA (1 << 1) +#define LOC_GNSS_SV_FLAGS_USED_IN_FIX (1 << 2) + +/** + * Constellation type of LocGnssSvInfo + */ +typedef uint8_t LocGnssConstellationType; +#define LOC_GNSS_CONSTELLATION_UNKNOWN 0 +#define LOC_GNSS_CONSTELLATION_GPS 1 +#define LOC_GNSS_CONSTELLATION_SBAS 2 +#define LOC_GNSS_CONSTELLATION_GLONASS 3 +#define LOC_GNSS_CONSTELLATION_QZSS 4 +#define LOC_GNSS_CONSTELLATION_BEIDOU 5 +#define LOC_GNSS_CONSTELLATION_GALILEO 6 + +/** + * Name for the GPS XTRA interface. + */ +#define LOC_GPS_XTRA_INTERFACE "gps-xtra" + +/** + * Name for the GPS DEBUG interface. + */ +#define LOC_GPS_DEBUG_INTERFACE "gps-debug" + +/** + * Name for the AGPS interface. + */ + +#define LOC_AGPS_INTERFACE "agps" + +/** + * Name of the Supl Certificate interface. + */ +#define LOC_SUPL_CERTIFICATE_INTERFACE "supl-certificate" + +/** + * Name for NI interface + */ +#define LOC_GPS_NI_INTERFACE "gps-ni" + +/** + * Name for the AGPS-RIL interface. + */ +#define LOC_AGPS_RIL_INTERFACE "agps_ril" + +/** + * Name for the GPS_Geofencing interface. + */ +#define LOC_GPS_GEOFENCING_INTERFACE "gps_geofencing" + +/** + * Name of the GPS Measurements interface. + */ +#define LOC_GPS_MEASUREMENT_INTERFACE "gps_measurement" + +/** + * Name of the GPS navigation message interface. + */ +#define LOC_GPS_NAVIGATION_MESSAGE_INTERFACE "gps_navigation_message" + +/** + * Name of the GNSS/GPS configuration interface. + */ +#define LOC_GNSS_CONFIGURATION_INTERFACE "gnss_configuration" + +/** Represents a location. */ +typedef struct { + /** set to sizeof(LocGpsLocation) */ + uint32_t size; + /** Contains LocGpsLocationFlags bits. */ + uint16_t flags; + /** The spoof mask */ + LocGpsSpoofMask spoof_mask; + /** Represents latitude in degrees. */ + double latitude; + /** Represents longitude in degrees. */ + double longitude; + /** + * Represents altitude in meters above the WGS 84 reference ellipsoid. + */ + double altitude; + /** Represents horizontal speed in meters per second. */ + float speed; + /** Represents heading in degrees. */ + float bearing; + /** Represents expected accuracy in meters. */ + float accuracy; + /** Represents the expected vertical uncertainity in meters*/ + float vertUncertainity; + /** Timestamp for the location fix. */ + LocGpsUtcTime timestamp; +} LocGpsLocation; + +/** Represents the status. */ +typedef struct { + /** set to sizeof(LocGpsStatus) */ + size_t size; + LocGpsStatusValue status; +} LocGpsStatus; + +/** + * Legacy struct to represents SV information. + * Deprecated, to be removed in the next Android release. + * Use LocGnssSvInfo instead. + */ +typedef struct { + /** set to sizeof(LocGpsSvInfo) */ + size_t size; + /** Pseudo-random number for the SV. */ + int prn; + /** Signal to noise ratio. */ + float snr; + /** Elevation of SV in degrees. */ + float elevation; + /** Azimuth of SV in degrees. */ + float azimuth; +} LocGpsSvInfo; + +typedef struct { + /** set to sizeof(LocGnssSvInfo) */ + size_t size; + + /** + * Pseudo-random number for the SV, or FCN/OSN number for Glonass. The + * distinction is made by looking at constellation field. Values should be + * in the range of: + * + * - GPS: 1-32 + * - SBAS: 120-151, 183-192 + * - GLONASS: 1-24, the orbital slot number (OSN), if known. Or, if not: + * 93-106, the frequency channel number (FCN) (-7 to +6) offset by + 100 + * i.e. report an FCN of -7 as 93, FCN of 0 as 100, and FCN of +6 as 106. + * - QZSS: 193-200 + * - Galileo: 1-36 + * - Beidou: 1-37 + */ + int16_t svid; + + /** + * Defines the constellation of the given SV. Value should be one of those + * LOC_GNSS_CONSTELLATION_* constants + */ + LocGnssConstellationType constellation; + + /** + * Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. + * It contains the measured C/N0 value for the signal at the antenna port. + * + * This is a mandatory value. + */ + float c_n0_dbhz; + + /** Elevation of SV in degrees. */ + float elevation; + + /** Azimuth of SV in degrees. */ + float azimuth; + + /** + * Contains additional data about the given SV. Value should be one of those + * LOC_GNSS_SV_FLAGS_* constants + */ + LocGnssSvFlags flags; + +} LocGnssSvInfo; + +/** + * Legacy struct to represents SV status. + * Deprecated, to be removed in the next Android release. + * Use LocGnssSvStatus instead. + */ +typedef struct { + /** set to sizeof(LocGpsSvStatus) */ + size_t size; + int num_svs; + LocGpsSvInfo sv_list[LOC_GPS_MAX_SVS]; + uint32_t ephemeris_mask; + uint32_t almanac_mask; + uint32_t used_in_fix_mask; +} LocGpsSvStatus; + +/** + * Represents SV status. + */ +typedef struct { + /** set to sizeof(LocGnssSvStatus) */ + size_t size; + + /** Number of GPS SVs currently visible, refers to the SVs stored in sv_list */ + int num_svs; + /** + * Pointer to an array of SVs information for all GNSS constellations, + * except GPS, which is reported using sv_list + */ + LocGnssSvInfo gnss_sv_list[LOC_GNSS_MAX_SVS]; + +} LocGnssSvStatus; + +/* CellID for 2G, 3G and LTE, used in AGPS. */ +typedef struct { + LocAGpsRefLocationType type; + /** Mobile Country Code. */ + uint16_t mcc; + /** Mobile Network Code .*/ + uint16_t mnc; + /** Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE, + * lac is populated with tac, to ensure that we don't break old clients that + * might rely in the old (wrong) behavior. + */ + uint16_t lac; + /** Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE. */ + uint32_t cid; + /** Tracking Area Code in LTE. */ + uint16_t tac; + /** Physical Cell id in LTE (not used in 2G and 3G) */ + uint16_t pcid; +} LocAGpsRefLocationCellID; + +typedef struct { + uint8_t mac[6]; +} LocAGpsRefLocationMac; + +/** Represents ref locations */ +typedef struct { + LocAGpsRefLocationType type; + union { + LocAGpsRefLocationCellID cellID; + LocAGpsRefLocationMac mac; + } u; +} LocAGpsRefLocation; + +/** + * Callback with location information. Can only be called from a thread created + * by create_thread_cb. + */ +typedef void (* loc_gps_location_callback)(LocGpsLocation* location); + +/** + * Callback with status information. Can only be called from a thread created by + * create_thread_cb. + */ +typedef void (* loc_gps_status_callback)(LocGpsStatus* status); +/** + * Legacy callback with SV status information. + * Can only be called from a thread created by create_thread_cb. + * + * This callback is deprecated, and will be removed in the next release. Use + * loc_gnss_sv_status_callback() instead. + */ +typedef void (* loc_gps_sv_status_callback)(LocGpsSvStatus* sv_info); + +/** + * Callback with SV status information. + * Can only be called from a thread created by create_thread_cb. + */ +typedef void (* loc_gnss_sv_status_callback)(LocGnssSvStatus* sv_info); + +/** + * Callback for reporting NMEA sentences. Can only be called from a thread + * created by create_thread_cb. + */ +typedef void (* loc_gps_nmea_callback)(LocGpsUtcTime timestamp, const char* nmea, int length); + +/** + * Callback to inform framework of the GPS engine's capabilities. Capability + * parameter is a bit field of LOC_GPS_CAPABILITY_* flags. + */ +typedef void (* loc_gps_set_capabilities)(uint32_t capabilities); + +/** + * Callback utility for acquiring the GPS wakelock. This can be used to prevent + * the CPU from suspending while handling GPS events. + */ +typedef void (* loc_gps_acquire_wakelock)(); + +/** Callback utility for releasing the GPS wakelock. */ +typedef void (* loc_gps_release_wakelock)(); + +/** Callback for requesting NTP time */ +typedef void (* loc_gps_request_utc_time)(); + +/** + * Callback for creating a thread that can call into the Java framework code. + * This must be used to create any threads that report events up to the + * framework. + */ +typedef pthread_t (* loc_gps_create_thread)(const char* name, void (*start)(void *), void* arg); + +/** + * Provides information about how new the underlying GPS/GNSS hardware and + * software is. + * + * This information will be available for Android Test Applications. If a GPS + * HAL does not provide this information, it will be considered "2015 or + * earlier". + * + * If a GPS HAL does provide this information, then newer years will need to + * meet newer CTS standards. E.g. if the date are 2016 or above, then N+ level + * LocGpsMeasurement support will be verified. + */ +typedef struct { + /** Set to sizeof(LocGnssSystemInfo) */ + size_t size; + /* year in which the last update was made to the underlying hardware/firmware + * used to capture GNSS signals, e.g. 2016 */ + uint16_t year_of_hw; +} LocGnssSystemInfo; + +/** + * Callback to inform framework of the engine's hardware version information. + */ +typedef void (*loc_gnss_set_system_info)(const LocGnssSystemInfo* info); + +/** New GPS callback structure. */ +typedef struct { + /** set to sizeof(LocGpsCallbacks) */ + size_t size; + loc_gps_location_callback location_cb; + loc_gps_status_callback status_cb; + loc_gps_sv_status_callback sv_status_cb; + loc_gps_nmea_callback nmea_cb; + loc_gps_set_capabilities set_capabilities_cb; + loc_gps_acquire_wakelock acquire_wakelock_cb; + loc_gps_release_wakelock release_wakelock_cb; + loc_gps_create_thread create_thread_cb; + loc_gps_request_utc_time request_utc_time_cb; + + loc_gnss_set_system_info set_system_info_cb; + loc_gnss_sv_status_callback gnss_sv_status_cb; +} LocGpsCallbacks; + +/** Represents the standard GPS interface. */ +typedef struct { + /** set to sizeof(LocGpsInterface) */ + size_t size; + /** + * Opens the interface and provides the callback routines + * to the implementation of this interface. + */ + int (*init)( LocGpsCallbacks* callbacks ); + + /** Starts navigating. */ + int (*start)( void ); + + /** Stops navigating. */ + int (*stop)( void ); + + /** Closes the interface. */ + void (*cleanup)( void ); + + /** Injects the current time. */ + int (*inject_time)(LocGpsUtcTime time, int64_t timeReference, + int uncertainty); + + /** + * Injects current location from another location provider (typically cell + * ID). Latitude and longitude are measured in degrees expected accuracy is + * measured in meters + */ + int (*inject_location)(double latitude, double longitude, float accuracy); + + /** + * Specifies that the next call to start will not use the + * information defined in the flags. LOC_GPS_DELETE_ALL is passed for + * a cold start. + */ + void (*delete_aiding_data)(LocGpsAidingData flags); + + /** + * min_interval represents the time between fixes in milliseconds. + * preferred_accuracy represents the requested fix accuracy in meters. + * preferred_time represents the requested time to first fix in milliseconds. + * + * 'mode' parameter should be one of LOC_GPS_POSITION_MODE_MS_BASED + * or LOC_GPS_POSITION_MODE_STANDALONE. + * It is allowed by the platform (and it is recommended) to fallback to + * LOC_GPS_POSITION_MODE_MS_BASED if LOC_GPS_POSITION_MODE_MS_ASSISTED is passed in, and + * LOC_GPS_POSITION_MODE_MS_BASED is supported. + */ + int (*set_position_mode)(LocGpsPositionMode mode, LocGpsPositionRecurrence recurrence, + uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time); + + /** Get a pointer to extension information. */ + const void* (*get_extension)(const char* name); +} LocGpsInterface; + +/** + * Callback to request the client to download XTRA data. The client should + * download XTRA data and inject it by calling inject_xtra_data(). Can only be + * called from a thread created by create_thread_cb. + */ +typedef void (* loc_gps_xtra_download_request)(); + +/** Callback structure for the XTRA interface. */ +typedef struct { + loc_gps_xtra_download_request download_request_cb; + loc_gps_create_thread create_thread_cb; +} LocGpsXtraCallbacks; + +/** Extended interface for XTRA support. */ +typedef struct { + /** set to sizeof(LocGpsXtraInterface) */ + size_t size; + /** + * Opens the XTRA interface and provides the callback routines + * to the implementation of this interface. + */ + int (*init)( LocGpsXtraCallbacks* callbacks ); + /** Injects XTRA data into the GPS. */ + int (*inject_xtra_data)( char* data, int length ); +} LocGpsXtraInterface; + +#if 0 +/** Extended interface for DEBUG support. */ +typedef struct { + /** set to sizeof(LocGpsDebugInterface) */ + size_t size; + + /** + * This function should return any information that the native + * implementation wishes to include in a bugreport. + */ + size_t (*get_internal_state)(char* buffer, size_t bufferSize); +} LocGpsDebugInterface; +#endif + +/* + * Represents the status of AGPS augmented to support IPv4 and IPv6. + */ +typedef struct { + /** set to sizeof(LocAGpsStatus) */ + size_t size; + + LocAGpsType type; + LocAGpsStatusValue status; + + /** + * Must be set to a valid IPv4 address if the field 'addr' contains an IPv4 + * address, or set to INADDR_NONE otherwise. + */ + uint32_t ipaddr; + + /** + * Must contain the IPv4 (AF_INET) or IPv6 (AF_INET6) address to report. + * Any other value of addr.ss_family will be rejected. + */ + struct sockaddr_storage addr; +} LocAGpsStatus; + +/** + * Callback with AGPS status information. Can only be called from a thread + * created by create_thread_cb. + */ +typedef void (* loc_agps_status_callback)(LocAGpsStatus* status); + +/** Callback structure for the AGPS interface. */ +typedef struct { + loc_agps_status_callback status_cb; + loc_gps_create_thread create_thread_cb; +} LocAGpsCallbacks; + +/** + * Extended interface for AGPS support, it is augmented to enable to pass + * extra APN data. + */ +typedef struct { + /** set to sizeof(LocAGpsInterface) */ + size_t size; + + /** + * Opens the AGPS interface and provides the callback routines to the + * implementation of this interface. + */ + void (*init)(LocAGpsCallbacks* callbacks); + /** + * Deprecated. + * If the HAL supports LocAGpsInterface_v2 this API will not be used, see + * data_conn_open_with_apn_ip_type for more information. + */ + int (*data_conn_open)(const char* apn); + /** + * Notifies that the AGPS data connection has been closed. + */ + int (*data_conn_closed)(); + /** + * Notifies that a data connection is not available for AGPS. + */ + int (*data_conn_failed)(); + /** + * Sets the hostname and port for the AGPS server. + */ + int (*set_server)(LocAGpsType type, const char* hostname, int port); + + /** + * Notifies that a data connection is available and sets the name of the + * APN, and its IP type, to be used for SUPL connections. + */ + int (*data_conn_open_with_apn_ip_type)( + const char* apn, + LocApnIpType apnIpType); +} LocAGpsInterface; + +/** Error codes associated with certificate operations */ +#define LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS 0 +#define LOC_AGPS_CERTIFICATE_ERROR_GENERIC -100 +#define LOC_AGPS_CERTIFICATE_ERROR_TOO_MANY_CERTIFICATES -101 + +/** A data structure that represents an X.509 certificate using DER encoding */ +typedef struct { + size_t length; + u_char* data; +} LocDerEncodedCertificate; + +/** + * A type definition for SHA1 Fingerprints used to identify X.509 Certificates + * The Fingerprint is a digest of the DER Certificate that uniquely identifies it. + */ +typedef struct { + u_char data[20]; +} LocSha1CertificateFingerprint; + +/** AGPS Interface to handle SUPL certificate operations */ +typedef struct { + /** set to sizeof(LocSuplCertificateInterface) */ + size_t size; + + /** + * Installs a set of Certificates used for SUPL connections to the AGPS server. + * If needed the HAL should find out internally any certificates that need to be removed to + * accommodate the certificates to install. + * The certificates installed represent a full set of valid certificates needed to connect to + * AGPS SUPL servers. + * The list of certificates is required, and all must be available at the same time, when trying + * to establish a connection with the AGPS Server. + * + * Parameters: + * certificates - A pointer to an array of DER encoded certificates that are need to be + * installed in the HAL. + * length - The number of certificates to install. + * Returns: + * LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS if the operation is completed successfully + * LOC_AGPS_CERTIFICATE_ERROR_TOO_MANY_CERTIFICATES if the HAL cannot store the number of + * certificates attempted to be installed, the state of the certificates stored should + * remain the same as before on this error case. + * + * IMPORTANT: + * If needed the HAL should find out internally the set of certificates that need to be + * removed to accommodate the certificates to install. + */ + int (*install_certificates) ( const LocDerEncodedCertificate* certificates, size_t length ); + + /** + * Notifies the HAL that a list of certificates used for SUPL connections are revoked. It is + * expected that the given set of certificates is removed from the internal store of the HAL. + * + * Parameters: + * fingerprints - A pointer to an array of SHA1 Fingerprints to identify the set of + * certificates to revoke. + * length - The number of fingerprints provided. + * Returns: + * LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS if the operation is completed successfully. + * + * IMPORTANT: + * If any of the certificates provided (through its fingerprint) is not known by the HAL, + * it should be ignored and continue revoking/deleting the rest of them. + */ + int (*revoke_certificates) ( const LocSha1CertificateFingerprint* fingerprints, size_t length ); +} LocSuplCertificateInterface; + +/** Represents an NI request */ +typedef struct { + /** set to sizeof(LocGpsNiNotification) */ + size_t size; + + /** + * An ID generated by HAL to associate NI notifications and UI + * responses + */ + int notification_id; + + /** + * An NI type used to distinguish different categories of NI + * events, such as LOC_GPS_NI_TYPE_VOICE, LOC_GPS_NI_TYPE_UMTS_SUPL, ... + */ + LocGpsNiType ni_type; + + /** + * Notification/verification options, combinations of LocGpsNiNotifyFlags constants + */ + LocGpsNiNotifyFlags notify_flags; + + /** + * Timeout period to wait for user response. + * Set to 0 for no time out limit. + */ + int timeout; + + /** + * Default response when time out. + */ + LocGpsUserResponseType default_response; + + /** + * Requestor ID + */ + char requestor_id[LOC_GPS_NI_SHORT_STRING_MAXLEN]; + + /** + * Notification message. It can also be used to store client_id in some cases + */ + char text[LOC_GPS_NI_LONG_STRING_MAXLEN]; + + /** + * Client name decoding scheme + */ + LocGpsNiEncodingType requestor_id_encoding; + + /** + * Client name decoding scheme + */ + LocGpsNiEncodingType text_encoding; + + /** + * A pointer to extra data. Format: + * key_1 = value_1 + * key_2 = value_2 + */ + char extras[LOC_GPS_NI_LONG_STRING_MAXLEN]; + +} LocGpsNiNotification; + +/** + * Callback with NI notification. Can only be called from a thread created by + * create_thread_cb. + */ +typedef void (*loc_gps_ni_notify_callback)(LocGpsNiNotification *notification); + +/** GPS NI callback structure. */ +typedef struct +{ + /** + * Sends the notification request from HAL to GPSLocationProvider. + */ + loc_gps_ni_notify_callback notify_cb; + loc_gps_create_thread create_thread_cb; +} LocGpsNiCallbacks; + +/** + * Extended interface for Network-initiated (NI) support. + */ +typedef struct +{ + /** set to sizeof(LocGpsNiInterface) */ + size_t size; + + /** Registers the callbacks for HAL to use. */ + void (*init) (LocGpsNiCallbacks *callbacks); + + /** Sends a response to HAL. */ + void (*respond) (int notif_id, LocGpsUserResponseType user_response); +} LocGpsNiInterface; + +#define LOC_AGPS_RIL_REQUEST_SETID_IMSI (1<<0L) +#define LOC_AGPS_RIL_REQUEST_SETID_MSISDN (1<<1L) + +#define LOC_AGPS_RIL_REQUEST_REFLOC_CELLID (1<<0L) +#define LOC_AGPS_RIL_REQUEST_REFLOC_MAC (1<<1L) + +typedef void (*loc_agps_ril_request_set_id)(uint32_t flags); +typedef void (*loc_agps_ril_request_ref_loc)(uint32_t flags); + +typedef struct { + loc_agps_ril_request_set_id request_setid; + loc_agps_ril_request_ref_loc request_refloc; + loc_gps_create_thread create_thread_cb; +} LocAGpsRilCallbacks; + +/** Extended interface for AGPS_RIL support. */ +typedef struct { + /** set to sizeof(LocAGpsRilInterface) */ + size_t size; + /** + * Opens the AGPS interface and provides the callback routines + * to the implementation of this interface. + */ + void (*init)( LocAGpsRilCallbacks* callbacks ); + + /** + * Sets the reference location. + */ + void (*set_ref_location) (const LocAGpsRefLocation *agps_reflocation, size_t sz_struct); + /** + * Sets the set ID. + */ + void (*set_set_id) (LocAGpsSetIDType type, const char* setid); + + /** + * Send network initiated message. + */ + void (*ni_message) (uint8_t *msg, size_t len); + + /** + * Notify GPS of network status changes. + * These parameters match values in the android.net.NetworkInfo class. + */ + void (*update_network_state) (int connected, int type, int roaming, const char* extra_info); + + /** + * Notify GPS of network status changes. + * These parameters match values in the android.net.NetworkInfo class. + */ + void (*update_network_availability) (int avaiable, const char* apn); +} LocAGpsRilInterface; + +/** + * GPS Geofence. + * There are 3 states associated with a Geofence: Inside, Outside, Unknown. + * There are 3 transitions: ENTERED, EXITED, UNCERTAIN. + * + * An example state diagram with confidence level: 95% and Unknown time limit + * set as 30 secs is shown below. (confidence level and Unknown time limit are + * explained latter) + * ____________________________ + * | Unknown (30 secs) | + * """""""""""""""""""""""""""" + * ^ | | ^ + * UNCERTAIN| |ENTERED EXITED| |UNCERTAIN + * | v v | + * ________ EXITED _________ + * | Inside | -----------> | Outside | + * | | <----------- | | + * """""""" ENTERED """"""""" + * + * Inside state: We are 95% confident that the user is inside the geofence. + * Outside state: We are 95% confident that the user is outside the geofence + * Unknown state: Rest of the time. + * + * The Unknown state is better explained with an example: + * + * __________ + * | c| + * | ___ | _______ + * | |a| | | b | + * | """ | """"""" + * | | + * """""""""" + * In the diagram above, "a" and "b" are 2 geofences and "c" is the accuracy + * circle reported by the GPS subsystem. Now with regard to "b", the system is + * confident that the user is outside. But with regard to "a" is not confident + * whether it is inside or outside the geofence. If the accuracy remains the + * same for a sufficient period of time, the UNCERTAIN transition would be + * triggered with the state set to Unknown. If the accuracy improves later, an + * appropriate transition should be triggered. This "sufficient period of time" + * is defined by the parameter in the add_geofence_area API. + * In other words, Unknown state can be interpreted as a state in which the + * GPS subsystem isn't confident enough that the user is either inside or + * outside the Geofence. It moves to Unknown state only after the expiry of the + * timeout. + * + * The geofence callback needs to be triggered for the ENTERED and EXITED + * transitions, when the GPS system is confident that the user has entered + * (Inside state) or exited (Outside state) the Geofence. An implementation + * which uses a value of 95% as the confidence is recommended. The callback + * should be triggered only for the transitions requested by the + * add_geofence_area call. + * + * Even though the diagram and explanation talks about states and transitions, + * the callee is only interested in the transistions. The states are mentioned + * here for illustrative purposes. + * + * Startup Scenario: When the device boots up, if an application adds geofences, + * and then we get an accurate GPS location fix, it needs to trigger the + * appropriate (ENTERED or EXITED) transition for every Geofence it knows about. + * By default, all the Geofences will be in the Unknown state. + * + * When the GPS system is unavailable, loc_gps_geofence_status_callback should be + * called to inform the upper layers of the same. Similarly, when it becomes + * available the callback should be called. This is a global state while the + * UNKNOWN transition described above is per geofence. + * + * An important aspect to note is that users of this API (framework), will use + * other subsystems like wifi, sensors, cell to handle Unknown case and + * hopefully provide a definitive state transition to the third party + * application. GPS Geofence will just be a signal indicating what the GPS + * subsystem knows about the Geofence. + * + */ +#define LOC_GPS_GEOFENCE_ENTERED (1<<0L) +#define LOC_GPS_GEOFENCE_EXITED (1<<1L) +#define LOC_GPS_GEOFENCE_UNCERTAIN (1<<2L) + +#define LOC_GPS_GEOFENCE_UNAVAILABLE (1<<0L) +#define LOC_GPS_GEOFENCE_AVAILABLE (1<<1L) + +#define LOC_GPS_GEOFENCE_OPERATION_SUCCESS 0 +#define LOC_GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES -100 +#define LOC_GPS_GEOFENCE_ERROR_ID_EXISTS -101 +#define LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN -102 +#define LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION -103 +#define LOC_GPS_GEOFENCE_ERROR_GENERIC -149 + +/** + * The callback associated with the geofence. + * Parameters: + * geofence_id - The id associated with the add_geofence_area. + * location - The current GPS location. + * transition - Can be one of LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED, + * LOC_GPS_GEOFENCE_UNCERTAIN. + * timestamp - Timestamp when the transition was detected. + * + * The callback should only be called when the caller is interested in that + * particular transition. For instance, if the caller is interested only in + * ENTERED transition, then the callback should NOT be called with the EXITED + * transition. + * + * IMPORTANT: If a transition is triggered resulting in this callback, the GPS + * subsystem will wake up the application processor, if its in suspend state. + */ +typedef void (*loc_gps_geofence_transition_callback) (int32_t geofence_id, LocGpsLocation* location, + int32_t transition, LocGpsUtcTime timestamp); + +/** + * The callback associated with the availability of the GPS system for geofencing + * monitoring. If the GPS system determines that it cannot monitor geofences + * because of lack of reliability or unavailability of the GPS signals, it will + * call this callback with LOC_GPS_GEOFENCE_UNAVAILABLE parameter. + * + * Parameters: + * status - LOC_GPS_GEOFENCE_UNAVAILABLE or LOC_GPS_GEOFENCE_AVAILABLE. + * last_location - Last known location. + */ +typedef void (*loc_gps_geofence_status_callback) (int32_t status, LocGpsLocation* last_location); + +/** + * The callback associated with the add_geofence call. + * + * Parameter: + * geofence_id - Id of the geofence. + * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS + * LOC_GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES - geofence limit has been reached. + * LOC_GPS_GEOFENCE_ERROR_ID_EXISTS - geofence with id already exists + * LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION - the monitorTransition contains an + * invalid transition + * LOC_GPS_GEOFENCE_ERROR_GENERIC - for other errors. + */ +typedef void (*loc_gps_geofence_add_callback) (int32_t geofence_id, int32_t status); + +/** + * The callback associated with the remove_geofence call. + * + * Parameter: + * geofence_id - Id of the geofence. + * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS + * LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id + * LOC_GPS_GEOFENCE_ERROR_GENERIC for others. + */ +typedef void (*loc_gps_geofence_remove_callback) (int32_t geofence_id, int32_t status); + + +/** + * The callback associated with the pause_geofence call. + * + * Parameter: + * geofence_id - Id of the geofence. + * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS + * LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id + * LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION - + * when monitor_transitions is invalid + * LOC_GPS_GEOFENCE_ERROR_GENERIC for others. + */ +typedef void (*loc_gps_geofence_pause_callback) (int32_t geofence_id, int32_t status); + +/** + * The callback associated with the resume_geofence call. + * + * Parameter: + * geofence_id - Id of the geofence. + * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS + * LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id + * LOC_GPS_GEOFENCE_ERROR_GENERIC for others. + */ +typedef void (*loc_gps_geofence_resume_callback) (int32_t geofence_id, int32_t status); + +typedef struct { + loc_gps_geofence_transition_callback geofence_transition_callback; + loc_gps_geofence_status_callback geofence_status_callback; + loc_gps_geofence_add_callback geofence_add_callback; + loc_gps_geofence_remove_callback geofence_remove_callback; + loc_gps_geofence_pause_callback geofence_pause_callback; + loc_gps_geofence_resume_callback geofence_resume_callback; + loc_gps_create_thread create_thread_cb; +} LocGpsGeofenceCallbacks; + +/** Extended interface for GPS_Geofencing support */ +typedef struct { + /** set to sizeof(LocGpsGeofencingInterface) */ + size_t size; + + /** + * Opens the geofence interface and provides the callback routines + * to the implementation of this interface. + */ + void (*init)( LocGpsGeofenceCallbacks* callbacks ); + + /** + * Add a geofence area. This api currently supports circular geofences. + * Parameters: + * geofence_id - The id for the geofence. If a geofence with this id + * already exists, an error value (LOC_GPS_GEOFENCE_ERROR_ID_EXISTS) + * should be returned. + * latitude, longtitude, radius_meters - The lat, long and radius + * (in meters) for the geofence + * last_transition - The current state of the geofence. For example, if + * the system already knows that the user is inside the geofence, + * this will be set to LOC_GPS_GEOFENCE_ENTERED. In most cases, it + * will be LOC_GPS_GEOFENCE_UNCERTAIN. + * monitor_transition - Which transitions to monitor. Bitwise OR of + * LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED and + * LOC_GPS_GEOFENCE_UNCERTAIN. + * notification_responsiveness_ms - Defines the best-effort description + * of how soon should the callback be called when the transition + * associated with the Geofence is triggered. For instance, if set + * to 1000 millseconds with LOC_GPS_GEOFENCE_ENTERED, the callback + * should be called 1000 milliseconds within entering the geofence. + * This parameter is defined in milliseconds. + * NOTE: This is not to be confused with the rate that the GPS is + * polled at. It is acceptable to dynamically vary the rate of + * sampling the GPS for power-saving reasons; thus the rate of + * sampling may be faster or slower than this. + * unknown_timer_ms - The time limit after which the UNCERTAIN transition + * should be triggered. This parameter is defined in milliseconds. + * See above for a detailed explanation. + */ + void (*add_geofence_area) (int32_t geofence_id, double latitude, double longitude, + double radius_meters, int last_transition, int monitor_transitions, + int notification_responsiveness_ms, int unknown_timer_ms); + + /** + * Pause monitoring a particular geofence. + * Parameters: + * geofence_id - The id for the geofence. + */ + void (*pause_geofence) (int32_t geofence_id); + + /** + * Resume monitoring a particular geofence. + * Parameters: + * geofence_id - The id for the geofence. + * monitor_transitions - Which transitions to monitor. Bitwise OR of + * LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED and + * LOC_GPS_GEOFENCE_UNCERTAIN. + * This supersedes the value associated provided in the + * add_geofence_area call. + */ + void (*resume_geofence) (int32_t geofence_id, int monitor_transitions); + + /** + * Remove a geofence area. After the function returns, no notifications + * should be sent. + * Parameter: + * geofence_id - The id for the geofence. + */ + void (*remove_geofence_area) (int32_t geofence_id); +} LocGpsGeofencingInterface; + +/** + * Legacy struct to represent an estimate of the GPS clock time. + * Deprecated, to be removed in the next Android release. + * Use LocGnssClock instead. + */ +typedef struct { + /** set to sizeof(LocGpsClock) */ + size_t size; + LocGpsClockFlags flags; + int16_t leap_second; + LocGpsClockType type; + int64_t time_ns; + double time_uncertainty_ns; + int64_t full_bias_ns; + double bias_ns; + double bias_uncertainty_ns; + double drift_nsps; + double drift_uncertainty_nsps; +} LocGpsClock; + +/** + * Represents an estimate of the GPS clock time. + */ +typedef struct { + /** set to sizeof(LocGnssClock) */ + size_t size; + + /** + * A set of flags indicating the validity of the fields in this data + * structure. + */ + LocGnssClockFlags flags; + + /** + * Leap second data. + * The sign of the value is defined by the following equation: + * utc_time_ns = time_ns - (full_bias_ns + bias_ns) - leap_second * + * 1,000,000,000 + * + * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_LEAP_SECOND. + */ + int16_t leap_second; + + /** + * The GNSS receiver internal clock value. This is the local hardware clock + * value. + * + * For local hardware clock, this value is expected to be monotonically + * increasing while the hardware clock remains power on. (For the case of a + * HW clock that is not continuously on, see the + * hw_clock_discontinuity_count field). The receiver's estimate of GPS time + * can be derived by substracting the sum of full_bias_ns and bias_ns (when + * available) from this value. + * + * This GPS time is expected to be the best estimate of current GPS time + * that GNSS receiver can achieve. + * + * Sub-nanosecond accuracy can be provided by means of the 'bias_ns' field. + * The value contains the 'time uncertainty' in it. + * + * This field is mandatory. + */ + int64_t time_ns; + + /** + * 1-Sigma uncertainty associated with the clock's time in nanoseconds. + * The uncertainty is represented as an absolute (single sided) value. + * + * If the data is available, 'flags' must contain + * LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY. This value is effectively zero (it is + * the reference local clock, by which all other times and time + * uncertainties are measured.) (And thus this field can be not provided, + * per LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY flag, or provided & set to 0.) + */ + double time_uncertainty_ns; + + /** + * The difference between hardware clock ('time' field) inside GPS receiver + * and the true GPS time since 0000Z, January 6, 1980, in nanoseconds. + * + * The sign of the value is defined by the following equation: + * local estimate of GPS time = time_ns - (full_bias_ns + bias_ns) + * + * This value is mandatory if the receiver has estimated GPS time. If the + * computed time is for a non-GPS constellation, the time offset of that + * constellation to GPS has to be applied to fill this value. The error + * estimate for the sum of this and the bias_ns is the bias_uncertainty_ns, + * and the caller is responsible for using this uncertainty (it can be very + * large before the GPS time has been solved for.) If the data is available + * 'flags' must contain LOC_GNSS_CLOCK_HAS_FULL_BIAS. + */ + int64_t full_bias_ns; + + /** + * Sub-nanosecond bias. + * The error estimate for the sum of this and the full_bias_ns is the + * bias_uncertainty_ns + * + * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_BIAS. If GPS + * has computed a position fix. This value is mandatory if the receiver has + * estimated GPS time. + */ + double bias_ns; + + /** + * 1-Sigma uncertainty associated with the local estimate of GPS time (clock + * bias) in nanoseconds. The uncertainty is represented as an absolute + * (single sided) value. + * + * If the data is available 'flags' must contain + * LOC_GNSS_CLOCK_HAS_BIAS_UNCERTAINTY. This value is mandatory if the receiver + * has estimated GPS time. + */ + double bias_uncertainty_ns; + + /** + * The clock's drift in nanoseconds (per second). + * + * A positive value means that the frequency is higher than the nominal + * frequency, and that the (full_bias_ns + bias_ns) is growing more positive + * over time. + * + * The value contains the 'drift uncertainty' in it. + * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_DRIFT. + * + * This value is mandatory if the receiver has estimated GNSS time + */ + double drift_nsps; + + /** + * 1-Sigma uncertainty associated with the clock's drift in nanoseconds (per second). + * The uncertainty is represented as an absolute (single sided) value. + * + * If the data is available 'flags' must contain + * LOC_GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY. If GPS has computed a position fix this + * field is mandatory and must be populated. + */ + double drift_uncertainty_nsps; + + /** + * When there are any discontinuities in the HW clock, this field is + * mandatory. + * + * A "discontinuity" is meant to cover the case of a switch from one source + * of clock to another. A single free-running crystal oscillator (XO) + * should generally not have any discontinuities, and this can be set and + * left at 0. + * + * If, however, the time_ns value (HW clock) is derived from a composite of + * sources, that is not as smooth as a typical XO, or is otherwise stopped & + * restarted, then this value shall be incremented each time a discontinuity + * occurs. (E.g. this value may start at zero at device boot-up and + * increment each time there is a change in clock continuity. In the + * unlikely event that this value reaches full scale, rollover (not + * clamping) is required, such that this value continues to change, during + * subsequent discontinuity events.) + * + * While this number stays the same, between LocGnssClock reports, it can be + * safely assumed that the time_ns value has been running continuously, e.g. + * derived from a single, high quality clock (XO like, or better, that's + * typically used during continuous GNSS signal sampling.) + * + * It is expected, esp. during periods where there are few GNSS signals + * available, that the HW clock be discontinuity-free as long as possible, + * as this avoids the need to use (waste) a GNSS measurement to fully + * re-solve for the GPS clock bias and drift, when using the accompanying + * measurements, from consecutive LocGnssData reports. + */ + uint32_t hw_clock_discontinuity_count; + +} LocGnssClock; + +/** + * Legacy struct to represent a GPS Measurement, it contains raw and computed + * information. + * Deprecated, to be removed in the next Android release. + * Use LocGnssMeasurement instead. + */ +typedef struct { + /** set to sizeof(LocGpsMeasurement) */ + size_t size; + LocGpsMeasurementFlags flags; + int8_t prn; + double time_offset_ns; + LocGpsMeasurementState state; + int64_t received_gps_tow_ns; + int64_t received_gps_tow_uncertainty_ns; + double c_n0_dbhz; + double pseudorange_rate_mps; + double pseudorange_rate_uncertainty_mps; + LocGpsAccumulatedDeltaRangeState accumulated_delta_range_state; + double accumulated_delta_range_m; + double accumulated_delta_range_uncertainty_m; + double pseudorange_m; + double pseudorange_uncertainty_m; + double code_phase_chips; + double code_phase_uncertainty_chips; + float carrier_frequency_hz; + int64_t carrier_cycles; + double carrier_phase; + double carrier_phase_uncertainty; + LocGpsLossOfLock loss_of_lock; + int32_t bit_number; + int16_t time_from_last_bit_ms; + double doppler_shift_hz; + double doppler_shift_uncertainty_hz; + LocGpsMultipathIndicator multipath_indicator; + double snr_db; + double elevation_deg; + double elevation_uncertainty_deg; + double azimuth_deg; + double azimuth_uncertainty_deg; + bool used_in_fix; +} LocGpsMeasurement; + +/** + * Represents a GNSS Measurement, it contains raw and computed information. + * + * Independence - All signal measurement information (e.g. sv_time, + * pseudorange_rate, multipath_indicator) reported in this struct should be + * based on GNSS signal measurements only. You may not synthesize measurements + * by calculating or reporting expected measurements based on known or estimated + * position, velocity, or time. + */ +typedef struct { + /** set to sizeof(LocGnssMeasurement) */ + size_t size; + + /** A set of flags indicating the validity of the fields in this data structure. */ + LocGnssMeasurementFlags flags; + + /** + * Satellite vehicle ID number, as defined in LocGnssSvInfo::svid + * This is a mandatory value. + */ + int16_t svid; + + /** + * Defines the constellation of the given SV. Value should be one of those + * LOC_GNSS_CONSTELLATION_* constants + */ + LocGnssConstellationType constellation; + + /** + * Time offset at which the measurement was taken in nanoseconds. + * The reference receiver's time is specified by LocGpsData::clock::time_ns and should be + * interpreted in the same way as indicated by LocGpsClock::type. + * + * The sign of time_offset_ns is given by the following equation: + * measurement time = LocGpsClock::time_ns + time_offset_ns + * + * It provides an individual time-stamp for the measurement, and allows sub-nanosecond accuracy. + * This is a mandatory value. + */ + double time_offset_ns; + + /** + * Per satellite sync state. It represents the current sync state for the associated satellite. + * Based on the sync state, the 'received GPS tow' field should be interpreted accordingly. + * + * This is a mandatory value. + */ + LocGnssMeasurementState state; + + /** + * The received GNSS Time-of-Week at the measurement time, in nanoseconds. + * Ensure that this field is independent (see comment at top of + * LocGnssMeasurement struct.) + * + * For GPS & QZSS, this is: + * Received GPS Time-of-Week at the measurement time, in nanoseconds. + * The value is relative to the beginning of the current GPS week. + * + * Given the highest sync state that can be achieved, per each satellite, valid range + * for this field can be: + * Searching : [ 0 ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN + * C/A code lock : [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set + * Bit sync : [ 0 20ms ] : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set + * Subframe sync : [ 0 6s ] : LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC is set + * TOW decoded : [ 0 1week ] : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set + * + * Note well: if there is any ambiguity in integer millisecond, + * LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS should be set accordingly, in the 'state' field. + * + * This value must be populated if 'state' != LOC_GNSS_MEASUREMENT_STATE_UNKNOWN. + * + * For Glonass, this is: + * Received Glonass time of day, at the measurement time in nanoseconds. + * + * Given the highest sync state that can be achieved, per each satellite, valid range for + * this field can be: + * Searching : [ 0 ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN + * C/A code lock : [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set + * Symbol sync : [ 0 10ms ] : LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC is set + * Bit sync : [ 0 20ms ] : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set + * String sync : [ 0 2s ] : LOC_GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC is set + * Time of day : [ 0 1day ] : LOC_GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED is set + * + * For Beidou, this is: + * Received Beidou time of week, at the measurement time in nanoseconds. + * + * Given the highest sync state that can be achieved, per each satellite, valid range for + * this field can be: + * Searching : [ 0 ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN + * C/A code lock: [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set + * Bit sync (D2): [ 0 2ms ] : LOC_GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC is set + * Bit sync (D1): [ 0 20ms ] : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set + * Subframe (D2): [ 0 0.6s ] : LOC_GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC is set + * Subframe (D1): [ 0 6s ] : LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC is set + * Time of week : [ 0 1week ] : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set + * + * For Galileo, this is: + * Received Galileo time of week, at the measurement time in nanoseconds. + * + * E1BC code lock : [ 0 4ms ] : LOC_GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK is set + * E1C 2nd code lock: [ 0 100ms ] : + * LOC_GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK is set + * + * E1B page : [ 0 2s ] : LOC_GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC is set + * Time of week: [ 0 1week ] : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set + * + * For SBAS, this is: + * Received SBAS time, at the measurement time in nanoseconds. + * + * Given the highest sync state that can be achieved, per each satellite, + * valid range for this field can be: + * Searching : [ 0 ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN + * C/A code lock: [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set + * Symbol sync : [ 0 2ms ] : LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC is set + * Message : [ 0 1s ] : LOC_GNSS_MEASUREMENT_STATE_SBAS_SYNC is set + */ + int64_t received_sv_time_in_ns; + + /** + * 1-Sigma uncertainty of the Received GPS Time-of-Week in nanoseconds. + * + * This value must be populated if 'state' != LOC_GPS_MEASUREMENT_STATE_UNKNOWN. + */ + int64_t received_sv_time_uncertainty_in_ns; + + /** + * Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. + * It contains the measured C/N0 value for the signal at the antenna port. + * + * This is a mandatory value. + */ + double c_n0_dbhz; + + /** + * Pseudorange rate at the timestamp in m/s. The correction of a given + * Pseudorange Rate value includes corrections for receiver and satellite + * clock frequency errors. Ensure that this field is independent (see + * comment at top of LocGnssMeasurement struct.) + * + * It is mandatory to provide the 'uncorrected' 'pseudorange rate', and provide LocGpsClock's + * 'drift' field as well (When providing the uncorrected pseudorange rate, do not apply the + * corrections described above.) + * + * The value includes the 'pseudorange rate uncertainty' in it. + * A positive 'uncorrected' value indicates that the SV is moving away from the receiver. + * + * The sign of the 'uncorrected' 'pseudorange rate' and its relation to the sign of 'doppler + * shift' is given by the equation: + * pseudorange rate = -k * doppler shift (where k is a constant) + * + * This should be the most accurate pseudorange rate available, based on + * fresh signal measurements from this channel. + * + * It is mandatory that this value be provided at typical carrier phase PRR + * quality (few cm/sec per second of uncertainty, or better) - when signals + * are sufficiently strong & stable, e.g. signals from a GPS simulator at >= + * 35 dB-Hz. + */ + double pseudorange_rate_mps; + + /** + * 1-Sigma uncertainty of the pseudorange_rate_mps. + * The uncertainty is represented as an absolute (single sided) value. + * + * This is a mandatory value. + */ + double pseudorange_rate_uncertainty_mps; + + /** + * Accumulated delta range's state. It indicates whether ADR is reset or there is a cycle slip + * (indicating loss of lock). + * + * This is a mandatory value. + */ + LocGnssAccumulatedDeltaRangeState accumulated_delta_range_state; + + /** + * Accumulated delta range since the last channel reset in meters. + * A positive value indicates that the SV is moving away from the receiver. + * + * The sign of the 'accumulated delta range' and its relation to the sign of 'carrier phase' + * is given by the equation: + * accumulated delta range = -k * carrier phase (where k is a constant) + * + * This value must be populated if 'accumulated delta range state' != LOC_GPS_ADR_STATE_UNKNOWN. + * However, it is expected that the data is only accurate when: + * 'accumulated delta range state' == LOC_GPS_ADR_STATE_VALID. + */ + double accumulated_delta_range_m; + + /** + * 1-Sigma uncertainty of the accumulated delta range in meters. + * This value must be populated if 'accumulated delta range state' != LOC_GPS_ADR_STATE_UNKNOWN. + */ + double accumulated_delta_range_uncertainty_m; + + /** + * Carrier frequency at which codes and messages are modulated, it can be L1 or L2. + * If the field is not set, the carrier frequency is assumed to be L1. + * + * If the data is available, 'flags' must contain + * LOC_GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY. + */ + float carrier_frequency_hz; + + /** + * The number of full carrier cycles between the satellite and the receiver. + * The reference frequency is given by the field 'carrier_frequency_hz'. + * Indications of possible cycle slips and resets in the accumulation of + * this value can be inferred from the accumulated_delta_range_state flags. + * + * If the data is available, 'flags' must contain + * LOC_GNSS_MEASUREMENT_HAS_CARRIER_CYCLES. + */ + int64_t carrier_cycles; + + /** + * The RF phase detected by the receiver, in the range [0.0, 1.0]. + * This is usually the fractional part of the complete carrier phase measurement. + * + * The reference frequency is given by the field 'carrier_frequency_hz'. + * The value contains the 'carrier-phase uncertainty' in it. + * + * If the data is available, 'flags' must contain + * LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE. + */ + double carrier_phase; + + /** + * 1-Sigma uncertainty of the carrier-phase. + * If the data is available, 'flags' must contain + * LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY. + */ + double carrier_phase_uncertainty; + + /** + * An enumeration that indicates the 'multipath' state of the event. + * + * The multipath Indicator is intended to report the presence of overlapping + * signals that manifest as distorted correlation peaks. + * + * - if there is a distorted correlation peak shape, report that multipath + * is LOC_GNSS_MULTIPATH_INDICATOR_PRESENT. + * - if there is not a distorted correlation peak shape, report + * LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT + * - if signals are too weak to discern this information, report + * LOC_GNSS_MULTIPATH_INDICATOR_UNKNOWN + * + * Example: when doing the standardized overlapping Multipath Performance + * test (3GPP TS 34.171) the Multipath indicator should report + * LOC_GNSS_MULTIPATH_INDICATOR_PRESENT for those signals that are tracked, and + * contain multipath, and LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT for those + * signals that are tracked and do not contain multipath. + */ + LocGnssMultipathIndicator multipath_indicator; + + /** + * Signal-to-noise ratio at correlator output in dB. + * If the data is available, 'flags' must contain LOC_GNSS_MEASUREMENT_HAS_SNR. + * This is the power ratio of the "correlation peak height above the + * observed noise floor" to "the noise RMS". + */ + double snr_db; +} LocGnssMeasurement; + +/** + * Legacy struct to represents a reading of GPS measurements. + * Deprecated, to be removed in the next Android release. + * Use LocGnssData instead. + */ +typedef struct { + /** set to sizeof(LocGpsData) */ + size_t size; + size_t measurement_count; + LocGpsMeasurement measurements[LOC_GPS_MAX_MEASUREMENT]; + + /** The GPS clock time reading. */ + LocGpsClock clock; +} LocGpsData; + +/** + * Represents a reading of GNSS measurements. For devices where LocGnssSystemInfo's + * year_of_hw is set to 2016+, it is mandatory that these be provided, on + * request, when the GNSS receiver is searching/tracking signals. + * + * - Reporting of GPS constellation measurements is mandatory. + * - Reporting of all tracked constellations are encouraged. + */ +typedef struct { + /** set to sizeof(LocGnssData) */ + size_t size; + + /** Number of measurements. */ + size_t measurement_count; + + /** The array of measurements. */ + LocGnssMeasurement measurements[LOC_GNSS_MAX_MEASUREMENT]; + + /** The GPS clock time reading. */ + LocGnssClock clock; +} LocGnssData; + +/** + * The legacy callback for to report measurements from the HAL. + * + * This callback is deprecated, and will be removed in the next release. Use + * loc_gnss_measurement_callback() instead. + * + * Parameters: + * data - A data structure containing the measurements. + */ +typedef void (*loc_gps_measurement_callback) (LocGpsData* data); + +/** + * The callback for to report measurements from the HAL. + * + * Parameters: + * data - A data structure containing the measurements. + */ +typedef void (*loc_gnss_measurement_callback) (LocGnssData* data); + +typedef struct { + /** set to sizeof(LocGpsMeasurementCallbacks) */ + size_t size; + loc_gps_measurement_callback measurement_callback; + loc_gnss_measurement_callback loc_gnss_measurement_callback; +} LocGpsMeasurementCallbacks; + +#define LOC_GPS_MEASUREMENT_OPERATION_SUCCESS 0 +#define LOC_GPS_MEASUREMENT_ERROR_ALREADY_INIT -100 +#define LOC_GPS_MEASUREMENT_ERROR_GENERIC -101 + +/** + * Extended interface for GPS Measurements support. + */ +typedef struct { + /** Set to sizeof(LocGpsMeasurementInterface) */ + size_t size; + + /** + * Initializes the interface and registers the callback routines with the HAL. + * After a successful call to 'init' the HAL must begin to provide updates at its own phase. + * + * Status: + * LOC_GPS_MEASUREMENT_OPERATION_SUCCESS + * LOC_GPS_MEASUREMENT_ERROR_ALREADY_INIT - if a callback has already been registered without a + * corresponding call to 'close' + * LOC_GPS_MEASUREMENT_ERROR_GENERIC - if any other error occurred, it is expected that the HAL + * will not generate any updates upon returning this error code. + */ + int (*init) (LocGpsMeasurementCallbacks* callbacks); + + /** + * Stops updates from the HAL, and unregisters the callback routines. + * After a call to stop, the previously registered callbacks must be considered invalid by the + * HAL. + * If stop is invoked without a previous 'init', this function should perform no work. + */ + void (*close) (); + +} LocGpsMeasurementInterface; + +#if 0 +/** + * Legacy struct to represents a GPS navigation message (or a fragment of it). + * Deprecated, to be removed in the next Android release. + * Use GnssNavigationMessage instead. + */ +typedef struct { + /** set to sizeof(GpsNavigationMessage) */ + size_t size; + int8_t prn; + GpsNavigationMessageType type; + NavigationMessageStatus status; + int16_t message_id; + int16_t submessage_id; + size_t data_length; + uint8_t* data; +} GpsNavigationMessage; + +/** Represents a GPS navigation message (or a fragment of it). */ +typedef struct { + /** set to sizeof(GnssNavigationMessage) */ + size_t size; + + /** + * Satellite vehicle ID number, as defined in LocGnssSvInfo::svid + * This is a mandatory value. + */ + int16_t svid; + + /** + * The type of message contained in the structure. + * This is a mandatory value. + */ + GnssNavigationMessageType type; + + /** + * The status of the received navigation message. + * No need to send any navigation message that contains words with parity error and cannot be + * corrected. + */ + NavigationMessageStatus status; + + /** + * Message identifier. It provides an index so the complete Navigation + * Message can be assembled. + * + * - For GPS L1 C/A subframe 4 and 5, this value corresponds to the 'frame + * id' of the navigation message, in the range of 1-25 (Subframe 1, 2, 3 + * does not contain a 'frame id' and this value can be set to -1.) + * + * - For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5. + * + * - For BeiDou D1, this refers to the frame number in the range of 1-24 + * + * - For Beidou D2, this refers to the frame number, in the range of 1-120 + * + * - For Galileo F/NAV nominal frame structure, this refers to the subframe + * number, in the range of 1-12 + * + * - For Galileo I/NAV nominal frame structure, this refers to the subframe + * number in the range of 1-24 + */ + int16_t message_id; + + /** + * Sub-message identifier. If required by the message 'type', this value + * contains a sub-index within the current message (or frame) that is being + * transmitted. + * + * - For GPS L1 C/A, BeiDou D1 & BeiDou D2, the submessage id corresponds to + * the subframe number of the navigation message, in the range of 1-5. + * + * - For Glonass L1 C/A, this refers to the String number, in the range from + * 1-15 + * + * - For Galileo F/NAV, this refers to the page type in the range 1-6 + * + * - For Galileo I/NAV, this refers to the word type in the range 1-10+ + */ + int16_t submessage_id; + + /** + * The length of the data (in bytes) contained in the current message. + * If this value is different from zero, 'data' must point to an array of the same size. + * e.g. for L1 C/A the size of the sub-frame will be 40 bytes (10 words, 30 bits/word). + * + * This is a mandatory value. + */ + size_t data_length; + + /** + * The data of the reported GPS message. The bytes (or words) specified + * using big endian format (MSB first). + * + * - For GPS L1 C/A, Beidou D1 & Beidou D2, each subframe contains 10 30-bit + * words. Each word (30 bits) should be fit into the last 30 bits in a + * 4-byte word (skip B31 and B32), with MSB first, for a total of 40 + * bytes, covering a time period of 6, 6, and 0.6 seconds, respectively. + * + * - For Glonass L1 C/A, each string contains 85 data bits, including the + * checksum. These bits should be fit into 11 bytes, with MSB first (skip + * B86-B88), covering a time period of 2 seconds. + * + * - For Galileo F/NAV, each word consists of 238-bit (sync & tail symbols + * excluded). Each word should be fit into 30-bytes, with MSB first (skip + * B239, B240), covering a time period of 10 seconds. + * + * - For Galileo I/NAV, each page contains 2 page parts, even and odd, with + * a total of 2x114 = 228 bits, (sync & tail excluded) that should be fit + * into 29 bytes, with MSB first (skip B229-B232). + */ + uint8_t* data; + +} GnssNavigationMessage; + +/** + * The legacy callback to report an available fragment of a GPS navigation + * messages from the HAL. + * + * This callback is deprecated, and will be removed in the next release. Use + * gnss_navigation_message_callback() instead. + * + * Parameters: + * message - The GPS navigation submessage/subframe representation. + */ +typedef void (*gps_navigation_message_callback) (GpsNavigationMessage* message); + +/** + * The callback to report an available fragment of a GPS navigation messages from the HAL. + * + * Parameters: + * message - The GPS navigation submessage/subframe representation. + */ +typedef void (*gnss_navigation_message_callback) (GnssNavigationMessage* message); + +typedef struct { + /** set to sizeof(GpsNavigationMessageCallbacks) */ + size_t size; + gps_navigation_message_callback navigation_message_callback; + gnss_navigation_message_callback gnss_navigation_message_callback; +} GpsNavigationMessageCallbacks; + +#define GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS 0 +#define GPS_NAVIGATION_MESSAGE_ERROR_ALREADY_INIT -100 +#define GPS_NAVIGATION_MESSAGE_ERROR_GENERIC -101 + +/** + * Extended interface for GPS navigation message reporting support. + */ +typedef struct { + /** Set to sizeof(GpsNavigationMessageInterface) */ + size_t size; + + /** + * Initializes the interface and registers the callback routines with the HAL. + * After a successful call to 'init' the HAL must begin to provide updates as they become + * available. + * + * Status: + * GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS + * GPS_NAVIGATION_MESSAGE_ERROR_ALREADY_INIT - if a callback has already been registered + * without a corresponding call to 'close'. + * GPS_NAVIGATION_MESSAGE_ERROR_GENERIC - if any other error occurred, it is expected that + * the HAL will not generate any updates upon returning this error code. + */ + int (*init) (GpsNavigationMessageCallbacks* callbacks); + + /** + * Stops updates from the HAL, and unregisters the callback routines. + * After a call to stop, the previously registered callbacks must be considered invalid by the + * HAL. + * If stop is invoked without a previous 'init', this function should perform no work. + */ + void (*close) (); + +} GpsNavigationMessageInterface; +#endif + +/** + * Interface for passing GNSS configuration contents from platform to HAL. + */ +typedef struct { + /** Set to sizeof(LocGnssConfigurationInterface) */ + size_t size; + + /** + * Deliver GNSS configuration contents to HAL. + * Parameters: + * config_data - a pointer to a char array which holds what usually is expected from + file(/vendor/etc/gps.conf), i.e., a sequence of UTF8 strings separated by '\n'. + * length - total number of UTF8 characters in configuraiton data. + * + * IMPORTANT: + * GPS HAL should expect this function can be called multiple times. And it may be + * called even when GpsLocationProvider is already constructed and enabled. GPS HAL + * should maintain the existing requests for various callback regardless the change + * in configuration data. + */ + void (*configuration_update) (const char* config_data, int32_t length); +} LocGnssConfigurationInterface; + +__END_DECLS + +#endif /* LOC_GPS_H */ + diff --git a/gps/utils/loc_log.cpp b/gps/utils/loc_log.cpp new file mode 100644 index 0000000..ab28998 --- /dev/null +++ b/gps/utils/loc_log.cpp @@ -0,0 +1,238 @@ +/* Copyright (c) 2011-2012, 2015, 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. + * + */ + +#define LOG_NDEBUG 0 + +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include "log_util.h" +#include "loc_log.h" +#include "msg_q.h" +#include <loc_pla.h> + +#define BUFFER_SIZE 120 + +// Logging Improvements +const char *loc_logger_boolStr[]={"False","True"}; +const char VOID_RET[] = "None"; +const char FROM_AFW[] = "===>"; +const char TO_MODEM[] = "--->"; +const char FROM_MODEM[] = "<---"; +const char TO_AFW[] = "<==="; +const char EXIT_TAG[] = "Exiting"; +const char ENTRY_TAG[] = "Entering"; +const char EXIT_ERROR_TAG[] = "Exiting with error"; + +/* Logging Mechanism */ +loc_logger_s_type loc_logger; + +/* Get names from value */ +const char* loc_get_name_from_mask(const loc_name_val_s_type table[], size_t table_size, long mask) +{ + size_t i; + for (i = 0; i < table_size; i++) + { + if (table[i].val & (long) mask) + { + return table[i].name; + } + } + return UNKNOWN_STR; +} + +/* Get names from value */ +const char* loc_get_name_from_val(const loc_name_val_s_type table[], size_t table_size, long value) +{ + size_t i; + for (i = 0; i < table_size; i++) + { + if (table[i].val == (long) value) + { + return table[i].name; + } + } + return UNKNOWN_STR; +} + +static const loc_name_val_s_type loc_msg_q_status[] = +{ + NAME_VAL( eMSG_Q_SUCCESS ), + NAME_VAL( eMSG_Q_FAILURE_GENERAL ), + NAME_VAL( eMSG_Q_INVALID_PARAMETER ), + NAME_VAL( eMSG_Q_INVALID_HANDLE ), + NAME_VAL( eMSG_Q_UNAVAILABLE_RESOURCE ), + NAME_VAL( eMSG_Q_INSUFFICIENT_BUFFER ) +}; +static const size_t loc_msg_q_status_num = LOC_TABLE_SIZE(loc_msg_q_status); + +/* Find msg_q status name */ +const char* loc_get_msg_q_status(int status) +{ + return loc_get_name_from_val(loc_msg_q_status, loc_msg_q_status_num, (long) status); +} + +const char* log_succ_fail_string(int is_succ) +{ + return is_succ? "successful" : "failed"; +} + +//Target names +static const loc_name_val_s_type target_name[] = +{ + NAME_VAL(GNSS_NONE), + NAME_VAL(GNSS_MSM), + NAME_VAL(GNSS_GSS), + NAME_VAL(GNSS_MDM), + NAME_VAL(GNSS_AUTO), + NAME_VAL(GNSS_UNKNOWN) +}; + +static const size_t target_name_num = LOC_TABLE_SIZE(target_name); + +/*=========================================================================== + +FUNCTION loc_get_target_name + +DESCRIPTION + Returns pointer to a string that contains name of the target + + XX:XX:XX.000\0 + +RETURN VALUE + The target name string + +===========================================================================*/ +const char *loc_get_target_name(unsigned int target) +{ + int index = 0; + static char ret[BUFFER_SIZE]; + + index = getTargetGnssType(target); + if( index < 0 || (unsigned)index >= target_name_num ) + index = target_name_num - 1; + + if( (target & HAS_SSC) == HAS_SSC ) { + snprintf(ret, sizeof(ret), " %s with SSC", + loc_get_name_from_val(target_name, target_name_num, (long)index) ); + } + else { + snprintf(ret, sizeof(ret), " %s without SSC", + loc_get_name_from_val(target_name, target_name_num, (long)index) ); + } + return ret; +} + + +/*=========================================================================== + +FUNCTION loc_get_time + +DESCRIPTION + Logs a callback event header. + The pointer time_string should point to a buffer of at least 13 bytes: + + XX:XX:XX.000\0 + +RETURN VALUE + The time string + +===========================================================================*/ +char *loc_get_time(char *time_string, size_t buf_size) +{ + struct timeval now; /* sec and usec */ + struct tm now_tm; /* broken-down time */ + char hms_string[80]; /* HH:MM:SS */ + + gettimeofday(&now, NULL); + localtime_r(&now.tv_sec, &now_tm); + + strftime(hms_string, sizeof hms_string, "%H:%M:%S", &now_tm); + snprintf(time_string, buf_size, "%s.%03d", hms_string, (int) (now.tv_usec / 1000)); + + return time_string; +} + + +/*=========================================================================== +FUNCTION loc_logger_init + +DESCRIPTION + Initializes the state of DEBUG_LEVEL and TIMESTAMP + +DEPENDENCIES + N/A + +RETURN VALUE + None + +SIDE EFFECTS + N/A +===========================================================================*/ +void loc_logger_init(unsigned long debug, unsigned long timestamp) +{ + loc_logger.DEBUG_LEVEL = debug; +#ifdef TARGET_BUILD_VARIANT_USER + // force user builds to 2 or less + if (loc_logger.DEBUG_LEVEL > 2) { + loc_logger.DEBUG_LEVEL = 2; + } +#endif + loc_logger.TIMESTAMP = timestamp; +} + + +/*=========================================================================== +FUNCTION get_timestamp + +DESCRIPTION + Generates a timestamp using the current system time + +DEPENDENCIES + N/A + +RETURN VALUE + Char pointer to the parameter str + +SIDE EFFECTS + N/A +===========================================================================*/ +char * get_timestamp(char *str, unsigned long buf_size) +{ + struct timeval tv; + struct timezone tz; + int hh, mm, ss; + gettimeofday(&tv, &tz); + hh = tv.tv_sec/3600%24; + mm = (tv.tv_sec%3600)/60; + ss = tv.tv_sec%60; + snprintf(str, buf_size, "%02d:%02d:%02d.%06ld", hh, mm, ss, tv.tv_usec); + return str; +} + diff --git a/gps/utils/loc_log.h b/gps/utils/loc_log.h new file mode 100644 index 0000000..be492b1 --- /dev/null +++ b/gps/utils/loc_log.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2011-2012, 2015 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. + * + */ + +#ifndef LOC_LOG_H +#define LOC_LOG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <ctype.h> +#include <stdlib.h> +#include "loc_target.h" + +typedef struct +{ + const char *name; + long val; +} loc_name_val_s_type; + +#define NAME_VAL(x) {"" #x "", x } + +#define UNKNOWN_STR "UNKNOWN" + +#define CHECK_MASK(type, value, mask_var, mask) \ + (((mask_var) & (mask)) ? (type) (value) : (type) (-1)) + +#define LOC_TABLE_SIZE(table) (sizeof(table)/sizeof((table)[0])) + +/* Get names from value */ +const char* loc_get_name_from_mask(const loc_name_val_s_type table[], size_t table_size, long mask); +const char* loc_get_name_from_val(const loc_name_val_s_type table[], size_t table_size, long value); +const char* loc_get_msg_q_status(int status); +const char* loc_get_target_name(unsigned int target); + +extern const char* log_succ_fail_string(int is_succ); + +extern char *loc_get_time(char *time_string, size_t buf_size); + +#ifdef __cplusplus +} +#endif + +#endif /* LOC_LOG_H */ diff --git a/gps/utils/loc_misc_utils.cpp b/gps/utils/loc_misc_utils.cpp new file mode 100644 index 0000000..70fdbc3 --- /dev/null +++ b/gps/utils/loc_misc_utils.cpp @@ -0,0 +1,145 @@ +/* Copyright (c) 2014, 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. + * + */ +#define LOG_NDEBUG 0 +#define LOG_TAG "LocSvc_misc_utils" +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include <log_util.h> +#include <loc_misc_utils.h> +#include <ctype.h> + + +int loc_util_split_string(char *raw_string, char **split_strings_ptr, + int max_num_substrings, char delimiter) +{ + int raw_string_index=0; + int num_split_strings=0; + unsigned char end_string=0; + int raw_string_length=0; + + if(!raw_string || !split_strings_ptr) { + LOC_LOGE("%s:%d]: NULL parameters", __func__, __LINE__); + num_split_strings = -1; + goto err; + } + LOC_LOGD("%s:%d]: raw string: %s\n", __func__, __LINE__, raw_string); + raw_string_length = strlen(raw_string) + 1; + split_strings_ptr[num_split_strings] = &raw_string[raw_string_index]; + for(raw_string_index=0; raw_string_index < raw_string_length; raw_string_index++) { + if(raw_string[raw_string_index] == '\0') + end_string=1; + if((raw_string[raw_string_index] == delimiter) || end_string) { + raw_string[raw_string_index] = '\0'; + LOC_LOGD("%s:%d]: split string: %s\n", + __func__, __LINE__, split_strings_ptr[num_split_strings]); + num_split_strings++; + if(((raw_string_index + 1) < raw_string_length) && + (num_split_strings < max_num_substrings)) { + split_strings_ptr[num_split_strings] = &raw_string[raw_string_index+1]; + } + else { + break; + } + } + if(end_string) + break; + } +err: + LOC_LOGD("%s:%d]: num_split_strings: %d\n", __func__, __LINE__, num_split_strings); + return num_split_strings; +} + +void loc_util_trim_space(char *org_string) +{ + char *scan_ptr, *write_ptr; + char *first_nonspace = NULL, *last_nonspace = NULL; + + if(org_string == NULL) { + LOC_LOGE("%s:%d]: NULL parameter", __func__, __LINE__); + goto err; + } + + scan_ptr = write_ptr = org_string; + + while (*scan_ptr) { + //Find the first non-space character + if ( !isspace(*scan_ptr) && first_nonspace == NULL) { + first_nonspace = scan_ptr; + } + //Once the first non-space character is found in the + //above check, keep shifting the characters to the left + //to replace the spaces + if (first_nonspace != NULL) { + *(write_ptr++) = *scan_ptr; + //Keep track of which was the last non-space character + //encountered + //last_nonspace will not be updated in the case where + //the string ends with spaces + if ( !isspace(*scan_ptr)) { + last_nonspace = write_ptr; + } + } + scan_ptr++; + } + //Add NULL terminator after the last non-space character + if (last_nonspace) { *last_nonspace = '\0'; } +err: + return; +} + +inline void logDlError(const char* failedCall) { + const char * err = dlerror(); + LOC_LOGe("%s error: %s", failedCall, (nullptr == err) ? "unknown" : err); +} + +void* dlGetSymFromLib(void*& libHandle, const char* libName, const char* symName) +{ + void* sym = nullptr; + if ((nullptr != libHandle || nullptr != libName) && nullptr != symName) { + if (nullptr == libHandle) { + libHandle = dlopen(libName, RTLD_NOW); + if (nullptr == libHandle) { + logDlError("dlopen"); + } + } + // NOT else, as libHandle gets assigned 5 line above + if (nullptr != libHandle) { + sym = dlsym(libHandle, symName); + if (nullptr == sym) { + logDlError("dlsym"); + } + } + } else { + LOC_LOGe("Either libHandle (%p) or libName (%p) must not be null; " + "symName (%p) can not be null.", libHandle, libName, symName); + } + + return sym; +} diff --git a/gps/utils/loc_misc_utils.h b/gps/utils/loc_misc_utils.h new file mode 100644 index 0000000..fad1b6d --- /dev/null +++ b/gps/utils/loc_misc_utils.h @@ -0,0 +1,127 @@ +/* Copyright (c) 2014, 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. + * + */ +#ifndef _LOC_MISC_UTILS_H_ +#define _LOC_MISC_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/*=========================================================================== +FUNCTION loc_split_string + +DESCRIPTION: + This function is used to split a delimiter separated string into + sub-strings. This function does not allocate new memory to store the split + strings. Instead, it places '\0' in places of delimiters and assings the + starting address of the substring within the raw string as the string address + The input raw_string no longer remains to be a collection of sub-strings + after this function is executed. + Please make a copy of the input string before calling this function if + necessary + +PARAMETERS: + char *raw_string: is the original string with delimiter separated substrings + char **split_strings_ptr: is the arraw of pointers which will hold the addresses + of individual substrings + int max_num_substrings: is the maximum number of substrings that are expected + by the caller. The array of pointers in the above parameter + is usually this long + char delimiter: is the delimiter that separates the substrings. Examples: ' ', ';' + +DEPENDENCIES + N/A + +RETURN VALUE + int Number of split strings + +SIDE EFFECTS + The input raw_string no longer remains a delimiter separated single string. + +EXAMPLE + delimiter = ' ' //space + raw_string = "hello new user" //delimiter is space ' ' + addresses = 0123456789abcd + split_strings_ptr[0] = &raw_string[0]; //split_strings_ptr[0] contains "hello" + split_strings_ptr[1] = &raw_string[6]; //split_strings_ptr[1] contains "new" + split_strings_ptr[2] = &raw_string[a]; //split_strings_ptr[2] contains "user" + +===========================================================================*/ +int loc_util_split_string(char *raw_string, char **split_strings_ptr, int max_num_substrings, + char delimiter); + +/*=========================================================================== +FUNCTION trim_space + +DESCRIPTION + Removes leading and trailing spaces of the string + +DEPENDENCIES + N/A + +RETURN VALUE + None + +SIDE EFFECTS + N/A +===========================================================================*/ +void loc_util_trim_space(char *org_string); + +/*=========================================================================== +FUNCTION dlGetSymFromLib + +DESCRIPTION + Handy function to get a pointer to a symbol from a library. + + If libHandle is not null, it will be used as the handle to the library. In + that case libName wll not be used; + libHandle is an in / out parameter. + If libHandle is null, libName will be used to dlopen. + Either libHandle or libName must not be nullptr. + symName must not be null. + +DEPENDENCIES + N/A + +RETURN VALUE + pointer to symName. Could be nullptr if + Parameters are incorrect; or + libName can not be opened; or + symName can not be found. + +SIDE EFFECTS + N/A +===========================================================================*/ +void* dlGetSymFromLib(void*& libHandle, const char* libName, const char* symName); + +#ifdef __cplusplus +} +#endif + +#endif //_LOC_MISC_UTILS_H_ diff --git a/gps/utils/loc_nmea.cpp b/gps/utils/loc_nmea.cpp new file mode 100644 index 0000000..41a707d --- /dev/null +++ b/gps/utils/loc_nmea.cpp @@ -0,0 +1,2088 @@ +/* Copyright (c) 2012-2017, 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. + * + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "LocSvc_nmea" +#include <loc_nmea.h> +#include <math.h> +#include <log_util.h> +#include <loc_pla.h> +#include <loc_cfg.h> + +#define GLONASS_SV_ID_OFFSET 64 +#define QZSS_SV_ID_OFFSET (-192) +#define MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION 64 +#define MAX_SATELLITES_IN_USE 12 +#define MSEC_IN_ONE_WEEK 604800000ULL +#define UTC_GPS_OFFSET_MSECS 315964800000ULL + +// GNSS system id according to NMEA spec +#define SYSTEM_ID_GPS 1 +#define SYSTEM_ID_GLONASS 2 +#define SYSTEM_ID_GALILEO 3 +#define SYSTEM_ID_BDS 4 +#define SYSTEM_ID_QZSS 5 +#define SYSTEM_ID_NAVIC 6 + +//GNSS signal id according to NMEA spec +#define SIGNAL_ID_ALL_SIGNALS 0 +#define SIGNAL_ID_GPS_L1CA 1 +#define SIGNAL_ID_GPS_L1P 2 +#define SIGNAL_ID_GPS_L1M 3 +#define SIGNAL_ID_GPS_L2P 4 +#define SIGNAL_ID_GPS_L2CM 5 +#define SIGNAL_ID_GPS_L2CL 6 +#define SIGNAL_ID_GPS_L5I 7 +#define SIGNAL_ID_GPS_L5Q 8 + + +#define SIGNAL_ID_GLO_G1CA 1 +#define SIGNAL_ID_GLO_G1P 2 +#define SIGNAL_ID_GLO_G2CA 3 +#define SIGNAL_ID_GLO_G2P 4 + + +#define SIGNAL_ID_GAL_E5A 1 +#define SIGNAL_ID_GAL_E5B 2 +#define SIGNAL_ID_GAL_E5AB 3 +#define SIGNAL_ID_GAL_E6A 4 +#define SIGNAL_ID_GAL_E6BC 5 +#define SIGNAL_ID_GAL_L1A 6 +#define SIGNAL_ID_GAL_L1BC 7 + +#define SIGNAL_ID_BDS_B1I 1 +#define SIGNAL_ID_BDS_B1Q 2 +#define SIGNAL_ID_BDS_B1C 3 +#define SIGNAL_ID_BDS_B1A 4 +#define SIGNAL_ID_BDS_B2A 5 +#define SIGNAL_ID_BDS_B2B 6 +#define SIGNAL_ID_BDS_B2AB 7 +#define SIGNAL_ID_BDS_B3I 8 +#define SIGNAL_ID_BDS_B3Q 9 +#define SIGNAL_ID_BDS_B3A 0xA +#define SIGNAL_ID_BDS_B2I 0xB +#define SIGNAL_ID_BDS_B2Q 0xC + +#define SIGNAL_ID_QZSS_L1CA 1 +#define SIGNAL_ID_QZSS_L1CD 2 +#define SIGNAL_ID_QZSS_L1CP 3 +#define SIGNAL_ID_QZSS_LIS 4 +#define SIGNAL_ID_QZSS_L2CM 5 +#define SIGNAL_ID_QZSS_L2CL 6 +#define SIGNAL_ID_QZSS_L5I 7 +#define SIGNAL_ID_QZSS_L5Q 8 +#define SIGNAL_ID_QZSS_L6D 9 +#define SIGNAL_ID_QZSS_L6E 0xA + +#define SIGNAL_ID_NAVIC_L5SPS 1 +#define SIGNAL_ID_NAVIC_SSPS 2 +#define SIGNAL_ID_NAVIC_L5RS 3 +#define SIGNAL_ID_NAVIC_SRS 4 +#define SIGNAL_ID_NAVIC_L1SPS 5 + + +typedef struct loc_nmea_sv_meta_s +{ + char talker[3]; + LocGnssConstellationType svType; + uint64_t mask; + uint32_t svCount; + uint32_t totalSvUsedCount; + uint32_t svIdOffset; + uint32_t signalId; + uint32_t systemId; +} loc_nmea_sv_meta; + +typedef struct loc_sv_cache_info_s +{ + uint64_t gps_used_mask; + uint64_t glo_used_mask; + uint64_t gal_used_mask; + uint64_t qzss_used_mask; + uint64_t bds_used_mask; + uint64_t navic_used_mask; + uint32_t gps_l1_count; + uint32_t gps_l5_count; + uint32_t glo_g1_count; + uint32_t glo_g2_count; + uint32_t gal_e1_count; + uint32_t gal_e5_count; + uint32_t qzss_l1_count; + uint32_t qzss_l5_count; + uint32_t bds_b1_count; + uint32_t bds_b2_count; + uint32_t navic_l5_count; + float hdop; + float pdop; + float vdop; +} loc_sv_cache_info; + +/*=========================================================================== +FUNCTION convert_Lla_to_Ecef + +DESCRIPTION + Convert LLA to ECEF + +DEPENDENCIES + NONE + +RETURN VALUE + NONE + +SIDE EFFECTS + N/A + +===========================================================================*/ +static void convert_Lla_to_Ecef(const LocLla& plla, LocEcef& pecef) +{ + double r; + + r = MAJA / sqrt(1.0 - ESQR * sin(plla.lat) * sin(plla.lat)); + pecef.X = (r + plla.alt) * cos(plla.lat) * cos(plla.lon); + pecef.Y = (r + plla.alt) * cos(plla.lat) * sin(plla.lon); + pecef.Z = (r * OMES + plla.alt) * sin(plla.lat); +} + +/*=========================================================================== +FUNCTION convert_WGS84_to_PZ90 + +DESCRIPTION + Convert datum from WGS84 to PZ90 + +DEPENDENCIES + NONE + +RETURN VALUE + NONE + +SIDE EFFECTS + N/A + +===========================================================================*/ +static void convert_WGS84_to_PZ90(const LocEcef& pWGS84, LocEcef& pPZ90) +{ + double deltaX = DatumConstFromWGS84[0]; + double deltaY = DatumConstFromWGS84[1]; + double deltaZ = DatumConstFromWGS84[2]; + double deltaScale = DatumConstFromWGS84[3]; + double rotX = DatumConstFromWGS84[4]; + double rotY = DatumConstFromWGS84[5]; + double rotZ = DatumConstFromWGS84[6]; + + pPZ90.X = deltaX + deltaScale * (pWGS84.X + rotZ * pWGS84.Y - rotY * pWGS84.Z); + pPZ90.Y = deltaY + deltaScale * (pWGS84.Y - rotZ * pWGS84.X + rotX * pWGS84.Z); + pPZ90.Z = deltaZ + deltaScale * (pWGS84.Z + rotY * pWGS84.X - rotX * pWGS84.Y); +} + +/*=========================================================================== +FUNCTION convert_Ecef_to_Lla + +DESCRIPTION + Convert ECEF to LLA + +DEPENDENCIES + NONE + +RETURN VALUE + NONE + +SIDE EFFECTS + N/A + +===========================================================================*/ +static void convert_Ecef_to_Lla(const LocEcef& pecef, LocLla& plla) +{ + double p, r; + double EcefA = C_PZ90A; + double EcefB = C_PZ90B; + double Ecef1Mf; + double EcefE2; + double Mu; + double Smu; + double Cmu; + double Phi; + double Sphi; + double N; + + p = sqrt(pecef.X * pecef.X + pecef.Y * pecef.Y); + r = sqrt(p * p + pecef.Z * pecef.Z); + if (r < 1.0) { + plla.lat = 1.0; + plla.lon = 1.0; + plla.alt = 1.0; + } + Ecef1Mf = 1.0 - (EcefA - EcefB) / EcefA; + EcefE2 = 1.0 - (EcefB * EcefB) / (EcefA * EcefA); + if (p > 1.0) { + Mu = atan2(pecef.Z * (Ecef1Mf + EcefE2 * EcefA / r), p); + } else { + if (pecef.Z > 0.0) { + Mu = M_PI / 2.0; + } else { + Mu = -M_PI / 2.0; + } + } + Smu = sin(Mu); + Cmu = cos(Mu); + Phi = atan2(pecef.Z * Ecef1Mf + EcefE2 * EcefA * Smu * Smu * Smu, + Ecef1Mf * (p - EcefE2 * EcefA * Cmu * Cmu * Cmu)); + Sphi = sin(Phi); + N = EcefA / sqrt(1.0 - EcefE2 * Sphi * Sphi); + plla.alt = p * cos(Phi) + pecef.Z * Sphi - EcefA * EcefA/N; + plla.lat = Phi; + if ( p > 1.0) { + plla.lon = atan2(pecef.Y, pecef.X); + } else { + plla.lon = 0.0; + } +} + +/*=========================================================================== +FUNCTION convert_signalType_to_signalId + +DESCRIPTION + convert signalType to signal ID + +DEPENDENCIES + NONE + +RETURN VALUE + value of signal ID + +SIDE EFFECTS + N/A + +===========================================================================*/ +static uint32_t convert_signalType_to_signalId(GnssSignalTypeMask signalType) +{ + uint32_t signalId = SIGNAL_ID_ALL_SIGNALS; + + switch (signalType) { + case GNSS_SIGNAL_GPS_L1CA: + signalId = SIGNAL_ID_GPS_L1CA; + break; + case GNSS_SIGNAL_GPS_L2: + signalId = SIGNAL_ID_GPS_L2CL; + break; + case GNSS_SIGNAL_GPS_L5: + signalId = SIGNAL_ID_GPS_L5Q; + break; + case GNSS_SIGNAL_GLONASS_G1: + signalId = SIGNAL_ID_GLO_G1CA; + break; + case GNSS_SIGNAL_GLONASS_G2: + signalId = SIGNAL_ID_GLO_G2CA; + break; + case GNSS_SIGNAL_GALILEO_E1: + signalId = SIGNAL_ID_GAL_L1BC; + break; + case GNSS_SIGNAL_GALILEO_E5A: + signalId = SIGNAL_ID_GAL_E5A; + break; + case GNSS_SIGNAL_GALILEO_E5B: + signalId = SIGNAL_ID_GAL_E5B; + break; + case GNSS_SIGNAL_QZSS_L1CA: + signalId = SIGNAL_ID_QZSS_L1CA; + break; + case GNSS_SIGNAL_QZSS_L2: + signalId = SIGNAL_ID_QZSS_L2CL; + break; + case GNSS_SIGNAL_QZSS_L5: + signalId = SIGNAL_ID_QZSS_L5Q; + break; + case GNSS_SIGNAL_BEIDOU_B1I: + signalId = SIGNAL_ID_BDS_B1I; + break; + case GNSS_SIGNAL_BEIDOU_B1C: + signalId = SIGNAL_ID_BDS_B1C; + break; + case GNSS_SIGNAL_BEIDOU_B2I: + signalId = SIGNAL_ID_BDS_B2I; + break; + case GNSS_SIGNAL_BEIDOU_B2AI: + case GNSS_SIGNAL_BEIDOU_B2AQ: + signalId = SIGNAL_ID_BDS_B2A; + break; + case GNSS_SIGNAL_NAVIC_L5: + signalId = SIGNAL_ID_NAVIC_L5SPS; + break; + default: + signalId = SIGNAL_ID_ALL_SIGNALS; + } + + return signalId; + +} + +/*=========================================================================== +FUNCTION get_sv_count_from_mask + +DESCRIPTION + get the sv count from bit mask + +DEPENDENCIES + NONE + +RETURN VALUE + value of sv count + +SIDE EFFECTS + N/A + +===========================================================================*/ +static uint32_t get_sv_count_from_mask(uint64_t svMask, int totalSvCount) +{ + int index = 0; + uint32_t svCount = 0; + + if(totalSvCount > MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION) { + LOC_LOGE("total SV count in this constellation %d exceeded limit %d", + totalSvCount, MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION); + } + for(index = 0; index < totalSvCount; index++) { + if(svMask & 0x1) + svCount += 1; + svMask >>= 1; + } + return svCount; +} + +/*=========================================================================== +FUNCTION loc_nmea_sv_meta_init + +DESCRIPTION + Init loc_nmea_sv_meta passed in + +DEPENDENCIES + NONE + +RETURN VALUE + Pointer to loc_nmea_sv_meta + +SIDE EFFECTS + N/A + +===========================================================================*/ +static loc_nmea_sv_meta* loc_nmea_sv_meta_init(loc_nmea_sv_meta& sv_meta, + loc_sv_cache_info& sv_cache_info, + GnssSvType svType, + GnssSignalTypeMask signalType, + bool needCombine) +{ + memset(&sv_meta, 0, sizeof(sv_meta)); + sv_meta.svType = svType; + + switch (svType) + { + case GNSS_SV_TYPE_GPS: + sv_meta.talker[0] = 'G'; + sv_meta.talker[1] = 'P'; + sv_meta.mask = sv_cache_info.gps_used_mask; + sv_meta.systemId = SYSTEM_ID_GPS; + if (GNSS_SIGNAL_GPS_L1CA == signalType) { + sv_meta.svCount = sv_cache_info.gps_l1_count; + } else if (GNSS_SIGNAL_GPS_L5 == signalType) { + sv_meta.svCount = sv_cache_info.gps_l5_count; + } + break; + case GNSS_SV_TYPE_GLONASS: + sv_meta.talker[0] = 'G'; + sv_meta.talker[1] = 'L'; + sv_meta.mask = sv_cache_info.glo_used_mask; + // GLONASS SV ids are from 65-96 + sv_meta.svIdOffset = GLONASS_SV_ID_OFFSET; + sv_meta.systemId = SYSTEM_ID_GLONASS; + if (GNSS_SIGNAL_GLONASS_G1 == signalType) { + sv_meta.svCount = sv_cache_info.glo_g1_count; + } else if (GNSS_SIGNAL_GLONASS_G2 == signalType) { + sv_meta.svCount = sv_cache_info.glo_g2_count; + } + break; + case GNSS_SV_TYPE_GALILEO: + sv_meta.talker[0] = 'G'; + sv_meta.talker[1] = 'A'; + sv_meta.mask = sv_cache_info.gal_used_mask; + sv_meta.systemId = SYSTEM_ID_GALILEO; + if (GNSS_SIGNAL_GALILEO_E1 == signalType) { + sv_meta.svCount = sv_cache_info.gal_e1_count; + } else if (GNSS_SIGNAL_GALILEO_E5A == signalType) { + sv_meta.svCount = sv_cache_info.gal_e5_count; + } + break; + case GNSS_SV_TYPE_QZSS: + sv_meta.talker[0] = 'G'; + sv_meta.talker[1] = 'Q'; + sv_meta.mask = sv_cache_info.qzss_used_mask; + // QZSS SV ids are from 193-199. So keep svIdOffset -192 + sv_meta.svIdOffset = QZSS_SV_ID_OFFSET; + sv_meta.systemId = SYSTEM_ID_QZSS; + if (GNSS_SIGNAL_QZSS_L1CA == signalType) { + sv_meta.svCount = sv_cache_info.qzss_l1_count; + } else if (GNSS_SIGNAL_QZSS_L5 == signalType) { + sv_meta.svCount = sv_cache_info.qzss_l5_count; + } + break; + case GNSS_SV_TYPE_BEIDOU: + sv_meta.talker[0] = 'G'; + sv_meta.talker[1] = 'B'; + sv_meta.mask = sv_cache_info.bds_used_mask; + // BDS SV ids are from 201-235. So keep svIdOffset 0 + sv_meta.systemId = SYSTEM_ID_BDS; + if (GNSS_SIGNAL_BEIDOU_B1I == signalType) { + sv_meta.svCount = sv_cache_info.bds_b1_count; + } else if (GNSS_SIGNAL_BEIDOU_B2AI == signalType) { + sv_meta.svCount = sv_cache_info.bds_b2_count; + } + break; + case GNSS_SV_TYPE_NAVIC: + sv_meta.talker[0] = 'G'; + sv_meta.talker[1] = 'I'; + sv_meta.mask = sv_cache_info.navic_used_mask; + // NAVIC SV ids are from 401-414. So keep svIdOffset 0 + sv_meta.systemId = SYSTEM_ID_NAVIC; + if (GNSS_SIGNAL_NAVIC_L5 == signalType) { + sv_meta.svCount = sv_cache_info.navic_l5_count; + } + break; + default: + LOC_LOGE("NMEA Error unknow constellation type: %d", svType); + return NULL; + } + sv_meta.signalId = convert_signalType_to_signalId(signalType); + sv_meta.totalSvUsedCount = + get_sv_count_from_mask(sv_cache_info.gps_used_mask, + GPS_SV_PRN_MAX - GPS_SV_PRN_MIN + 1) + + get_sv_count_from_mask(sv_cache_info.glo_used_mask, + GLO_SV_PRN_MAX - GLO_SV_PRN_MIN + 1) + + get_sv_count_from_mask(sv_cache_info.gal_used_mask, + GAL_SV_PRN_MAX - GAL_SV_PRN_MIN + 1) + + get_sv_count_from_mask(sv_cache_info.qzss_used_mask, + QZSS_SV_PRN_MAX - QZSS_SV_PRN_MIN + 1) + + get_sv_count_from_mask(sv_cache_info.bds_used_mask, + BDS_SV_PRN_MAX - BDS_SV_PRN_MIN + 1) + + get_sv_count_from_mask(sv_cache_info.navic_used_mask, + NAVIC_SV_PRN_MAX - NAVIC_SV_PRN_MIN + 1); + if (needCombine && + (sv_cache_info.gps_used_mask ? 1 : 0) + + (sv_cache_info.glo_used_mask ? 1 : 0) + + (sv_cache_info.gal_used_mask ? 1 : 0) + + (sv_cache_info.qzss_used_mask ? 1 : 0) + + (sv_cache_info.bds_used_mask ? 1 : 0) + + (sv_cache_info.navic_used_mask ? 1 : 0) > 1) + { + // If GPS, GLONASS, Galileo, QZSS, BDS etc. are combined + // to obtain the reported position solution, + // talker shall be set to GN, to indicate that + // the satellites are used in a combined solution + sv_meta.talker[0] = 'G'; + sv_meta.talker[1] = 'N'; + } + return &sv_meta; +} + +/*=========================================================================== +FUNCTION loc_nmea_put_checksum + +DESCRIPTION + Generate NMEA sentences generated based on position report + +DEPENDENCIES + NONE + +RETURN VALUE + Total length of the nmea sentence + +SIDE EFFECTS + N/A + +===========================================================================*/ +static int loc_nmea_put_checksum(char *pNmea, int maxSize) +{ + uint8_t checksum = 0; + int length = 0; + if(NULL == pNmea) + return 0; + + pNmea++; //skip the $ + while (*pNmea != '\0') + { + checksum ^= *pNmea++; + length++; + } + + // length now contains nmea sentence string length not including $ sign. + int checksumLength = snprintf(pNmea,(maxSize-length-1),"*%02X\r\n", checksum); + + // total length of nmea sentence is length of nmea sentence inc $ sign plus + // length of checksum (+1 is to cover the $ character in the length). + return (length + checksumLength + 1); +} + +/*=========================================================================== +FUNCTION loc_nmea_generate_GSA + +DESCRIPTION + Generate NMEA GSA sentences generated based on position report + Currently below sentences are generated: + - $GPGSA : GPS DOP and active SVs + - $GLGSA : GLONASS DOP and active SVs + - $GAGSA : GALILEO DOP and active SVs + - $GNGSA : GNSS DOP and active SVs + +DEPENDENCIES + NONE + +RETURN VALUE + Number of SVs used + +SIDE EFFECTS + N/A + +===========================================================================*/ +static uint32_t loc_nmea_generate_GSA(const GpsLocationExtended &locationExtended, + char* sentence, + int bufSize, + loc_nmea_sv_meta* sv_meta_p, + std::vector<std::string> &nmeaArraystr) +{ + if (!sentence || bufSize <= 0 || !sv_meta_p) + { + LOC_LOGE("NMEA Error invalid arguments."); + return 0; + } + + char* pMarker = sentence; + int lengthRemaining = bufSize; + int length = 0; + + uint32_t svUsedCount = 0; + uint32_t svUsedList[64] = {0}; + + char fixType = '\0'; + + const char* talker = sv_meta_p->talker; + uint32_t svIdOffset = sv_meta_p->svIdOffset; + uint64_t mask = sv_meta_p->mask; + + if(sv_meta_p->svType != GNSS_SV_TYPE_GLONASS) { + svIdOffset = 0; + } + + for (uint8_t i = 1; mask > 0 && svUsedCount < 64; i++) + { + if (mask & 1) + svUsedList[svUsedCount++] = i + svIdOffset; + mask = mask >> 1; + } + + if (svUsedCount == 0) + return 0; + + if (sv_meta_p->totalSvUsedCount == 0) + fixType = '1'; // no fix + else if (sv_meta_p->totalSvUsedCount <= 3) + fixType = '2'; // 2D fix + else + fixType = '3'; // 3D fix + + // Start printing the sentence + // Format: $--GSA,a,x,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,p.p,h.h,v.v,s*cc + // a : Mode : A : Automatic, allowed to automatically switch 2D/3D + // x : Fixtype : 1 (no fix), 2 (2D fix), 3 (3D fix) + // xx : 12 SV ID + // p.p : Position DOP (Dilution of Precision) + // h.h : Horizontal DOP + // v.v : Vertical DOP + // s : GNSS System Id + // cc : Checksum value + length = snprintf(pMarker, lengthRemaining, "$%sGSA,A,%c,", talker, fixType); + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return 0; + } + pMarker += length; + lengthRemaining -= length; + + // Add first 12 satellite IDs + for (uint8_t i = 0; i < 12; i++) + { + if (i < svUsedCount) + length = snprintf(pMarker, lengthRemaining, "%02d,", svUsedList[i]); + else + length = snprintf(pMarker, lengthRemaining, ","); + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return 0; + } + pMarker += length; + lengthRemaining -= length; + } + + // Add the position/horizontal/vertical DOP values + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP) + { + length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f,", + locationExtended.pdop, + locationExtended.hdop, + locationExtended.vdop); + } + else + { // no dop + length = snprintf(pMarker, lengthRemaining, ",,,"); + } + pMarker += length; + lengthRemaining -= length; + + // system id + length = snprintf(pMarker, lengthRemaining, "%d", sv_meta_p->systemId); + pMarker += length; + lengthRemaining -= length; + + /* Sentence is ready, add checksum and broadcast */ + length = loc_nmea_put_checksum(sentence, bufSize); + nmeaArraystr.push_back(sentence); + + return svUsedCount; +} + +/*=========================================================================== +FUNCTION loc_nmea_generate_GSV + +DESCRIPTION + Generate NMEA GSV sentences generated based on sv report + Currently below sentences are generated: + - $GPGSV: GPS Satellites in View + - $GLGSV: GLONASS Satellites in View + - $GAGSV: GALILEO Satellites in View + +DEPENDENCIES + NONE + +RETURN VALUE + NONE + +SIDE EFFECTS + N/A + +===========================================================================*/ +static void loc_nmea_generate_GSV(const GnssSvNotification &svNotify, + char* sentence, + int bufSize, + loc_nmea_sv_meta* sv_meta_p, + std::vector<std::string> &nmeaArraystr) +{ + if (!sentence || bufSize <= 0) + { + LOC_LOGE("NMEA Error invalid argument."); + return; + } + + char* pMarker = sentence; + int lengthRemaining = bufSize; + int length = 0; + int sentenceCount = 0; + int sentenceNumber = 1; + size_t svNumber = 1; + + const char* talker = sv_meta_p->talker; + uint32_t svIdOffset = sv_meta_p->svIdOffset; + int svCount = sv_meta_p->svCount; + if (svCount <= 0) + { + LOC_LOGV("No SV in view for talker ID:%s, signal ID:%X", talker, sv_meta_p->signalId); + return; + } + + svNumber = 1; + sentenceNumber = 1; + sentenceCount = svCount / 4 + (svCount % 4 != 0); + + while (sentenceNumber <= sentenceCount) + { + pMarker = sentence; + lengthRemaining = bufSize; + + length = snprintf(pMarker, lengthRemaining, "$%sGSV,%d,%d,%02d", + talker, sentenceCount, sentenceNumber, svCount); + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + for (int i=0; (svNumber <= svNotify.count) && (i < 4); svNumber++) + { + GnssSignalTypeMask signalType = svNotify.gnssSvs[svNumber-1].gnssSignalTypeMask; + if (0 == signalType) { + // If no signal type in report, it means default L1,G1,E1,B1I + switch (svNotify.gnssSvs[svNumber - 1].type) + { + case GNSS_SV_TYPE_GPS: + signalType = GNSS_SIGNAL_GPS_L1CA; + break; + case GNSS_SV_TYPE_GLONASS: + signalType = GNSS_SIGNAL_GLONASS_G1; + break; + case GNSS_SV_TYPE_GALILEO: + signalType = GNSS_SIGNAL_GALILEO_E1; + break; + case GNSS_SV_TYPE_QZSS: + signalType = GNSS_SIGNAL_QZSS_L1CA; + break; + case GNSS_SV_TYPE_BEIDOU: + signalType = GNSS_SIGNAL_BEIDOU_B1I; + break; + case GNSS_SV_TYPE_SBAS: + signalType = GNSS_SIGNAL_SBAS_L1; + break; + case GNSS_SV_TYPE_NAVIC: + signalType = GNSS_SIGNAL_NAVIC_L5; + break; + default: + LOC_LOGE("NMEA Error unknow constellation type: %d", + svNotify.gnssSvs[svNumber - 1].type); + continue; + } + } + + if (sv_meta_p->svType == svNotify.gnssSvs[svNumber - 1].type && + sv_meta_p->signalId == convert_signalType_to_signalId(signalType)) + { + length = snprintf(pMarker, lengthRemaining,",%02d,%02d,%03d,", + svNotify.gnssSvs[svNumber - 1].svId + svIdOffset, + (int)(0.5 + svNotify.gnssSvs[svNumber - 1].elevation), //float to int + (int)(0.5 + svNotify.gnssSvs[svNumber - 1].azimuth)); //float to int + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (svNotify.gnssSvs[svNumber - 1].cN0Dbhz > 0) + { + length = snprintf(pMarker, lengthRemaining,"%02d", + (int)(0.5 + svNotify.gnssSvs[svNumber - 1].cN0Dbhz)); //float to int + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + } + + i++; + } + + } + + // append signalId + length = snprintf(pMarker, lengthRemaining,",%X",sv_meta_p->signalId); + pMarker += length; + lengthRemaining -= length; + + length = loc_nmea_put_checksum(sentence, bufSize); + nmeaArraystr.push_back(sentence); + sentenceNumber++; + + } //while +} + +/*=========================================================================== +FUNCTION loc_nmea_generate_DTM + +DESCRIPTION + Generate NMEA DTM sentences generated based on position report + +DEPENDENCIES + NONE + +RETURN VALUE + NONE + +SIDE EFFECTS + N/A + +===========================================================================*/ +static void loc_nmea_generate_DTM(const LocLla &ref_lla, + const LocLla &local_lla, + char *talker, + char *sentence, + int bufSize) +{ + char* pMarker = sentence; + int lengthRemaining = bufSize; + int length = 0; + int datum_type; + char ref_datum[4] = {0}; + char local_datum[4] = {0}; + double lla_offset[3] = {0}; + char latHem, longHem; + double latMins, longMins; + + + + datum_type = loc_get_datum_type(); + switch (datum_type) { + case LOC_GNSS_DATUM_WGS84: + ref_datum[0] = 'W'; + ref_datum[1] = '8'; + ref_datum[2] = '4'; + local_datum[0] = 'P'; + local_datum[1] = '9'; + local_datum[2] = '0'; + break; + case LOC_GNSS_DATUM_PZ90: + ref_datum[0] = 'P'; + ref_datum[1] = '9'; + ref_datum[2] = '0'; + local_datum[0] = 'W'; + local_datum[1] = '8'; + local_datum[2] = '4'; + break; + default: + break; + } + length = snprintf(pMarker , lengthRemaining , "$%sDTM,%s,," , talker, local_datum); + if (length < 0 || length >= lengthRemaining) { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + lla_offset[0] = local_lla.lat - ref_lla.lat; + lla_offset[1] = fmod(local_lla.lon - ref_lla.lon, 360.0); + if (lla_offset[1] < -180.0) { + lla_offset[1] += 360.0; + } else if ( lla_offset[1] > 180.0) { + lla_offset[1] -= 360.0; + } + lla_offset[2] = local_lla.alt - ref_lla.alt; + if (lla_offset[0] > 0.0) { + latHem = 'N'; + } else { + latHem = 'S'; + lla_offset[0] *= -1.0; + } + latMins = fmod(lla_offset[0] * 60.0, 60.0); + if (lla_offset[1] < 0.0) { + longHem = 'W'; + lla_offset[1] *= -1.0; + }else { + longHem = 'E'; + } + longMins = fmod(lla_offset[1] * 60.0, 60.0); + length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,%.3lf,", + (uint8_t)floor(lla_offset[0]), latMins, latHem, + (uint8_t)floor(lla_offset[1]), longMins, longHem, lla_offset[2]); + if (length < 0 || length >= lengthRemaining) { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + length = snprintf(pMarker , lengthRemaining , "%s" , ref_datum); + if (length < 0 || length >= lengthRemaining) { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + length = loc_nmea_put_checksum(sentence, bufSize); +} + +/*=========================================================================== +FUNCTION get_utctime_with_leapsecond_transition + +DESCRIPTION + This function returns true if the position report is generated during + leap second transition period. If not, then the utc timestamp returned + will be set to the timestamp in the position report. If it is, + then the utc timestamp returned will need to take into account + of the leap second transition so that proper calendar year/month/date + can be calculated from the returned utc timestamp. + +DEPENDENCIES + NONE + +RETURN VALUE + true: position report is generated in leap second transition period. + +SIDE EFFECTS + N/A + +===========================================================================*/ +static bool get_utctime_with_leapsecond_transition( + const UlpLocation &location, + const GpsLocationExtended &locationExtended, + const LocationSystemInfo &systemInfo, + LocGpsUtcTime &utcPosTimestamp) +{ + bool inTransition = false; + + // position report is not generated during leap second transition, + // we can use the UTC timestamp from position report as is + utcPosTimestamp = location.gpsLocation.timestamp; + + // Check whether we are in leap second transition. + // If so, per NMEA spec, we need to display the extra second in format of 23:59:60 + // with year/month/date not getting advanced. + if ((locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_GPS_TIME) && + ((systemInfo.systemInfoMask & LOCATION_SYS_INFO_LEAP_SECOND) && + (systemInfo.leapSecondSysInfo.leapSecondInfoMask & + LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT))) { + + const LeapSecondChangeInfo &leapSecondChangeInfo = + systemInfo.leapSecondSysInfo.leapSecondChangeInfo; + const GnssSystemTimeStructType &gpsTimestampLsChange = + leapSecondChangeInfo.gpsTimestampLsChange; + + uint64_t gpsTimeLsChange = gpsTimestampLsChange.systemWeek * MSEC_IN_ONE_WEEK + + gpsTimestampLsChange.systemMsec; + uint64_t gpsTimePosReport = locationExtended.gpsTime.gpsWeek * MSEC_IN_ONE_WEEK + + locationExtended.gpsTime.gpsTimeOfWeekMs; + // we are only dealing with positive leap second change, as negative + // leap second change has never occurred and should not occur in future + if (leapSecondChangeInfo.leapSecondsAfterChange > + leapSecondChangeInfo.leapSecondsBeforeChange) { + // leap second adjustment is always 1 second at a time. It can happen + // every quarter end and up to four times per year. + if ((gpsTimePosReport >= gpsTimeLsChange) && + (gpsTimePosReport < (gpsTimeLsChange + 1000))) { + inTransition = true; + utcPosTimestamp = gpsTimeLsChange + UTC_GPS_OFFSET_MSECS - + leapSecondChangeInfo.leapSecondsBeforeChange * 1000; + + // we substract 1000 milli-seconds from UTC timestmap in order to calculate the + // proper year, month and date during leap second transtion. + // Let us give an example, assuming leap second transition is scheduled on 2019, + // Dec 31st mid night. When leap second transition is happening, + // instead of outputting the time as 2020, Jan, 1st, 00 hour, 00 min, and 00 sec. + // The time need to be displayed as 2019, Dec, 31st, 23 hour, 59 min and 60 sec. + utcPosTimestamp -= 1000; + } + } + } + return inTransition; +} + +/*=========================================================================== +FUNCTION loc_nmea_get_fix_quality + +DESCRIPTION + This function obtains the fix quality for GGA sentence, mode indicator + for RMC and VTG sentence based on nav solution mask and tech mask in + the postion report. + +DEPENDENCIES + NONE + +Output parameter + ggaGpsQuality: gps quality field in GGA sentence + rmcModeIndicator: mode indicator field in RMC sentence + vtgModeIndicator: mode indicator field in VTG sentence + +SIDE EFFECTS + N/A + +===========================================================================*/ +static void loc_nmea_get_fix_quality(const UlpLocation & location, + const GpsLocationExtended & locationExtended, + char & ggaGpsQuality, + char & rmcModeIndicator, + char & vtgModeIndicator) { + + ggaGpsQuality = '0'; + rmcModeIndicator = 'N'; + vtgModeIndicator = 'N'; + + do { + if (!(location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)){ + ggaGpsQuality = '0'; // 0 means no fix + rmcModeIndicator = 'N'; + vtgModeIndicator = 'N'; + break; + } + // NOTE: Order of the check is important + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK) { + if (LOC_NAV_MASK_PPP_CORRECTION & locationExtended.navSolutionMask) { + ggaGpsQuality = '2'; // 2 means DGPS fix + rmcModeIndicator = 'P'; // P means precise + vtgModeIndicator = 'P'; // P means precise + break; + } else if (LOC_NAV_MASK_RTK_FIXED_CORRECTION & locationExtended.navSolutionMask){ + ggaGpsQuality = '4'; // 4 means RTK Fixed fix + rmcModeIndicator = 'R'; // use R (RTK fixed) + vtgModeIndicator = 'D'; // use D (differential) as + // no RTK fixed defined for VTG in NMEA 183 spec + break; + } else if (LOC_NAV_MASK_RTK_CORRECTION & locationExtended.navSolutionMask){ + ggaGpsQuality = '5'; // 5 means RTK float fix + rmcModeIndicator = 'F'; // F means RTK float fix + vtgModeIndicator = 'D'; // use D (differential) as + // no RTK float defined for VTG in NMEA 183 spec + break; + } else if (LOC_NAV_MASK_DGNSS_CORRECTION & locationExtended.navSolutionMask){ + ggaGpsQuality = '2'; // 2 means DGPS fix + rmcModeIndicator = 'D'; // D means differential + vtgModeIndicator = 'D'; // D means differential + break; + } else if (LOC_NAV_MASK_SBAS_CORRECTION_IONO & locationExtended.navSolutionMask){ + ggaGpsQuality = '2'; // 2 means DGPS fix + rmcModeIndicator = 'D'; // D means differential + vtgModeIndicator = 'D'; // D means differential + break; + } + } + // NOTE: Order of the check is important + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK) { + if (LOC_POS_TECH_MASK_SATELLITE & locationExtended.tech_mask){ + ggaGpsQuality = '1'; // 1 means GPS + rmcModeIndicator = 'A'; // A means autonomous + vtgModeIndicator = 'A'; // A means autonomous + break; + } else if (LOC_POS_TECH_MASK_SENSORS & locationExtended.tech_mask){ + ggaGpsQuality = '6'; // 6 means estimated (dead reckoning) + rmcModeIndicator = 'E'; // E means estimated (dead reckoning) + vtgModeIndicator = 'E'; // E means estimated (dead reckoning) + break; + } + } + } while (0); + + LOC_LOGv("gps quality: %c, rmc mode indicator: %c, vtg mode indicator: %c", + ggaGpsQuality, rmcModeIndicator, vtgModeIndicator); +} + +/*=========================================================================== +FUNCTION loc_nmea_generate_pos + +DESCRIPTION + Generate NMEA sentences generated based on position report + Currently below sentences are generated within this function: + - $GPGSA : GPS DOP and active SVs + - $GLGSA : GLONASS DOP and active SVs + - $GAGSA : GALILEO DOP and active SVs + - $GNGSA : GNSS DOP and active SVs + - $--VTG : Track made good and ground speed + - $--RMC : Recommended minimum navigation information + - $--GGA : Time, position and fix related data + +DEPENDENCIES + NONE + +RETURN VALUE + 0 + +SIDE EFFECTS + N/A + +===========================================================================*/ +void loc_nmea_generate_pos(const UlpLocation &location, + const GpsLocationExtended &locationExtended, + const LocationSystemInfo &systemInfo, + unsigned char generate_nmea, + std::vector<std::string> &nmeaArraystr) +{ + ENTRY_LOG(); + + LocGpsUtcTime utcPosTimestamp = 0; + bool inLsTransition = false; + + inLsTransition = get_utctime_with_leapsecond_transition + (location, locationExtended, systemInfo, utcPosTimestamp); + + time_t utcTime(utcPosTimestamp/1000); + tm * pTm = gmtime(&utcTime); + if (NULL == pTm) { + LOC_LOGE("gmtime failed"); + return; + } + + char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0}; + char sentence_DTM[NMEA_SENTENCE_MAX_LENGTH] = {0}; + char sentence_RMC[NMEA_SENTENCE_MAX_LENGTH] = {0}; + char sentence_GNS[NMEA_SENTENCE_MAX_LENGTH] = {0}; + char sentence_GGA[NMEA_SENTENCE_MAX_LENGTH] = {0}; + char* pMarker = sentence; + int lengthRemaining = sizeof(sentence); + int length = 0; + int utcYear = pTm->tm_year % 100; // 2 digit year + int utcMonth = pTm->tm_mon + 1; // tm_mon starts at zero + int utcDay = pTm->tm_mday; + int utcHours = pTm->tm_hour; + int utcMinutes = pTm->tm_min; + int utcSeconds = pTm->tm_sec; + int utcMSeconds = (location.gpsLocation.timestamp)%1000; + int datum_type = loc_get_datum_type(); + LocEcef ecef_w84; + LocEcef ecef_p90; + LocLla lla_w84; + LocLla lla_p90; + LocLla ref_lla; + LocLla local_lla; + + if (inLsTransition) { + // During leap second transition, we need to display the extra + // leap second of hour, minute, second as (23:59:60) + utcHours = 23; + utcMinutes = 59; + utcSeconds = 60; + // As UTC timestamp is freezing during leap second transition, + // retrieve milli-seconds portion from GPS timestamp. + utcMSeconds = locationExtended.gpsTime.gpsTimeOfWeekMs % 1000; + } + + loc_sv_cache_info sv_cache_info = {}; + + if (GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA & locationExtended.flags) { + sv_cache_info.gps_used_mask = + locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask; + sv_cache_info.glo_used_mask = + locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask; + sv_cache_info.gal_used_mask = + locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask; + sv_cache_info.bds_used_mask = + locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask; + sv_cache_info.qzss_used_mask = + locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask; + sv_cache_info.navic_used_mask = + locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask; + } + + if (generate_nmea) { + char talker[3] = {'G', 'P', '\0'}; + char modeIndicator[7] = {0}; + uint32_t svUsedCount = 0; + uint32_t count = 0; + loc_nmea_sv_meta sv_meta; + // ------------------- + // ---$GPGSA/$GNGSA--- + // ------------------- + + count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS, + GNSS_SIGNAL_GPS_L1CA, true), nmeaArraystr); + if (count > 0) + { + svUsedCount += count; + talker[0] = sv_meta.talker[0]; + talker[1] = sv_meta.talker[1]; + } + + // ------------------- + // ---$GLGSA/$GNGSA--- + // ------------------- + + count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS, + GNSS_SIGNAL_GLONASS_G1, true), nmeaArraystr); + if (count > 0) + { + svUsedCount += count; + talker[0] = sv_meta.talker[0]; + talker[1] = sv_meta.talker[1]; + } + + // ------------------- + // ---$GAGSA/$GNGSA--- + // ------------------- + + count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO, + GNSS_SIGNAL_GALILEO_E1, true), nmeaArraystr); + if (count > 0) + { + svUsedCount += count; + talker[0] = sv_meta.talker[0]; + talker[1] = sv_meta.talker[1]; + } + + // ---------------------------- + // ---$GBGSA/$GNGSA (BEIDOU)--- + // ---------------------------- + count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU, + GNSS_SIGNAL_BEIDOU_B1I, true), nmeaArraystr); + if (count > 0) + { + svUsedCount += count; + talker[0] = sv_meta.talker[0]; + talker[1] = sv_meta.talker[1]; + } + + // -------------------------- + // ---$GQGSA/$GNGSA (QZSS)--- + // -------------------------- + + count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS, + GNSS_SIGNAL_QZSS_L1CA, true), nmeaArraystr); + if (count > 0) + { + svUsedCount += count; + talker[0] = sv_meta.talker[0]; + talker[1] = sv_meta.talker[1]; + } + + char ggaGpsQuality = '0'; + char rmcModeIndicator = 'N'; + char vtgModeIndicator = 'N'; + loc_nmea_get_fix_quality(location, locationExtended, + ggaGpsQuality, rmcModeIndicator, vtgModeIndicator); + + // ------------------- + // ------$--VTG------- + // ------------------- + + pMarker = sentence; + lengthRemaining = sizeof(sentence); + + if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_BEARING) + { + float magTrack = location.gpsLocation.bearing; + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV) + { + float magTrack = location.gpsLocation.bearing - locationExtended.magneticDeviation; + if (magTrack < 0.0) + magTrack += 360.0; + else if (magTrack > 360.0) + magTrack -= 360.0; + } + + length = snprintf(pMarker, lengthRemaining, "$%sVTG,%.1lf,T,%.1lf,M,", talker, location.gpsLocation.bearing, magTrack); + } + else + { + length = snprintf(pMarker, lengthRemaining, "$%sVTG,,T,,M,", talker); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_SPEED) + { + float speedKnots = location.gpsLocation.speed * (3600.0/1852.0); + float speedKmPerHour = location.gpsLocation.speed * 3.6; + + length = snprintf(pMarker, lengthRemaining, "%.1lf,N,%.1lf,K,", speedKnots, speedKmPerHour); + } + else + { + length = snprintf(pMarker, lengthRemaining, ",N,,K,"); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + length = snprintf(pMarker, lengthRemaining, "%c", vtgModeIndicator); + + length = loc_nmea_put_checksum(sentence, sizeof(sentence)); + nmeaArraystr.push_back(sentence); + + memset(&ecef_w84, 0, sizeof(ecef_w84)); + memset(&ecef_p90, 0, sizeof(ecef_p90)); + memset(&lla_w84, 0, sizeof(lla_w84)); + memset(&lla_p90, 0, sizeof(lla_p90)); + memset(&ref_lla, 0, sizeof(ref_lla)); + memset(&local_lla, 0, sizeof(local_lla)); + lla_w84.lat = location.gpsLocation.latitude / 180.0 * M_PI; + lla_w84.lon = location.gpsLocation.longitude / 180.0 * M_PI; + lla_w84.alt = location.gpsLocation.altitude; + + convert_Lla_to_Ecef(lla_w84, ecef_w84); + convert_WGS84_to_PZ90(ecef_w84, ecef_p90); + convert_Ecef_to_Lla(ecef_p90, lla_p90); + + switch (datum_type) { + case LOC_GNSS_DATUM_WGS84: + ref_lla.lat = location.gpsLocation.latitude; + ref_lla.lon = location.gpsLocation.longitude; + ref_lla.alt = location.gpsLocation.altitude; + local_lla.lat = lla_p90.lat / M_PI * 180.0; + local_lla.lon = lla_p90.lon / M_PI * 180.0; + local_lla.alt = lla_p90.alt; + break; + case LOC_GNSS_DATUM_PZ90: + ref_lla.lat = lla_p90.lat / M_PI * 180.0; + ref_lla.lon = lla_p90.lon / M_PI * 180.0; + ref_lla.alt = lla_p90.alt; + local_lla.lat = location.gpsLocation.latitude; + local_lla.lon = location.gpsLocation.longitude; + local_lla.alt = location.gpsLocation.altitude; + break; + default: + break; + } + + // ------------------- + // ------$--DTM------- + // ------------------- + loc_nmea_generate_DTM(ref_lla, local_lla, talker, sentence_DTM, sizeof(sentence_DTM)); + + // ------------------- + // ------$--RMC------- + // ------------------- + + pMarker = sentence_RMC; + lengthRemaining = sizeof(sentence_RMC); + + length = snprintf(pMarker, lengthRemaining, "$%sRMC,%02d%02d%02d.%02d,A," , + talker, utcHours, utcMinutes, utcSeconds,utcMSeconds/10); + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG) + { + double latitude = ref_lla.lat; + double longitude = ref_lla.lon; + char latHemisphere; + char lonHemisphere; + double latMinutes; + double lonMinutes; + + if (latitude > 0) + { + latHemisphere = 'N'; + } + else + { + latHemisphere = 'S'; + latitude *= -1.0; + } + + if (longitude < 0) + { + lonHemisphere = 'W'; + longitude *= -1.0; + } + else + { + lonHemisphere = 'E'; + } + + latMinutes = fmod(latitude * 60.0 , 60.0); + lonMinutes = fmod(longitude * 60.0 , 60.0); + + length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,", + (uint8_t)floor(latitude), latMinutes, latHemisphere, + (uint8_t)floor(longitude),lonMinutes, lonHemisphere); + } + else + { + length = snprintf(pMarker, lengthRemaining,",,,,"); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_SPEED) + { + float speedKnots = location.gpsLocation.speed * (3600.0/1852.0); + length = snprintf(pMarker, lengthRemaining, "%.1lf,", speedKnots); + } + else + { + length = snprintf(pMarker, lengthRemaining, ","); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_BEARING) + { + length = snprintf(pMarker, lengthRemaining, "%.1lf,", location.gpsLocation.bearing); + } + else + { + length = snprintf(pMarker, lengthRemaining, ","); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + length = snprintf(pMarker, lengthRemaining, "%2.2d%2.2d%2.2d,", + utcDay, utcMonth, utcYear); + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV) + { + float magneticVariation = locationExtended.magneticDeviation; + char direction; + if (magneticVariation < 0.0) + { + direction = 'W'; + magneticVariation *= -1.0; + } + else + { + direction = 'E'; + } + + length = snprintf(pMarker, lengthRemaining, "%.1lf,%c,", + magneticVariation, direction); + } + else + { + length = snprintf(pMarker, lengthRemaining, ",,"); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + length = snprintf(pMarker, lengthRemaining, "%c", rmcModeIndicator); + pMarker += length; + lengthRemaining -= length; + + // hardcode Navigation Status field to 'V' + length = snprintf(pMarker, lengthRemaining, ",%c", 'V'); + pMarker += length; + lengthRemaining -= length; + + length = loc_nmea_put_checksum(sentence_RMC, sizeof(sentence_RMC)); + + // ------------------- + // ------$--GNS------- + // ------------------- + + pMarker = sentence_GNS; + lengthRemaining = sizeof(sentence_GNS); + + length = snprintf(pMarker, lengthRemaining, "$%sGNS,%02d%02d%02d.%02d," , + talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10); + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG) + { + double latitude = ref_lla.lat; + double longitude = ref_lla.lon; + char latHemisphere; + char lonHemisphere; + double latMinutes; + double lonMinutes; + + if (latitude > 0) + { + latHemisphere = 'N'; + } + else + { + latHemisphere = 'S'; + latitude *= -1.0; + } + + if (longitude < 0) + { + lonHemisphere = 'W'; + longitude *= -1.0; + } + else + { + lonHemisphere = 'E'; + } + + latMinutes = fmod(latitude * 60.0 , 60.0); + lonMinutes = fmod(longitude * 60.0 , 60.0); + + length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,", + (uint8_t)floor(latitude), latMinutes, latHemisphere, + (uint8_t)floor(longitude),lonMinutes, lonHemisphere); + } + else + { + length = snprintf(pMarker, lengthRemaining,",,,,"); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if(!(sv_cache_info.gps_used_mask ? 1 : 0)) + modeIndicator[0] = 'N'; + else if (LOC_NAV_MASK_SBAS_CORRECTION_IONO & locationExtended.navSolutionMask) + modeIndicator[0] = 'D'; + else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask) + modeIndicator[0] = 'E'; + else + modeIndicator[0] = 'A'; + if(!(sv_cache_info.glo_used_mask ? 1 : 0)) + modeIndicator[1] = 'N'; + else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask) + modeIndicator[1] = 'E'; + else + modeIndicator[1] = 'A'; + if(!(sv_cache_info.gal_used_mask ? 1 : 0)) + modeIndicator[2] = 'N'; + else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask) + modeIndicator[2] = 'E'; + else + modeIndicator[2] = 'A'; + if(!(sv_cache_info.bds_used_mask ? 1 : 0)) + modeIndicator[3] = 'N'; + else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask) + modeIndicator[3] = 'E'; + else + modeIndicator[3] = 'A'; + if(!(sv_cache_info.qzss_used_mask ? 1 : 0)) + modeIndicator[4] = 'N'; + else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask) + modeIndicator[4] = 'E'; + else + modeIndicator[4] = 'A'; + if(!(sv_cache_info.navic_used_mask ? 1 : 0)) + modeIndicator[5] = 'N'; + else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask) + modeIndicator[5] = 'E'; + else + modeIndicator[5] = 'A'; + modeIndicator[6] = '\0'; + for(int index = 5; index > 0 && 'N' == modeIndicator[index]; index--) { + modeIndicator[index] = '\0'; + } + length = snprintf(pMarker, lengthRemaining,"%s,", modeIndicator); + + pMarker += length; + lengthRemaining -= length; + + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP) { + length = snprintf(pMarker, lengthRemaining, "%02d,%.1f,", + svUsedCount, locationExtended.hdop); + } + else { // no hdop + length = snprintf(pMarker, lengthRemaining, "%02d,,", + svUsedCount); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL) + { + length = snprintf(pMarker, lengthRemaining, "%.1lf,", + locationExtended.altitudeMeanSeaLevel); + } + else + { + length = snprintf(pMarker, lengthRemaining,","); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if ((location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_ALTITUDE) && + (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL)) + { + length = snprintf(pMarker, lengthRemaining, "%.1lf,,", + ref_lla.alt - locationExtended.altitudeMeanSeaLevel); + } + else + { + length = snprintf(pMarker, lengthRemaining,",,"); + } + + pMarker += length; + lengthRemaining -= length; + + // hardcode Navigation Status field to 'V' + length = snprintf(pMarker, lengthRemaining, ",%c", 'V'); + pMarker += length; + lengthRemaining -= length; + + length = loc_nmea_put_checksum(sentence_GNS, sizeof(sentence_GNS)); + + + // ------------------- + // ------$--GGA------- + // ------------------- + + pMarker = sentence_GGA; + lengthRemaining = sizeof(sentence_GGA); + + length = snprintf(pMarker, lengthRemaining, "$%sGGA,%02d%02d%02d.%02d," , + talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10); + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG) + { + double latitude = ref_lla.lat; + double longitude = ref_lla.lon; + char latHemisphere; + char lonHemisphere; + double latMinutes; + double lonMinutes; + + if (latitude > 0) + { + latHemisphere = 'N'; + } + else + { + latHemisphere = 'S'; + latitude *= -1.0; + } + + if (longitude < 0) + { + lonHemisphere = 'W'; + longitude *= -1.0; + } + else + { + lonHemisphere = 'E'; + } + + latMinutes = fmod(latitude * 60.0 , 60.0); + lonMinutes = fmod(longitude * 60.0 , 60.0); + + length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,", + (uint8_t)floor(latitude), latMinutes, latHemisphere, + (uint8_t)floor(longitude),lonMinutes, lonHemisphere); + } + else + { + length = snprintf(pMarker, lengthRemaining,",,,,"); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + // Number of satellites in use, 00-12 + if (svUsedCount > MAX_SATELLITES_IN_USE) + svUsedCount = MAX_SATELLITES_IN_USE; + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP) + { + length = snprintf(pMarker, lengthRemaining, "%c,%02d,%.1f,", + ggaGpsQuality, svUsedCount, locationExtended.hdop); + } + else + { // no hdop + length = snprintf(pMarker, lengthRemaining, "%c,%02d,,", + ggaGpsQuality, svUsedCount); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL) + { + length = snprintf(pMarker, lengthRemaining, "%.1lf,M,", + locationExtended.altitudeMeanSeaLevel); + } + else + { + length = snprintf(pMarker, lengthRemaining,",,"); + } + + if (length < 0 || length >= lengthRemaining) + { + LOC_LOGE("NMEA Error in string formatting"); + return; + } + pMarker += length; + lengthRemaining -= length; + + if ((location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_ALTITUDE) && + (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL)) + { + length = snprintf(pMarker, lengthRemaining, "%.1lf,M,,", + ref_lla.alt - locationExtended.altitudeMeanSeaLevel); + } + else + { + length = snprintf(pMarker, lengthRemaining,",,,"); + } + + length = loc_nmea_put_checksum(sentence_GGA, sizeof(sentence_GGA)); + + // ------$--DTM------- + nmeaArraystr.push_back(sentence_DTM); + // ------$--RMC------- + nmeaArraystr.push_back(sentence_RMC); + if(LOC_GNSS_DATUM_PZ90 == datum_type) { + // ------$--DTM------- + nmeaArraystr.push_back(sentence_DTM); + } + // ------$--GNS------- + nmeaArraystr.push_back(sentence_GNS); + if(LOC_GNSS_DATUM_PZ90 == datum_type) { + // ------$--DTM------- + nmeaArraystr.push_back(sentence_DTM); + } + // ------$--GGA------- + nmeaArraystr.push_back(sentence_GGA); + + } + //Send blank NMEA reports for non-final fixes + else { + strlcpy(sentence, "$GPGSA,A,1,,,,,,,,,,,,,,,,", sizeof(sentence)); + length = loc_nmea_put_checksum(sentence, sizeof(sentence)); + nmeaArraystr.push_back(sentence); + + strlcpy(sentence, "$GPVTG,,T,,M,,N,,K,N", sizeof(sentence)); + length = loc_nmea_put_checksum(sentence, sizeof(sentence)); + nmeaArraystr.push_back(sentence); + + strlcpy(sentence, "$GPDTM,,,,,,,,", sizeof(sentence)); + length = loc_nmea_put_checksum(sentence, sizeof(sentence)); + nmeaArraystr.push_back(sentence); + + strlcpy(sentence, "$GPRMC,,V,,,,,,,,,,N,V", sizeof(sentence)); + length = loc_nmea_put_checksum(sentence, sizeof(sentence)); + nmeaArraystr.push_back(sentence); + + strlcpy(sentence, "$GPGNS,,,,,,N,,,,,,,V", sizeof(sentence)); + length = loc_nmea_put_checksum(sentence, sizeof(sentence)); + nmeaArraystr.push_back(sentence); + + strlcpy(sentence, "$GPGGA,,,,,,0,,,,,,,,", sizeof(sentence)); + length = loc_nmea_put_checksum(sentence, sizeof(sentence)); + nmeaArraystr.push_back(sentence); + } + + EXIT_LOG(%d, 0); +} + + + +/*=========================================================================== +FUNCTION loc_nmea_generate_sv + +DESCRIPTION + Generate NMEA sentences generated based on sv report + +DEPENDENCIES + NONE + +RETURN VALUE + 0 + +SIDE EFFECTS + N/A + +===========================================================================*/ +void loc_nmea_generate_sv(const GnssSvNotification &svNotify, + std::vector<std::string> &nmeaArraystr) +{ + ENTRY_LOG(); + + char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0}; + int svCount = svNotify.count; + int svNumber = 1; + loc_sv_cache_info sv_cache_info = {}; + + //Count GPS SVs for saparating GPS from GLONASS and throw others + for(svNumber=1; svNumber <= svCount; svNumber++) { + if (GNSS_SV_TYPE_GPS == svNotify.gnssSvs[svNumber - 1].type) + { + // cache the used in fix mask, as it will be needed to send $GPGSA + // during the position report + if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT == + (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask & + GNSS_SV_OPTIONS_USED_IN_FIX_BIT)) + { + sv_cache_info.gps_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1)); + } + if (GNSS_SIGNAL_GPS_L5 == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask) { + sv_cache_info.gps_l5_count++; + } else { + // GNSS_SIGNAL_GPS_L1CA or default + // If no signal type in report, it means default L1 + sv_cache_info.gps_l1_count++; + } + } + else if (GNSS_SV_TYPE_GLONASS == svNotify.gnssSvs[svNumber - 1].type) + { + // cache the used in fix mask, as it will be needed to send $GNGSA + // during the position report + if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT == + (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask & + GNSS_SV_OPTIONS_USED_IN_FIX_BIT)) + { + sv_cache_info.glo_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1)); + } + if (GNSS_SIGNAL_GLONASS_G2 == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask){ + sv_cache_info.glo_g2_count++; + } else { + // GNSS_SIGNAL_GLONASS_G1 or default + // If no signal type in report, it means default G1 + sv_cache_info.glo_g1_count++; + } + } + else if (GNSS_SV_TYPE_GALILEO == svNotify.gnssSvs[svNumber - 1].type) + { + // cache the used in fix mask, as it will be needed to send $GAGSA + // during the position report + if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT == + (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask & + GNSS_SV_OPTIONS_USED_IN_FIX_BIT)) + { + sv_cache_info.gal_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1)); + } + if(GNSS_SIGNAL_GALILEO_E5A == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask){ + sv_cache_info.gal_e5_count++; + } else { + // GNSS_SIGNAL_GALILEO_E1 or default + // If no signal type in report, it means default E1 + sv_cache_info.gal_e1_count++; + } + } + else if (GNSS_SV_TYPE_QZSS == svNotify.gnssSvs[svNumber - 1].type) + { + // cache the used in fix mask, as it will be needed to send $PQGSA + // during the position report + if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT == + (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask & + GNSS_SV_OPTIONS_USED_IN_FIX_BIT)) + { + sv_cache_info.qzss_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1)); + } + if (GNSS_SIGNAL_QZSS_L5 == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask) { + sv_cache_info.qzss_l5_count++; + } else { + // GNSS_SIGNAL_QZSS_L1CA or default + // If no signal type in report, it means default L1 + sv_cache_info.qzss_l1_count++; + } + } + else if (GNSS_SV_TYPE_BEIDOU == svNotify.gnssSvs[svNumber - 1].type) + { + // cache the used in fix mask, as it will be needed to send $PQGSA + // during the position report + if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT == + (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask & + GNSS_SV_OPTIONS_USED_IN_FIX_BIT)) + { + sv_cache_info.bds_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1)); + } + if(GNSS_SIGNAL_BEIDOU_B2AI == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask){ + sv_cache_info.bds_b2_count++; + } else { + // GNSS_SIGNAL_BEIDOU_B1I or default + // If no signal type in report, it means default B1I + sv_cache_info.bds_b1_count++; + } + } + else if (GNSS_SV_TYPE_NAVIC == svNotify.gnssSvs[svNumber - 1].type) + { + // cache the used in fix mask, as it will be needed to send $PQGSA + // during the position report + if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT == + (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask & + GNSS_SV_OPTIONS_USED_IN_FIX_BIT)) + { + sv_cache_info.navic_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1)); + } + // GNSS_SIGNAL_NAVIC_L5 is the only signal type for NAVIC + sv_cache_info.navic_l5_count++; + } + } + + loc_nmea_sv_meta sv_meta; + // --------------------- + // ------$GPGSV:L1CA---- + // --------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS, + GNSS_SIGNAL_GPS_L1CA, false), nmeaArraystr); + + // --------------------- + // ------$GPGSV:L5------ + // --------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS, + GNSS_SIGNAL_GPS_L5, false), nmeaArraystr); + // --------------------- + // ------$GLGSV:G1------ + // --------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS, + GNSS_SIGNAL_GLONASS_G1, false), nmeaArraystr); + + // --------------------- + // ------$GLGSV:G2------ + // --------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS, + GNSS_SIGNAL_GLONASS_G2, false), nmeaArraystr); + + // --------------------- + // ------$GAGSV:E1------ + // --------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO, + GNSS_SIGNAL_GALILEO_E1, false), nmeaArraystr); + + // ------------------------- + // ------$GAGSV:E5A--------- + // ------------------------- + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO, + GNSS_SIGNAL_GALILEO_E5A, false), nmeaArraystr); + + // ----------------------------- + // ------$PQGSV (QZSS):L1CA----- + // ----------------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS, + GNSS_SIGNAL_QZSS_L1CA, false), nmeaArraystr); + + // ----------------------------- + // ------$PQGSV (QZSS):L5------- + // ----------------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS, + GNSS_SIGNAL_QZSS_L5, false), nmeaArraystr); + // ----------------------------- + // ------$PQGSV (BEIDOU:B1I)---- + // ----------------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU, + GNSS_SIGNAL_BEIDOU_B1I,false), nmeaArraystr); + + // ----------------------------- + // ------$PQGSV (BEIDOU:B2AI)--- + // ----------------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU, + GNSS_SIGNAL_BEIDOU_B2AI,false), nmeaArraystr); + + // ----------------------------- + // ------$GIGSV (NAVIC:L5)------ + // ----------------------------- + + loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence), + loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_NAVIC, + GNSS_SIGNAL_NAVIC_L5,false), nmeaArraystr); + + EXIT_LOG(%d, 0); +} diff --git a/gps/utils/loc_nmea.h b/gps/utils/loc_nmea.h new file mode 100644 index 0000000..c6c83db --- /dev/null +++ b/gps/utils/loc_nmea.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2012-2013, 2015-2017 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. + * + */ + +#ifndef LOC_ENG_NMEA_H +#define LOC_ENG_NMEA_H + +#include <gps_extended.h> +#include <vector> +#include <string> +#define NMEA_SENTENCE_MAX_LENGTH 200 + +/** gnss datum type */ +#define LOC_GNSS_DATUM_WGS84 0 +#define LOC_GNSS_DATUM_PZ90 1 + +/* len of semi major axis of ref ellips*/ +#define MAJA (6378137.0) +/* flattening coef of ref ellipsoid*/ +#define FLAT (1.0/298.2572235630) +/* 1st eccentricity squared*/ +#define ESQR (FLAT*(2.0 - FLAT)) +/*1 minus eccentricity squared*/ +#define OMES (1.0 - ESQR) +#define MILARCSEC2RAD (4.848136811095361e-09) +/*semi major axis */ +#define C_PZ90A (6378136.0) +/*semi minor axis */ +#define C_PZ90B (6356751.3618) +/* Transformation from WGS84 to PZ90 + * Cx,Cy,Cz,Rs,Rx,Ry,Rz,C_SYS_A,C_SYS_B*/ +const double DatumConstFromWGS84[9] = + {+0.003, +0.001, 0.000, (1.0+(0.000*1E-6)), (-0.019*MILARCSEC2RAD), + (+0.042*MILARCSEC2RAD), (-0.002*MILARCSEC2RAD), C_PZ90A, C_PZ90B}; + +/** Represents a LTP*/ +typedef struct { + double lat; + double lon; + double alt; +} LocLla; + +/** Represents a ECEF*/ +typedef struct { + double X; + double Y; + double Z; +} LocEcef; + +void loc_nmea_generate_sv(const GnssSvNotification &svNotify, + std::vector<std::string> &nmeaArraystr); + +void loc_nmea_generate_pos(const UlpLocation &location, + const GpsLocationExtended &locationExtended, + const LocationSystemInfo &systemInfo, + unsigned char generate_nmea, + std::vector<std::string> &nmeaArraystr); + +#define DEBUG_NMEA_MINSIZE 6 +#define DEBUG_NMEA_MAXSIZE 4096 +inline bool loc_nmea_is_debug(const char* nmea, int length) { + return ((nullptr != nmea) && + (length >= DEBUG_NMEA_MINSIZE) && (length <= DEBUG_NMEA_MAXSIZE) && + (nmea[0] == '$') && (nmea[1] == 'P') && (nmea[2] == 'Q') && (nmea[3] == 'W')); +} + +#endif // LOC_ENG_NMEA_H diff --git a/gps/utils/loc_target.cpp b/gps/utils/loc_target.cpp new file mode 100644 index 0000000..f6fd728 --- /dev/null +++ b/gps/utils/loc_target.cpp @@ -0,0 +1,210 @@ +/* Copyright (c) 2012-2015, 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. + * + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <log_util.h> +#include "loc_target.h" +#include "loc_log.h" +#include <loc_pla.h> + +#define APQ8064_ID_1 "109" +#define APQ8064_ID_2 "153" +#define MPQ8064_ID_1 "130" +#define MSM8930_ID_1 "142" +#define MSM8930_ID_2 "116" +#define APQ8030_ID_1 "157" +#define APQ8074_ID_1 "184" + +#define LINE_LEN 100 +#define STR_LIQUID "Liquid" +#define STR_SURF "Surf" +#define STR_MTP "MTP" +#define STR_APQ "apq" +#define STR_SDC "sdc" // alternative string for APQ targets +#define STR_QCS "qcs" // string for Gen9 APQ targets +#define STR_MSM "msm" +#define STR_SDM "sdm" // alternative string for MSM targets +#define STR_APQ_NO_WGR "baseband_apq_nowgr" +#define STR_AUTO "auto" +#define IS_STR_END(c) ((c) == '\0' || (c) == '\n' || (c) == '\r') +#define LENGTH(s) (sizeof(s) - 1) +#define GPS_CHECK_NO_ERROR 0 +#define GPS_CHECK_NO_GPS_HW 1 + +static unsigned int gTarget = (unsigned int)-1; + +static int read_a_line(const char * file_path, char * line, int line_size) +{ + FILE *fp; + int result = 0; + + * line = '\0'; + fp = fopen(file_path, "r" ); + if( fp == NULL ) { + LOC_LOGE("open failed: %s: %s\n", file_path, strerror(errno)); + result = -1; + } else { + int len; + fgets(line, line_size, fp); + len = strlen(line); + len = len < line_size - 1? len : line_size - 1; + line[len] = '\0'; + LOC_LOGD("cat %s: %s", file_path, line); + fclose(fp); + } + return result; +} + +/*The character array passed to this function should have length + of atleast PROPERTY_VALUE_MAX*/ +void loc_get_target_baseband(char *baseband, int array_length) +{ + if(baseband && (array_length >= PROPERTY_VALUE_MAX)) { + property_get("ro.baseband", baseband, ""); + LOC_LOGD("%s:%d]: Baseband: %s\n", __func__, __LINE__, baseband); + } + else { + LOC_LOGE("%s:%d]: NULL parameter or array length less than PROPERTY_VALUE_MAX\n", + __func__, __LINE__); + } +} + +/*The character array passed to this function should have length + of atleast PROPERTY_VALUE_MAX*/ +void loc_get_platform_name(char *platform_name, int array_length) +{ + if(platform_name && (array_length >= PROPERTY_VALUE_MAX)) { + property_get("ro.board.platform", platform_name, ""); + LOC_LOGD("%s:%d]: Target name: %s\n", __func__, __LINE__, platform_name); + } + else { + LOC_LOGE("%s:%d]: Null parameter or array length less than PROPERTY_VALUE_MAX\n", + __func__, __LINE__); + } +} + +/*The character array passed to this function should have length + of atleast PROPERTY_VALUE_MAX*/ +void loc_get_auto_platform_name(char *platform_name, int array_length) +{ + if(platform_name && (array_length >= PROPERTY_VALUE_MAX)) { + property_get("ro.hardware.type", platform_name, ""); + LOC_LOGD("%s:%d]: Autoplatform name: %s\n", __func__, __LINE__, platform_name); + } + else { + LOC_LOGE("%s:%d]: Null parameter or array length less than PROPERTY_VALUE_MAX\n", + __func__, __LINE__); + } +} + +unsigned int loc_get_target(void) +{ + if (gTarget != (unsigned int)-1) + return gTarget; + + static const char hw_platform[] = "/sys/devices/soc0/hw_platform"; + static const char id[] = "/sys/devices/soc0/soc_id"; + static const char hw_platform_dep[] = + "/sys/devices/system/soc/soc0/hw_platform"; + static const char id_dep[] = "/sys/devices/system/soc/soc0/id"; + static const char mdm[] = "/target"; // mdm target we are using + + char rd_hw_platform[LINE_LEN]; + char rd_id[LINE_LEN]; + char rd_mdm[LINE_LEN]; + char baseband[LINE_LEN]; + char rd_auto_platform[LINE_LEN]; + + loc_get_target_baseband(baseband, sizeof(baseband)); + + if (!access(hw_platform, F_OK)) { + read_a_line(hw_platform, rd_hw_platform, LINE_LEN); + } else { + read_a_line(hw_platform_dep, rd_hw_platform, LINE_LEN); + } + if (!access(id, F_OK)) { + read_a_line(id, rd_id, LINE_LEN); + } else { + read_a_line(id_dep, rd_id, LINE_LEN); + } + + /*check automotive platform*/ + loc_get_auto_platform_name(rd_auto_platform, sizeof(rd_auto_platform)); + if( !memcmp(rd_auto_platform, STR_AUTO, LENGTH(STR_AUTO)) ) + { + gTarget = TARGET_AUTO; + goto detected; + } + + if( !memcmp(baseband, STR_APQ_NO_WGR, LENGTH(STR_APQ_NO_WGR)) ){ + + gTarget = TARGET_NO_GNSS; + goto detected; + } + + if( !memcmp(baseband, STR_APQ, LENGTH(STR_APQ)) || + !memcmp(baseband, STR_SDC, LENGTH(STR_SDC)) || + !memcmp(baseband, STR_QCS, LENGTH(STR_QCS)) ) { + + if( !memcmp(rd_id, MPQ8064_ID_1, LENGTH(MPQ8064_ID_1)) + && IS_STR_END(rd_id[LENGTH(MPQ8064_ID_1)]) ) + gTarget = TARGET_NO_GNSS; + else + gTarget = TARGET_APQ_SA; + } else if (((!memcmp(rd_hw_platform, STR_LIQUID, LENGTH(STR_LIQUID)) + && IS_STR_END(rd_hw_platform[LENGTH(STR_LIQUID)])) || + (!memcmp(rd_hw_platform, STR_SURF, LENGTH(STR_SURF)) + && IS_STR_END(rd_hw_platform[LENGTH(STR_SURF)])) || + (!memcmp(rd_hw_platform, STR_MTP, LENGTH(STR_MTP)) + && IS_STR_END(rd_hw_platform[LENGTH(STR_MTP)]))) && + !read_a_line( mdm, rd_mdm, LINE_LEN)) { + gTarget = TARGET_MDM; + } else if( (!memcmp(rd_id, MSM8930_ID_1, LENGTH(MSM8930_ID_1)) + && IS_STR_END(rd_id[LENGTH(MSM8930_ID_1)])) || + (!memcmp(rd_id, MSM8930_ID_2, LENGTH(MSM8930_ID_2)) + && IS_STR_END(rd_id[LENGTH(MSM8930_ID_2)])) ) { + gTarget = TARGET_MSM_NO_SSC; + } else if ( !memcmp(baseband, STR_MSM, LENGTH(STR_MSM)) || + !memcmp(baseband, STR_SDM, LENGTH(STR_SDM)) ) { + gTarget = TARGET_DEFAULT; + } else { + gTarget = TARGET_UNKNOWN; + } + +detected: + LOC_LOGW("HAL: %s returned %d", __FUNCTION__, gTarget); + return gTarget; +} diff --git a/gps/utils/loc_target.h b/gps/utils/loc_target.h new file mode 100644 index 0000000..172b475 --- /dev/null +++ b/gps/utils/loc_target.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2012-2014, 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. + * + */ +#ifndef LOC_TARGET_H +#define LOC_TARGET_H +#define TARGET_SET(gnss,ssc) ( (gnss<<1)|ssc ) +#define TARGET_DEFAULT TARGET_SET(GNSS_MSM, HAS_SSC) +#define TARGET_MDM TARGET_SET(GNSS_MDM, HAS_SSC) +#define TARGET_APQ_SA TARGET_SET(GNSS_GSS, NO_SSC) +#define TARGET_NO_GNSS TARGET_SET(GNSS_NONE, NO_SSC) +#define TARGET_MSM_NO_SSC TARGET_SET(GNSS_MSM, NO_SSC) +#define TARGET_AUTO TARGET_SET(GNSS_AUTO, NO_SSC) +#define TARGET_UNKNOWN TARGET_SET(GNSS_UNKNOWN, NO_SSC) +#define getTargetGnssType(target) (target>>1) + +#ifdef __cplusplus +extern "C" +{ +#endif + +unsigned int loc_get_target(void); + +/*The character array passed to this function should have length + of atleast PROPERTY_VALUE_MAX*/ +void loc_get_target_baseband(char *baseband, int array_length); +/*The character array passed to this function should have length + of atleast PROPERTY_VALUE_MAX*/ +void loc_get_platform_name(char *platform_name, int array_length); +/*The character array passed to this function should have length + of atleast PROPERTY_VALUE_MAX*/ +void loc_get_auto_platform_name(char *platform_name, int array_length); + +/* Please remember to update 'target_name' in loc_log.cpp, + if do any changes to this enum. */ +typedef enum { + GNSS_NONE = 0, + GNSS_MSM, + GNSS_GSS, + GNSS_MDM, + GNSS_AUTO, + GNSS_UNKNOWN +}GNSS_TARGET; + +typedef enum { + NO_SSC = 0, + HAS_SSC +}SSC_TYPE; + +#ifdef __cplusplus +} +#endif + +#endif /*LOC_TARGET_H*/ diff --git a/gps/utils/loc_timer.h b/gps/utils/loc_timer.h new file mode 100644 index 0000000..fff0c46 --- /dev/null +++ b/gps/utils/loc_timer.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2013,2015 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. + * + */ + +#ifndef __LOC_DELAY_H__ +#define __LOC_DELAY_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +#include <stddef.h> +#include <stdint.h> +#include <loc_pla.h> +/* + user_data: client context pointer, passthrough. Originally received + from calling client when loc_timer_start() is called. + result: 0 if timer successfully timed out; else timer failed. +*/ +typedef void (*loc_timer_callback)(void *user_data, int32_t result); + + +/* + delay_msec: timeout value for the timer. + cb_func: callback function pointer, implemented by client. + Can not be NULL. + user_data: client context pointer, passthrough. Will be + returned when loc_timer_callback() is called. + wakeOnExpire: true if to wake up CPU (if sleeping) upon timer + expiration and notify the client. + false if to wait until next time CPU wakes up (if + sleeping) and then notify the client. + Returns the handle, which can be used to stop the timer + NULL, if timer start fails (e.g. if cb_func is NULL). +*/ +void* loc_timer_start(uint64_t delay_msec, + loc_timer_callback cb_func, + void *user_data, + bool wake_on_expire=false); + +/* + handle becomes invalid upon the return of the callback +*/ +void loc_timer_stop(void*& handle); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif //__LOC_DELAY_H__ diff --git a/gps/utils/log_util.h b/gps/utils/log_util.h new file mode 100644 index 0000000..ed7e19e --- /dev/null +++ b/gps/utils/log_util.h @@ -0,0 +1,203 @@ +/* Copyright (c) 2011-2014 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. + * + */ + +#ifndef __LOG_UTIL_H__ +#define __LOG_UTIL_H__ + +#if defined (USE_ANDROID_LOGGING) || defined (ANDROID) +// Android and LE targets with logcat support +#include <utils/Log.h> + +#elif defined (USE_GLIB) +// LE targets with no logcat support +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> + +#ifndef LOG_TAG +#define LOG_TAG "GPS_UTILS" +#endif /* LOG_TAG */ + +// LE targets with no logcat support +#ifdef FEATURE_EXTERNAL_AP +#include <syslog.h> +#define ALOGE(...) syslog(LOG_ERR, "LOC_LOGE: " __VA_ARGS__); +#define ALOGW(...) syslog(LOG_WARNING, "LOC_LOGW: " __VA_ARGS__); +#define ALOGI(...) syslog(LOG_NOTICE, "LOC_LOGI: " __VA_ARGS__); +#define ALOGD(...) syslog(LOG_DEBUG, "LOC_LOGD: " __VA_ARGS__); +#define ALOGV(...) syslog(LOG_NOTICE, "LOC_LOGV: " __VA_ARGS__); +#else /* FEATURE_EXTERNAL_AP */ +#define TS_PRINTF(format, x...) \ +{ \ + struct timeval tv; \ + struct timezone tz; \ + int hh, mm, ss; \ + gettimeofday(&tv, &tz); \ + hh = tv.tv_sec/3600%24; \ + mm = (tv.tv_sec%3600)/60; \ + ss = tv.tv_sec%60; \ + fprintf(stdout,"%02d:%02d:%02d.%06ld]" format "\n", hh, mm, ss, tv.tv_usec, ##x); \ +} + +#define ALOGE(format, x...) TS_PRINTF("E/%s (%d): " format , LOG_TAG, getpid(), ##x) +#define ALOGW(format, x...) TS_PRINTF("W/%s (%d): " format , LOG_TAG, getpid(), ##x) +#define ALOGI(format, x...) TS_PRINTF("I/%s (%d): " format , LOG_TAG, getpid(), ##x) +#define ALOGD(format, x...) TS_PRINTF("D/%s (%d): " format , LOG_TAG, getpid(), ##x) +#define ALOGV(format, x...) TS_PRINTF("V/%s (%d): " format , LOG_TAG, getpid(), ##x) +#endif /* FEATURE_EXTERNAL_AP */ + +#endif /* #if defined (USE_ANDROID_LOGGING) || defined (ANDROID) */ + +#ifdef __cplusplus +extern "C" +{ +#endif +/*============================================================================= + * + * LOC LOGGER TYPE DECLARATION + * + *============================================================================*/ +/* LOC LOGGER */ +typedef struct loc_logger_s +{ + unsigned long DEBUG_LEVEL; + unsigned long TIMESTAMP; +} loc_logger_s_type; + +/*============================================================================= + * + * EXTERNAL DATA + * + *============================================================================*/ +extern loc_logger_s_type loc_logger; + +// Logging Improvements +extern const char *loc_logger_boolStr[]; + +extern const char *boolStr[]; +extern const char VOID_RET[]; +extern const char FROM_AFW[]; +extern const char TO_MODEM[]; +extern const char FROM_MODEM[]; +extern const char TO_AFW[]; +extern const char EXIT_TAG[]; +extern const char ENTRY_TAG[]; +extern const char EXIT_ERROR_TAG[]; + +/*============================================================================= + * + * MODULE EXPORTED FUNCTIONS + * + *============================================================================*/ +extern void loc_logger_init(unsigned long debug, unsigned long timestamp); +extern char* get_timestamp(char* str, unsigned long buf_size); + +#ifndef DEBUG_DMN_LOC_API + +/* LOGGING MACROS */ +/*loc_logger.DEBUG_LEVEL is initialized to 0xff in loc_cfg.cpp + if that value remains unchanged, it means gps.conf did not + provide a value and we default to the initial value to use + Android's logging levels*/ +#define IF_LOC_LOGE if((loc_logger.DEBUG_LEVEL >= 1) && (loc_logger.DEBUG_LEVEL <= 5)) +#define IF_LOC_LOGW if((loc_logger.DEBUG_LEVEL >= 2) && (loc_logger.DEBUG_LEVEL <= 5)) +#define IF_LOC_LOGI if((loc_logger.DEBUG_LEVEL >= 3) && (loc_logger.DEBUG_LEVEL <= 5)) +#define IF_LOC_LOGD if((loc_logger.DEBUG_LEVEL >= 4) && (loc_logger.DEBUG_LEVEL <= 5)) +#define IF_LOC_LOGV if((loc_logger.DEBUG_LEVEL >= 5) && (loc_logger.DEBUG_LEVEL <= 5)) + +#define LOC_LOGE(...) IF_LOC_LOGE { ALOGE(__VA_ARGS__); } +#define LOC_LOGW(...) IF_LOC_LOGW { ALOGW(__VA_ARGS__); } +#define LOC_LOGI(...) IF_LOC_LOGI { ALOGI(__VA_ARGS__); } +#define LOC_LOGD(...) IF_LOC_LOGD { ALOGD(__VA_ARGS__); } +#define LOC_LOGV(...) IF_LOC_LOGV { ALOGV(__VA_ARGS__); } + +#else /* DEBUG_DMN_LOC_API */ + +#define LOC_LOGE(...) ALOGE(__VA_ARGS__) +#define LOC_LOGW(...) ALOGW(__VA_ARGS__) +#define LOC_LOGI(...) ALOGI(__VA_ARGS__) +#define LOC_LOGD(...) ALOGD(__VA_ARGS__) +#define LOC_LOGV(...) ALOGV(__VA_ARGS__) + +#endif /* DEBUG_DMN_LOC_API */ + +/*============================================================================= + * + * LOGGING IMPROVEMENT MACROS + * + *============================================================================*/ +#define LOG_(LOC_LOG, ID, WHAT, SPEC, VAL) \ + do { \ + if (loc_logger.TIMESTAMP) { \ + char ts[32]; \ + LOC_LOG("[%s] %s %s line %d " #SPEC, \ + get_timestamp(ts, sizeof(ts)), ID, WHAT, __LINE__, VAL); \ + } else { \ + LOC_LOG("%s %s line %d " #SPEC, \ + ID, WHAT, __LINE__, VAL); \ + } \ + } while(0) + +#define LOC_LOG_HEAD(fmt) "%s:%d] " fmt +#define LOC_LOGv(fmt,...) LOC_LOGV(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define LOC_LOGw(fmt,...) LOC_LOGW(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define LOC_LOGi(fmt,...) LOC_LOGI(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define LOC_LOGd(fmt,...) LOC_LOGD(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define LOC_LOGe(fmt,...) LOC_LOGE(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) + +#define LOG_I(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGI, ID, WHAT, SPEC, VAL) +#define LOG_V(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGV, ID, WHAT, SPEC, VAL) +#define LOG_E(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGE, ID, WHAT, SPEC, VAL) + +#define ENTRY_LOG() LOG_V(ENTRY_TAG, __FUNCTION__, %s, "") +#define EXIT_LOG(SPEC, VAL) LOG_V(EXIT_TAG, __FUNCTION__, SPEC, VAL) +#define EXIT_LOG_WITH_ERROR(SPEC, VAL) \ + if (VAL != 0) { \ + LOG_E(EXIT_ERROR_TAG, __FUNCTION__, SPEC, VAL); \ + } else { \ + LOG_V(EXIT_TAG, __FUNCTION__, SPEC, VAL); \ + } + + +// Used for logging callflow from Android Framework +#define ENTRY_LOG_CALLFLOW() LOG_I(FROM_AFW, __FUNCTION__, %s, "") +// Used for logging callflow to Modem +#define EXIT_LOG_CALLFLOW(SPEC, VAL) LOG_I(TO_MODEM, __FUNCTION__, SPEC, VAL) +// Used for logging callflow from Modem(TO_MODEM, __FUNCTION__, %s, "") +#define MODEM_LOG_CALLFLOW(SPEC, VAL) LOG_I(FROM_MODEM, __FUNCTION__, SPEC, VAL) +// Used for logging callflow to Android Framework +#define CALLBACK_LOG_CALLFLOW(CB, SPEC, VAL) LOG_I(TO_AFW, CB, SPEC, VAL) + +#ifdef __cplusplus +} +#endif + +#endif // __LOG_UTIL_H__ diff --git a/gps/utils/msg_q.c b/gps/utils/msg_q.c new file mode 100644 index 0000000..2d49b4a --- /dev/null +++ b/gps/utils/msg_q.c @@ -0,0 +1,378 @@ +/* Copyright (c) 2011-2012, 2014, 2017 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. + */ + +#define LOG_TAG "LocSvc_utils_q" +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <loc_pla.h> +#include <log_util.h> +#include "linked_list.h" +#include "msg_q.h" + +typedef struct msg_q { + void* msg_list; /* Linked list to store information */ + pthread_cond_t list_cond; /* Condition variable for waiting on msg queue */ + pthread_mutex_t list_mutex; /* Mutex for exclusive access to message queue */ + int unblocked; /* Has this message queue been unblocked? */ +} msg_q; + +/*=========================================================================== +FUNCTION convert_linked_list_err_type + +DESCRIPTION + Converts from one set of enum values to another. + + linked_list_val: Value to convert to msg_q_enum_type + +DEPENDENCIES + N/A + +RETURN VALUE + Corresponding linked_list_enum_type in msg_q_enum_type + +SIDE EFFECTS + N/A + +===========================================================================*/ +static msq_q_err_type convert_linked_list_err_type(linked_list_err_type linked_list_val) +{ + switch( linked_list_val ) + { + case eLINKED_LIST_SUCCESS: + return eMSG_Q_SUCCESS; + case eLINKED_LIST_INVALID_PARAMETER: + return eMSG_Q_INVALID_PARAMETER; + case eLINKED_LIST_INVALID_HANDLE: + return eMSG_Q_INVALID_HANDLE; + case eLINKED_LIST_UNAVAILABLE_RESOURCE: + return eMSG_Q_UNAVAILABLE_RESOURCE; + case eLINKED_LIST_INSUFFICIENT_BUFFER: + return eMSG_Q_INSUFFICIENT_BUFFER; + + case eLINKED_LIST_FAILURE_GENERAL: + default: + return eMSG_Q_FAILURE_GENERAL; + } +} + +/* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */ + +/*=========================================================================== + + FUNCTION: msg_q_init + + ===========================================================================*/ +msq_q_err_type msg_q_init(void** msg_q_data) +{ + if( msg_q_data == NULL ) + { + LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_PARAMETER; + } + + msg_q* tmp_msg_q; + tmp_msg_q = (msg_q*)calloc(1, sizeof(msg_q)); + if( tmp_msg_q == NULL ) + { + LOC_LOGE("%s: Unable to allocate space for message queue!\n", __FUNCTION__); + return eMSG_Q_FAILURE_GENERAL; + } + + if( linked_list_init(&tmp_msg_q->msg_list) != 0 ) + { + LOC_LOGE("%s: Unable to initialize storage list!\n", __FUNCTION__); + free(tmp_msg_q); + return eMSG_Q_FAILURE_GENERAL; + } + + if( pthread_mutex_init(&tmp_msg_q->list_mutex, NULL) != 0 ) + { + LOC_LOGE("%s: Unable to initialize list mutex!\n", __FUNCTION__); + linked_list_destroy(&tmp_msg_q->msg_list); + free(tmp_msg_q); + return eMSG_Q_FAILURE_GENERAL; + } + + if( pthread_cond_init(&tmp_msg_q->list_cond, NULL) != 0 ) + { + LOC_LOGE("%s: Unable to initialize msg q cond var!\n", __FUNCTION__); + linked_list_destroy(&tmp_msg_q->msg_list); + pthread_mutex_destroy(&tmp_msg_q->list_mutex); + free(tmp_msg_q); + return eMSG_Q_FAILURE_GENERAL; + } + + tmp_msg_q->unblocked = 0; + + *msg_q_data = tmp_msg_q; + + return eMSG_Q_SUCCESS; +} + +/*=========================================================================== + + FUNCTION: msg_q_init2 + + ===========================================================================*/ +const void* msg_q_init2() +{ + void* q = NULL; + if (eMSG_Q_SUCCESS != msg_q_init(&q)) { + q = NULL; + } + return q; +} + +/*=========================================================================== + + FUNCTION: msg_q_destroy + + ===========================================================================*/ +msq_q_err_type msg_q_destroy(void** msg_q_data) +{ + if( msg_q_data == NULL ) + { + LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_HANDLE; + } + + msg_q* p_msg_q = (msg_q*)*msg_q_data; + + linked_list_destroy(&p_msg_q->msg_list); + pthread_mutex_destroy(&p_msg_q->list_mutex); + pthread_cond_destroy(&p_msg_q->list_cond); + + p_msg_q->unblocked = 0; + + free(*msg_q_data); + *msg_q_data = NULL; + + return eMSG_Q_SUCCESS; +} + +/*=========================================================================== + + FUNCTION: msg_q_snd + + ===========================================================================*/ +msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*)) +{ + msq_q_err_type rv; + if( msg_q_data == NULL ) + { + LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_HANDLE; + } + if( msg_obj == NULL ) + { + LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_PARAMETER; + } + + msg_q* p_msg_q = (msg_q*)msg_q_data; + + pthread_mutex_lock(&p_msg_q->list_mutex); + LOC_LOGV("%s: Sending message with handle = %p\n", __FUNCTION__, msg_obj); + + if( p_msg_q->unblocked ) + { + LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__); + pthread_mutex_unlock(&p_msg_q->list_mutex); + return eMSG_Q_UNAVAILABLE_RESOURCE; + } + + rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc)); + + /* Show data is in the message queue. */ + pthread_cond_signal(&p_msg_q->list_cond); + + pthread_mutex_unlock(&p_msg_q->list_mutex); + + LOC_LOGV("%s: Finished Sending message with handle = %p\n", __FUNCTION__, msg_obj); + + return rv; +} + +/*=========================================================================== + + FUNCTION: msg_q_rcv + + ===========================================================================*/ +msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj) +{ + msq_q_err_type rv; + if( msg_q_data == NULL ) + { + LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_HANDLE; + } + + if( msg_obj == NULL ) + { + LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_PARAMETER; + } + + msg_q* p_msg_q = (msg_q*)msg_q_data; + + pthread_mutex_lock(&p_msg_q->list_mutex); + + if( p_msg_q->unblocked ) + { + LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__); + pthread_mutex_unlock(&p_msg_q->list_mutex); + return eMSG_Q_UNAVAILABLE_RESOURCE; + } + + /* Wait for data in the message queue */ + while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked ) + { + pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex); + } + + rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj)); + + pthread_mutex_unlock(&p_msg_q->list_mutex); + + LOC_LOGV("%s: Received message %p rv = %d\n", __FUNCTION__, *msg_obj, rv); + + return rv; +} + +/*=========================================================================== + + FUNCTION: msg_q_rmv + + ===========================================================================*/ +msq_q_err_type msg_q_rmv(void* msg_q_data, void** msg_obj) +{ + msq_q_err_type rv; + if (msg_q_data == NULL) { + LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_HANDLE; + } + + if (msg_obj == NULL) { + LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_PARAMETER; + } + + msg_q* p_msg_q = (msg_q*)msg_q_data; + + pthread_mutex_lock(&p_msg_q->list_mutex); + + if (p_msg_q->unblocked) { + LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__); + pthread_mutex_unlock(&p_msg_q->list_mutex); + return eMSG_Q_UNAVAILABLE_RESOURCE; + } + + if (linked_list_empty(p_msg_q->msg_list)) { + LOC_LOGW("%s: list is empty !!\n", __FUNCTION__); + pthread_mutex_unlock(&p_msg_q->list_mutex); + return eLINKED_LIST_EMPTY; + } + + rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj)); + + pthread_mutex_unlock(&p_msg_q->list_mutex); + + LOC_LOGV("%s: Removed message %p rv = %d\n", __FUNCTION__, *msg_obj, rv); + + return rv; +} + + + +/*=========================================================================== + + FUNCTION: msg_q_flush + + ===========================================================================*/ +msq_q_err_type msg_q_flush(void* msg_q_data) +{ + msq_q_err_type rv; + if ( msg_q_data == NULL ) + { + LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_HANDLE; + } + + msg_q* p_msg_q = (msg_q*)msg_q_data; + + LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__); + + pthread_mutex_lock(&p_msg_q->list_mutex); + + /* Remove all elements from the list */ + rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list)); + + pthread_mutex_unlock(&p_msg_q->list_mutex); + + LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__); + + return rv; +} + +/*=========================================================================== + + FUNCTION: msg_q_unblock + + ===========================================================================*/ +msq_q_err_type msg_q_unblock(void* msg_q_data) +{ + if ( msg_q_data == NULL ) + { + LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__); + return eMSG_Q_INVALID_HANDLE; + } + + msg_q* p_msg_q = (msg_q*)msg_q_data; + pthread_mutex_lock(&p_msg_q->list_mutex); + + if( p_msg_q->unblocked ) + { + LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__); + pthread_mutex_unlock(&p_msg_q->list_mutex); + return eMSG_Q_UNAVAILABLE_RESOURCE; + } + + LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__); + /* Unblocking message queue */ + p_msg_q->unblocked = 1; + + /* Allow all the waiters to wake up */ + pthread_cond_broadcast(&p_msg_q->list_cond); + + pthread_mutex_unlock(&p_msg_q->list_mutex); + + LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__); + + return eMSG_Q_SUCCESS; +} diff --git a/gps/utils/msg_q.h b/gps/utils/msg_q.h new file mode 100644 index 0000000..16df494 --- /dev/null +++ b/gps/utils/msg_q.h @@ -0,0 +1,230 @@ +/* Copyright (c) 2011, 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. + */ + +#ifndef __MSG_Q_H__ +#define __MSG_Q_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <stdlib.h> + +/** Linked List Return Codes */ +typedef enum +{ + eMSG_Q_SUCCESS = 0, + /**< Request was successful. */ + eMSG_Q_FAILURE_GENERAL = -1, + /**< Failed because of a general failure. */ + eMSG_Q_INVALID_PARAMETER = -2, + /**< Failed because the request contained invalid parameters. */ + eMSG_Q_INVALID_HANDLE = -3, + /**< Failed because an invalid handle was specified. */ + eMSG_Q_UNAVAILABLE_RESOURCE = -4, + /**< Failed because an there were not enough resources. */ + eMSG_Q_INSUFFICIENT_BUFFER = -5, + /**< Failed because an the supplied buffer was too small. */ +}msq_q_err_type; + +/*=========================================================================== +FUNCTION msg_q_init + +DESCRIPTION + Initializes internal structures for message queue. + + msg_q_data: pointer to an opaque Q handle to be returned; NULL if fails + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +msq_q_err_type msg_q_init(void** msg_q_data); + +/*=========================================================================== +FUNCTION msg_q_init2 + +DESCRIPTION + Initializes internal structures for message queue. + +DEPENDENCIES + N/A + +RETURN VALUE + opaque handle to the Q created; NULL if create fails + +SIDE EFFECTS + N/A + +===========================================================================*/ +const void* msg_q_init2(); + +/*=========================================================================== +FUNCTION msg_q_destroy + +DESCRIPTION + Releases internal structures for message queue. + + msg_q_data: State of message queue to be released. + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +msq_q_err_type msg_q_destroy(void** msg_q_data); + +/*=========================================================================== +FUNCTION msg_q_snd + +DESCRIPTION + Sends data to the message queue. The passed in data pointer + is not modified or freed. Passed in msg_obj is expected to live throughout + the use of the msg_q (i.e. data is not allocated internally) + + msg_q_data: Message Queue to add the element to. + msgp: Pointer to data to add into message queue. + dealloc: Function used to deallocate memory for this element. Pass NULL + if you do not want data deallocated during a flush operation + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*)); + +/*=========================================================================== +FUNCTION msg_q_rcv + +DESCRIPTION + Retrieves data from the message queue. msg_obj is the oldest message received + and pointer is simply removed from message queue. + + msg_q_data: Message Queue to copy data from into msgp. + msg_obj: Pointer to space to copy msg_q contents to. + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj); + +/*=========================================================================== +FUNCTION msg_q_rmv + +DESCRIPTION + Remove data from the message queue. msg_obj is the oldest message received + and pointer is simply removed from message queue. + + msg_q_data: Message Queue to copy data from into msgp. + msg_obj: Pointer to space to copy msg_q contents to. + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +msq_q_err_type msg_q_rmv(void* msg_q_data, void** msg_obj); + + +/*=========================================================================== +FUNCTION msg_q_flush + +DESCRIPTION + Function removes all elements from the message queue. + + msg_q_data: Message Queue to remove elements from. + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +msq_q_err_type msg_q_flush(void* msg_q_data); + +/*=========================================================================== +FUNCTION msg_q_unblock + +DESCRIPTION + This function will stop use of the message queue. All waiters will wake up + and likely receive nothing from the queue resulting in a negative return + value. The message queue can no longer be used until it is destroyed + and initialized again after calling this function. + + msg_q_data: Message queue to unblock. + +DEPENDENCIES + N/A + +RETURN VALUE + Look at error codes above. + +SIDE EFFECTS + N/A + +===========================================================================*/ +msq_q_err_type msg_q_unblock(void* msg_q_data); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MSG_Q_H__ */ |