From e1e6966c77655c64f089c5b4a3c49912e39f8257 Mon Sep 17 00:00:00 2001 From: Khurshid Date: Fri, 27 Sep 2013 10:27:48 -0600 Subject: Android_System_ANT-HAL_1-6-1 --- src/bluez_hci/ant_native_hci.c | 1 + src/common/inc/ant_version.h | 2 +- src/vfs/ant_rx_chardev.c | 56 +++++++++++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/bluez_hci/ant_native_hci.c b/src/bluez_hci/ant_native_hci.c index c2c453f..55cde44 100644 --- a/src/bluez_hci/ant_native_hci.c +++ b/src/bluez_hci/ant_native_hci.c @@ -798,6 +798,7 @@ ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) { if(currentTime < endTime) { + nanosleep((struct timespec[]){{0, 50000000}}, NULL); ANT_DEBUG_V("Retrying. Current time = %d. " "End time = %d", (int)currentTime, (int)endTime); diff --git a/src/common/inc/ant_version.h b/src/common/inc/ant_version.h index a682134..0b8988b 100644 --- a/src/common/inc/ant_version.h +++ b/src/common/inc/ant_version.h @@ -21,7 +21,7 @@ #define LIBANT_STACK_MAJOR "1" #define LIBANT_STACK_MINOR "6" -#define LIBANT_STACK_INCRE "0" +#define LIBANT_STACK_INCRE "1" #endif // __ANT_VERSION_H diff --git a/src/vfs/ant_rx_chardev.c b/src/vfs/ant_rx_chardev.c index 2f0cc33..b38757f 100644 --- a/src/vfs/ant_rx_chardev.c +++ b/src/vfs/ant_rx_chardev.c @@ -53,8 +53,32 @@ static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE]; static int iRxBufferLength[NUM_ANT_CHANNELS] = {0, 0}; #endif // +// Defines for use with the poll() call +#define EVENT_DATA_AVAILABLE (POLLIN|POLLRDNORM) +#define EVENT_DISABLE (POLLHUP) +#define EVENT_HARD_RESET (POLLERR|POLLPRI|POLLRDHUP) + +#define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_DISABLE|EVENT_HARD_RESET) + int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo); +/* + * Function to check that all given flags are set in a particular value. + * Designed for use with the revents field of pollfds filled out by poll(). + * + * Parameters: + * - value: The value that will be checked to contain all flags. + * - flags: Bitwise-or of the flags that value should be checked for. + * + * Returns: + * - true IFF all the bits that are set in 'flags' are also set in 'value' + */ +ANT_BOOL areAllFlagsSet(short value, short flags) +{ + value &= flags; + return (value == flags); +} + /* * This thread waits for ANT messages from a VFS file. */ @@ -70,7 +94,7 @@ void *fnRxThread(void *ant_rx_thread_info) stRxThreadInfo = (ant_rx_thread_info_t *)ant_rx_thread_info; for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { astPollFd[eChannel].fd = stRxThreadInfo->astChannels[eChannel].iFd; - astPollFd[eChannel].events = POLLIN | POLLRDNORM; + astPollFd[eChannel].events = EVENTS_TO_LISTEN_FOR; } /* continue running as long as not terminated */ @@ -83,7 +107,7 @@ void *fnRxThread(void *ant_rx_thread_info) ANT_ERROR("read thread exiting, unhandled error: %s", strerror(errno)); } else { for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { - if (astPollFd[eChannel].revents & (POLLERR | POLLPRI | POLLRDHUP)) { + if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_HARD_RESET)) { ANT_ERROR("poll error from %s. exiting rx thread", stRxThreadInfo->astChannels[eChannel].pcDevicePath); /* Chip was reset or other error, only way to recover is to @@ -95,12 +119,21 @@ void *fnRxThread(void *ant_rx_thread_info) } goto reset; - } else if (astPollFd[eChannel].revents & (POLLIN | POLLRDNORM)) { + } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DISABLE)) { + /* chip reported it was disabled, either unexpectedly or due to us closing the file */ + ANT_DEBUG_D( + "poll hang-up from %s. exiting rx thread", stRxThreadInfo->astChannels[eChannel].pcDevicePath); + + // set flag to exit out of Rx Loop + stRxThreadInfo->ucRunThread = 0; + + } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DATA_AVAILABLE)) { ANT_DEBUG_D("data on %s. reading it", stRxThreadInfo->astChannels[eChannel].pcDevicePath); if (readChannelMsg(eChannel, &stRxThreadInfo->astChannels[eChannel]) < 0) { - goto out; + // set flag to exit out of Rx Loop + stRxThreadInfo->ucRunThread = 0; } } else if (astPollFd[eChannel].revents) { ANT_DEBUG_W("unhandled poll result %#x from %s", @@ -111,19 +144,18 @@ void *fnRxThread(void *ant_rx_thread_info) } } -out: - stRxThreadInfo->ucRunThread = 0; - - /* Try to get stEnabledStatusLock. - * if you get it then noone is enabling or disabling - * if you can't get it assume something made you exit */ + /* disable ANT radio if not already disabling */ + // Try to get stEnabledStatusLock. + // if you get it then no one is enabling or disabling + // if you can't get it assume something made you exit ANT_DEBUG_V("try getting stEnabledStatusLock in %s", __FUNCTION__); iMutexLockResult = pthread_mutex_trylock(stRxThreadInfo->pstEnabledStatusLock); if (!iMutexLockResult) { ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); ANT_WARN("rx thread has unexpectedly crashed, cleaning up"); - stRxThreadInfo->stRxThread = 0; /* spoof our handle as closed so we don't - * try to join ourselves in disable */ + + // spoof our handle as closed so we don't try to join ourselves in disable + stRxThreadInfo->stRxThread = 0; if (g_fnStateCallback) { g_fnStateCallback(RADIO_STATUS_DISABLING); -- cgit v1.2.3 From 4d09cf1ee4023c5562a4d3a690d9e8bc24cde4a6 Mon Sep 17 00:00:00 2001 From: Khurshid Date: Tue, 1 Oct 2013 16:45:34 -0600 Subject: Android_System_ANT-HAL_1-6-2 --- src/common/inc/ant_version.h | 2 +- src/vfs/ant_native_chardev.c | 57 +++++++++++++++++++----- src/vfs/ant_rx_chardev.c | 78 ++++++++++++++++++++++++--------- src/vfs/inc/ant_hci_defines.h | 53 ++++++++++++++++++++++ src/vfs/inc/ant_rx_chardev.h | 4 +- src/vfs/prerelease/ant_driver_defines.h | 13 ------ src/vfs/ste/cg29xx/ant_driver_defines.h | 13 ------ 7 files changed, 161 insertions(+), 59 deletions(-) create mode 100644 src/vfs/inc/ant_hci_defines.h diff --git a/src/common/inc/ant_version.h b/src/common/inc/ant_version.h index 0b8988b..21f3660 100644 --- a/src/common/inc/ant_version.h +++ b/src/common/inc/ant_version.h @@ -21,7 +21,7 @@ #define LIBANT_STACK_MAJOR "1" #define LIBANT_STACK_MINOR "6" -#define LIBANT_STACK_INCRE "1" +#define LIBANT_STACK_INCRE "2" #endif // __ANT_VERSION_H diff --git a/src/vfs/ant_native_chardev.c b/src/vfs/ant_native_chardev.c index df209c2..2b49a8c 100644 --- a/src/vfs/ant_native_chardev.c +++ b/src/vfs/ant_native_chardev.c @@ -30,6 +30,9 @@ #include /* for open() */ #include /* For hard reset */ #include +#include /* for uint64_t */ +#include /* For eventfd() */ +#include /* for read(), write(), and close() */ #include "ant_types.h" #include "ant_native.h" @@ -37,7 +40,7 @@ #include "antradio_power.h" #include "ant_rx_chardev.h" -#include "ant_driver_defines.h" +#include "ant_hci_defines.h" #include "ant_log.h" #if ANT_HCI_SIZE_SIZE > 1 @@ -58,6 +61,8 @@ static pthread_mutex_t stFlowControlLock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t stFlowControlCond = PTHREAD_COND_INITIALIZER; ANTNativeANTStateCb g_fnStateCallback; +static const uint64_t EVENT_FD_PLUS_ONE = 1L; + static void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcCharDevName); //////////////////////////////////////////////////////////////////// @@ -69,13 +74,14 @@ static void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcChar // - // // Returns: -// ANT_STATUS_SUCCESS +// ANT_STATUS_SUCCESS if intialize completed, else ANT_STATUS_FAILED // // Psuedocode: /* Set variables to defaults Initialise each supported path to chip -RESULT = ANT_STATUS_SUCCESS +Setup eventfd object. +RESULT = ANT_STATUS_SUCCESS if no problems else ANT_STATUS_FAILED */ //////////////////////////////////////////////////////////////////// ANTStatus ant_init(void) @@ -96,7 +102,16 @@ ANTStatus ant_init(void) ant_channel_init(&stRxThreadInfo.astChannels[DATA_CHANNEL], ANT_DATA_DEVICE_NAME); #endif // Separate data/command paths - status = ANT_STATUS_SUCCESS; + // Make the eventfd. Want it non blocking so that we can easily reset it by reading. + stRxThreadInfo.iRxShutdownEventFd = eventfd(0, EFD_NONBLOCK); + + // Check for error case + if(stRxThreadInfo.iRxShutdownEventFd == -1) + { + ANT_ERROR("ANT init failed. Could not create event fd. Reason: %s", strerror(errno)); + } else { + status = ANT_STATUS_SUCCESS; + } ANT_FUNC_END(); return status; @@ -105,7 +120,7 @@ ANTStatus ant_init(void) //////////////////////////////////////////////////////////////////// // ant_deinit // -// Doesn't actually do anything. +// clean up eventfd object // // Parameters: // - @@ -123,7 +138,12 @@ ANTStatus ant_deinit(void) ANTStatus result_status = ANT_STATUS_FAILED; ANT_FUNC_START(); - result_status = ANT_STATUS_SUCCESS; + if(close(stRxThreadInfo.iRxShutdownEventFd) < 0) + { + ANT_ERROR("Could not close eventfd in deinit. Reason: %s", strerror(errno)); + } else { + result_status = ANT_STATUS_SUCCESS; + } ANT_FUNC_END(); return result_status; @@ -838,6 +858,16 @@ int ant_enable(void) ant_channel_type eChannel; ANT_FUNC_START(); + // Reset the shutdown signal. + uint64_t counter; + ssize_t result = read(stRxThreadInfo.iRxShutdownEventFd, &counter, sizeof(counter)); + // EAGAIN result indicates that the counter was already 0 in non-blocking mode. + if(result < 0 && errno != EAGAIN) + { + ANT_ERROR("Could not clear shutdown signal in enable. Reason: %s", strerror(errno)); + goto out; + } + stRxThreadInfo.ucRunThread = 1; for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { @@ -878,11 +908,14 @@ int ant_disable(void) stRxThreadInfo.ucRunThread = 0; - for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { - ant_disable_channel(&stRxThreadInfo.astChannels[eChannel]); - } - if (stRxThreadInfo.stRxThread != 0) { + ANT_DEBUG_I("Sending shutdown signal to rx thread."); + if(write(stRxThreadInfo.iRxShutdownEventFd, &EVENT_FD_PLUS_ONE, sizeof(EVENT_FD_PLUS_ONE)) < 0) + { + ANT_ERROR("failed to signal rx thread with eventfd. Reason: %s", strerror(errno)); + goto out; + } + ANT_DEBUG_I("Waiting for rx thread to finish."); if (pthread_join(stRxThreadInfo.stRxThread, NULL) < 0) { ANT_ERROR("failed to join rx thread: %s", strerror(errno)); goto out; @@ -891,6 +924,10 @@ int ant_disable(void) ANT_DEBUG_D("rx thread is not running"); } + for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { + ant_disable_channel(&stRxThreadInfo.astChannels[eChannel]); + } + iRet = 0; out: diff --git a/src/vfs/ant_rx_chardev.c b/src/vfs/ant_rx_chardev.c index b38757f..aa51825 100644 --- a/src/vfs/ant_rx_chardev.c +++ b/src/vfs/ant_rx_chardev.c @@ -29,11 +29,12 @@ #include #include #include +#include /* for uint64_t */ #include "ant_types.h" #include "antradio_power.h" #include "ant_rx_chardev.h" -#include "ant_driver_defines.h" +#include "ant_hci_defines.h" #include "ant_log.h" #include "ant_native.h" // ANT_HCI_MAX_MSG_SIZE, ANT_MSG_ID_OFFSET, ANT_MSG_DATA_OFFSET, // ant_radio_enabled_status() @@ -60,6 +61,11 @@ static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE]; #define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_DISABLE|EVENT_HARD_RESET) +// Plus one is for the eventfd shutdown signal. +#define NUM_POLL_FDS (NUM_ANT_CHANNELS + 1) +#define EVENTFD_IDX NUM_ANT_CHANNELS + +void doReset(ant_rx_thread_info_t *stRxThreadInfo); int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo); /* @@ -87,7 +93,7 @@ void *fnRxThread(void *ant_rx_thread_info) int iMutexLockResult; int iPollRet; ant_rx_thread_info_t *stRxThreadInfo; - struct pollfd astPollFd[NUM_ANT_CHANNELS]; + struct pollfd astPollFd[NUM_POLL_FDS]; ant_channel_type eChannel; ANT_FUNC_START(); @@ -96,29 +102,27 @@ void *fnRxThread(void *ant_rx_thread_info) astPollFd[eChannel].fd = stRxThreadInfo->astChannels[eChannel].iFd; astPollFd[eChannel].events = EVENTS_TO_LISTEN_FOR; } + // Fill out poll request for the shutdown signaller. + astPollFd[EVENTFD_IDX].fd = stRxThreadInfo->iRxShutdownEventFd; + astPollFd[EVENTFD_IDX].events = POLL_IN; /* continue running as long as not terminated */ while (stRxThreadInfo->ucRunThread) { /* Wait for data available on any file (transport path) */ - iPollRet = poll(astPollFd, NUM_ANT_CHANNELS, ANT_POLL_TIMEOUT); + iPollRet = poll(astPollFd, NUM_POLL_FDS, ANT_POLL_TIMEOUT); if (!iPollRet) { ANT_DEBUG_V("poll timed out, checking exit cond"); } else if (iPollRet < 0) { - ANT_ERROR("read thread exiting, unhandled error: %s", strerror(errno)); + ANT_ERROR("unhandled error: %s, attempting recovery.", strerror(errno)); + doReset(stRxThreadInfo); + goto out; } else { for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_HARD_RESET)) { - ANT_ERROR("poll error from %s. exiting rx thread", + ANT_ERROR("Hard reset indicated by %s. Attempting recovery.", stRxThreadInfo->astChannels[eChannel].pcDevicePath); - /* Chip was reset or other error, only way to recover is to - * close and open ANT chardev */ - stRxThreadInfo->ucChipResetting = 1; - - if (g_fnStateCallback) { - g_fnStateCallback(RADIO_STATUS_RESETTING); - } - - goto reset; + doReset(stRxThreadInfo); + goto out; } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DISABLE)) { /* chip reported it was disabled, either unexpectedly or due to us closing the file */ ANT_DEBUG_D( @@ -135,12 +139,36 @@ void *fnRxThread(void *ant_rx_thread_info) // set flag to exit out of Rx Loop stRxThreadInfo->ucRunThread = 0; } + } else if (areAllFlagsSet(astPollFd[eChannel].revents, POLLNVAL)) { + ANT_ERROR("poll was called on invalid file descriptor %s. Attempting recovery.", + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + doReset(stRxThreadInfo); + goto out; + } else if (areAllFlagsSet(astPollFd[eChannel].revents, POLLERR)) { + ANT_ERROR("Unknown error from %s. Attempting recovery.", + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + doReset(stRxThreadInfo); + goto out; } else if (astPollFd[eChannel].revents) { ANT_DEBUG_W("unhandled poll result %#x from %s", astPollFd[eChannel].revents, stRxThreadInfo->astChannels[eChannel].pcDevicePath); } } + // Now check for shutdown signal + if(areAllFlagsSet(astPollFd[EVENTFD_IDX].revents, POLLIN)) + { + ANT_DEBUG_I("rx thread caught shutdown signal."); + // reset the counter by reading. + uint64_t counter; + read(stRxThreadInfo->iRxShutdownEventFd, &counter, sizeof(counter)); + // don't care if read error, going to close the thread anyways. + stRxThreadInfo->ucRunThread = 0; + } else if (astPollFd[EVENTFD_IDX].revents != 0) { + ANT_ERROR("Shutdown event descriptor had unexpected event: %#x. exiting rx thread.", + astPollFd[EVENTFD_IDX].revents); + stRxThreadInfo->ucRunThread = 0; + } } } @@ -177,15 +205,26 @@ void *fnRxThread(void *ant_rx_thread_info) ANT_DEBUG_V("stEnabledStatusLock busy"); } - // FIXME This is not the end of the function - // Probably because goto:reset is a bad implementation; can have a reset function. - // Will only end here on Android. + out: ANT_FUNC_END(); #ifdef ANDROID return NULL; #endif +} + +void doReset(ant_rx_thread_info_t *stRxThreadInfo) +{ + int iMutexLockResult; + + ANT_FUNC_START(); + /* Chip was reset or other error, only way to recover is to + * close and open ANT chardev */ + stRxThreadInfo->ucChipResetting = 1; + + if (g_fnStateCallback) { + g_fnStateCallback(RADIO_STATUS_RESETTING); + } -reset: stRxThreadInfo->ucRunThread = 0; ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); @@ -220,9 +259,6 @@ reset: stRxThreadInfo->ucChipResetting = 0; ANT_FUNC_END(); -#ifdef ANDROID - return NULL; -#endif } //////////////////////////////////////////////////////////////////// diff --git a/src/vfs/inc/ant_hci_defines.h b/src/vfs/inc/ant_hci_defines.h new file mode 100644 index 0000000..3ffe672 --- /dev/null +++ b/src/vfs/inc/ant_hci_defines.h @@ -0,0 +1,53 @@ +/* + * ANT Stack + * + * Copyright 2013 Dynastream Innovations + * + * 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. + */ +/*******************************************************************************\ +* +* FILE NAME: ant_hci_defines.h +* +* BRIEF: +* This file defines ANT specific HCI values used by the ANT chip that are +* not specific to the underlying chip. These should not need to be modified, +* but should be verified they are correct. +* +\*******************************************************************************/ + +#ifndef __VFS_INDEPENDENT_H +#define __VFS_INDEPENDENT_H + +// ANT HCI Packet Structure +// ----------------------------------------- +// | Header | Data | Footer | +// |----------------------|-----------------| +// |Optional| Data | Opt. | ... | Optional | +// | Opcode | Size | Sync | | Checksum | +// Data may include any number of ANT packets, with no sync byte or checksum. +// A read from the driver may return any number of ANT HCI packets. + +#include "ant_driver_defines.h" + +#define ANT_HCI_HEADER_SIZE ((ANT_HCI_OPCODE_SIZE) + (ANT_HCI_SIZE_SIZE) + (ANT_HCI_SYNC_SIZE)) +#define ANT_HCI_FOOTER_SIZE (ANT_HCI_CHECKSUM_SIZE) + +#define ANT_HCI_OPCODE_OFFSET 0 +#define ANT_HCI_SIZE_OFFSET ((ANT_HCI_OPCODE_OFFSET) + (ANT_HCI_OPCODE_SIZE)) +#define ANT_HCI_SYNC_OFFSET ((ANT_HCI_SIZE_OFFSET) + (ANT_HCI_SIZE_SIZE)) +#define ANT_HCI_DATA_OFFSET (ANT_HCI_HEADER_SIZE) + +#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10 + +#endif /* ifndef __VFS_INDEPENDENT_H */ diff --git a/src/vfs/inc/ant_rx_chardev.h b/src/vfs/inc/ant_rx_chardev.h index 526070c..1024dac 100644 --- a/src/vfs/inc/ant_rx_chardev.h +++ b/src/vfs/inc/ant_rx_chardev.h @@ -32,7 +32,7 @@ #define __ANT_RX_NATIVE_H #include "ant_native.h" -#include "ant_driver_defines.h" +#include "ant_hci_defines.h" /* same as HCI_MAX_EVENT_SIZE from hci.h, but hci.h is not included for vfs */ #define ANT_HCI_MAX_MSG_SIZE 260 @@ -84,6 +84,8 @@ typedef struct { pthread_mutex_t *pstEnabledStatusLock; /* ANT channels */ ant_channel_info_t astChannels[NUM_ANT_CHANNELS]; + /* Event file descriptor used to interrupt the poll() loop in the rx thread. */ + int iRxShutdownEventFd; } ant_rx_thread_info_t; extern ANTNativeANTStateCb g_fnStateCallback; // TODO State callback should be inside ant_rx_thread_info_t. diff --git a/src/vfs/prerelease/ant_driver_defines.h b/src/vfs/prerelease/ant_driver_defines.h index f2e843b..692de0d 100644 --- a/src/vfs/prerelease/ant_driver_defines.h +++ b/src/vfs/prerelease/ant_driver_defines.h @@ -82,17 +82,4 @@ // That signals Flow Stop: #define ANT_FLOW_STOP ((ANT_U8)0x80) -// ---------------------- NOT CHIP SPECIFIC -// These should not need to be modified, but should be verified they are correct - -#define ANT_HCI_HEADER_SIZE ((ANT_HCI_OPCODE_SIZE) + (ANT_HCI_SIZE_SIZE) + (ANT_HCI_SYNC_SIZE)) -#define ANT_HCI_FOOTER_SIZE (ANT_HCI_CHECKSUM_SIZE) - -#define ANT_HCI_OPCODE_OFFSET 0 -#define ANT_HCI_SIZE_OFFSET ((ANT_HCI_OPCODE_OFFSET) + (ANT_HCI_OPCODE_SIZE)) -#define ANT_HCI_SYNC_OFFSET ((ANT_HCI_SIZE_OFFSET) + (ANT_HCI_SIZE_SIZE)) -#define ANT_HCI_DATA_OFFSET (ANT_HCI_HEADER_SIZE) - -#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10 - #endif /* ifndef __VFS_PRERELEASE_H */ diff --git a/src/vfs/ste/cg29xx/ant_driver_defines.h b/src/vfs/ste/cg29xx/ant_driver_defines.h index aa75ffa..c47415d 100644 --- a/src/vfs/ste/cg29xx/ant_driver_defines.h +++ b/src/vfs/ste/cg29xx/ant_driver_defines.h @@ -79,17 +79,4 @@ // That signals Flow Stop: #define ANT_FLOW_STOP ((ANT_U8)0x80) - -// ---------------------- NOT CHIP SPECIFIC -// These should not need to be modified, but should be verified they are correct - -#define ANT_HCI_HEADER_SIZE ((ANT_HCI_OPCODE_SIZE) + (ANT_HCI_SIZE_SIZE) + (ANT_HCI_SYNC_SIZE)) - -#define ANT_HCI_OPCODE_OFFSET 0 -#define ANT_HCI_SIZE_OFFSET ((ANT_HCI_OPCODE_OFFSET) + (ANT_HCI_OPCODE_SIZE)) -#define ANT_HCI_SYNC_OFFSET ((ANT_HCI_SIZE_OFFSET) + (ANT_HCI_SIZE_SIZE)) -#define ANT_HCI_DATA_OFFSET (ANT_HCI_HEADER_SIZE) - -#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10 - #endif /* ifndef __VFS_PRERELEASE_H */ -- cgit v1.2.3 From b238ba4c16aab347efcab90cdfb148e019f74593 Mon Sep 17 00:00:00 2001 From: Rohan Martin Date: Fri, 15 Nov 2013 21:19:00 +1100 Subject: Detailed purpose of branches. --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d7f30d..a67a03f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ -Linux ANT HAL library -===================== \ No newline at end of file +# Linux ANT HAL library # + +This repository contains the source to build the ANT HAL library (antradio_library.so) for use on Linux based platforms, including Android. Android makefiles are included to configure the build for a specific ANT part which is set in the board config. + +## Branches ## +*Note: Development versions 1.6.1 and 1.6.2 were previously available on the _master_ branch. Any working branches created since version 1.6.0 (18 July 2013) must be rebased to the _development_ branch. While this may be irritating, it forces everyone on these branches to realise they are not using code which is "safe for release".* + +### master ### +Versions that have been tested and are suitable for consumer devices. + +### development ### +The latest, untested, development versions. These are made available for silicon vendors to verify code changes on parts/boards not available to ANT Wireless engineers. + +### _debug ### +Unmaintained, unsupported and untested code. These branches are purely used as a means of distributing in-progress work between engineers at different sites. They generally contain features and fixes developed by third parties. + -- cgit v1.2.3 From 047c33b632dabaa4c060ee5a4d08980a63673d46 Mon Sep 17 00:00:00 2001 From: Rohan Martin Date: Fri, 15 Nov 2013 22:44:34 +1100 Subject: Applied patch for UART serial transport. --- src/vfs/Android.mk | 10 ++ src/vfs/ant_native_chardev.c | 174 ++++++++++++++++++++++++++++---- src/vfs/inc/ant_rx_chardev.h | 8 ++ src/vfs/prerelease/ant_driver_defines.h | 4 +- 4 files changed, 173 insertions(+), 23 deletions(-) diff --git a/src/vfs/Android.mk b/src/vfs/Android.mk index 92ea171..a87645c 100644 --- a/src/vfs/Android.mk +++ b/src/vfs/Android.mk @@ -18,10 +18,18 @@ include $(CLEAR_VARS) LOCAL_CFLAGS := -g -c -W -Wall -O2 +BDROID_DIR:= external/bluetooth/bluedroid + +ifeq ($(ANT_DEVICE_USES_UART),true) +LOCAL_CFLAGS += -DANT_DEVICE_NAME +endif #ANT_DEVICE_USES_UART + LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/src/common/inc \ $(LOCAL_PATH)/$(ANT_DIR)/inc \ +LOCAL_C_INCLUDES += $(BDROID_DIR)/hci/include \ + ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"cg29xx") LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/$(ANT_DIR)/ste/cg29xx \ @@ -48,6 +56,8 @@ LOCAL_SHARED_LIBRARIES += \ LOCAL_SHARED_LIBRARIES += \ libcutils \ +LOCAL_SHARED_LIBRARIES += libdl + LOCAL_MODULE_TAGS := optional LOCAL_PRELINK_MODULE := false LOCAL_MODULE := libantradio diff --git a/src/vfs/ant_native_chardev.c b/src/vfs/ant_native_chardev.c index 2b49a8c..3c0e7a5 100644 --- a/src/vfs/ant_native_chardev.c +++ b/src/vfs/ant_native_chardev.c @@ -33,6 +33,7 @@ #include /* for uint64_t */ #include /* For eventfd() */ #include /* for read(), write(), and close() */ +#include #include "ant_types.h" #include "ant_native.h" @@ -42,6 +43,38 @@ #include "ant_rx_chardev.h" #include "ant_hci_defines.h" #include "ant_log.h" +#include "bt_vendor_lib.h" +#include +static void vendor_fwcfg_cb(bt_vendor_op_result_t result) { +} +static void vendor_scocfg_cb(bt_vendor_op_result_t result) { +} +static void vendor_lpm_vnd_cb(bt_vendor_op_result_t result) { +} +static void* vendor_alloc(int size) { + return NULL; +} +static void vendor_dealloc(void *p_buf) { +} +static uint8_t vendor_xmit_cb(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback) { + return 0; +} +static void vendor_epilog_cb(bt_vendor_op_result_t result) { +} + + +bt_vendor_interface_t *vendor_interface=NULL; +static const bt_vendor_callbacks_t vendor_callbacks = { + sizeof(bt_vendor_callbacks_t), + vendor_fwcfg_cb, + vendor_scocfg_cb, + vendor_lpm_vnd_cb, + vendor_alloc, + vendor_dealloc, + vendor_xmit_cb, + vendor_epilog_cb +}; + #if ANT_HCI_SIZE_SIZE > 1 #include "ant_utils.h" // Put HCI Size value across multiple bytes @@ -96,7 +129,7 @@ ANTStatus ant_init(void) g_fnStateCallback = 0; #ifdef ANT_DEVICE_NAME // Single transport path - ant_channel_init(&stRxThreadInfo.astChannels[SINGLE_CHANNEL], ANT_DEVICE_NAME); + ant_channel_init(&stRxThreadInfo.astChannels[SINGLE_CHANNEL], DEVICE_NAME); #else // Separate data/command paths ant_channel_init(&stRxThreadInfo.astChannels[COMMAND_CHANNEL], ANT_COMMANDS_DEVICE_NAME); ant_channel_init(&stRxThreadInfo.astChannels[DATA_CHANNEL], ANT_DATA_DEVICE_NAME); @@ -724,10 +757,10 @@ ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) { ANTStatus status = ANT_STATUS_FAILED; // TODO ANT_HCI_MAX_MSG_SIZE is transport (driver) dependent. - ANT_U8 txBuffer[ANT_HCI_MAX_MSG_SIZE]; + ANT_U8 txBuffer[ANT_HCI_MAX_MSG_SIZE+1];// +2 bytes for opcode and packet length // TODO Message length can be greater than ANT_U8 can hold. // Not changed as ANT_SERIAL takes length as ANT_U8. - ANT_U8 txMessageLength = ucLen + ANT_HCI_HEADER_SIZE; + ANT_U8 txMessageLength = ucLen + ANT_HCI_HEADER_SIZE;// +2 for opcode[0x0C - ctrl pkt , 0x0E - data pkt ANT_FUNC_START(); if (ant_radio_enabled_status() != RADIO_STATUS_ENABLED) { @@ -736,27 +769,27 @@ ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) } #if ANT_HCI_OPCODE_SIZE == 1 - txBuffer[ANT_HCI_OPCODE_OFFSET] = ANT_HCI_OPCODE_TX; + txBuffer[ANT_HCI_OPCODE_OFFSET+1] = ANT_HCI_OPCODE_TX; #elif ANT_HCI_OPCODE_SIZE > 1 #error "Specified ANT_HCI_OPCODE_SIZE not currently supported" #endif #if ANT_HCI_SIZE_SIZE == 1 - txBuffer[ANT_HCI_SIZE_OFFSET] = ucLen; + txBuffer[ANT_HCI_SIZE_OFFSET+1] = ucLen; #elif ANT_HCI_SIZE_SIZE == 2 ANT_UTILS_StoreLE16(txBuffer + ANT_HCI_SIZE_OFFSET, (ANT_U16)ucLen); #else #error "Specified ANT_HCI_SIZE_SIZE not currently supported" #endif - memcpy(txBuffer + ANT_HCI_HEADER_SIZE, pucMesg, ucLen); + memcpy(txBuffer + ANT_HCI_HEADER_SIZE+1, pucMesg, ucLen); - ANT_SERIAL(txBuffer, txMessageLength, 'T'); + // ANT_SERIAL(txBuffer, txMessageLength, 'T'); -#ifdef ANT_DEVICE_NAME // Single transport path - status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength, txBuffer); -#else // Separate data/command paths - switch (txBuffer[ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET]) { + +// status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength, txBuffer); +//#else // Separate data/command paths + switch (txBuffer[ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET+1]) { case MESG_BROADCAST_DATA_ID: case MESG_ACKNOWLEDGED_DATA_ID: case MESG_BURST_DATA_ID: @@ -764,12 +797,26 @@ ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) case MESG_EXT_ACKNOWLEDGED_DATA_ID: case MESG_EXT_BURST_DATA_ID: case MESG_ADV_BURST_DATA_ID: + ANT_DEBUG_V("Data Path"); + #ifdef ANT_DEVICE_NAME + txBuffer[0] = ANT_DATA_TYPE_PACKET; + ANT_SERIAL(txBuffer, txMessageLength+1, 'T'); + status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength+1, txBuffer); + #else status = ant_tx_message_flowcontrol_wait(DATA_CHANNEL, COMMAND_CHANNEL, txMessageLength, txBuffer); + #endif break; default: + ANT_DEBUG_V("Control Path"); + #ifdef ANT_DEVICE_NAME + txBuffer[0] = ANT_CMD_TYPE_PACKET; + ANT_SERIAL(txBuffer, txMessageLength+1, 'T'); + status = ant_tx_message_flowcontrol_none(SINGLE_CHANNEL, txMessageLength+1, txBuffer); + #else status = ant_tx_message_flowcontrol_none(COMMAND_CHANNEL, txMessageLength, txBuffer); + #endif } -#endif // Separate data/command paths +//#endif // Separate data/command paths out: ANT_FUNC_END(); @@ -803,20 +850,91 @@ static void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcChar ANT_FUNC_END(); } + +int init_transport_bdroid(int on) { + + void *so_handle; + unsigned char bdaddr[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; + int fd[CH_MAX], powerstate, ret; + + if (on) { + so_handle = dlopen("libbt-vendor.so", RTLD_NOW); + if (!so_handle) + { + ALOGE("Failed to load vendor component"); + return -1; + } + + vendor_interface = (bt_vendor_interface_t *) dlsym(so_handle, "BLUETOOTH_VENDOR_LIB_INTERFACE"); + if (!vendor_interface) + { + ALOGE("Failed to accesst bt vendor interface"); + return -1; + } + + vendor_interface->init(&vendor_callbacks, bdaddr); + + ALOGI("Turn On BT power"); + powerstate = BT_VND_PWR_ON; + ret = vendor_interface->op(BT_VND_OP_POWER_CTRL, &powerstate); + if (ret < 0) + { + ALOGE("Failed to turn on power from bt vendor interface"); + return -1; + } + /*call ANT_USERIAL_OPEN to get ANT handle*/ + ret = vendor_interface->op(BT_VND_OP_ANT_USERIAL_OPEN, fd); + ALOGE("ret value: %d", ret); + if (ret != 1) + { + ALOGE("Failed to get fd from bt vendor interface"); + return -1; + } else { + ALOGE("FD: %x", fd[0]); + return fd[0]; + } + } else { + if (vendor_interface) { + ALOGE("Close and cleanup the interfaces"); + int ret = vendor_interface->op(BT_VND_OP_ANT_USERIAL_CLOSE, NULL); + + ALOGE("ret value: %d", ret); + ALOGI("Turn off BT power"); + powerstate = BT_VND_PWR_OFF; + ret = vendor_interface->op(BT_VND_OP_POWER_CTRL, &powerstate); + if (ret < 0) + { + ALOGE("Failed to turn off power from bt vendor interface"); + return -1; + } + vendor_interface->cleanup(); + vendor_interface = NULL; + return 0; + } else { + + ALOGE("Not able to find vendor interface handle"); + return -1; + } + } +} + static void ant_disable_channel(ant_channel_info_t *pstChnlInfo) { ANT_FUNC_START(); - + char bt_soc_type[PROPERTY_VALUE_MAX]; if (!pstChnlInfo) { ANT_ERROR("null channel info passed to channel disable function"); goto out; } - + property_get("qcom.bluetooth.soc", bt_soc_type, NULL); if (pstChnlInfo->iFd != -1) { + if(!(strncasecmp(bt_soc_type,"rome", sizeof("rome")))) + init_transport_bdroid(0); + else{ if (close(pstChnlInfo->iFd) < 0) { ANT_ERROR("failed to close channel %s(%#x): %s", pstChnlInfo->pcDevicePath, pstChnlInfo->iFd, strerror(errno)); } - + } pstChnlInfo->iFd = -1; //TODO can this overwrite a still valid fd? } else { ANT_DEBUG_D("%s file is already closed", pstChnlInfo->pcDevicePath); @@ -826,23 +944,35 @@ out: ANT_FUNC_END(); } + + + static int ant_enable_channel(ant_channel_info_t *pstChnlInfo) { int iRet = -1; + char bt_soc_type[PROPERTY_VALUE_MAX]; ANT_FUNC_START(); if (!pstChnlInfo) { ANT_ERROR("null channel info passed to channel enable function"); errno = EINVAL; goto out; } + property_get("qcom.bluetooth.soc", bt_soc_type, NULL); + ANT_ERROR("BT_SOC_TYPE is %s",bt_soc_type); if (pstChnlInfo->iFd == -1) { - pstChnlInfo->iFd = open(pstChnlInfo->pcDevicePath, O_RDWR); - if (pstChnlInfo->iFd < 0) { - ANT_ERROR("failed to open dev %s: %s", pstChnlInfo->pcDevicePath, strerror(errno)); - goto out; - } - } else { - ANT_DEBUG_D("%s is already enabled", pstChnlInfo->pcDevicePath); + if(!(strncasecmp(bt_soc_type,"rome", sizeof("rome")))) + pstChnlInfo->iFd = init_transport_bdroid(1); + else + pstChnlInfo->iFd = open(pstChnlInfo->pcDevicePath, O_RDWR); + + if (pstChnlInfo->iFd < 0) { + ANT_ERROR("failed to open dev %s: %s", pstChnlInfo->pcDevicePath, strerror(errno)); + goto out; + } + } + else + { + ANT_DEBUG_D("%s is already enabled", pstChnlInfo->pcDevicePath); } iRet = 0; out: diff --git a/src/vfs/inc/ant_rx_chardev.h b/src/vfs/inc/ant_rx_chardev.h index 1024dac..b0fd8de 100644 --- a/src/vfs/inc/ant_rx_chardev.h +++ b/src/vfs/inc/ant_rx_chardev.h @@ -41,6 +41,14 @@ #define ANT_MSG_ID_OFFSET ((ANT_U8)1) #define ANT_MSG_DATA_OFFSET ((ANT_U8)2) +#ifdef ANT_DEVICE_NAME // Single transport path +//Define protocol byte to be added +//as multiple data will be sent/received over +//same transport(BT, ANT ..etc) +#define ANT_CMD_TYPE_PACKET 0x0C +#define ANT_DATA_TYPE_PACKET 0x0E +#endif + /* This struct defines the info passed to an rx thread */ typedef struct { /* Device path */ diff --git a/src/vfs/prerelease/ant_driver_defines.h b/src/vfs/prerelease/ant_driver_defines.h index 692de0d..9aa13ec 100644 --- a/src/vfs/prerelease/ant_driver_defines.h +++ b/src/vfs/prerelease/ant_driver_defines.h @@ -50,8 +50,10 @@ #define ANT_DATA_DEVICE_NAME "/dev/smd6" // OR // If chip uses one path: -// #define ANT_DEVICE_NAME "/dev/Z" +#ifdef ANT_DEVICE_NAME +#define DEVICE_NAME "/dev/ttyHS0" +#endif // Set to the number of bytes of header is for Opcode: #define ANT_HCI_OPCODE_SIZE 0 -- cgit v1.2.3 From d494ba37b8b173d56ddd45c9f45b9f118160a8b6 Mon Sep 17 00:00:00 2001 From: ANT-Shane Date: Fri, 15 Nov 2013 11:19:05 -0700 Subject: Refactored qualcomm uart changes on pre-release to qualcomm-uart, also refactored old qualcomm code to qualcomm-smd qualcomm-uart builds should now set BOARD_ANT_WIRELESS_DEVICE to "qualcomm-uart" --- Android.mk | 16 + src/bt-vendor_vfs/Android.mk | 57 ++ src/bt-vendor_vfs/ant_native_chardev.c | 1078 ++++++++++++++++++++ src/bt-vendor_vfs/ant_rx_chardev.c | 421 ++++++++ src/bt-vendor_vfs/inc/ant_hci_defines.h | 53 + src/bt-vendor_vfs/inc/ant_rx_chardev.h | 98 ++ src/bt-vendor_vfs/inc/antradio_power.h | 48 + .../qualcomm/uart/ant_driver_defines.h | 98 ++ src/vfs/Android.mk | 14 +- src/vfs/ant_native_chardev.c | 174 +--- src/vfs/inc/ant_rx_chardev.h | 200 ++-- src/vfs/prerelease/ant_driver_defines.h | 172 ++-- src/vfs/qualcomm/smd/ant_driver_defines.h | 85 ++ 13 files changed, 2161 insertions(+), 353 deletions(-) create mode 100644 src/bt-vendor_vfs/Android.mk create mode 100644 src/bt-vendor_vfs/ant_native_chardev.c create mode 100644 src/bt-vendor_vfs/ant_rx_chardev.c create mode 100644 src/bt-vendor_vfs/inc/ant_hci_defines.h create mode 100644 src/bt-vendor_vfs/inc/ant_rx_chardev.h create mode 100644 src/bt-vendor_vfs/inc/antradio_power.h create mode 100644 src/bt-vendor_vfs/qualcomm/uart/ant_driver_defines.h create mode 100644 src/vfs/qualcomm/smd/ant_driver_defines.h diff --git a/Android.mk b/Android.mk index 3ee7f89..007a6c3 100644 --- a/Android.mk +++ b/Android.mk @@ -24,6 +24,14 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) +# For known qualcomm smd devices we remap the chip name to "qualcomm-smd" + +ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"wcn3680") + +BOARD_ANT_WIRELESS_DEVICE := "qualcomm-smd" + +endif + ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"wl12xx") ANT_DIR := src/bluez_hci @@ -36,6 +44,14 @@ else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"cg29xx") ANT_DIR := src/vfs +else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"qualcomm-smd") + +ANT_DIR := src/vfs + +else ifeq($(BOARD_ANT_WIRELESS_DEVICE),"qualcomm-uart") + +ANT_DIR := src/bt-vendor_vfs + else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"vfs-prerelease") ANT_DIR := src/vfs diff --git a/src/bt-vendor_vfs/Android.mk b/src/bt-vendor_vfs/Android.mk new file mode 100644 index 0000000..e6813d0 --- /dev/null +++ b/src/bt-vendor_vfs/Android.mk @@ -0,0 +1,57 @@ +# +# Copyright (C) 2011 Dynastream Innovations +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include $(CLEAR_VARS) + +LOCAL_CFLAGS := -g -c -W -Wall -O2 + +# needed to pull in the header file for libbt-vendor.so +BDROID_DIR:= external/bluetooth/bluedroid + +# Added hci/include to give access to the header for the libbt-vendorso interface. +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/src/common/inc \ + $(LOCAL_PATH)/$(ANT_DIR)/inc \ + $(BDROID_DIR)/hci/include \ + +ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"qualcomm-uart") +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/$(ANT_DIR)/qualcomm/uart \ + +endif # BOARD_ANT_WIRELESS_DEVICE = "qualcomm-uart" + +LOCAL_SRC_FILES := \ + $(COMMON_DIR)/JAntNative.cpp \ + $(COMMON_DIR)/ant_utils.c \ + $(ANT_DIR)/ant_native_chardev.c \ + $(ANT_DIR)/ant_rx_chardev.c \ + +# JNI +LOCAL_C_INCLUDE += $(JNI_H_INCLUDE) + +LOCAL_SHARED_LIBRARIES += \ + libnativehelper \ + +# logging and dll loading +LOCAL_SHARED_LIBRARIES += \ + libcutils \ + libdl \ + +LOCAL_MODULE_TAGS := optional +LOCAL_PRELINK_MODULE := false +LOCAL_MODULE := libantradio + +include $(BUILD_SHARED_LIBRARY) diff --git a/src/bt-vendor_vfs/ant_native_chardev.c b/src/bt-vendor_vfs/ant_native_chardev.c new file mode 100644 index 0000000..a90c8c4 --- /dev/null +++ b/src/bt-vendor_vfs/ant_native_chardev.c @@ -0,0 +1,1078 @@ +/* + * ANT Stack + * + * Copyright 2011 Dynastream Innovations + * + * 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. + */ +/******************************************************************************\ +* +* FILE NAME: ant_native_chardev.c +* +* BRIEF: +* This file provides the VFS implementation of ant_native.h +* VFS could be Character Device, TTY, etc. +* +* +\******************************************************************************/ + +#include +#include /* for open() */ +#include /* For hard reset */ +#include +#include /* needed for runtime dll loading. */ +#include /* for uint64_t */ +#include /* For eventfd() */ +#include /* for read(), write(), and close() */ + +#include "ant_types.h" +#include "ant_native.h" +#include "ant_version.h" + +#include "antradio_power.h" +#include "ant_rx_chardev.h" +#include "ant_hci_defines.h" +#include "ant_log.h" +#include "bt_vendor_lib.h" /* used by qualcomms code to call into libbt-vendor.so */ +#include /* used by qualcomms additions for logging. */ +// The following functions are dummy implementations of the callbacks required by libbt-vendor. +static void vendor_fwcfg_cb(bt_vendor_op_result_t result) { +} +static void vendor_scocfg_cb(bt_vendor_op_result_t result) { +} +static void vendor_lpm_vnd_cb(bt_vendor_op_result_t result) { +} +static void* vendor_alloc(int size) { + return NULL; +} +static void vendor_dealloc(void *p_buf) { +} +static uint8_t vendor_xmit_cb(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback) { + return 0; +} +static void vendor_epilog_cb(bt_vendor_op_result_t result) { +} + +// This struct is used to regsiter the dummy callbacks with libbt-vendor +bt_vendor_interface_t *vendor_interface=NULL; +static const bt_vendor_callbacks_t vendor_callbacks = { + sizeof(bt_vendor_callbacks_t), + vendor_fwcfg_cb, + vendor_scocfg_cb, + vendor_lpm_vnd_cb, + vendor_alloc, + vendor_dealloc, + vendor_xmit_cb, + vendor_epilog_cb +}; + +#if ANT_HCI_SIZE_SIZE > 1 +#include "ant_utils.h" // Put HCI Size value across multiple bytes +#endif + +#define MESG_BROADCAST_DATA_ID ((ANT_U8)0x4E) +#define MESG_ACKNOWLEDGED_DATA_ID ((ANT_U8)0x4F) +#define MESG_BURST_DATA_ID ((ANT_U8)0x50) +#define MESG_EXT_BROADCAST_DATA_ID ((ANT_U8)0x5D) +#define MESG_EXT_ACKNOWLEDGED_DATA_ID ((ANT_U8)0x5E) +#define MESG_EXT_BURST_DATA_ID ((ANT_U8)0x5F) +#define MESG_ADV_BURST_DATA_ID ((ANT_U8)0x72) + +static ant_rx_thread_info_t stRxThreadInfo; +static pthread_mutex_t stEnabledStatusLock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t stFlowControlLock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t stFlowControlCond = PTHREAD_COND_INITIALIZER; +ANTNativeANTStateCb g_fnStateCallback; + +static const uint64_t EVENT_FD_PLUS_ONE = 1L; + +static void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcCharDevName); + +//////////////////////////////////////////////////////////////////// +// ant_init +// +// Initialises the native environment. +// +// Parameters: +// - +// +// Returns: +// ANT_STATUS_SUCCESS if intialize completed, else ANT_STATUS_FAILED +// +// Psuedocode: +/* +Set variables to defaults +Initialise each supported path to chip +Setup eventfd object. +RESULT = ANT_STATUS_SUCCESS if no problems else ANT_STATUS_FAILED +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_init(void) +{ + ANTStatus status = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + stRxThreadInfo.stRxThread = 0; + stRxThreadInfo.ucRunThread = 0; + stRxThreadInfo.ucChipResetting = 0; + stRxThreadInfo.pstEnabledStatusLock = &stEnabledStatusLock; + g_fnStateCallback = 0; + +#ifdef ANT_DEVICE_NAME // Single transport path + ant_channel_init(&stRxThreadInfo.astChannels[SINGLE_CHANNEL], ANT_DEVICE_NAME); +#else // Separate data/command paths + ant_channel_init(&stRxThreadInfo.astChannels[COMMAND_CHANNEL], ANT_COMMANDS_DEVICE_NAME); + ant_channel_init(&stRxThreadInfo.astChannels[DATA_CHANNEL], ANT_DATA_DEVICE_NAME); +#endif // Separate data/command paths + + // Make the eventfd. Want it non blocking so that we can easily reset it by reading. + stRxThreadInfo.iRxShutdownEventFd = eventfd(0, EFD_NONBLOCK); + + // Check for error case + if(stRxThreadInfo.iRxShutdownEventFd == -1) + { + ANT_ERROR("ANT init failed. Could not create event fd. Reason: %s", strerror(errno)); + } else { + status = ANT_STATUS_SUCCESS; + } + + ANT_FUNC_END(); + return status; +} + +//////////////////////////////////////////////////////////////////// +// ant_deinit +// +// clean up eventfd object +// +// Parameters: +// - +// +// Returns: +// ANT_STATUS_SUCCESS +// +// Psuedocode: +/* +RESULT = SUCCESS +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_deinit(void) +{ + ANTStatus result_status = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + if(close(stRxThreadInfo.iRxShutdownEventFd) < 0) + { + ANT_ERROR("Could not close eventfd in deinit. Reason: %s", strerror(errno)); + } else { + result_status = ANT_STATUS_SUCCESS; + } + + ANT_FUNC_END(); + return result_status; +} + + +//////////////////////////////////////////////////////////////////// +// ant_enable_radio +// +// Powers on the ANT part and initialises the transport to the chip. +// Changes occur in part implementing ant_enable() call +// +// Parameters: +// - +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failures: +// ANT_STATUS_TRANSPORT_INIT_ERR if could not enable +// ANT_STATUS_FAILED if failed to get mutex or init rx thread +// +// Psuedocode: +/* +LOCK enable_LOCK + State callback: STATE = ENABLING + ant enable + IF ant_enable success + State callback: STATE = ENABLED + RESULT = SUCCESS + ELSE + ant disable + State callback: STATE = Current state + RESULT = FAILURE + ENDIF +UNLOCK +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_enable_radio(void) +{ + int iLockResult; + ANTStatus result_status = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); + iLockResult = pthread_mutex_lock(&stEnabledStatusLock); + if(iLockResult) { + ANT_ERROR("enable failed to get state lock: %s", strerror(iLockResult)); + goto out; + } + ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); + + if (g_fnStateCallback) { + g_fnStateCallback(RADIO_STATUS_ENABLING); + } + + if (ant_enable() < 0) { + ANT_ERROR("ant enable failed: %s", strerror(errno)); + + ant_disable(); + + if (g_fnStateCallback) { + g_fnStateCallback(ant_radio_enabled_status()); + } + } else { + if (g_fnStateCallback) { + g_fnStateCallback(RADIO_STATUS_ENABLED); + } + + result_status = ANT_STATUS_SUCCESS; + } + + ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); + pthread_mutex_unlock(&stEnabledStatusLock); + ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); + +out: + ANT_FUNC_END(); + return result_status; +} + +//////////////////////////////////////////////////////////////////// +// ant_radio_hard_reset +// +// IF SUPPORTED triggers a hard reset of the chip providing ANT functionality. +// +// Parameters: +// - +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failures: +// ANT_STATUS_NOT_SUPPORTED if the chip can't hard reset +// ANT_STATUS_FAILED if failed to get mutex or enable +// +// Psuedocode: +/* +IF Hard Reset not supported + RESULT = NOT SUPPORTED +ELSE + LOCK enable_LOCK + IF Lock failed + RESULT = FAILED + ELSE + Set Flag Rx thread that chip is resetting + FOR each path to chip + Send Reset IOCTL to path + ENDFOR + ant disable + ant enable + IF ant_enable success + State callback: STATE = RESET + RESULT = SUCCESS + ELSE + State callback: STATE = DISABLED + RESULT = FAILURE + ENDIF + Clear Flag Rx thread that chip is resetting + UNLOCK +ENDIF +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_radio_hard_reset(void) +{ + ANTStatus result_status = ANT_STATUS_NOT_SUPPORTED; + ANT_FUNC_START(); + +#ifdef ANT_IOCTL_RESET + ant_channel_type eChannel; + int iLockResult; + + result_status = ANT_STATUS_FAILED; + + ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); + iLockResult = pthread_mutex_lock(&stEnabledStatusLock); + if(iLockResult) { + ANT_ERROR("enable failed to get state lock: %s", strerror(iLockResult)); + goto out; + } + ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); + + stRxThreadInfo.ucChipResetting = 1; + if (g_fnStateCallback) + g_fnStateCallback(RADIO_STATUS_RESETTING); + +#ifdef ANT_IOCTL_RESET_PARAMETER + ioctl(stRxThreadInfo.astChannels[0].iFd, ANT_IOCTL_RESET, ANT_IOCTL_RESET_PARAMETER); +#else + ioctl(stRxThreadInfo.astChannels[0].iFd, ANT_IOCTL_RESET); +#endif // ANT_IOCTL_RESET_PARAMETER + + ant_disable(); + + if (ant_enable()) { /* failed */ + if (g_fnStateCallback) + g_fnStateCallback(RADIO_STATUS_DISABLED); + } else { /* success */ + if (g_fnStateCallback) + g_fnStateCallback(RADIO_STATUS_RESET); + result_status = ANT_STATUS_SUCCESS; + } + stRxThreadInfo.ucChipResetting = 0; + + ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); + pthread_mutex_unlock(&stEnabledStatusLock); + ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); +out: +#endif // ANT_IOCTL_RESET + + ANT_FUNC_END(); + return result_status; +} + +//////////////////////////////////////////////////////////////////// +// ant_disable_radio +// +// Powers off the ANT part and closes the transport to the chip. +// +// Parameters: +// - +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failures: +// ANT_STATUS_FAILED if failed to get mutex +// +// Psuedocode: +/* +LOCK enable_LOCK + State callback: STATE = DISABLING + ant disable + State callback: STATE = Current state + RESULT = SUCCESS +UNLOCK +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_disable_radio(void) +{ + int iLockResult; + ANTStatus ret = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); + iLockResult = pthread_mutex_lock(&stEnabledStatusLock); + if(iLockResult) { + ANT_ERROR("disable failed to get state lock: %s", strerror(iLockResult)); + goto out; + } + ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); + + if (g_fnStateCallback) { + g_fnStateCallback(RADIO_STATUS_DISABLING); + } + + ant_disable(); + + if (g_fnStateCallback) { + g_fnStateCallback(ant_radio_enabled_status()); + } + + ret = ANT_STATUS_SUCCESS; + + ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); + pthread_mutex_unlock(&stEnabledStatusLock); + ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); + +out: + ANT_FUNC_END(); + return ret; +} + +//////////////////////////////////////////////////////////////////// +// ant_radio_enabled_status +// +// Gets the current chip/transport state; either disabled, disabling, +// enabling, enabled, or resetting. Determines this on the fly by checking +// if Rx thread is running and how many of the paths for the ANT chip have +// open VFS files. +// +// Parameters: +// - +// +// Returns: +// The current radio status (ANTRadioEnabledStatus) +// +// Psuedocode: +/* +IF Thread Resetting Flag is set + RESULT = Resetting +ELSE + COUNT the number of open files + IF Thread Run Flag is Not Set + IF there are open files OR Rx thread exists + RESULT = Disabling + ELSE + RESULT = Disabled + ENDIF + ELSE + IF All files are open (all paths) AND Rx thread exists + RESULT = ENABLED + ELSE IF there are open files (Not 0 open files) AND Rx thread exists + RESULT = UNKNOWN + ELSE (0 open files or Rx thread does not exist [while Thread Run set]) + RESULT = ENABLING + ENDIF + ENDIF +ENDIF +*/ +//////////////////////////////////////////////////////////////////// +ANTRadioEnabledStatus ant_radio_enabled_status(void) +{ + ant_channel_type eChannel; + int iOpenFiles = 0; + int iOpenThread; + ANTRadioEnabledStatus uiRet = RADIO_STATUS_UNKNOWN; + ANT_FUNC_START(); + + if (stRxThreadInfo.ucChipResetting) { + uiRet = RADIO_STATUS_RESETTING; + goto out; + } + + for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { + if (stRxThreadInfo.astChannels[eChannel].iFd != -1) { + iOpenFiles++; + } + } + + iOpenThread = (stRxThreadInfo.stRxThread) ? 1 : 0; + + if (!stRxThreadInfo.ucRunThread) { + if (iOpenFiles || iOpenThread) { + uiRet = RADIO_STATUS_DISABLING; + } else { + uiRet = RADIO_STATUS_DISABLED; + } + } else { + if ((iOpenFiles == NUM_ANT_CHANNELS) && iOpenThread) { + uiRet = RADIO_STATUS_ENABLED; + } else if (!iOpenFiles && iOpenThread) { + uiRet = RADIO_STATUS_UNKNOWN; + } else { + uiRet = RADIO_STATUS_ENABLING; + } + } + +out: + ANT_DEBUG_D("get radio enabled status returned %d", uiRet); + + ANT_FUNC_END(); + return uiRet; +} + +//////////////////////////////////////////////////////////////////// +// set_ant_rx_callback +// +// Sets which function to call when an ANT message is received. +// +// Parameters: +// rx_callback_func the ANTNativeANTEventCb function to be used for +// received messages (from all transport paths). +// +// Returns: +// ANT_STATUS_SUCCESS +// +// Psuedocode: +/* +FOR each transport path + Path Rx Callback = rx_callback_func +ENDFOR +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus set_ant_rx_callback(ANTNativeANTEventCb rx_callback_func) +{ + ANTStatus status = ANT_STATUS_SUCCESS; + ANT_FUNC_START(); + +#ifdef ANT_DEVICE_NAME // Single transport path + stRxThreadInfo.astChannels[SINGLE_CHANNEL].fnRxCallback = rx_callback_func; +#else // Separate data/command paths + stRxThreadInfo.astChannels[COMMAND_CHANNEL].fnRxCallback = rx_callback_func; + stRxThreadInfo.astChannels[DATA_CHANNEL].fnRxCallback = rx_callback_func; +#endif // Separate data/command paths + + ANT_FUNC_END(); + return status; +} + +//////////////////////////////////////////////////////////////////// +// set_ant_state_callback +// +// Sets which function to call when an ANT state change occurs. +// +// Parameters: +// state_callback_func the ANTNativeANTStateCb function to be used +// for received state changes. +// +// Returns: +// ANT_STATUS_SUCCESS +// +// Psuedocode: +/* + State Callback = state_callback_func +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus set_ant_state_callback(ANTNativeANTStateCb state_callback_func) +{ + ANTStatus status = ANT_STATUS_SUCCESS; + ANT_FUNC_START(); + + g_fnStateCallback = state_callback_func; + + ANT_FUNC_END(); + return status; +} + +//////////////////////////////////////////////////////////////////// +// ant_tx_message_flowcontrol_wait +// +// Sends an ANT message to the chip and waits for a CTS signal +// +// Parameters: +// eTxPath device to transmit message on +// eFlowMessagePath device that receives CTS +// ucMessageLength the length of the message +// pucMesg pointer to the message data +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failure: +// ANT_STATUS_NOT_ENABLED +// +// Psuedocode: +/* + LOCK flow control + IF Lock failed + RESULT = FAILED + ELSE + SET flowMessagePath Flow Control response as FLOW_STOP + WRITE txBuffer to txPath (only length of packet part) + IF Wrote less then 0 bytes + Log error + RESULT = FAILED + ELSE IF Didn't write 'length of packet' bytes + Log error + RESULT = FAILED + ELSE + IF flowMessagePath Flow Control response is not FLOW_GO + WAIT until flowMessagePath Flow Control response is FLOW_GO, UNTIL FLOW_GO Wait Timeout seconds (10) from Now + IF error Waiting + IF error is Timeout + RESULT = HARDWARE ERROR + ELSE + RESULT = FAILED + ENDIF + ELSE + RESULT = SUCCESS + ENDIF + ELSE + RESULT = SUCCESS; + ENDIF + ENDIF + UNLOCK flow control + ENDIF +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_tx_message_flowcontrol_wait(ant_channel_type eTxPath, ant_channel_type eFlowMessagePath, ANT_U8 ucMessageLength, ANT_U8 *pucTxMessage) +{ + int iMutexResult; + int iResult; + struct timespec stTimeout; + int iCondWaitResult; + ANTStatus status = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + ANT_DEBUG_V("getting stFlowControlLock in %s", __FUNCTION__); + iMutexResult = pthread_mutex_lock(&stFlowControlLock); + if (iMutexResult) { + ANT_ERROR("failed to lock flow control mutex during tx: %s", strerror(iMutexResult)); + goto out; + } + ANT_DEBUG_V("got stFlowControlLock in %s", __FUNCTION__); + + stRxThreadInfo.astChannels[eFlowMessagePath].ucFlowControlResp = ANT_FLOW_STOP; + +#ifdef ANT_FLOW_RESEND + // Store Tx message so can resend it from Rx thread + stRxThreadInfo.astChannels[eFlowMessagePath].ucResendMessageLength = ucMessageLength; + stRxThreadInfo.astChannels[eFlowMessagePath].pucResendMessage = pucTxMessage; +#endif // ANT_FLOW_RESEND + + iResult = write(stRxThreadInfo.astChannels[eTxPath].iFd, pucTxMessage, ucMessageLength); + if (iResult < 0) { + ANT_ERROR("failed to write data message to device: %s", strerror(errno)); + } else if (iResult != ucMessageLength) { + ANT_ERROR("bytes written and message size don't match up"); + } else { + stTimeout.tv_sec = time(0) + ANT_FLOW_GO_WAIT_TIMEOUT_SEC; + stTimeout.tv_nsec = 0; + + while (stRxThreadInfo.astChannels[eFlowMessagePath].ucFlowControlResp != ANT_FLOW_GO) { + iCondWaitResult = pthread_cond_timedwait(&stFlowControlCond, &stFlowControlLock, &stTimeout); + if (iCondWaitResult) { + ANT_ERROR("failed to wait for flow control response: %s", strerror(iCondWaitResult)); + + if (iCondWaitResult == ETIMEDOUT) { + status = ANT_STATUS_HARDWARE_ERR; + +#ifdef ANT_FLOW_RESEND + // Clear Tx message so will stop resending it from Rx thread + stRxThreadInfo.astChannels[eFlowMessagePath].ucResendMessageLength = 0; + stRxThreadInfo.astChannels[eFlowMessagePath].pucResendMessage = NULL; +#endif // ANT_FLOW_RESEND + } + goto wait_error; + } + } + + status = ANT_STATUS_SUCCESS; + } + +wait_error: + ANT_DEBUG_V("releasing stFlowControlLock in %s", __FUNCTION__); + pthread_mutex_unlock(&stFlowControlLock); + ANT_DEBUG_V("released stFlowControlLock in %s", __FUNCTION__); + +out: + ANT_FUNC_END(); + return status; +} + +//////////////////////////////////////////////////////////////////// +// ant_tx_message_flowcontrol_none +// +// Sends an ANT message to the chip without waiting for flow control +// +// Parameters: +// eTxPath device to transmit on +// ucMessageLength the length of the message +// pucMesg pointer to the message data +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failure: +// ANT_STATUS_NOT_ENABLED +// +// Psuedocode: +/* + WRITE txBuffer to Tx Path (only length of packet part) + IF Wrote less then 0 bytes + Log error + RESULT = FAILED + ELSE IF Didn't write 'length of packet' bytes + Log error + RESULT = FAILED + ELSE + RESULT = SUCCESS + ENDIF +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_tx_message_flowcontrol_none(ant_channel_type eTxPath, ANT_U8 ucMessageLength, ANT_U8 *pucTxMessage) +{ + int iResult; + ANTStatus status = ANT_STATUS_FAILED;\ + ANT_FUNC_START(); + + iResult = write(stRxThreadInfo.astChannels[eTxPath].iFd, pucTxMessage, ucMessageLength); + if (iResult < 0) { + ANT_ERROR("failed to write message to device: %s", strerror(errno)); + } else if (iResult != ucMessageLength) { + ANT_ERROR("bytes written and message size don't match up"); + } else { + status = ANT_STATUS_SUCCESS; + } + + ANT_FUNC_END(); + return status; +} + +//////////////////////////////////////////////////////////////////// +// ant_tx_message +// +// Frames ANT data and decides which flow control method to use for sending the +// ANT message to the chip +// +// Parameters: +// ucLen the length of the message +// pucMesg pointer to the message data +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failure: +// ANT_STATUS_NOT_ENABLED +// +// Psuedocode: +/* +IF not enabled + RESULT = BT NOT INITIALIZED +ELSE + Create txBuffer, MAX HCI Message Size large + PUT ucLen in txBuffer AT ANT HCI Size Offset (0) + COPY pucMesg to txBuffer AT ANT HCI Header Size (1) <- ? Not at offset? + LOG txBuffer as a serial Tx (only length of packet part) + IF is a data message + Tx message on Data Path with FLOW_GO/FLOW_STOP flow control (ant_tx_message_flowcontrol_go_stop()) + ELSE + Tx message on Command Path with no flow control (ant_tx_message_flowcontrol_none()) + ENDIF +ENDIF +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) +{ + // During a tx we must prepend a packet type byte. Thus HCI_PACKET_TYPE_SIZE is added + // to all offsets when writing into the tx buffer. + ANTStatus status = ANT_STATUS_FAILED; + // TODO ANT_HCI_MAX_MSG_SIZE is transport (driver) dependent. + ANT_U8 txBuffer[HCI_PACKET_TYPE_SIZE + ANT_HCI_MAX_MSG_SIZE]; + // TODO Message length can be greater than ANT_U8 can hold. + // Not changed as ANT_SERIAL takes length as ANT_U8. + ANT_U8 txMessageLength = HCI_PACKET_TYPE_SIZE + ucLen + ANT_HCI_HEADER_SIZE; + ANT_FUNC_START(); + + if (ant_radio_enabled_status() != RADIO_STATUS_ENABLED) { + status = ANT_STATUS_FAILED_BT_NOT_INITIALIZED; + goto out; + } + +#if ANT_HCI_OPCODE_SIZE == 1 + txBuffer[HCI_PACKET_TYPE_SIZE + ANT_HCI_OPCODE_OFFSET] = ANT_HCI_OPCODE_TX; +#elif ANT_HCI_OPCODE_SIZE > 1 +#error "Specified ANT_HCI_OPCODE_SIZE not currently supported" +#endif + +#if ANT_HCI_SIZE_SIZE == 1 + txBuffer[HCI_PACKET_TYPE_SIZE + ANT_HCI_SIZE_OFFSET] = ucLen; +#elif ANT_HCI_SIZE_SIZE == 2 + ANT_UTILS_StoreLE16(txBuffer + HCI_PACKET_TYPE_SIZE + ANT_HCI_SIZE_OFFSET, (ANT_U16)ucLen); +#else +#error "Specified ANT_HCI_SIZE_SIZE not currently supported" +#endif + + memcpy(txBuffer + HCI_PACKET_TYPE_SIZE + ANT_HCI_HEADER_SIZE, pucMesg, ucLen); + +// We no longer do the serial logging here because the packet type byte is not yet written. +//ANT_SERIAL(txBuffer, txMessageLength, 'T'); + +// We only do this if we are using single physical and logical channels. +#if defined(ANT_DEVICE_NAME) && (HCI_PACKET_TYPE_SIZE == 0) // Single transport path + ANT_SERIAL(txBuffer, txMessageLength, 'T'); + status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength, txBuffer); +#else // Separate data/command paths + // Each path follows this structure: + // write the packet type if needed. + // log the packet + // Send using the appropriate physical channel, waiting for flow control for data commands. + switch (txBuffer[HCI_PACKET_TYPE_SIZE + ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET]) { + case MESG_BROADCAST_DATA_ID: + case MESG_ACKNOWLEDGED_DATA_ID: + case MESG_BURST_DATA_ID: + case MESG_EXT_BROADCAST_DATA_ID: + case MESG_EXT_ACKNOWLEDGED_DATA_ID: + case MESG_EXT_BURST_DATA_ID: + case MESG_ADV_BURST_DATA_ID: + ANT_DEBUG_V("Data Path"); + #if HCI_PACKET_TYPE_SIZE == 1 + txBuffer[0] = ANT_DATA_TYPE_PACKET; + #elif HCI_PACKET_TYPE_SIZE > 1 + #error "Specified HCI_PACKET_TYPE_SIZE not supported" + #endif + ANT_SERIAL(txBuffer, txMessageLength, 'T'); + #ifdef ANT_DEVICE_NAME + status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength, txBuffer); + #else + status = ant_tx_message_flowcontrol_wait(DATA_CHANNEL, COMMAND_CHANNEL, txMessageLength, txBuffer); + #endif + break; + default: + ANT_DEBUG_V("Control Path"); + #if HCI_PACKET_TYPE_SIZE == 1 + txBuffer[0] = ANT_CMD_TYPE_PACKET; + #elif HCI_PACKET_TYPE_SIZE > 1 + #error "Specified HCI_PACKET_TYPE_SIZE not supported" + #endif + ANT_SERIAL(txBuffer, txMessageLength, 'T'); + #ifdef ANT_DEVICE_NAME + status = ant_tx_message_flowcontrol_none(SINGLE_CHANNEL, txMessageLength, txBuffer); + #else + status = ant_tx_message_flowcontrol_none(COMMAND_CHANNEL, txMessageLength, txBuffer); + #endif + } +#endif // Separate data/command paths + +out: + ANT_FUNC_END(); + return status; +} + +//----------------- TODO Move these somewhere for multi transport path / dedicated channel support: + +static void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcCharDevName) +{ + ANT_FUNC_START(); + + // TODO Don't need to store, only accessed when trying to open: + // Is however useful for logs. + pstChnlInfo->pcDevicePath = pcCharDevName; + + // This is the only piece of info that needs to be stored per channel + pstChnlInfo->iFd = -1; + + // TODO Only 1 of these (not per-channel) is actually ever used: + pstChnlInfo->fnRxCallback = NULL; + pstChnlInfo->ucFlowControlResp = ANT_FLOW_GO; +#ifdef ANT_FLOW_RESEND + pstChnlInfo->ucResendMessageLength = 0; + pstChnlInfo->pucResendMessage = NULL; +#endif // ANT_FLOW_RESEND + // TODO Only used when Flow Control message received, so must only be Command path Rx thread + pstChnlInfo->pstFlowControlCond = &stFlowControlCond; + pstChnlInfo->pstFlowControlLock = &stFlowControlLock; + + ANT_FUNC_END(); +} + +// This function is used as an alternative to opening the char device directly. +// It is needed as libbt-vendor does the power up/down control for us when we open/close the file descriptor. +int init_transport_bdroid(int on) { + + void *so_handle; + unsigned char bdaddr[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; + int fd[CH_MAX], powerstate, ret; + + if (on) { + so_handle = dlopen("libbt-vendor.so", RTLD_NOW); + if (!so_handle) + { + ALOGE("Failed to load vendor component"); + return -1; + } + + vendor_interface = (bt_vendor_interface_t *) dlsym(so_handle, "BLUETOOTH_VENDOR_LIB_INTERFACE"); + if (!vendor_interface) + { + ALOGE("Failed to accesst bt vendor interface"); + return -1; + } + + vendor_interface->init(&vendor_callbacks, bdaddr); + + ALOGI("Turn On BT power"); + powerstate = BT_VND_PWR_ON; + ret = vendor_interface->op(BT_VND_OP_POWER_CTRL, &powerstate); + if (ret < 0) + { + ALOGE("Failed to turn on power from bt vendor interface"); + return -1; + } + /*call ANT_USERIAL_OPEN to get ANT handle*/ + ret = vendor_interface->op(BT_VND_OP_ANT_USERIAL_OPEN, fd); + ALOGE("ret value: %d", ret); + if (ret != 1) + { + ALOGE("Failed to get fd from bt vendor interface"); + return -1; + } else { + ALOGE("FD: %x", fd[0]); + return fd[0]; + } + } else { + if (vendor_interface) { + ALOGE("Close and cleanup the interfaces"); + int ret = vendor_interface->op(BT_VND_OP_ANT_USERIAL_CLOSE, NULL); + + ALOGE("ret value: %d", ret); + ALOGI("Turn off BT power"); + powerstate = BT_VND_PWR_OFF; + ret = vendor_interface->op(BT_VND_OP_POWER_CTRL, &powerstate); + if (ret < 0) + { + ALOGE("Failed to turn off power from bt vendor interface"); + return -1; + } + vendor_interface->cleanup(); + vendor_interface = NULL; + return 0; + } else { + + ALOGE("Not able to find vendor interface handle"); + return -1; + } + } +} + +static void ant_disable_channel(ant_channel_info_t *pstChnlInfo) +{ + ANT_FUNC_START(); + if (!pstChnlInfo) { + ANT_ERROR("null channel info passed to channel disable function"); + goto out; + } + if (pstChnlInfo->iFd != -1) { + // Use the new init_transport function instead of open() to get our fd. + if (init_transport_bdroid(0) < 0) { + ANT_ERROR("failed to close channel %s(%#x): %s", pstChnlInfo->pcDevicePath, pstChnlInfo->iFd, strerror(errno)); + } + + pstChnlInfo->iFd = -1; //TODO can this overwrite a still valid fd? + } else { + ANT_DEBUG_D("%s file is already closed", pstChnlInfo->pcDevicePath); + } + +out: + ANT_FUNC_END(); +} + +static int ant_enable_channel(ant_channel_info_t *pstChnlInfo) +{ + int iRet = -1; + ANT_FUNC_START(); + if (!pstChnlInfo) { + ANT_ERROR("null channel info passed to channel enable function"); + errno = EINVAL; + goto out; + } + if (pstChnlInfo->iFd == -1) { + // Use the init_transport function to release our fd instead of close() + pstChnlInfo->iFd = init_transport_bdroid(1); + if (pstChnlInfo->iFd < 0) { + ANT_ERROR("failed to open dev %s: %s", pstChnlInfo->pcDevicePath, strerror(errno)); + goto out; + } + } else { + ANT_DEBUG_D("%s is already enabled", pstChnlInfo->pcDevicePath); + } + iRet = 0; +out: + ANT_FUNC_END(); + return iRet; +} + +//----------------------------------------------------------------------- This is antradio_power.h: + +int ant_enable(void) +{ + int iRet = -1; + ant_channel_type eChannel; + ANT_FUNC_START(); + + // Reset the shutdown signal. + uint64_t counter; + ssize_t result = read(stRxThreadInfo.iRxShutdownEventFd, &counter, sizeof(counter)); + // EAGAIN result indicates that the counter was already 0 in non-blocking mode. + if(result < 0 && errno != EAGAIN) + { + ANT_ERROR("Could not clear shutdown signal in enable. Reason: %s", strerror(errno)); + goto out; + } + + stRxThreadInfo.ucRunThread = 1; + + for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { + if (ant_enable_channel(&stRxThreadInfo.astChannels[eChannel]) < 0) { + ANT_ERROR("failed to enable channel %s: %s", + stRxThreadInfo.astChannels[eChannel].pcDevicePath, + strerror(errno)); + goto out; + } + } + + if (stRxThreadInfo.stRxThread == 0) { + if (pthread_create(&stRxThreadInfo.stRxThread, NULL, fnRxThread, &stRxThreadInfo) < 0) { + ANT_ERROR("failed to start rx thread: %s", strerror(errno)); + goto out; + } + } else { + ANT_DEBUG_D("rx thread is already running"); + } + + if (!stRxThreadInfo.ucRunThread) { + ANT_ERROR("rx thread crashed during init"); + goto out; + } + + iRet = 0; + +out: + ANT_FUNC_END(); + return iRet; +} + +int ant_disable(void) +{ + int iRet = -1; + ant_channel_type eChannel; + ANT_FUNC_START(); + + stRxThreadInfo.ucRunThread = 0; + + if (stRxThreadInfo.stRxThread != 0) { + ANT_DEBUG_I("Sending shutdown signal to rx thread."); + if(write(stRxThreadInfo.iRxShutdownEventFd, &EVENT_FD_PLUS_ONE, sizeof(EVENT_FD_PLUS_ONE)) < 0) + { + ANT_ERROR("failed to signal rx thread with eventfd. Reason: %s", strerror(errno)); + goto out; + } + ANT_DEBUG_I("Waiting for rx thread to finish."); + if (pthread_join(stRxThreadInfo.stRxThread, NULL) < 0) { + ANT_ERROR("failed to join rx thread: %s", strerror(errno)); + goto out; + } + } else { + ANT_DEBUG_D("rx thread is not running"); + } + + for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { + ant_disable_channel(&stRxThreadInfo.astChannels[eChannel]); + } + + iRet = 0; + +out: + stRxThreadInfo.stRxThread = 0; + ANT_FUNC_END(); + return iRet; +} + +//--------------------------------------------------------- + +const char *ant_get_lib_version() +{ + return "libantradio.so: "ANT_CHIP_NAME". Version " + LIBANT_STACK_MAJOR"."LIBANT_STACK_MINOR"."LIBANT_STACK_INCRE; +} diff --git a/src/bt-vendor_vfs/ant_rx_chardev.c b/src/bt-vendor_vfs/ant_rx_chardev.c new file mode 100644 index 0000000..a8f150c --- /dev/null +++ b/src/bt-vendor_vfs/ant_rx_chardev.c @@ -0,0 +1,421 @@ +/* + * ANT Stack + * + * Copyright 2011 Dynastream Innovations + * + * 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. + */ +/******************************************************************************\ +* +* FILE NAME: ant_rx_chardev.c +* +* BRIEF: +* This file implements the receive thread function which will loop reading +* ANT messages until told to exit. +* +* +\******************************************************************************/ + +#include +#include +#include +#include /* for uint64_t */ + +#include "ant_types.h" +#include "antradio_power.h" +#include "ant_rx_chardev.h" +#include "ant_hci_defines.h" +#include "ant_log.h" +#include "ant_native.h" // ANT_HCI_MAX_MSG_SIZE, ANT_MSG_ID_OFFSET, ANT_MSG_DATA_OFFSET, + // ant_radio_enabled_status() + +extern ANTStatus ant_tx_message_flowcontrol_none(ant_channel_type eTxPath, ANT_U8 ucMessageLength, ANT_U8 *pucTxMessage); + +#undef LOG_TAG +#define LOG_TAG "antradio_rx" + +#define ANT_POLL_TIMEOUT ((int)30000) + +static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE]; + +#ifdef ANT_DEVICE_NAME // Single transport path + static int iRxBufferLength[NUM_ANT_CHANNELS] = {0}; +#else + static int iRxBufferLength[NUM_ANT_CHANNELS] = {0, 0}; +#endif // + +// Defines for use with the poll() call +#define EVENT_DATA_AVAILABLE (POLLIN|POLLRDNORM) +#define EVENT_DISABLE (POLLHUP) +#define EVENT_HARD_RESET (POLLERR|POLLPRI|POLLRDHUP) + +#define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_DISABLE|EVENT_HARD_RESET) + +// Plus one is for the eventfd shutdown signal. +#define NUM_POLL_FDS (NUM_ANT_CHANNELS + 1) +#define EVENTFD_IDX NUM_ANT_CHANNELS + +void doReset(ant_rx_thread_info_t *stRxThreadInfo); +int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo); + +/* + * Function to check that all given flags are set in a particular value. + * Designed for use with the revents field of pollfds filled out by poll(). + * + * Parameters: + * - value: The value that will be checked to contain all flags. + * - flags: Bitwise-or of the flags that value should be checked for. + * + * Returns: + * - true IFF all the bits that are set in 'flags' are also set in 'value' + */ +ANT_BOOL areAllFlagsSet(short value, short flags) +{ + value &= flags; + return (value == flags); +} + +/* + * This thread waits for ANT messages from a VFS file. + */ +void *fnRxThread(void *ant_rx_thread_info) +{ + int iMutexLockResult; + int iPollRet; + ant_rx_thread_info_t *stRxThreadInfo; + struct pollfd astPollFd[NUM_POLL_FDS]; + ant_channel_type eChannel; + ANT_FUNC_START(); + + stRxThreadInfo = (ant_rx_thread_info_t *)ant_rx_thread_info; + for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { + astPollFd[eChannel].fd = stRxThreadInfo->astChannels[eChannel].iFd; + astPollFd[eChannel].events = EVENTS_TO_LISTEN_FOR; + } + // Fill out poll request for the shutdown signaller. + astPollFd[EVENTFD_IDX].fd = stRxThreadInfo->iRxShutdownEventFd; + astPollFd[EVENTFD_IDX].events = POLL_IN; + + /* continue running as long as not terminated */ + while (stRxThreadInfo->ucRunThread) { + /* Wait for data available on any file (transport path) */ + iPollRet = poll(astPollFd, NUM_POLL_FDS, ANT_POLL_TIMEOUT); + if (!iPollRet) { + ANT_DEBUG_V("poll timed out, checking exit cond"); + } else if (iPollRet < 0) { + ANT_ERROR("unhandled error: %s, attempting recovery.", strerror(errno)); + doReset(stRxThreadInfo); + goto out; + } else { + for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { + if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_HARD_RESET)) { + ANT_ERROR("Hard reset indicated by %s. Attempting recovery.", + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + doReset(stRxThreadInfo); + goto out; + } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DISABLE)) { + /* chip reported it was disabled, either unexpectedly or due to us closing the file */ + ANT_DEBUG_D( + "poll hang-up from %s. exiting rx thread", stRxThreadInfo->astChannels[eChannel].pcDevicePath); + + // set flag to exit out of Rx Loop + stRxThreadInfo->ucRunThread = 0; + + } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DATA_AVAILABLE)) { + ANT_DEBUG_D("data on %s. reading it", + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + + if (readChannelMsg(eChannel, &stRxThreadInfo->astChannels[eChannel]) < 0) { + // set flag to exit out of Rx Loop + stRxThreadInfo->ucRunThread = 0; + } + } else if (areAllFlagsSet(astPollFd[eChannel].revents, POLLNVAL)) { + ANT_ERROR("poll was called on invalid file descriptor %s. Attempting recovery.", + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + doReset(stRxThreadInfo); + goto out; + } else if (areAllFlagsSet(astPollFd[eChannel].revents, POLLERR)) { + ANT_ERROR("Unknown error from %s. Attempting recovery.", + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + doReset(stRxThreadInfo); + goto out; + } else if (astPollFd[eChannel].revents) { + ANT_DEBUG_W("unhandled poll result %#x from %s", + astPollFd[eChannel].revents, + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + } + } + // Now check for shutdown signal + if(areAllFlagsSet(astPollFd[EVENTFD_IDX].revents, POLLIN)) + { + ANT_DEBUG_I("rx thread caught shutdown signal."); + // reset the counter by reading. + uint64_t counter; + read(stRxThreadInfo->iRxShutdownEventFd, &counter, sizeof(counter)); + // don't care if read error, going to close the thread anyways. + stRxThreadInfo->ucRunThread = 0; + } else if (astPollFd[EVENTFD_IDX].revents != 0) { + ANT_ERROR("Shutdown event descriptor had unexpected event: %#x. exiting rx thread.", + astPollFd[EVENTFD_IDX].revents); + stRxThreadInfo->ucRunThread = 0; + } + } + } + + /* disable ANT radio if not already disabling */ + // Try to get stEnabledStatusLock. + // if you get it then no one is enabling or disabling + // if you can't get it assume something made you exit + ANT_DEBUG_V("try getting stEnabledStatusLock in %s", __FUNCTION__); + iMutexLockResult = pthread_mutex_trylock(stRxThreadInfo->pstEnabledStatusLock); + if (!iMutexLockResult) { + ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); + ANT_WARN("rx thread has unexpectedly crashed, cleaning up"); + + // spoof our handle as closed so we don't try to join ourselves in disable + stRxThreadInfo->stRxThread = 0; + + if (g_fnStateCallback) { + g_fnStateCallback(RADIO_STATUS_DISABLING); + } + + ant_disable(); + + if (g_fnStateCallback) { + g_fnStateCallback(ant_radio_enabled_status()); + } + + ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); + pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock); + ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); + } else if (iMutexLockResult != EBUSY) { + ANT_ERROR("rx thread closing code, trylock on state lock failed: %s", + strerror(iMutexLockResult)); + } else { + ANT_DEBUG_V("stEnabledStatusLock busy"); + } + + out: + ANT_FUNC_END(); +#ifdef ANDROID + return NULL; +#endif +} + +void doReset(ant_rx_thread_info_t *stRxThreadInfo) +{ + int iMutexLockResult; + + ANT_FUNC_START(); + /* Chip was reset or other error, only way to recover is to + * close and open ANT chardev */ + stRxThreadInfo->ucChipResetting = 1; + + if (g_fnStateCallback) { + g_fnStateCallback(RADIO_STATUS_RESETTING); + } + + stRxThreadInfo->ucRunThread = 0; + + ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); + iMutexLockResult = pthread_mutex_lock(stRxThreadInfo->pstEnabledStatusLock); + if (iMutexLockResult < 0) { + ANT_ERROR("chip was reset, getting state mutex failed: %s", + strerror(iMutexLockResult)); + stRxThreadInfo->stRxThread = 0; + } else { + ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); + + stRxThreadInfo->stRxThread = 0; /* spoof our handle as closed so we don't + * try to join ourselves in disable */ + + ant_disable(); + + if (ant_enable()) { /* failed */ + if (g_fnStateCallback) { + g_fnStateCallback(RADIO_STATUS_DISABLED); + } + } else { /* success */ + if (g_fnStateCallback) { + g_fnStateCallback(RADIO_STATUS_RESET); + } + } + + ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); + pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock); + ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); + } + + stRxThreadInfo->ucChipResetting = 0; + + ANT_FUNC_END(); +} + +//////////////////////////////////////////////////////////////////// +// setFlowControl +// +// Sets the flow control "flag" to the value provided and signals the transmit +// thread to check the value. +// +// Parameters: +// pstChnlInfo the details of the channel being updated +// ucFlowSetting the value to use +// +// Returns: +// Success: +// 0 +// Failure: +// -1 +//////////////////////////////////////////////////////////////////// +int setFlowControl(ant_channel_info_t *pstChnlInfo, ANT_U8 ucFlowSetting) +{ + int iRet = -1; + int iMutexResult; + ANT_FUNC_START(); + + ANT_DEBUG_V("getting stFlowControlLock in %s", __FUNCTION__); + iMutexResult = pthread_mutex_lock(pstChnlInfo->pstFlowControlLock); + if (iMutexResult) { + ANT_ERROR("failed to lock flow control mutex during response: %s", strerror(iMutexResult)); + } else { + ANT_DEBUG_V("got stFlowControlLock in %s", __FUNCTION__); + + pstChnlInfo->ucFlowControlResp = ucFlowSetting; + + ANT_DEBUG_V("releasing stFlowControlLock in %s", __FUNCTION__); + pthread_mutex_unlock(pstChnlInfo->pstFlowControlLock); + ANT_DEBUG_V("released stFlowControlLock in %s", __FUNCTION__); + + pthread_cond_signal(pstChnlInfo->pstFlowControlCond); + + iRet = 0; + } + + ANT_FUNC_END(); + return iRet; +} + +int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo) +{ + int iRet = -1; + int iRxLenRead; + int iCurrentHciPacketOffset; + int iHciDataSize; + ANT_FUNC_START(); + + // Keep trying to read while there is an error, and that error is EAGAIN + while (((iRxLenRead = read(pstChnlInfo->iFd, &aucRxBuffer[eChannel][iRxBufferLength[eChannel]], (sizeof(aucRxBuffer[eChannel]) - iRxBufferLength[eChannel]))) < 0) + && errno == EAGAIN) + ; + + if (iRxLenRead < 0) { + if (errno == ENODEV) { + ANT_ERROR("%s not enabled, exiting rx thread", + pstChnlInfo->pcDevicePath); + + goto out; + } else if (errno == ENXIO) { + ANT_ERROR("%s there is no physical ANT device connected", + pstChnlInfo->pcDevicePath); + + goto out; + } else { + ANT_ERROR("%s read thread exiting, unhandled error: %s", + pstChnlInfo->pcDevicePath, strerror(errno)); + + goto out; + } + } else { + ANT_SERIAL(aucRxBuffer[eChannel], iRxLenRead, 'R'); + + iRxLenRead += iRxBufferLength[eChannel]; // add existing data on + + // if we didn't get a full packet, then just exit + if (iRxLenRead < (aucRxBuffer[eChannel][ANT_HCI_SIZE_OFFSET] + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE)) { + iRxBufferLength[eChannel] = iRxLenRead; + iRet = 0; + goto out; + } + + iRxBufferLength[eChannel] = 0; // reset buffer length here since we should have a full packet + +#if ANT_HCI_OPCODE_SIZE == 1 // Check the different message types by opcode + ANT_U8 opcode = aucRxBuffer[eChannel][ANT_HCI_OPCODE_OFFSET]; + + if(ANT_HCI_OPCODE_COMMAND_COMPLETE == opcode) { + // Command Complete, so signal a FLOW_GO + if(setFlowControl(pstChnlInfo, ANT_FLOW_GO)) { + goto out; + } + } else if(ANT_HCI_OPCODE_FLOW_ON == opcode) { + // FLow On, so resend the last Tx +#ifdef ANT_FLOW_RESEND + // Check if there is a message to resend + if(pstChnlInfo->ucResendMessageLength > 0) { + ant_tx_message_flowcontrol_none(eChannel, pstChnlInfo->ucResendMessageLength, pstChnlInfo->pucResendMessage); + } else { + ANT_DEBUG_D("Resend requested by chip, but tx request cancelled"); + } +#endif // ANT_FLOW_RESEND + } else if(ANT_HCI_OPCODE_ANT_EVENT == opcode) + // ANT Event, send ANT packet to Rx Callback +#endif // ANT_HCI_OPCODE_SIZE == 1 + { + // Received an ANT packet + iCurrentHciPacketOffset = 0; + + while(iCurrentHciPacketOffset < iRxLenRead) { + + // TODO Allow HCI Packet Size value to be larger than 1 byte + // This currently works as no size value is greater than 255, and little endian + iHciDataSize = aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_SIZE_OFFSET]; + + if ((iHciDataSize + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE + iCurrentHciPacketOffset) > + iRxLenRead) { + // we don't have a whole packet + iRxBufferLength[eChannel] = iRxLenRead - iCurrentHciPacketOffset; + memcpy(aucRxBuffer[eChannel], &aucRxBuffer[eChannel][iCurrentHciPacketOffset], iRxBufferLength[eChannel]); + // the increment at the end should push us out of the while loop + } else +#ifdef ANT_MESG_FLOW_CONTROL + if (aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET] == + ANT_MESG_FLOW_CONTROL) { + // This is a flow control packet, not a standard ANT message + if(setFlowControl(pstChnlInfo, \ + aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET + ANT_MSG_DATA_OFFSET])) { + goto out; + } + } else +#endif // ANT_MESG_FLOW_CONTROL + { + if (pstChnlInfo->fnRxCallback != NULL) { + + // Loop through read data until all HCI packets are written to callback + pstChnlInfo->fnRxCallback(iHciDataSize, \ + &aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET]); + } else { + ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath); + } + } + + iCurrentHciPacketOffset = iCurrentHciPacketOffset + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE + iHciDataSize; + } + } + + iRet = 0; + } + +out: + ANT_FUNC_END(); + return iRet; +} diff --git a/src/bt-vendor_vfs/inc/ant_hci_defines.h b/src/bt-vendor_vfs/inc/ant_hci_defines.h new file mode 100644 index 0000000..3ffe672 --- /dev/null +++ b/src/bt-vendor_vfs/inc/ant_hci_defines.h @@ -0,0 +1,53 @@ +/* + * ANT Stack + * + * Copyright 2013 Dynastream Innovations + * + * 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. + */ +/*******************************************************************************\ +* +* FILE NAME: ant_hci_defines.h +* +* BRIEF: +* This file defines ANT specific HCI values used by the ANT chip that are +* not specific to the underlying chip. These should not need to be modified, +* but should be verified they are correct. +* +\*******************************************************************************/ + +#ifndef __VFS_INDEPENDENT_H +#define __VFS_INDEPENDENT_H + +// ANT HCI Packet Structure +// ----------------------------------------- +// | Header | Data | Footer | +// |----------------------|-----------------| +// |Optional| Data | Opt. | ... | Optional | +// | Opcode | Size | Sync | | Checksum | +// Data may include any number of ANT packets, with no sync byte or checksum. +// A read from the driver may return any number of ANT HCI packets. + +#include "ant_driver_defines.h" + +#define ANT_HCI_HEADER_SIZE ((ANT_HCI_OPCODE_SIZE) + (ANT_HCI_SIZE_SIZE) + (ANT_HCI_SYNC_SIZE)) +#define ANT_HCI_FOOTER_SIZE (ANT_HCI_CHECKSUM_SIZE) + +#define ANT_HCI_OPCODE_OFFSET 0 +#define ANT_HCI_SIZE_OFFSET ((ANT_HCI_OPCODE_OFFSET) + (ANT_HCI_OPCODE_SIZE)) +#define ANT_HCI_SYNC_OFFSET ((ANT_HCI_SIZE_OFFSET) + (ANT_HCI_SIZE_SIZE)) +#define ANT_HCI_DATA_OFFSET (ANT_HCI_HEADER_SIZE) + +#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10 + +#endif /* ifndef __VFS_INDEPENDENT_H */ diff --git a/src/bt-vendor_vfs/inc/ant_rx_chardev.h b/src/bt-vendor_vfs/inc/ant_rx_chardev.h new file mode 100644 index 0000000..1024dac --- /dev/null +++ b/src/bt-vendor_vfs/inc/ant_rx_chardev.h @@ -0,0 +1,98 @@ +/* + * ANT Stack + * + * Copyright 2011 Dynastream Innovations + * + * 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. + */ +/*******************************************************************************\ +* +* FILE NAME: ant_rx_chardev.h +* +* BRIEF: +* This file defines the receive thread function, the ant_rx_thread_info_t +* type for storing the -configuration- of the receive thread, the +* ant_channel_info_t type for storing a channel's (transport path) +* configuration, and an enumeration of all ANT channels (transport paths). +* +* +\*******************************************************************************/ + +#ifndef __ANT_RX_NATIVE_H +#define __ANT_RX_NATIVE_H + +#include "ant_native.h" +#include "ant_hci_defines.h" + +/* same as HCI_MAX_EVENT_SIZE from hci.h, but hci.h is not included for vfs */ +#define ANT_HCI_MAX_MSG_SIZE 260 + +#define ANT_MSG_SIZE_OFFSET ((ANT_U8)0) +#define ANT_MSG_ID_OFFSET ((ANT_U8)1) +#define ANT_MSG_DATA_OFFSET ((ANT_U8)2) + +/* This struct defines the info passed to an rx thread */ +typedef struct { + /* Device path */ + const char *pcDevicePath; + /* File descriptor to read from */ + int iFd; + /* Callback to call with ANT packet */ + ANTNativeANTEventCb fnRxCallback; + /* Flow control response if channel supports it */ + ANT_U8 ucFlowControlResp; + /* Handle to flow control condition */ + pthread_cond_t *pstFlowControlCond; + /* Handle to flow control mutex */ + pthread_mutex_t *pstFlowControlLock; +#ifdef ANT_FLOW_RESEND + /* Length of message to resend on request from chip */ + ANT_U8 ucResendMessageLength; + /* The message to resend on request from chip */ + ANT_U8 *pucResendMessage; +#endif // ANT_FLOW_RESEND +} ant_channel_info_t; + +typedef enum { +#ifdef ANT_DEVICE_NAME // Single transport path + SINGLE_CHANNEL, +#else // Separate data/command paths + DATA_CHANNEL, + COMMAND_CHANNEL, +#endif // Separate data/command paths + NUM_ANT_CHANNELS +} ant_channel_type; + +typedef struct { + /* Thread handle */ + pthread_t stRxThread; + /* Exit condition */ + ANT_U8 ucRunThread; + /* Set state as resetting override */ + ANT_U8 ucChipResetting; + /* Handle to state change lock for crash cleanup */ + pthread_mutex_t *pstEnabledStatusLock; + /* ANT channels */ + ant_channel_info_t astChannels[NUM_ANT_CHANNELS]; + /* Event file descriptor used to interrupt the poll() loop in the rx thread. */ + int iRxShutdownEventFd; +} ant_rx_thread_info_t; + +extern ANTNativeANTStateCb g_fnStateCallback; // TODO State callback should be inside ant_rx_thread_info_t. + +/* This is the rx thread function. It loops reading ANT packets until told to + * exit */ +void *fnRxThread(void *ant_rx_thread_info); + +#endif /* ifndef __ANT_RX_NATIVE_H */ + diff --git a/src/bt-vendor_vfs/inc/antradio_power.h b/src/bt-vendor_vfs/inc/antradio_power.h new file mode 100644 index 0000000..1aa0b24 --- /dev/null +++ b/src/bt-vendor_vfs/inc/antradio_power.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 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 __ANTRADIOPM_H +#define __ANTRADIOPM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enable the ANT radio interface. + * + * Responsible for power on, and bringing up HCI interface. + * Will block until the HCI interface is ready to use. + * + * Returns 0 on success, -ve on error */ +int ant_enable(); + +/* Disable the ANT radio interface. + * + * Responsbile for pulling down the HCI interface, and powering down the chip. + * Will block until power down is complete, and it is safe to immediately call + * enable(). + * + * Returns 0 on success, -ve on error */ +int ant_disable(); + +/* Returns 1 if enabled, 0 if disabled, and -ve on error */ +int ant_is_enabled(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/bt-vendor_vfs/qualcomm/uart/ant_driver_defines.h b/src/bt-vendor_vfs/qualcomm/uart/ant_driver_defines.h new file mode 100644 index 0000000..06b2e22 --- /dev/null +++ b/src/bt-vendor_vfs/qualcomm/uart/ant_driver_defines.h @@ -0,0 +1,98 @@ +/* + * ANT Stack + * + * Copyright 2011 Dynastream Innovations + * + * 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. + */ +/*******************************************************************************\ +* +* FILE NAME: ant_driver_defines.h +* +* BRIEF: +* This file defines ANT specific HCI values used by the ANT chip for a +* Qualcomm UART implementation. +* +* +\*******************************************************************************/ + +#ifndef __VFS_PRERELEASE_H +#define __VFS_PRERELEASE_H + +// Packets may be prefixed with an optional packet type byte when being sent to +// the chip. Will not be present in messages received. + +// ----------------------------------------- +// | Header | Data | Footer | +// |----------------------|-----------------| +// |Optional| Data | Opt. | ... | Optional | +// | Opcode | Size | Sync | | Checksum | + +// Data may include any number of ANT packets, with no sync byte or checksum. +// A read from the driver may return any number of ANT HCI packets. + + +// ---------------------- REQUIRED + +// Which chip is this library being built for: +#define ANT_CHIP_NAME "Qualcomm UART" + +// Set the file name the driver creates for the ANT device: +// If chip uses separate command and data paths: +// #define ANT_COMMANDS_DEVICE_NAME "/dev/X" +// #define ANT_DATA_DEVICE_NAME "/dev/Y" +// OR +// If chip uses one path: + +#define ANT_DEVICE_NAME "/dev/ttyHS0" + +// Optional Packet prefix byte. +#define HCI_PACKET_TYPE_SIZE 1 + +// Set to the number of bytes of header is for Opcode: +#define ANT_HCI_OPCODE_SIZE 0 + +// Set to the number of bytes of header is for Data Size: +#define ANT_HCI_SIZE_SIZE 1 + +// Set to the number of bytes of header is for Sync: +#define ANT_HCI_SYNC_SIZE 0 + +// Set to the number of bytes of footer is for Checksum: +#define ANT_HCI_CHECKSUM_SIZE 0 + +// ---------------------- OPTIONAL + +// If hard reset is supported, define ANT_IOCTL_RESET +// #define ANT_IOCTL_RESET _IOW('U', 210, int) +// #define ANT_IOCTL_RESET_PARAMETER (0) + +// If the chip sends flow control messages: +// Define the Opcode for a Flow Control message: +#define ANT_MESG_FLOW_CONTROL ((ANT_U8)0xC9) +// AND +// define the message content: +// That signals Flow Go: +#define ANT_FLOW_GO ((ANT_U8)0x00) + +// That signals Flow Stop: +#define ANT_FLOW_STOP ((ANT_U8)0x80) + +// Define protocol byte to be added +// as multiple data will be sent/received over +// same transport(BT, ANT ..etc) +// needed for HCI_PACKET_TYPE_SIZE > 1. +#define ANT_CMD_TYPE_PACKET ((ANT_U8)0x0C) +#define ANT_DATA_TYPE_PACKET ((ANT_U8)0x0E) + +#endif /* ifndef __VFS_PRERELEASE_H */ diff --git a/src/vfs/Android.mk b/src/vfs/Android.mk index a87645c..3d0af04 100644 --- a/src/vfs/Android.mk +++ b/src/vfs/Android.mk @@ -18,22 +18,18 @@ include $(CLEAR_VARS) LOCAL_CFLAGS := -g -c -W -Wall -O2 -BDROID_DIR:= external/bluetooth/bluedroid - -ifeq ($(ANT_DEVICE_USES_UART),true) -LOCAL_CFLAGS += -DANT_DEVICE_NAME -endif #ANT_DEVICE_USES_UART - LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/src/common/inc \ $(LOCAL_PATH)/$(ANT_DIR)/inc \ -LOCAL_C_INCLUDES += $(BDROID_DIR)/hci/include \ - ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"cg29xx") LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/$(ANT_DIR)/ste/cg29xx \ +else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"qualcomm-smd") +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/$(ANT_DIR)/qualcomm/smd \ + else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"vfs-prerelease") LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/$(ANT_DIR)/prerelease \ @@ -56,8 +52,6 @@ LOCAL_SHARED_LIBRARIES += \ LOCAL_SHARED_LIBRARIES += \ libcutils \ -LOCAL_SHARED_LIBRARIES += libdl - LOCAL_MODULE_TAGS := optional LOCAL_PRELINK_MODULE := false LOCAL_MODULE := libantradio diff --git a/src/vfs/ant_native_chardev.c b/src/vfs/ant_native_chardev.c index 3c0e7a5..2b49a8c 100644 --- a/src/vfs/ant_native_chardev.c +++ b/src/vfs/ant_native_chardev.c @@ -33,7 +33,6 @@ #include /* for uint64_t */ #include /* For eventfd() */ #include /* for read(), write(), and close() */ -#include #include "ant_types.h" #include "ant_native.h" @@ -43,38 +42,6 @@ #include "ant_rx_chardev.h" #include "ant_hci_defines.h" #include "ant_log.h" -#include "bt_vendor_lib.h" -#include -static void vendor_fwcfg_cb(bt_vendor_op_result_t result) { -} -static void vendor_scocfg_cb(bt_vendor_op_result_t result) { -} -static void vendor_lpm_vnd_cb(bt_vendor_op_result_t result) { -} -static void* vendor_alloc(int size) { - return NULL; -} -static void vendor_dealloc(void *p_buf) { -} -static uint8_t vendor_xmit_cb(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback) { - return 0; -} -static void vendor_epilog_cb(bt_vendor_op_result_t result) { -} - - -bt_vendor_interface_t *vendor_interface=NULL; -static const bt_vendor_callbacks_t vendor_callbacks = { - sizeof(bt_vendor_callbacks_t), - vendor_fwcfg_cb, - vendor_scocfg_cb, - vendor_lpm_vnd_cb, - vendor_alloc, - vendor_dealloc, - vendor_xmit_cb, - vendor_epilog_cb -}; - #if ANT_HCI_SIZE_SIZE > 1 #include "ant_utils.h" // Put HCI Size value across multiple bytes @@ -129,7 +96,7 @@ ANTStatus ant_init(void) g_fnStateCallback = 0; #ifdef ANT_DEVICE_NAME // Single transport path - ant_channel_init(&stRxThreadInfo.astChannels[SINGLE_CHANNEL], DEVICE_NAME); + ant_channel_init(&stRxThreadInfo.astChannels[SINGLE_CHANNEL], ANT_DEVICE_NAME); #else // Separate data/command paths ant_channel_init(&stRxThreadInfo.astChannels[COMMAND_CHANNEL], ANT_COMMANDS_DEVICE_NAME); ant_channel_init(&stRxThreadInfo.astChannels[DATA_CHANNEL], ANT_DATA_DEVICE_NAME); @@ -757,10 +724,10 @@ ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) { ANTStatus status = ANT_STATUS_FAILED; // TODO ANT_HCI_MAX_MSG_SIZE is transport (driver) dependent. - ANT_U8 txBuffer[ANT_HCI_MAX_MSG_SIZE+1];// +2 bytes for opcode and packet length + ANT_U8 txBuffer[ANT_HCI_MAX_MSG_SIZE]; // TODO Message length can be greater than ANT_U8 can hold. // Not changed as ANT_SERIAL takes length as ANT_U8. - ANT_U8 txMessageLength = ucLen + ANT_HCI_HEADER_SIZE;// +2 for opcode[0x0C - ctrl pkt , 0x0E - data pkt + ANT_U8 txMessageLength = ucLen + ANT_HCI_HEADER_SIZE; ANT_FUNC_START(); if (ant_radio_enabled_status() != RADIO_STATUS_ENABLED) { @@ -769,27 +736,27 @@ ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) } #if ANT_HCI_OPCODE_SIZE == 1 - txBuffer[ANT_HCI_OPCODE_OFFSET+1] = ANT_HCI_OPCODE_TX; + txBuffer[ANT_HCI_OPCODE_OFFSET] = ANT_HCI_OPCODE_TX; #elif ANT_HCI_OPCODE_SIZE > 1 #error "Specified ANT_HCI_OPCODE_SIZE not currently supported" #endif #if ANT_HCI_SIZE_SIZE == 1 - txBuffer[ANT_HCI_SIZE_OFFSET+1] = ucLen; + txBuffer[ANT_HCI_SIZE_OFFSET] = ucLen; #elif ANT_HCI_SIZE_SIZE == 2 ANT_UTILS_StoreLE16(txBuffer + ANT_HCI_SIZE_OFFSET, (ANT_U16)ucLen); #else #error "Specified ANT_HCI_SIZE_SIZE not currently supported" #endif - memcpy(txBuffer + ANT_HCI_HEADER_SIZE+1, pucMesg, ucLen); + memcpy(txBuffer + ANT_HCI_HEADER_SIZE, pucMesg, ucLen); - // ANT_SERIAL(txBuffer, txMessageLength, 'T'); + ANT_SERIAL(txBuffer, txMessageLength, 'T'); - -// status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength, txBuffer); -//#else // Separate data/command paths - switch (txBuffer[ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET+1]) { +#ifdef ANT_DEVICE_NAME // Single transport path + status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength, txBuffer); +#else // Separate data/command paths + switch (txBuffer[ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET]) { case MESG_BROADCAST_DATA_ID: case MESG_ACKNOWLEDGED_DATA_ID: case MESG_BURST_DATA_ID: @@ -797,26 +764,12 @@ ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) case MESG_EXT_ACKNOWLEDGED_DATA_ID: case MESG_EXT_BURST_DATA_ID: case MESG_ADV_BURST_DATA_ID: - ANT_DEBUG_V("Data Path"); - #ifdef ANT_DEVICE_NAME - txBuffer[0] = ANT_DATA_TYPE_PACKET; - ANT_SERIAL(txBuffer, txMessageLength+1, 'T'); - status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength+1, txBuffer); - #else status = ant_tx_message_flowcontrol_wait(DATA_CHANNEL, COMMAND_CHANNEL, txMessageLength, txBuffer); - #endif break; default: - ANT_DEBUG_V("Control Path"); - #ifdef ANT_DEVICE_NAME - txBuffer[0] = ANT_CMD_TYPE_PACKET; - ANT_SERIAL(txBuffer, txMessageLength+1, 'T'); - status = ant_tx_message_flowcontrol_none(SINGLE_CHANNEL, txMessageLength+1, txBuffer); - #else status = ant_tx_message_flowcontrol_none(COMMAND_CHANNEL, txMessageLength, txBuffer); - #endif } -//#endif // Separate data/command paths +#endif // Separate data/command paths out: ANT_FUNC_END(); @@ -850,91 +803,20 @@ static void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcChar ANT_FUNC_END(); } - -int init_transport_bdroid(int on) { - - void *so_handle; - unsigned char bdaddr[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; - int fd[CH_MAX], powerstate, ret; - - if (on) { - so_handle = dlopen("libbt-vendor.so", RTLD_NOW); - if (!so_handle) - { - ALOGE("Failed to load vendor component"); - return -1; - } - - vendor_interface = (bt_vendor_interface_t *) dlsym(so_handle, "BLUETOOTH_VENDOR_LIB_INTERFACE"); - if (!vendor_interface) - { - ALOGE("Failed to accesst bt vendor interface"); - return -1; - } - - vendor_interface->init(&vendor_callbacks, bdaddr); - - ALOGI("Turn On BT power"); - powerstate = BT_VND_PWR_ON; - ret = vendor_interface->op(BT_VND_OP_POWER_CTRL, &powerstate); - if (ret < 0) - { - ALOGE("Failed to turn on power from bt vendor interface"); - return -1; - } - /*call ANT_USERIAL_OPEN to get ANT handle*/ - ret = vendor_interface->op(BT_VND_OP_ANT_USERIAL_OPEN, fd); - ALOGE("ret value: %d", ret); - if (ret != 1) - { - ALOGE("Failed to get fd from bt vendor interface"); - return -1; - } else { - ALOGE("FD: %x", fd[0]); - return fd[0]; - } - } else { - if (vendor_interface) { - ALOGE("Close and cleanup the interfaces"); - int ret = vendor_interface->op(BT_VND_OP_ANT_USERIAL_CLOSE, NULL); - - ALOGE("ret value: %d", ret); - ALOGI("Turn off BT power"); - powerstate = BT_VND_PWR_OFF; - ret = vendor_interface->op(BT_VND_OP_POWER_CTRL, &powerstate); - if (ret < 0) - { - ALOGE("Failed to turn off power from bt vendor interface"); - return -1; - } - vendor_interface->cleanup(); - vendor_interface = NULL; - return 0; - } else { - - ALOGE("Not able to find vendor interface handle"); - return -1; - } - } -} - static void ant_disable_channel(ant_channel_info_t *pstChnlInfo) { ANT_FUNC_START(); - char bt_soc_type[PROPERTY_VALUE_MAX]; + if (!pstChnlInfo) { ANT_ERROR("null channel info passed to channel disable function"); goto out; } - property_get("qcom.bluetooth.soc", bt_soc_type, NULL); + if (pstChnlInfo->iFd != -1) { - if(!(strncasecmp(bt_soc_type,"rome", sizeof("rome")))) - init_transport_bdroid(0); - else{ if (close(pstChnlInfo->iFd) < 0) { ANT_ERROR("failed to close channel %s(%#x): %s", pstChnlInfo->pcDevicePath, pstChnlInfo->iFd, strerror(errno)); } - } + pstChnlInfo->iFd = -1; //TODO can this overwrite a still valid fd? } else { ANT_DEBUG_D("%s file is already closed", pstChnlInfo->pcDevicePath); @@ -944,35 +826,23 @@ out: ANT_FUNC_END(); } - - - static int ant_enable_channel(ant_channel_info_t *pstChnlInfo) { int iRet = -1; - char bt_soc_type[PROPERTY_VALUE_MAX]; ANT_FUNC_START(); if (!pstChnlInfo) { ANT_ERROR("null channel info passed to channel enable function"); errno = EINVAL; goto out; } - property_get("qcom.bluetooth.soc", bt_soc_type, NULL); - ANT_ERROR("BT_SOC_TYPE is %s",bt_soc_type); if (pstChnlInfo->iFd == -1) { - if(!(strncasecmp(bt_soc_type,"rome", sizeof("rome")))) - pstChnlInfo->iFd = init_transport_bdroid(1); - else - pstChnlInfo->iFd = open(pstChnlInfo->pcDevicePath, O_RDWR); - - if (pstChnlInfo->iFd < 0) { - ANT_ERROR("failed to open dev %s: %s", pstChnlInfo->pcDevicePath, strerror(errno)); - goto out; - } - } - else - { - ANT_DEBUG_D("%s is already enabled", pstChnlInfo->pcDevicePath); + pstChnlInfo->iFd = open(pstChnlInfo->pcDevicePath, O_RDWR); + if (pstChnlInfo->iFd < 0) { + ANT_ERROR("failed to open dev %s: %s", pstChnlInfo->pcDevicePath, strerror(errno)); + goto out; + } + } else { + ANT_DEBUG_D("%s is already enabled", pstChnlInfo->pcDevicePath); } iRet = 0; out: diff --git a/src/vfs/inc/ant_rx_chardev.h b/src/vfs/inc/ant_rx_chardev.h index b0fd8de..a3481b0 100644 --- a/src/vfs/inc/ant_rx_chardev.h +++ b/src/vfs/inc/ant_rx_chardev.h @@ -1,106 +1,98 @@ -/* - * ANT Stack - * - * Copyright 2011 Dynastream Innovations - * - * 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. - */ -/*******************************************************************************\ -* -* FILE NAME: ant_rx_chardev.h -* -* BRIEF: -* This file defines the receive thread function, the ant_rx_thread_info_t -* type for storing the -configuration- of the receive thread, the -* ant_channel_info_t type for storing a channel's (transport path) -* configuration, and an enumeration of all ANT channels (transport paths). -* -* -\*******************************************************************************/ - -#ifndef __ANT_RX_NATIVE_H -#define __ANT_RX_NATIVE_H - -#include "ant_native.h" -#include "ant_hci_defines.h" - -/* same as HCI_MAX_EVENT_SIZE from hci.h, but hci.h is not included for vfs */ -#define ANT_HCI_MAX_MSG_SIZE 260 - -#define ANT_MSG_SIZE_OFFSET ((ANT_U8)0) -#define ANT_MSG_ID_OFFSET ((ANT_U8)1) -#define ANT_MSG_DATA_OFFSET ((ANT_U8)2) - +/* + * ANT Stack + * + * Copyright 2011 Dynastream Innovations + * + * 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. + */ +/*******************************************************************************\ +* +* FILE NAME: ant_rx_chardev.h +* +* BRIEF: +* This file defines the receive thread function, the ant_rx_thread_info_t +* type for storing the -configuration- of the receive thread, the +* ant_channel_info_t type for storing a channel's (transport path) +* configuration, and an enumeration of all ANT channels (transport paths). +* +* +\*******************************************************************************/ + +#ifndef __ANT_RX_NATIVE_H +#define __ANT_RX_NATIVE_H + +#include "ant_native.h" +#include "ant_hci_defines.h" + +/* same as HCI_MAX_EVENT_SIZE from hci.h, but hci.h is not included for vfs */ +#define ANT_HCI_MAX_MSG_SIZE 260 + +#define ANT_MSG_SIZE_OFFSET ((ANT_U8)0) +#define ANT_MSG_ID_OFFSET ((ANT_U8)1) +#define ANT_MSG_DATA_OFFSET ((ANT_U8)2) + +/* This struct defines the info passed to an rx thread */ +typedef struct { + /* Device path */ + const char *pcDevicePath; + /* File descriptor to read from */ + int iFd; + /* Callback to call with ANT packet */ + ANTNativeANTEventCb fnRxCallback; + /* Flow control response if channel supports it */ + ANT_U8 ucFlowControlResp; + /* Handle to flow control condition */ + pthread_cond_t *pstFlowControlCond; + /* Handle to flow control mutex */ + pthread_mutex_t *pstFlowControlLock; +#ifdef ANT_FLOW_RESEND + /* Length of message to resend on request from chip */ + ANT_U8 ucResendMessageLength; + /* The message to resend on request from chip */ + ANT_U8 *pucResendMessage; +#endif // ANT_FLOW_RESEND +} ant_channel_info_t; + +typedef enum { #ifdef ANT_DEVICE_NAME // Single transport path -//Define protocol byte to be added -//as multiple data will be sent/received over -//same transport(BT, ANT ..etc) -#define ANT_CMD_TYPE_PACKET 0x0C -#define ANT_DATA_TYPE_PACKET 0x0E -#endif + SINGLE_CHANNEL, +#else // Separate data/command paths + DATA_CHANNEL, + COMMAND_CHANNEL, +#endif // Separate data/command paths + NUM_ANT_CHANNELS +} ant_channel_type; + +typedef struct { + /* Thread handle */ + pthread_t stRxThread; + /* Exit condition */ + ANT_U8 ucRunThread; + /* Set state as resetting override */ + ANT_U8 ucChipResetting; + /* Handle to state change lock for crash cleanup */ + pthread_mutex_t *pstEnabledStatusLock; + /* ANT channels */ + ant_channel_info_t astChannels[NUM_ANT_CHANNELS]; + /* Event file descriptor used to interrupt the poll() loop in the rx thread. */ + int iRxShutdownEventFd; +} ant_rx_thread_info_t; + +extern ANTNativeANTStateCb g_fnStateCallback; // TODO State callback should be inside ant_rx_thread_info_t. + +/* This is the rx thread function. It loops reading ANT packets until told to + * exit */ +void *fnRxThread(void *ant_rx_thread_info); + +#endif /* ifndef __ANT_RX_NATIVE_H */ -/* This struct defines the info passed to an rx thread */ -typedef struct { - /* Device path */ - const char *pcDevicePath; - /* File descriptor to read from */ - int iFd; - /* Callback to call with ANT packet */ - ANTNativeANTEventCb fnRxCallback; - /* Flow control response if channel supports it */ - ANT_U8 ucFlowControlResp; - /* Handle to flow control condition */ - pthread_cond_t *pstFlowControlCond; - /* Handle to flow control mutex */ - pthread_mutex_t *pstFlowControlLock; -#ifdef ANT_FLOW_RESEND - /* Length of message to resend on request from chip */ - ANT_U8 ucResendMessageLength; - /* The message to resend on request from chip */ - ANT_U8 *pucResendMessage; -#endif // ANT_FLOW_RESEND -} ant_channel_info_t; - -typedef enum { -#ifdef ANT_DEVICE_NAME // Single transport path - SINGLE_CHANNEL, -#else // Separate data/command paths - DATA_CHANNEL, - COMMAND_CHANNEL, -#endif // Separate data/command paths - NUM_ANT_CHANNELS -} ant_channel_type; - -typedef struct { - /* Thread handle */ - pthread_t stRxThread; - /* Exit condition */ - ANT_U8 ucRunThread; - /* Set state as resetting override */ - ANT_U8 ucChipResetting; - /* Handle to state change lock for crash cleanup */ - pthread_mutex_t *pstEnabledStatusLock; - /* ANT channels */ - ant_channel_info_t astChannels[NUM_ANT_CHANNELS]; - /* Event file descriptor used to interrupt the poll() loop in the rx thread. */ - int iRxShutdownEventFd; -} ant_rx_thread_info_t; - -extern ANTNativeANTStateCb g_fnStateCallback; // TODO State callback should be inside ant_rx_thread_info_t. - -/* This is the rx thread function. It loops reading ANT packets until told to - * exit */ -void *fnRxThread(void *ant_rx_thread_info); - -#endif /* ifndef __ANT_RX_NATIVE_H */ - diff --git a/src/vfs/prerelease/ant_driver_defines.h b/src/vfs/prerelease/ant_driver_defines.h index 9aa13ec..c30c6e4 100644 --- a/src/vfs/prerelease/ant_driver_defines.h +++ b/src/vfs/prerelease/ant_driver_defines.h @@ -1,87 +1,85 @@ -/* - * ANT Stack - * - * Copyright 2011 Dynastream Innovations - * - * 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. - */ -/*******************************************************************************\ -* -* FILE NAME: ant_driver_defines.h -* -* BRIEF: -* This file defines ANT specific HCI values used by the ANT chip for a -* sample TTY implementation. -* -* -\*******************************************************************************/ - -#ifndef __VFS_PRERELEASE_H -#define __VFS_PRERELEASE_H - -// ----------------------------------------- -// | Header | Data | Footer | -// |----------------------|-----------------| -// |Optional| Data | Opt. | ... | Optional | -// | Opcode | Size | Sync | | Checksum | - -// Data may include any number of ANT packets, with no sync byte or checksum. -// A read from the driver may return any number of ANT HCI packets. - - -// ---------------------- REQUIRED - -// Which chip is this library being built for: -#define ANT_CHIP_NAME "TTY" - -// Set the file name the driver creates for the ANT device: -// If chip uses separate command and data paths: -#define ANT_COMMANDS_DEVICE_NAME "/dev/smd5" -#define ANT_DATA_DEVICE_NAME "/dev/smd6" -// OR -// If chip uses one path: - -#ifdef ANT_DEVICE_NAME -#define DEVICE_NAME "/dev/ttyHS0" -#endif - -// Set to the number of bytes of header is for Opcode: -#define ANT_HCI_OPCODE_SIZE 0 - -// Set to the number of bytes of header is for Data Size: -#define ANT_HCI_SIZE_SIZE 1 - -// Set to the number of bytes of header is for Sync: -#define ANT_HCI_SYNC_SIZE 0 - -// Set to the number of bytes of footer is for Checksum: -#define ANT_HCI_CHECKSUM_SIZE 0 - -// ---------------------- OPTIONAL - -// If hard reset is supported, define ANT_IOCTL_RESET -// #define ANT_IOCTL_RESET _IOW('U', 210, int) -// #define ANT_IOCTL_RESET_PARAMETER (0) - -// If the chip sends flow control messages: -// Define the Opcode for a Flow Control message: -#define ANT_MESG_FLOW_CONTROL ((ANT_U8)0xC9) -// AND -// define the message content: -// That signals Flow Go: -#define ANT_FLOW_GO ((ANT_U8)0x00) - -// That signals Flow Stop: -#define ANT_FLOW_STOP ((ANT_U8)0x80) - -#endif /* ifndef __VFS_PRERELEASE_H */ +/* + * ANT Stack + * + * Copyright 2011 Dynastream Innovations + * + * 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. + */ +/*******************************************************************************\ +* +* FILE NAME: ant_driver_defines.h +* +* BRIEF: +* This file defines ANT specific HCI values used by the ANT chip for a +* sample TTY implementation. +* +* +\*******************************************************************************/ + +#ifndef __VFS_PRERELEASE_H +#define __VFS_PRERELEASE_H + +// ----------------------------------------- +// | Header | Data | Footer | +// |----------------------|-----------------| +// |Optional| Data | Opt. | ... | Optional | +// | Opcode | Size | Sync | | Checksum | + +// Data may include any number of ANT packets, with no sync byte or checksum. +// A read from the driver may return any number of ANT HCI packets. + + +// ---------------------- REQUIRED + +// Which chip is this library being built for: +#define ANT_CHIP_NAME "TTY" + +// Set the file name the driver creates for the ANT device: +// If chip uses separate command and data paths: +#define ANT_COMMANDS_DEVICE_NAME "/dev/smd5" +#define ANT_DATA_DEVICE_NAME "/dev/smd6" +// OR +// If chip uses one path: +// #define ANT_DEVICE_NAME "/dev/Z" + + +// Set to the number of bytes of header is for Opcode: +#define ANT_HCI_OPCODE_SIZE 0 + +// Set to the number of bytes of header is for Data Size: +#define ANT_HCI_SIZE_SIZE 1 + +// Set to the number of bytes of header is for Sync: +#define ANT_HCI_SYNC_SIZE 0 + +// Set to the number of bytes of footer is for Checksum: +#define ANT_HCI_CHECKSUM_SIZE 0 + +// ---------------------- OPTIONAL + +// If hard reset is supported, define ANT_IOCTL_RESET +// #define ANT_IOCTL_RESET _IOW('U', 210, int) +// #define ANT_IOCTL_RESET_PARAMETER (0) + +// If the chip sends flow control messages: +// Define the Opcode for a Flow Control message: +#define ANT_MESG_FLOW_CONTROL ((ANT_U8)0xC9) +// AND +// define the message content: +// That signals Flow Go: +#define ANT_FLOW_GO ((ANT_U8)0x00) + +// That signals Flow Stop: +#define ANT_FLOW_STOP ((ANT_U8)0x80) + +#endif /* ifndef __VFS_PRERELEASE_H */ diff --git a/src/vfs/qualcomm/smd/ant_driver_defines.h b/src/vfs/qualcomm/smd/ant_driver_defines.h new file mode 100644 index 0000000..273286d --- /dev/null +++ b/src/vfs/qualcomm/smd/ant_driver_defines.h @@ -0,0 +1,85 @@ +/* + * ANT Stack + * + * Copyright 2011 Dynastream Innovations + * + * 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. + */ +/*******************************************************************************\ +* +* FILE NAME: ant_driver_defines.h +* +* BRIEF: +* This file defines ANT specific HCI values used by the ANT chip for a +* sample TTY implementation. +* +* +\*******************************************************************************/ + +#ifndef __VFS_PRERELEASE_H +#define __VFS_PRERELEASE_H + +// ----------------------------------------- +// | Header | Data | Footer | +// |----------------------|-----------------| +// |Optional| Data | Opt. | ... | Optional | +// | Opcode | Size | Sync | | Checksum | + +// Data may include any number of ANT packets, with no sync byte or checksum. +// A read from the driver may return any number of ANT HCI packets. + + +// ---------------------- REQUIRED + +// Which chip is this library being built for: +#define ANT_CHIP_NAME "Qualcomm SMD" + +// Set the file name the driver creates for the ANT device: +// If chip uses separate command and data paths: +#define ANT_COMMANDS_DEVICE_NAME "/dev/smd5" +#define ANT_DATA_DEVICE_NAME "/dev/smd6" +// OR +// If chip uses one path: +// #define ANT_DEVICE_NAME "/dev/Z" + + +// Set to the number of bytes of header is for Opcode: +#define ANT_HCI_OPCODE_SIZE 0 + +// Set to the number of bytes of header is for Data Size: +#define ANT_HCI_SIZE_SIZE 1 + +// Set to the number of bytes of header is for Sync: +#define ANT_HCI_SYNC_SIZE 0 + +// Set to the number of bytes of footer is for Checksum: +#define ANT_HCI_CHECKSUM_SIZE 0 + +// ---------------------- OPTIONAL + +// If hard reset is supported, define ANT_IOCTL_RESET +// #define ANT_IOCTL_RESET _IOW('U', 210, int) +// #define ANT_IOCTL_RESET_PARAMETER (0) + +// If the chip sends flow control messages: +// Define the Opcode for a Flow Control message: +#define ANT_MESG_FLOW_CONTROL ((ANT_U8)0xC9) +// AND +// define the message content: +// That signals Flow Go: +#define ANT_FLOW_GO ((ANT_U8)0x00) + +// That signals Flow Stop: +#define ANT_FLOW_STOP ((ANT_U8)0x80) + +#endif /* ifndef __VFS_PRERELEASE_H */ -- cgit v1.2.3