diff options
Diffstat (limited to 'src/bluez_hci/ant_rx.c')
-rw-r--r-- | src/bluez_hci/ant_rx.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/src/bluez_hci/ant_rx.c b/src/bluez_hci/ant_rx.c new file mode 100644 index 0000000..76d29ff --- /dev/null +++ b/src/bluez_hci/ant_rx.c @@ -0,0 +1,275 @@ +/* + * ANT Stack + * + * Copyright 2009 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.c +* +* BRIEF: +* This file Implements the receive thread for an HCI implementation +* using Vendor Specific messages. +* +* +\******************************************************************************/ + + +#define _GNU_SOURCE /* needed for PTHREAD_MUTEX_RECURSIVE */ + +#include <errno.h> +#include <poll.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/un.h> + +#include "antradio_power.h" + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#include "ant_rx.h" +#include "ant_hciutils.h" +#include "ant_types.h" +#include "ant_framing.h" +#include "ant_log.h" +#undef LOG_TAG +#define LOG_TAG "antradio_rx" + +static char EVT_PKT_VENDOR_FILTER[] = {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x05,0x00,0x00}; + +/* Global Options */ +ANTHCIRxParams RxParams = { + .pfRxCallback = NULL, + .pfStateCallback = NULL, + .thread = 0 +}; + +extern pthread_mutex_t enableLock; +extern ANTRadioEnabledStatus get_and_set_radio_status(void); +/* + * This thread opens a Bluez HCI socket and waits for ANT messages. + */ +void *ANTHCIRxThread(void *pvHCIDevice) +{ + int ret = ANT_STATUS_SUCCESS; + int rxSocket; + int len; + unsigned char buf[HCI_MAX_EVENT_SIZE]; + int result; + ANT_FUNC_START(); + + (void)pvHCIDevice; //unused waring + + ANT_DEBUG_D("Entering ANTHCIRxThread"); + + rxSocket = create_hci_sock(); + if (rxSocket < 0) + { + ANT_DEBUG_E("can't open HCI socket in rx thread: %s", strerror(errno)); + + ret = ANT_STATUS_FAILED; + goto out; + } + + if (setsockopt(rxSocket, SOL_HCI, HCI_FILTER, &EVT_PKT_VENDOR_FILTER, + sizeof(EVT_PKT_VENDOR_FILTER)) < 0) + { + ANT_ERROR("failed to set socket options: %s", strerror(errno)); + + ret = ANT_STATUS_FAILED; + goto close; + } + + /* continue running as long as not terminated */ + while (get_and_set_radio_status() == RADIO_STATUS_ENABLED) + { + struct pollfd p; + int n; + + p.fd = rxSocket; + p.events = POLLIN; + + ANT_DEBUG_V(" RX: Polling HCI for data..."); + + /* poll socket, wait for ANT messages */ + while ((n = poll(&p, 1, 2500)) == -1) + { + if (errno == EAGAIN || errno == EINTR) + continue; + + ANT_ERROR("failed to poll socket: %s", strerror(errno)); + + ret = ANT_STATUS_FAILED; + goto close; + } + + /* we timeout once in a while */ + /* this let's us the chance to check if we were terminated */ + if (0 == n) + { + ANT_DEBUG_V(" RX: Timeout"); + continue; + } + + ANT_DEBUG_D("New HCI data available, reading..."); + + /* read newly arrived data */ + /* TBD: rethink assumption about single arrival */ + while ((len = read(rxSocket, buf, sizeof(buf))) < 0) + { + if (errno == EAGAIN || errno == EINTR) + continue; + + ANT_ERROR("failed to read socket: %s", strerror(errno)); + + ret = ANT_STATUS_FAILED; + goto close; + } + + // 0 = packet type eg. HCI_EVENT_PKT + // FOR EVENT: + // 1 = event code eg. EVT_VENDOR, EVT_CMD_COMPLETE + // 2 = Parameter total length + // 3... parameters + // FOR CC + // 3 = Num HCI Command packets allowed to be sent + // 4+5 = ANT Opcode + // 6 = Result ?? + // FOR VS + // 3+4 = ANT Opcode + // 5 = length + // 6 ? MSB of length ? + // 7... ant message + + if (len >= 7) + { + ANT_DEBUG_V("HCI Data: [%02X][%02X][%02X][%02X][%02X][%02X][%02X]...", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + } + else + { + ANT_ERROR("Failed to read full header off socket. len = %d", len); + continue; + } + + if (len != (buf[2] + 3)) + { + ANT_WARN("HCI packet length(%d) and bytes read(%d) dont match", buf[2] + 3, len); + } + + if(HCI_EVENT_PKT == buf[0]) + { + ANT_DEBUG_D("Received Event Packet"); + + if (EVT_VENDOR == buf[1]) + { + if ((HCI_VSOP_ANT_LSB == buf[3]) && (HCI_VSOP_ANT_MSB == buf[4])) + { + ANT_DEBUG_D("Received ANT VS Message"); + + if (len < 9) + { + ANT_ERROR("Malformed ANT header"); + ret = ANT_STATUS_FAILED; + goto close; + } + + ANT_DEBUG_V("ANT Mesg: ANTMesgSize:%d ANTMesgID:0x%02X ...", + buf[7], buf[8]); + + ANT_SERIAL(&(buf[7]), buf[5], 'R'); + + if(RxParams.pfRxCallback != NULL) + { + RxParams.pfRxCallback(buf[5], &(buf[7])); + } + else + { + ANT_ERROR("Can't send rx message - no callback registered"); + } + + continue; + } + else + { + ANT_DEBUG_W("Vendor Specific message for another vendor. " + "Should filter out"); + } + } + else + { + ANT_DEBUG_V("Other Event Packet, Ignoring"); + } + } + else + { + ANT_DEBUG_V("Non-Event Packet, Ignoring"); + } + } + +close: + result = pthread_mutex_trylock(&enableLock); + ANT_DEBUG_D("rx thread close: trylock enableLock returned %d", result); + + if (result == 0) + { + ANT_DEBUG_W("rx thread socket has unexpectedly crashed"); + if (RxParams.pfStateCallback) + RxParams.pfStateCallback(RADIO_STATUS_DISABLING); + ant_disable(); + get_and_set_radio_status(); + RxParams.thread = 0; + pthread_mutex_unlock(&enableLock); + } + else if (result == EBUSY) + { + ANT_DEBUG_V("rx thread socket was closed"); + } + else + { + ANT_ERROR("rx thread close: trylock failed: %s", strerror(result)); + } + + if (-1 == close(rxSocket)) + { + ANT_ERROR("failed to close hci device (socket handle=%#x): %s", rxSocket, strerror(errno)); + } + else + { + ANT_DEBUG_D("closed hci device (socket handle=%#x)", rxSocket); + } + +out: + ANT_FUNC_END(); + + pthread_exit((void *)ret); + +#if defined(ANDROID) + return 0; +#endif +} + |