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.c275
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
+}
+