blob: 76d29ffc82cabf536bc4bfddd665ff093e08aa39 [file] [log] [blame]
/*
* 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
}