aboutsummaryrefslogtreecommitdiffstats
path: root/src/bluez_hci/ant_rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluez_hci/ant_rx.c')
-rw-r--r--src/bluez_hci/ant_rx.c227
1 files changed, 227 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..3894cd6
--- /dev/null
+++ b/src/bluez_hci/ant_rx.c
@@ -0,0 +1,227 @@
+/*
+ * 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 a BlueZ 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 <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "ant_types.h"
+
+#if USE_EXTERNAL_POWER_LIBRARY
+#include "antradio_power.h"
+#endif
+
+#include "ant_rx.h"
+#include "ant_hciutils.h"
+#include "ant_framing.h"
+#include "ant_log.h"
+
+#undef LOG_TAG
+#define LOG_TAG "antradio_rx"
+
+/* Global Options */
+ANTHCIRxParams RxParams = {
+ .pfRxCallback = NULL,
+ .pfStateCallback = NULL,
+ .thread = 0
+};
+
+extern pthread_mutex_t enableLock;
+extern ANTRadioEnabledStatus get_and_set_radio_status(void);
+#ifndef USE_EXTERNAL_POWER_LIBRARY
+extern ANTRadioEnabledStatus radio_status;
+#endif
+
+/*
+ * 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;
+ struct hci_filter eventVendorFilter;
+ 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;
+ }
+
+ eventVendorFilter.type_mask = TYPE_MASK_EVENT_PACKET;
+ eventVendorFilter.event_mask[0] = 0;
+ eventVendorFilter.event_mask[1] = EVENT_MASK_1_EVENT_VENDOR;
+ eventVendorFilter.opcode = htobs(ANT_EVENT_VENDOR_CODE);
+
+ if (setsockopt(rxSocket, SOL_HCI, HCI_FILTER, &eventVendorFilter, sizeof(eventVendorFilter)) < 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;
+ }
+
+ hci_event_packet_t *event_packet = (hci_event_packet_t *)buf;
+ int hci_payload_len = validate_hci_event_packet(event_packet, len);
+ if (hci_payload_len == -1)
+ {
+ // part of the message is incorrect, ignore it. validate_event_packet will log error
+ continue;
+ }
+
+ ANT_SERIAL(event_packet->hci_payload, hci_payload_len, 'R');
+
+ if(RxParams.pfRxCallback != NULL)
+ {
+ RxParams.pfRxCallback(hci_payload_len, event_packet->hci_payload);
+ }
+ else
+ {
+ ANT_ERROR("Can't send rx message - no callback registered");
+ }
+ }
+
+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 USE_EXTERNAL_POWER_LIBRARY
+ if (RxParams.pfStateCallback)
+ RxParams.pfStateCallback(RADIO_STATUS_DISABLING);
+ ant_disable();
+ get_and_set_radio_status();
+#else
+ radio_status = RADIO_STATUS_DISABLED;
+#endif
+ 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
+}
+