Merge pull request #2 from rohan-martin/master

Android_System_Package_2-0-0
This commit is contained in:
Rohan Martin
2012-12-05 22:11:24 -08:00
27 changed files with 1697 additions and 1667 deletions

View File

@@ -16,6 +16,8 @@
ifneq ($(BOARD_ANT_WIRELESS_DEVICE),)
LOCAL_PATH := $(call my-dir)
#
# ANT native library
#
@@ -24,15 +26,19 @@ include $(CLEAR_VARS)
ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"wl12xx")
include $(LOCAL_PATH)/hal/bluez_hci/Android.mk
ANT_DIR := src/bluez_hci
else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"chip-B")
else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"bcm433x")
include $(LOCAL_PATH)/hal/chip-B/Android.mk
ANT_DIR := src/bluez_hci
else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"chip-C")
else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"cg29xx")
include $(LOCAL_PATH)/hal/chip-C/Android.mk
ANT_DIR := src/vfs
else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"vfs-prerelease")
ANT_DIR := src/vfs
else
@@ -40,6 +46,9 @@ $(error Unsupported BOARD_ANT_WIRELESS_DEVICE := $(BOARD_ANT_WIRELESS_DEVICE))
endif # BOARD_ANT_WIRELESS_DEVICE type
COMMON_DIR := src/common
include $(LOCAL_PATH)/$(ANT_DIR)/Android.mk
#
# ANT Application
@@ -54,7 +63,7 @@ LOCAL_C_INCLUDES:= \
LOCAL_CFLAGS:= -g -c -W -Wall -O2
LOCAL_SRC_FILES:= \
$(LOCAL_PATH)/app/ant_app.c
app/ant_app.c
LOCAL_SHARED_LIBRARIES := \
libantradio \

View File

@@ -14,39 +14,41 @@
# limitations under the License.
#
ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"wl12xx")
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -g -c -W -Wall -O2
# Check which chip is used so correct values in messages
ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"wl12xx")
LOCAL_CFLAGS += -DBOARD_ANT_DEVICE_WILINK
endif # BOARD_ANT_WIRELESS_DEVICE = wl12xx
LOCAL_CFLAGS += -DBOARD_ANT_DEVICE_WL12XX
else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"bcm433x")
LOCAL_CFLAGS += -DBOARD_ANT_DEVICE_BCM433X
endif
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../common/inc \
$(LOCAL_PATH)/inc \
$(LOCAL_PATH)/src/common/inc \
$(LOCAL_PATH)/$(ANT_DIR)/inc \
system/bluetooth/bluez-clean-headers \
ifeq ($(BOARD_ANT_WIRELESS_POWER),"bluedroid")
LOCAL_CFLAGS += -DBOARD_HAVE_ANT_WIRELESS
LOCAL_CFLAGS += \
-DBOARD_HAVE_ANT_WIRELESS \
-DUSE_EXTERNAL_POWER_LIBRARY \
LOCAL_C_INCLUDES += system/bluetooth/bluedroid/include/bluedroid
endif # BOARD_ANT_WIRELESS_POWER = bluedroid
LOCAL_SRC_FILES := \
$(COMMON_DIR)/JAntNative.cpp \
$(COMMON_DIR)/ant_utils.c \
$(ANT_DIR)/ant_native_hci.c \
$(ANT_DIR)/ant_rx.c \
$(ANT_DIR)/ant_tx.c \
# JNI
LOCAL_C_INCLUDE += $(JNI_H_INCLUDE)
LOCAL_SRC_FILES := \
../../JAntNative.cpp \
../common/ant_utils.c \
ant_native_hci.c \
ant_rx.c \
ant_tx.c \
# jni
LOCAL_SHARED_LIBRARIES += \
LOCAL_SHARED_LIBRARIES += \
libnativehelper \
# chip power
@@ -63,5 +65,3 @@ LOCAL_MODULE := libantradio
include $(BUILD_SHARED_LIBRARY)
endif # BOARD_ANT_WIRELESS_DEVICE = "wl12xx"

View File

@@ -1,26 +1,26 @@
/*
* 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.
*/
* 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_native_hci.c
*
* BRIEF:
* This file provides the HCI implementation of ant_native.h
* This file provides the BlueZ HCI implementation of ant_native.h
*
*
\******************************************************************************/
@@ -29,13 +29,15 @@
#include <string.h>
#include <unistd.h>
#include "antradio_power.h"
#include "ant_types.h"
#include "ant_native.h"
#include "ant_utils.h"
#include "ant_version.h"
#if USE_EXTERNAL_POWER_LIBRARY
#include "antradio_power.h"
#endif
#include "ant_rx.h"
#include "ant_tx.h"
#include "ant_hciutils.h"
@@ -44,7 +46,7 @@
static pthread_mutex_t txLock;
pthread_mutex_t enableLock;
static ANTRadioEnabledStatus radio_status = RADIO_STATUS_DISABLED;
ANTRadioEnabledStatus radio_status = RADIO_STATUS_DISABLED;
ANTRadioEnabledStatus get_and_set_radio_status(void);
////////////////////////////////////////////////////////////////////
@@ -238,6 +240,11 @@ ANTStatus ant_enable_radio(void)
}
ANT_DEBUG_V("got enableLock in %s", __FUNCTION__);
if(RADIO_STATUS_DISABLED == radio_status)
{
radio_status = RADIO_STATUS_ENABLING;
}
ANT_DEBUG_V("getting txLock in %s", __FUNCTION__);
lockResult = pthread_mutex_lock(&txLock);
if (lockResult)
@@ -258,15 +265,23 @@ ANTStatus ant_enable_radio(void)
RxParams.thread = 0;
ANT_DEBUG_V("recovered. joined by rx thread");
}
ANT_DEBUG_I("radio_status (%d -> %d)", radio_status, RADIO_STATUS_ENABLING);
radio_status = RADIO_STATUS_ENABLING;
#if USE_EXTERNAL_POWER_LIBRARY
if (RxParams.pfStateCallback)
RxParams.pfStateCallback(radio_status);
#endif
}
#if USE_EXTERNAL_POWER_LIBRARY
result = ant_enable();
ANT_DEBUG_D("ant_enable() result is %d", result);
#else
result = 0;
#endif
if (result == 0)
{
if (RxParams.thread)
@@ -286,6 +301,7 @@ ANTStatus ant_enable_radio(void)
else
{
result_status = ANT_STATUS_SUCCESS;
#if USE_EXTERNAL_POWER_LIBRARY
if (radio_status == RADIO_STATUS_ENABLING)
{
ANT_DEBUG_I("radio_status (%d -> %d)", radio_status, RADIO_STATUS_ENABLED);
@@ -298,6 +314,9 @@ ANTStatus ant_enable_radio(void)
{
ANT_WARN("radio was already enabled but rx thread was not running");
}
#else
radio_status = RADIO_STATUS_ENABLED;
#endif
}
}
}
@@ -306,9 +325,11 @@ ANTStatus ant_enable_radio(void)
result_status = ANT_STATUS_TRANSPORT_INIT_ERR;
}
if (result_status != ANT_STATUS_SUCCESS)
if (result_status != ANT_STATUS_SUCCESS) // ant_enable() or rx thread creating failed
{
#if USE_EXTERNAL_POWER_LIBRARY
ant_disable();
#endif
switch (get_and_set_radio_status())
{
@@ -333,6 +354,22 @@ ANTStatus ant_enable_radio(void)
return result_status;
}
////////////////////////////////////////////////////////////////////
// ant_radio_hard_reset
//
// Does nothing as Hard Reset is not supported.
//
// Parameters:
// -
//
// Returns:
// ANT_NOT_SUPPORTED
//
// Psuedocode:
/*
RESULT = NOT SUPPORTED
*/
////////////////////////////////////////////////////////////////////
ANTStatus ant_radio_hard_reset(void)
{
ANTStatus result_status = ANT_STATUS_NOT_SUPPORTED;
@@ -406,6 +443,7 @@ ANTStatus ant_disable_radio(void)
}
ANT_DEBUG_V("got txLock in %s", __FUNCTION__);
#if USE_EXTERNAL_POWER_LIBRARY
if (get_and_set_radio_status() != RADIO_STATUS_DISABLED)
{
ANT_DEBUG_I("radio_status (%d -> %d)", radio_status, RADIO_STATUS_DISABLING);
@@ -416,7 +454,11 @@ ANTStatus ant_disable_radio(void)
}
result = ant_disable();
ANT_DEBUG_D("ant_disable() result is %d", result);
#else
radio_status = RADIO_STATUS_DISABLED;
#endif
// If rx thread exists ( != 0)
if (RxParams.thread)
@@ -512,7 +554,7 @@ ANTRadioEnabledStatus ant_radio_enabled_status(void)
// change internal state from enabled, disabled, or unknown to any of these
// three on errors.
//
// Paramerters:
// Parameters:
// -
//
// Returns:
@@ -521,9 +563,9 @@ ANTRadioEnabledStatus ant_radio_enabled_status(void)
////////////////////////////////////////////////////////////////////
ANTRadioEnabledStatus get_and_set_radio_status(void)
{
ANTRadioEnabledStatus orig_status = radio_status;
ANT_FUNC_START();
#if USE_EXTERNAL_POWER_LIBRARY
ANTRadioEnabledStatus orig_status = radio_status;
switch (ant_is_enabled())
{
case 0:
@@ -544,7 +586,7 @@ ANTRadioEnabledStatus get_and_set_radio_status(void)
if (RxParams.pfStateCallback)
RxParams.pfStateCallback(radio_status);
}
#endif
ANT_FUNC_END();
return radio_status;
}
@@ -556,7 +598,7 @@ ANTRadioEnabledStatus get_and_set_radio_status(void)
//
// Parameters:
// rx_callback_func the ANTNativeANTEventCb function to be used
// for recieved messages.
// for received messages.
//
// Returns:
// ANT_STATUS_SUCCESS
@@ -569,13 +611,11 @@ ANTRadioEnabledStatus get_and_set_radio_status(void)
ANTStatus set_ant_rx_callback(ANTNativeANTEventCb rx_callback_func)
{
ANTStatus status = ANT_STATUS_SUCCESS;
ANT_FUNC_START();
RxParams.pfRxCallback = rx_callback_func;
ANT_FUNC_END();
return status;
}
@@ -586,7 +626,7 @@ ANTStatus set_ant_rx_callback(ANTNativeANTEventCb rx_callback_func)
//
// Parameters:
// state_callback_func the ANTNativeANTStateCb function to be used
// for recieved state changes.
// for received state changes.
//
// Returns:
// ANT_STATUS_SUCCESS
@@ -599,7 +639,6 @@ ANTStatus set_ant_rx_callback(ANTNativeANTEventCb rx_callback_func)
ANTStatus set_ant_state_callback(ANTNativeANTStateCb state_callback_func)
{
ANTStatus status = ANT_STATUS_SUCCESS;
ANT_FUNC_START();
RxParams.pfStateCallback = state_callback_func;

View File

@@ -20,13 +20,12 @@
* FILE NAME: ant_rx.c
*
* BRIEF:
* This file Implements the receive thread for an HCI implementation
* 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>
@@ -44,23 +43,24 @@
#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_types.h"
#if USE_EXTERNAL_POWER_LIBRARY
#include "antradio_power.h"
#endif
#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,
@@ -70,6 +70,10 @@ ANTHCIRxParams RxParams = {
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.
*/
@@ -80,6 +84,7 @@ void *ANTHCIRxThread(void *pvHCIDevice)
int len;
unsigned char buf[HCI_MAX_EVENT_SIZE];
int result;
struct hci_filter eventVendorFilter;
ANT_FUNC_START();
(void)pvHCIDevice; //unused waring
@@ -95,8 +100,12 @@ void *ANTHCIRxThread(void *pvHCIDevice)
goto out;
}
if (setsockopt(rxSocket, SOL_HCI, HCI_FILTER, &EVT_PKT_VENDOR_FILTER,
sizeof(EVT_PKT_VENDOR_FILTER)) < 0)
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));
@@ -150,84 +159,23 @@ void *ANTHCIRxThread(void *pvHCIDevice)
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)
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)
{
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);
// part of the message is incorrect, ignore it. validate_event_packet will log error
continue;
}
if (len != (buf[2] + 3))
ANT_SERIAL(event_packet->hci_payload, hci_payload_len, 'R');
if(RxParams.pfRxCallback != NULL)
{
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");
}
RxParams.pfRxCallback(hci_payload_len, event_packet->hci_payload);
}
else
{
ANT_DEBUG_V("Non-Event Packet, Ignoring");
ANT_ERROR("Can't send rx message - no callback registered");
}
}
@@ -238,10 +186,14 @@ close:
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);
}

View File

@@ -20,8 +20,8 @@
* FILE NAME: ant_tx.c
*
* BRIEF:
* This file Implements the transmit functionality for an HCI implementation
* using Vendor Specific messages.
* This file Implements the transmit functionality for a BlueZ HCI
* implementation using Vendor Specific messages.
*
*
\******************************************************************************/
@@ -39,31 +39,35 @@
#include "ant_framing.h"
#include "ant_utils.h"
#include "ant_log.h"
#undef LOG_TAG
#define LOG_TAG "antradio_tx"
static char EVT_PKT_CMD_COMPLETE_FILTER[] = {0x10,0x00,0x00,0x00,0x00,0x40,0x00,
0x00,0x00,0x00,0x00,0x00,0xD1,0xFD,0x00,0x00};
int g_ant_cmd_socket = -1;
int ant_open_tx_transport(void)
{
int socket = -1;
struct hci_filter commandCompleteFilter;
ANT_FUNC_START();
socket = create_hci_sock();
if (socket < 0)
if (socket < 0)
{
ANT_DEBUG_E("failed to open HCI socket for tx: %s", strerror(errno));
}
else
{
g_ant_cmd_socket = socket;
ANT_DEBUG_D("socket handle %#x", g_ant_cmd_socket);
if (setsockopt(g_ant_cmd_socket, SOL_HCI, HCI_FILTER,
&EVT_PKT_CMD_COMPLETE_FILTER, sizeof(EVT_PKT_CMD_COMPLETE_FILTER)) < 0)
ANT_DEBUG_D("socket handle %#x", socket);
commandCompleteFilter.type_mask = TYPE_MASK_EVENT_PACKET;
commandCompleteFilter.event_mask[0] = EVENT_MASK_0_COMMAND_COMPLETE;
commandCompleteFilter.event_mask[1] = 0;
commandCompleteFilter.opcode = htobs(ANT_COMMAND_OPCODE);
if (setsockopt(socket, SOL_HCI, HCI_FILTER, &commandCompleteFilter, sizeof(commandCompleteFilter)) < 0)
{
ANT_ERROR("failed to set socket options: %s", strerror(errno));
close(socket);
@@ -81,7 +85,7 @@ void ant_close_tx_transport(int socket)
if(0 < socket)
{
if (0 == close(socket))
if (0 == close(socket))
{
ANT_DEBUG_D("closed hci device (socket handle=%#x)", socket);
}
@@ -176,17 +180,11 @@ ANTStatus write_data(ANT_U8 ant_message[], int ant_message_len)
ANT_BOOL retry = ANT_FALSE;
int bytes_written;
struct iovec iov[2];
hci_vendor_cmd_packet_t hci_header;
ANT_U16 hci_opcode;
hci_command_vendor_header_t hci_header;
ANT_FUNC_START();
hci_opcode = cmd_opcode_pack(OGF_VENDOR_CMD, HCI_CMD_ANT_MESSAGE_WRITE);
hci_header.packet_type = HCI_COMMAND_PKT;
ANT_UTILS_StoreLE16(hci_header.cmd_header.opcode, hci_opcode);
hci_header.cmd_header.plen = ((ant_message_len + HCI_VENDOR_HEADER_SIZE) & 0xFF);
ANT_UTILS_StoreLE16(hci_header.vendor_header.hcilen, ant_message_len);
create_command_header(&hci_header, ant_message_len);
iov[0].iov_base = &hci_header;
iov[0].iov_len = sizeof(hci_header);
@@ -257,9 +255,8 @@ ANTStatus get_command_complete_result(int socket)
{
ANTStatus status = ANT_STATUS_NO_VALUE_AVAILABLE;
int len;
ANTStatus ret = ANT_STATUS_SUCCESS;
ANT_U8 ucResult = -1;
ANT_U8 buf[ANT_NATIVE_MAX_PARMS_LEN];
ANT_U8 buf[HCI_MAX_EVENT_SIZE];
ANT_FUNC_START();
ANT_DEBUG_V("reading off socket %#x", socket);
@@ -272,82 +269,62 @@ ANTStatus get_command_complete_result(int socket)
ANT_ERROR("failed to read socket. error: %s", strerror(errno));
ret = ANT_STATUS_FAILED;
status = ANT_STATUS_FAILED;
goto close;
}
ANT_SERIAL(buf, len, 'C');
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]);
// 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 Vommand 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(HCI_EVENT_PKT == buf[0])
// validate that we have a single command complete packet
if (len != sizeof(hci_command_complete_packet_t))
{
ANT_DEBUG_D("Received Event Packet");
status = ANT_STATUS_FAILED;
}
else
{
hci_command_complete_packet_t *command_complete = (hci_command_complete_packet_t *)buf;
if(EVT_CMD_COMPLETE == buf[1])
if(command_complete->packet_type == HCI_EVENT_PKT)
{
if(len < HCI_EVENT_OVERHEAD_SIZE)
ANT_DEBUG_D("Received Event Packet");
if(command_complete->event_header.evt == EVT_CMD_COMPLETE)
{
status = ANT_STATUS_FAILED;
ANT_U16 opcode = ANT_UTILS_LEtoHost16((ANT_U8 *)&command_complete->command_complete_hdr.opcode);
if(opcode == ANT_COMMAND_OPCODE)
{
ANT_DEBUG_V("Received COMMAND COMPLETE");
ucResult = command_complete->response;
if(ucResult == 0)
{
ANT_DEBUG_D("Command Complete = SUCCESS");
status = ANT_STATUS_SUCCESS;
}
else if(ucResult == HCI_UNSPECIFIED_ERROR)
{
ANT_DEBUG_D("Command Complete = UNSPECIFIED_ERROR");
status = ANT_STATUS_TRANSPORT_UNSPECIFIED_ERROR;
}
else
{
status = ANT_STATUS_COMMAND_WRITE_FAILED;
ANT_DEBUG_D("Command Complete = WRITE_FAILED");
}
}
else
{
ANT_DEBUG_W("Command complete has wrong opcode, this should have been filtered out");
}
}
else
{
if((HCI_CMD_OPCODE_ANT_LSB == buf[4]) &&
(HCI_CMD_OPCODE_ANT_MSB == buf[5]))
{
ucResult = buf[6];
ANT_DEBUG_V("Received COMMAND COMPLETE");
}
else
{
ANT_DEBUG_V("Command complete has wrong opcode");
}
}
/*
* if got a status byte, pass it forward, otherwise pass a failure
* status
*/
if(status != ANT_STATUS_FAILED)
{
if(ucResult == 0)
{
ANT_DEBUG_D("Command Complete = SUCCESS");
status = ANT_STATUS_SUCCESS;
}
else if(ucResult == HCI_UNSPECIFIED_ERROR)
{
ANT_DEBUG_D("Command Complete = UNSPECIFIED_ERROR");
status = ANT_STATUS_TRANSPORT_UNSPECIFIED_ERROR;
}
else
{
status = ANT_STATUS_COMMAND_WRITE_FAILED;
ANT_DEBUG_D("Command Complete = WRITE_FAILED");
}
ANT_DEBUG_W("Event is not a command complete, this should have been filtered out");
}
}
else
{
ANT_DEBUG_W("Other Event Packet, Should filter out");
ANT_DEBUG_W("Other Event Packet, this should have been filtered out");
}
}

View File

@@ -2,25 +2,26 @@
* 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
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/******************************************************************************\
*
* FILE NAME: ANT_Framing.h
* FILE NAME: ant_framing.h
*
* BRIEF:
* This file defines ANT specific HCI values used by the ANT chip.
* BRIEF:
* This file defines ANT specific HCI values used by the ANT chip with a
* shared BlueZ HCI transport.
*
*
\******************************************************************************/
@@ -28,23 +29,167 @@
#ifndef __ANT_HCIFRAMING_H
#define __ANT_HCIFRAMING_H
#ifdef BOARD_ANT_DEVICE_WILINK
#if defined(BOARD_ANT_DEVICE_WL12XX)
/* Number to used by the VS Parameters Len field */
#define ANT_NATIVE_HCI_VS_PARMS_LEN_FIELD_LEN (2)
#define ANT_COMMAND_OPCODE 0xFDD1
#define ANT_EVENT_VENDOR_CODE 0x0500
#define HCI_CMD_ANT_MESSAGE_WRITE ((ANT_U16)0x01D1)
typedef struct {
ANT_U16 vendor_msg_len;
} __attribute__ ((packed)) hci_cmd_vendor_hdr_t;
#define HCI_COMMAND_VENDOR_HDR_SIZE 2
#define HCI_CMD_OPCODE_ANT_LSB 0xD1
#define HCI_CMD_OPCODE_ANT_MSB 0xFD
typedef struct {
ANT_U16 vendor_code;
ANT_U16 vendor_msg_len;
} __attribute__ ((packed)) hci_evt_vendor_hdr_t;
#define HCI_EVENT_VENDOR_HDR_SIZE 4
#define HCI_VSOP_ANT_LSB 0x00
#define HCI_VSOP_ANT_MSB 0x05
#elif defined(BOARD_ANT_DEVICE_BCM433X)
#else
#define ANT_COMMAND_OPCODE 0xFCEC
#define ANT_EVENT_VENDOR_CODE 0x2D
#error "Board ANT Device Type not recognised"
typedef struct {
ANT_U8 command_id_padding;
} __attribute__ ((packed)) hci_cmd_vendor_hdr_t;
#define HCI_COMMAND_VENDOR_HDR_SIZE 1
typedef struct {
ANT_U8 vendor_code;
ANT_U8 status;
} __attribute__ ((packed)) hci_evt_vendor_hdr_t;
#define HCI_EVENT_VENDOR_HDR_SIZE 2
#define COMMAND_ID_PADDING 0xFF
#endif
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include "ant_native.h"
#include "ant_types.h"
#include "ant_utils.h"
#define HCI_EVENT_HEADER_OVERHEAD (HCI_TYPE_LEN + HCI_EVENT_HDR_SIZE)
#define HCI_EVENT_TOTAL_OVERHEAD (HCI_EVENT_HEADER_OVERHEAD + HCI_EVENT_VENDOR_HDR_SIZE)
#define TYPE_MASK_EVENT_PACKET 0x00000010
#define EVENT_MASK_0_COMMAND_COMPLETE 0x00004000
#define EVENT_MASK_1_EVENT_VENDOR 0x80000000
// -------------------------------------------------
typedef struct {
ANT_U8 packet_type; // HCI_COMMAND_PKT
hci_command_hdr command_header; // from hci.h
hci_cmd_vendor_hdr_t vendor_header;
} __attribute__ ((packed)) hci_command_vendor_header_t;
typedef struct {
ANT_U8 packet_type; // HCI_EVENT_PKT
hci_event_hdr event_header; // from hci.h
hci_evt_vendor_hdr_t vendor_header;
ANT_U8 hci_payload[HCI_MAX_EVENT_SIZE];
} __attribute__ ((packed)) hci_event_packet_t;
typedef struct {
ANT_U8 packet_type; // HCI_EVENT_PKT
hci_event_hdr event_header; // from hci.h
evt_cmd_complete command_complete_hdr;// from hci.h
ANT_U8 response;
} __attribute__ ((packed)) hci_command_complete_packet_t;
// -------------------------------------------------
/**
* @param header the struct to fill with chip specific hci header
* @param ant_message_len total ant length, size, id, and data
*/
static inline void create_command_header(hci_command_vendor_header_t *header, ANT_U8 ant_message_len)
{
header->packet_type = HCI_COMMAND_PKT;
header->command_header.opcode = htobs(ANT_COMMAND_OPCODE);
header->command_header.plen = ant_message_len + HCI_COMMAND_VENDOR_HDR_SIZE;
#if defined(BOARD_ANT_DEVICE_WL12XX)
header->vendor_header.vendor_msg_len = htobs(ant_message_len);
#elif defined(BOARD_ANT_DEVICE_BCM433X)
header->vendor_header.command_id_padding = COMMAND_ID_PADDING;
#endif
}
/**
* @param packet the struct to check if is an ANT hci payload
* @param packet_len the total length of the packet
* @return 0 if valid, -1 if not valid
*/
static inline int validate_hci_event_vendor(hci_event_packet_t *packet, int packet_len)
{
#if defined(BOARD_ANT_DEVICE_WL12XX)
ANT_U16 vendor_code = ANT_UTILS_LEtoHost16((ANT_U8 *)&packet->vendor_header.vendor_code);
#elif defined(BOARD_ANT_DEVICE_BCM433X)
ANT_U8 vendor_code = packet->vendor_header.vendor_code;
#endif
if (vendor_code != ANT_EVENT_VENDOR_CODE) {
ANT_ERROR("HCI packet vendor event code is not ANT");
return -1;
}
#if defined(BOARD_ANT_DEVICE_WL12XX)
ANT_U16 vendor_msg_len = ANT_UTILS_LEtoHost16((ANT_U8 *)&packet->vendor_header.vendor_msg_len);
if (packet_len != vendor_msg_len + HCI_EVENT_TOTAL_OVERHEAD) {
ANT_ERROR("HCI packet length (%d) should be %d bytes more than HCI payload length (%d)",
packet_len, HCI_EVENT_TOTAL_OVERHEAD, vendor_msg_len);
return -1;
}
#elif defined(BOARD_ANT_DEVICE_BCM433X)
(void)packet_len; // unused warning
#endif
return 0;
}
/**
* @param packet the struct to validate
* @param packet_len the total length of the packet
* @return -1 if not valid, or length of the ANT hci payload
*/
static inline int validate_hci_event_packet(hci_event_packet_t *packet, int packet_len)
{
// Make sure we have at the minimum the hci header, vendor header, and ANT size/id bytes
if (packet_len < HCI_EVENT_TOTAL_OVERHEAD) {
ANT_ERROR("HCI packet length (%d) is less than minimum (%d)",
packet_len, HCI_EVENT_TOTAL_OVERHEAD);
return -1;
}
if (packet->packet_type != HCI_EVENT_PKT) {
ANT_ERROR("HCI packet is not an event packet");
return -1;
}
if (packet->event_header.evt != EVT_VENDOR) {
ANT_ERROR("HCI packet is not a vendor event");
return -1;
}
if (packet_len != packet->event_header.plen + HCI_EVENT_HEADER_OVERHEAD) {
ANT_ERROR("HCI packet length (%d) should be %d bytes more than HCI event length (%d)",
packet_len, HCI_EVENT_HDR_SIZE, packet->event_header.plen);
return -1;
}
if (validate_hci_event_vendor(packet, packet_len) == -1)
{
return -1;
}
else
{
// return HCI payload len
return packet_len - HCI_EVENT_TOTAL_OVERHEAD;
}
}
#endif /* __ANT_HCIFRAMING_H */

View File

@@ -17,10 +17,10 @@
*/
/******************************************************************************\
*
* FILE NAME: ant_hciuntils.h
* FILE NAME: ant_hciutils.h
*
* BRIEF:
* This file defines the utility functions for an HCI implementation
* This file defines the utility functions for a Bluetooth HCI implementation
*
*
\******************************************************************************/
@@ -33,65 +33,9 @@
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include "ant_types.h"
#include "ant_native.h"
#include "ant_log.h"
// -------------------------------------------------
#define HCI_COMMAND_HEADER_SIZE 3
typedef struct {
ANT_U8 opcode[2]; // 0xFDD1 for ANT
ANT_U8 plen;
} __attribute__ ((packed)) hci_command_header_t;
#define HCI_VENDOR_HEADER_SIZE 2
typedef struct {
ANT_U8 hcilen[2];
} __attribute__ ((packed)) hci_vendor_header_t;
#define HCI_COMMAND_OVERHEAD_SIZE ( HCI_COMMAND_HEADER_SIZE + \
HCI_VENDOR_HEADER_SIZE + 1)
typedef struct {
ANT_U8 packet_type; // 0x01 for HCI_COMMAND_PKT
hci_command_header_t cmd_header;
hci_vendor_header_t vendor_header;
} __attribute__ ((packed)) hci_vendor_cmd_packet_t;
#define HCI_EVENT_HEADER_SIZE 2
typedef struct {
ANT_U8 event_c; // 0xFF for Vendor Specific,
// 0x0E for EVNT_CMD_COMPLETE
ANT_U8 plen; // data/parameter length
} __attribute__ ((packed)) hci_event_header_t;
#define HCI_EVENT_OVERHEAD_SIZE (HCI_EVENT_HEADER_SIZE + 5)
typedef struct {
ANT_U8 packet_type; // HCI_EVENT_PKT
hci_event_header_t header;
union {
struct {
ANT_U8 vendor_c[2]; // 0x0500 for ANT
ANT_U8 hcilen[2];
} vendor;
struct {
ANT_U8 num_token;
ANT_U8 opcode[2]; // 0xFDD1 for ANT
ANT_U8 resp;
} cmd_cmplt;
};
ANT_U8 data[ANT_NATIVE_MAX_PARMS_LEN]; // Should be 255
} __attribute__ ((packed)) hci_event_packet_t;
typedef struct {
union {
hci_event_packet_t hci_event_packet;
ANT_U8 raw_packet[sizeof(hci_event_packet_t)];
};
} rx_data_t; // Use this is for vendor specific and command complete events
// -------------------------------------------------
static inline int create_hci_sock() {
struct sockaddr_hci sa;
int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);

View File

@@ -20,7 +20,8 @@
* FILE NAME: ant_rx.h
*
* BRIEF:
* This file defines the receive thread function
* This file defines the receive thread function and the ANTHCIRxParams
* type for storing the configuration of the receive thread.
*
*
\******************************************************************************/
@@ -32,6 +33,7 @@
#include "ant_types.h"
#include "ant_native.h"
// The configuration of a receive thread
typedef struct
{
//The function to call back with received data

View File

@@ -20,7 +20,7 @@
* FILE NAME: ant_tx.h
*
* BRIEF:
* This file defines the transmit function
* This file defines the utility functions used by the transmit function.
*
*
\******************************************************************************/

View File

@@ -1,424 +0,0 @@
/*
* 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 character device implementation of ant_native.h
*
*
\*******************************************************************************/
#include <errno.h>
#include <fcntl.h> /* for open() */
#include <linux/ioctl.h>
#include <pthread.h>
#include "ant_native.h"
#include "ant_types.h"
#include "ant_log.h"
#include "ant_version.h"
#include "ant_native_chardev.h"
#include "ant_rx_chardev.h"
#define CHIP_B_CHAR_DEV_IOCTL_RESET _IO('H', 160)
#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)
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 void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcCharDevName)
{
pstChnlInfo->pcDevicePath = pcCharDevName;
pstChnlInfo->iFd = -1;
pstChnlInfo->fnRxCallback = NULL;
pstChnlInfo->ucFlowControlResp = FLOW_GO;
pstChnlInfo->pstFlowControlCond = &stFlowControlCond;
pstChnlInfo->pstFlowControlLock = &stFlowControlLock;
}
ANTStatus ant_init(void)
{
ANTStatus uiRet = ANT_STATUS_FAILED;
ANT_FUNC_START();
stRxThreadInfo.stRxThread = 0;
stRxThreadInfo.ucRunThread = 0;
stRxThreadInfo.ucChipResetting = 0;
stRxThreadInfo.pstEnabledStatusLock = &stEnabledStatusLock;
g_fnStateCallback = 0;
ant_channel_init(&stRxThreadInfo.astChannels[COMMAND_CHANNEL], ANT_COMMANDS_DEVICE_NAME);
ant_channel_init(&stRxThreadInfo.astChannels[DATA_CHANNEL], ANT_DATA_DEVICE_NAME);
uiRet = ANT_STATUS_SUCCESS;
ANT_FUNC_END();
return uiRet;
}
ANTStatus ant_deinit(void)
{
ANTStatus uiRet = ANT_STATUS_FAILED;
ANT_FUNC_START();
uiRet = ANT_STATUS_SUCCESS;
ANT_FUNC_END();
return uiRet;
}
ANTStatus set_ant_rx_callback(ANTNativeANTEventCb rx_callback_func)
{
ANT_FUNC_START();
stRxThreadInfo.astChannels[COMMAND_CHANNEL].fnRxCallback = rx_callback_func;
stRxThreadInfo.astChannels[DATA_CHANNEL].fnRxCallback = rx_callback_func;
ANT_FUNC_END();
return ANT_STATUS_SUCCESS;
}
ANTStatus set_ant_state_callback(ANTNativeANTStateCb state_callback_func)
{
ANT_FUNC_START();
g_fnStateCallback = state_callback_func;
ANT_FUNC_END();
return ANT_STATUS_SUCCESS;
}
ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg)
{
ANTStatus uiRet = ANT_STATUS_FAILED;
int iMutexResult;
int iResult;
struct timespec stTimeout;
int iCondWaitResult;
ANT_U8 txBuffer[ANT_HCI_MAX_MSG_SIZE];
ANT_FUNC_START();
if (ant_radio_enabled_status() != RADIO_STATUS_ENABLED) {
uiRet = ANT_STATUS_FAILED_BT_NOT_INITIALIZED;
goto out;
}
txBuffer[CHIP_B_HCI_SIZE_OFFSET] = ucLen;
memcpy(txBuffer + CHIP_B_HCI_HEADER_SIZE, pucMesg, ucLen);
ANT_SERIAL(txBuffer, ucLen + CHIP_B_HCI_HEADER_SIZE, 'T');
switch (txBuffer[CHIP_B_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:
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[COMMAND_CHANNEL].ucFlowControlResp = FLOW_STOP;
iResult = write(stRxThreadInfo.astChannels[DATA_CHANNEL].iFd, txBuffer, ucLen + CHIP_B_HCI_HEADER_SIZE);
if (iResult < 0) {
ANT_ERROR("failed to write data message to device: %s", strerror(errno));
} else if (iResult != ucLen + CHIP_B_HCI_HEADER_SIZE) {
ANT_ERROR("bytes written and message size dont match up");
} else {
stTimeout.tv_sec = time(0) + CHIP_B_FLOW_GO_WAIT_TIMEOUT_SEC;
stTimeout.tv_nsec = 0;
while (stRxThreadInfo.astChannels[COMMAND_CHANNEL].ucFlowControlResp != 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)
uiRet = ANT_STATUS_HARDWARE_ERR;
goto wait_error;
}
}
uiRet = 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__);
break;
default:
iResult = write(stRxThreadInfo.astChannels[COMMAND_CHANNEL].iFd, txBuffer, ucLen + CHIP_B_HCI_HEADER_SIZE);
if (iResult < 0) {
ANT_ERROR("failed to write message to device: %s", strerror(errno));
} else if (iResult != ucLen + CHIP_B_HCI_HEADER_SIZE) {
ANT_ERROR("bytes written and message size dont match up");
} else {
uiRet = ANT_STATUS_SUCCESS;
}
}
out:
ANT_FUNC_END();
return uiRet;
}
ANTStatus ant_radio_hard_reset(void)
{
enum ant_channel_type eChannel;
int iLockResult;
ANTStatus uiRet = 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__);
stRxThreadInfo.ucChipResetting = 1;
if (g_fnStateCallback)
g_fnStateCallback(RADIO_STATUS_RESETTING);
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++)
ioctl(stRxThreadInfo.astChannels[eChannel].iFd, CHIP_B_CHAR_DEV_IOCTL_RESET); //TODO only one?
ant_do_disable();
if (ant_do_enable()) { /* failed */
if (g_fnStateCallback)
g_fnStateCallback(RADIO_STATUS_DISABLED);
} else { /* success */
if (g_fnStateCallback)
g_fnStateCallback(RADIO_STATUS_RESET);
uiRet = 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:
ANT_FUNC_END();
return uiRet;
}
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) {
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);
}
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) {
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:
ANT_FUNC_END();
return iRet;
}
int ant_do_enable(void)
{
int iRet = -1;
enum ant_channel_type eChannel;
ANT_FUNC_START();
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;
}
void ant_do_disable(void)
{
enum ant_channel_type eChannel;
ANT_FUNC_START();
stRxThreadInfo.ucRunThread = 0;
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++)
ant_disable_channel(&stRxThreadInfo.astChannels[eChannel]);
if (stRxThreadInfo.stRxThread != 0) {
if (pthread_join(stRxThreadInfo.stRxThread, NULL) < 0) {
ANT_ERROR("failed to join rx thread: %s", strerror(errno));
}
stRxThreadInfo.stRxThread = 0;
} else {
ANT_DEBUG_D("rx thread is not running");
}
ANT_FUNC_END();
}
ANTStatus ant_enable_radio(void)
{
int iLockResult;
ANTStatus uiRet = 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_do_enable() < 0) {
ANT_ERROR("ant enable failed: %s", strerror(errno));
ant_do_disable();
if (g_fnStateCallback)
g_fnStateCallback(ant_radio_enabled_status());
} else {
if (g_fnStateCallback)
g_fnStateCallback(RADIO_STATUS_ENABLED);
uiRet = 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 uiRet;
}
ANTStatus ant_disable_radio(void)
{
int iLockResult;
ANTStatus uiRet = 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_do_disable();
if (g_fnStateCallback)
g_fnStateCallback(ant_radio_enabled_status());
uiRet = 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 uiRet;
}
ANTRadioEnabledStatus ant_radio_enabled_status(void)
{
enum 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;
}
const char *ant_get_lib_version()
{
return "libantradio.so: CHIP_B Character Device Transport. Version "
LIBANT_STACK_MAJOR"."LIBANT_STACK_MINOR"."LIBANT_STACK_INCRE;
}

View File

@@ -1,48 +0,0 @@
/*
* 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.h
*
* BRIEF:
* This file defines constants for the char dev implementation
*
*
\*******************************************************************************/
#ifndef __ANT_NATIVE_CHARDEV_H
#define __ANT_NATIVE_CHARDEV_H
#define ANT_COMMANDS_DEVICE_NAME "/dev/antradio_cmd"
#define ANT_DATA_DEVICE_NAME "/dev/antradio_data"
#define CHIP_B_HCI_SIZE_OFFSET 0
#define CHIP_B_HCI_DATA_OFFSET 1
#define CHIP_B_HCI_HEADER_SIZE 1
#define ANT_MESG_FLOW_CONTROL ((ANT_U8)0xC9)
#define FLOW_GO ((ANT_U8)0x00)
#define FLOW_STOP ((ANT_U8)0x80)
#define CHIP_B_FLOW_GO_WAIT_TIMEOUT_SEC 10
int ant_do_enable(void);
void ant_do_disable(void);
extern ANTNativeANTStateCb g_fnStateCallback;
#endif /* ifndef __ANT_NATIVE_CHARDEV_H */

View File

@@ -1,50 +0,0 @@
#
# 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.
#
ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"chip-C")
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -g -c -W -Wall -O2
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../common/inc \
$(LOCAL_PATH)/inc \
LOCAL_SRC_FILES:= \
../../JAntNative.cpp \
../common/ant_utils.c \
ant_native_chardev.c \
ant_rx_chardev.c \
#JNI
LOCAL_C_INCLUDE += $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES += \
libnativehelper
# logging
LOCAL_SHARED_LIBRARIES += \
libcutils
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libantradio
include $(BUILD_SHARED_LIBRARY)
endif # BOARD_ANT_WIRELESS_DEVICE = "chip-C"

View File

@@ -1,389 +0,0 @@
/*
* 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 character device implementation of ant_native.h
*
*
\*******************************************************************************/
#include <errno.h>
#include <fcntl.h> /* for open() */
#include <linux/ioctl.h>
#include <pthread.h>
#include "ant_native.h"
#include "ant_types.h"
#include "ant_log.h"
#include "ant_version.h"
#include "ant_native_chardev.h"
#include "ant_rx_chardev.h"
#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)
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 void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcCharDevName)
{
pstChnlInfo->pcDevicePath = pcCharDevName;
pstChnlInfo->iFd = -1;
pstChnlInfo->fnRxCallback = NULL;
pstChnlInfo->ucFlowControlResp = FLOW_GO;
pstChnlInfo->pstFlowControlCond = &stFlowControlCond;
pstChnlInfo->pstFlowControlLock = &stFlowControlLock;
}
ANTStatus ant_init(void)
{
ANTStatus uiRet = ANT_STATUS_FAILED;
ANT_FUNC_START();
stRxThreadInfo.stRxThread = 0;
stRxThreadInfo.ucRunThread = 0;
stRxThreadInfo.ucChipResetting = 0;
stRxThreadInfo.pstEnabledStatusLock = &stEnabledStatusLock;
g_fnStateCallback = 0;
ant_channel_init(&stRxThreadInfo.astChannels[COMMAND_CHANNEL], ANT_COMMANDS_DEVICE_NAME);
ant_channel_init(&stRxThreadInfo.astChannels[DATA_CHANNEL], ANT_DATA_DEVICE_NAME);
uiRet = ANT_STATUS_SUCCESS;
ANT_FUNC_END();
return uiRet;
}
ANTStatus ant_deinit(void)
{
ANTStatus uiRet = ANT_STATUS_FAILED;
ANT_FUNC_START();
uiRet = ANT_STATUS_SUCCESS;
ANT_FUNC_END();
return uiRet;
}
ANTStatus set_ant_rx_callback(ANTNativeANTEventCb rx_callback_func)
{
ANT_FUNC_START();
stRxThreadInfo.astChannels[COMMAND_CHANNEL].fnRxCallback = rx_callback_func;
stRxThreadInfo.astChannels[DATA_CHANNEL].fnRxCallback = rx_callback_func;
ANT_FUNC_END();
return ANT_STATUS_SUCCESS;
}
ANTStatus set_ant_state_callback(ANTNativeANTStateCb state_callback_func)
{
ANT_FUNC_START();
g_fnStateCallback = state_callback_func;
ANT_FUNC_END();
return ANT_STATUS_SUCCESS;
}
ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg)
{
ANTStatus uiRet = ANT_STATUS_FAILED;
int iMutexResult;
int iResult;
struct timespec stTimeout;
int iCondWaitResult;
ANT_U8 txBuffer[ANT_HCI_MAX_MSG_SIZE];
ANT_FUNC_START();
if (ant_radio_enabled_status() != RADIO_STATUS_ENABLED) {
uiRet = ANT_STATUS_FAILED_BT_NOT_INITIALIZED;
goto out;
}
txBuffer[CHIP_C_HCI_SIZE_OFFSET] = ucLen;
memcpy(txBuffer + CHIP_C_HCI_HEADER_SIZE, pucMesg, ucLen);
ANT_SERIAL(txBuffer, ucLen + CHIP_C_HCI_HEADER_SIZE, 'T');
switch (txBuffer[CHIP_C_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:
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[COMMAND_CHANNEL].ucFlowControlResp = FLOW_STOP;
iResult = write(stRxThreadInfo.astChannels[DATA_CHANNEL].iFd, txBuffer, ucLen + CHIP_C_HCI_HEADER_SIZE);
if (iResult < 0) {
ANT_ERROR("failed to write data message to device: %s", strerror(errno));
} else if (iResult != ucLen + CHIP_C_HCI_HEADER_SIZE) {
ANT_ERROR("bytes written and message size dont match up");
} else {
stTimeout.tv_sec = time(0) + CHIP_C_FLOW_GO_WAIT_TIMEOUT_SEC;
stTimeout.tv_nsec = 0;
while (stRxThreadInfo.astChannels[COMMAND_CHANNEL].ucFlowControlResp != 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)
uiRet = ANT_STATUS_HARDWARE_ERR;
goto wait_error;
}
}
uiRet = 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__);
break;
default:
iResult = write(stRxThreadInfo.astChannels[COMMAND_CHANNEL].iFd, txBuffer, ucLen + CHIP_C_HCI_HEADER_SIZE);
if (iResult < 0) {
ANT_ERROR("failed to write message to device: %s", strerror(errno));
} else if (iResult != ucLen + CHIP_C_HCI_HEADER_SIZE) {
ANT_ERROR("bytes written and message size dont match up");
} else {
uiRet = ANT_STATUS_SUCCESS;
}
}
out:
ANT_FUNC_END();
return uiRet;
}
ANTStatus ant_radio_hard_reset(void)
{
ANTStatus result_status = ANT_STATUS_NOT_SUPPORTED;
ANT_FUNC_START();
ANT_FUNC_END();
return result_status;
}
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) {
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);
}
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) {
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:
ANT_FUNC_END();
return iRet;
}
int ant_do_enable(void)
{
int iRet = -1;
enum ant_channel_type eChannel;
ANT_FUNC_START();
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;
}
void ant_do_disable(void)
{
enum ant_channel_type eChannel;
ANT_FUNC_START();
stRxThreadInfo.ucRunThread = 0;
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++)
ant_disable_channel(&stRxThreadInfo.astChannels[eChannel]);
if (stRxThreadInfo.stRxThread != 0) {
if (pthread_join(stRxThreadInfo.stRxThread, NULL) < 0) {
ANT_ERROR("failed to join rx thread: %s", strerror(errno));
}
stRxThreadInfo.stRxThread = 0;
} else {
ANT_DEBUG_D("rx thread is not running");
}
ANT_FUNC_END();
}
ANTStatus ant_enable_radio(void)
{
int iLockResult;
ANTStatus uiRet = 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_do_enable() < 0) {
ANT_ERROR("ant enable failed: %s", strerror(errno));
ant_do_disable();
if (g_fnStateCallback)
g_fnStateCallback(ant_radio_enabled_status());
} else {
if (g_fnStateCallback)
g_fnStateCallback(RADIO_STATUS_ENABLED);
uiRet = 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 uiRet;
}
ANTStatus ant_disable_radio(void)
{
int iLockResult;
ANTStatus uiRet = 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_do_disable();
if (g_fnStateCallback)
g_fnStateCallback(ant_radio_enabled_status());
uiRet = 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 uiRet;
}
ANTRadioEnabledStatus ant_radio_enabled_status(void)
{
enum 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;
}
const char *ant_get_lib_version()
{
return "libantradio.so: CHIP_C TTY Transport. Version "
LIBANT_STACK_MAJOR"."LIBANT_STACK_MINOR"."LIBANT_STACK_INCRE;
}

View File

@@ -1,213 +0,0 @@
/*
* 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 provides the rx function which will loop reading ANT messages
* until told to exit.
*
*
\*******************************************************************************/
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include "ant_rx_chardev.h"
#include "ant_native_chardev.h"
#include "ant_native.h"
#include "ant_types.h"
#include "ant_log.h"
#undef LOG_TAG
#define LOG_TAG "antradio_rx"
#define ANT_POLL_TIMEOUT ((int)30000)
int readChannelMsg(ant_channel_info_t *pstChnlInfo)
{
int iRet = -1;
ANT_U8 aucRxBuffer[ANT_HCI_MAX_MSG_SIZE];
int iRxLenRead;
int iMutexResult;
ANT_FUNC_START();
while (((iRxLenRead = read(pstChnlInfo->iFd, aucRxBuffer, sizeof(aucRxBuffer))) < 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, iRxLenRead, 'R');
if (aucRxBuffer[CHIP_C_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET] == ANT_MESG_FLOW_CONTROL) {
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));
goto out;
}
ANT_DEBUG_V("got stFlowControlLock in %s", __FUNCTION__);
pstChnlInfo->ucFlowControlResp = aucRxBuffer[CHIP_C_HCI_DATA_OFFSET + ANT_MSG_DATA_OFFSET];
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);
} else {
if (pstChnlInfo->fnRxCallback != NULL) {
pstChnlInfo->fnRxCallback(aucRxBuffer[CHIP_C_HCI_SIZE_OFFSET], &aucRxBuffer[CHIP_C_HCI_DATA_OFFSET]);
} else {
ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath);
}
}
iRet = 0;
}
out:
ANT_FUNC_END();
return iRet;
}
void *fnRxThread(void *ant_rx_thread_info)
{
int iMutexLockResult;
int iPollRet;
ant_rx_thread_info_t *stRxThreadInfo;
struct pollfd astPollFd[NUM_ANT_CHANNELS];
enum 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 = POLLIN | POLLRDNORM;
}
while (stRxThreadInfo->ucRunThread) {
iPollRet = poll(astPollFd, NUM_ANT_CHANNELS, 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));
} else {
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) {
if (astPollFd[eChannel].revents & (POLLERR | POLLPRI | POLLRDHUP)) {
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
* close and open ANT chardev */
stRxThreadInfo->ucChipResetting = 1;
if (g_fnStateCallback)
g_fnStateCallback(RADIO_STATUS_RESETTING);
goto reset;
} else if (astPollFd[eChannel].revents & (POLLIN | POLLRDNORM)) {
ANT_DEBUG_D("data on %s. reading it",
stRxThreadInfo->astChannels[eChannel].pcDevicePath);
if (readChannelMsg(&stRxThreadInfo->astChannels[eChannel]) < 0)
goto out;
} else if (astPollFd[eChannel].revents) {
ANT_DEBUG_W("unhandled poll result %#x from %s",
astPollFd[eChannel].revents,
stRxThreadInfo->astChannels[eChannel].pcDevicePath);
}
}
}
}
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 */
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 */
if (g_fnStateCallback)
g_fnStateCallback(RADIO_STATUS_DISABLING);
ant_do_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");
}
ANT_FUNC_END();
#ifdef ANDROID
return NULL;
#endif
reset:
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_do_disable();
if (ant_do_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();
#ifdef ANDROID
return NULL;
#endif
}

View File

@@ -1,48 +0,0 @@
/*
* 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.h
*
* BRIEF:
* This file defines constants for the char dev implementation
*
*
\*******************************************************************************/
#ifndef __ANT_NATIVE_CHARDEV_H
#define __ANT_NATIVE_CHARDEV_H
#define ANT_COMMANDS_DEVICE_NAME "/dev/smd5"
#define ANT_DATA_DEVICE_NAME "/dev/smd6"
#define CHIP_C_HCI_SIZE_OFFSET 0
#define CHIP_C_HCI_DATA_OFFSET 1
#define CHIP_C_HCI_HEADER_SIZE 1
#define ANT_MESG_FLOW_CONTROL ((ANT_U8)0xC9)
#define FLOW_GO ((ANT_U8)0x00)
#define FLOW_STOP ((ANT_U8)0x80)
#define CHIP_C_FLOW_GO_WAIT_TIMEOUT_SEC 10
int ant_do_enable(void);
void ant_do_disable(void);
extern ANTNativeANTStateCb g_fnStateCallback;
#endif /* ifndef __ANT_NATIVE_CHARDEV_H */

View File

@@ -1,73 +0,0 @@
/*
* 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 public members in ant_rx_chardev.c
*
*
\*******************************************************************************/
#ifndef __ANT_RX_NATIVE_H
#define __ANT_RX_NATIVE_H
#include "ant_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;
} ant_channel_info_t;
enum ant_channel_type {
DATA_CHANNEL,
COMMAND_CHANNEL,
NUM_ANT_CHANNELS
};
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];
} 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 */

View File

@@ -1,26 +1,26 @@
/*
* 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.
*/
* 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_log.h
* FILE NAME: ANT_log.h
*
* BRIEF:
* This file defines logging functions
* BRIEF:
* This file defines logging functions
*
*
\******************************************************************************/
@@ -108,11 +108,11 @@
#undef NDEBUG /* Define verbose logging for logcat if required */
#endif
#include <cutils/log.h>
#define OUTPUT_VERBOSE(...) LOGV(__VA_ARGS__)
#define OUTPUT_DEBUG(...) LOGD(__VA_ARGS__)
#define OUTPUT_INFO(...) LOGI(__VA_ARGS__)
#define OUTPUT_WARNING(...) LOGW(__VA_ARGS__)
#define OUTPUT_ERROR(...) LOGE(__VA_ARGS__)
#define OUTPUT_VERBOSE(...) ALOGV(__VA_ARGS__)
#define OUTPUT_DEBUG(...) ALOGD(__VA_ARGS__)
#define OUTPUT_INFO(...) ALOGI(__VA_ARGS__)
#define OUTPUT_WARNING(...) ALOGW(__VA_ARGS__)
#define OUTPUT_ERROR(...) ALOGE(__VA_ARGS__)
#endif
#define ANT_WARN(...) OUTPUT_WARNING(__VA_ARGS__)

View File

@@ -40,13 +40,6 @@
* Constants
*
******************************************************************************/
#define ANT_NATIVE_MAX_PARMS_LEN 255
#define ANT_NATIVE_MESSAGE_OVERHEAD_SIZE 2
#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)
/*******************************************************************************
*

View File

@@ -19,8 +19,8 @@
#ifndef __ANT_VERSION_H
#define __ANT_VERSION_H
#define LIBANT_STACK_MAJOR "0"
#define LIBANT_STACK_MINOR "7"
#define LIBANT_STACK_MAJOR "1"
#define LIBANT_STACK_MINOR "3"
#define LIBANT_STACK_INCRE "0"
#endif // __ANT_VERSION_H

View File

@@ -14,37 +14,42 @@
# limitations under the License.
#
ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"chip-B")
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -g -c -W -Wall -O2
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../common/inc \
$(LOCAL_PATH)/inc \
$(LOCAL_PATH)/src/common/inc \
$(LOCAL_PATH)/$(ANT_DIR)/inc \
LOCAL_SRC_FILES:= \
../../JAntNative.cpp \
../common/ant_utils.c \
ant_native_chardev.c \
ant_rx_chardev.c \
ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"cg29xx")
LOCAL_C_INCLUDES += \
$(ANT_DIR)/ste/cg29xx \
#JNI
else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"vfs-prerelease")
LOCAL_C_INCLUDES += \
$(ANT_DIR)/prerelease \
endif # BOARD_ANT_WIRELESS_DEVICE = "vfs-prerelease"
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
libnativehelper \
# logging
LOCAL_SHARED_LIBRARIES += \
libcutils
libcutils \
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libantradio
include $(BUILD_SHARED_LIBRARY)
endif # BOARD_ANT_WIRELESS_DEVICE = "chip-B"

View File

@@ -0,0 +1,905 @@
/*
* 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 <errno.h>
#include <fcntl.h> /* for open() */
#include <linux/ioctl.h> /* For hard reset */
#include <pthread.h>
#include "ant_types.h"
#include "ant_native.h"
#include "ant_version.h"
#include "antradio_power.h"
#include "ant_rx_chardev.h"
#include "ant_driver_defines.h"
#include "ant_log.h"
#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 void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcCharDevName);
////////////////////////////////////////////////////////////////////
// ant_init
//
// Initialises the native environment.
//
// Parameters:
// -
//
// Returns:
// ANT_STATUS_SUCCESS
//
// Psuedocode:
/*
Set variables to defaults
Initialise each supported path to chip
RESULT = ANT_STATUS_SUCCESS
*/
////////////////////////////////////////////////////////////////////
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
status = ANT_STATUS_SUCCESS;
ANT_FUNC_END();
return status;
}
////////////////////////////////////////////////////////////////////
// ant_deinit
//
// Doesn't actually do anything.
//
// Parameters:
// -
//
// Returns:
// ANT_STATUS_SUCCESS
//
// Psuedocode:
/*
RESULT = SUCCESS
*/
////////////////////////////////////////////////////////////////////
ANTStatus ant_deinit(void)
{
ANTStatus result_status = ANT_STATUS_FAILED;
ANT_FUNC_START();
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);
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++)
ioctl(stRxThreadInfo.astChannels[eChannel].iFd, ANT_IOCTL_RESET); //TODO only one?
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)
{
ANTStatus status = ANT_STATUS_FAILED;
// TODO ANT_HCI_MAX_MSG_SIZE is transport (driver) dependent.
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;
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[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] = 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);
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]) {
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:
status = ant_tx_message_flowcontrol_wait(DATA_CHANNEL, COMMAND_CHANNEL, txMessageLength, txBuffer);
break;
default:
status = ant_tx_message_flowcontrol_none(COMMAND_CHANNEL, txMessageLength, txBuffer);
}
#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();
}
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) {
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);
}
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) {
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:
ANT_FUNC_END();
return iRet;
}
//----------------------------------------------------------------------- This is antradio_power.h:
int ant_enable(void)
{
int iRet = -1;
ant_channel_type eChannel;
ANT_FUNC_START();
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;
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) {
ant_disable_channel(&stRxThreadInfo.astChannels[eChannel]);
}
if (stRxThreadInfo.stRxThread != 0) {
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");
}
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;
}

View File

@@ -7,7 +7,7 @@
* 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
* 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,
@@ -15,96 +15,48 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*******************************************************************************\
/******************************************************************************\
*
* FILE NAME: ant_rx_chardev.c
* FILE NAME: ant_rx_chardev.c
*
* BRIEF:
* This file provides the rx function which will loop reading ANT messages
* until told to exit.
* This file implements the receive thread function which will loop reading
* ANT messages until told to exit.
*
*
\*******************************************************************************/
\******************************************************************************/
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include "ant_rx_chardev.h"
#include "ant_native_chardev.h"
#include "ant_native.h"
#include "ant_types.h"
#include "antradio_power.h"
#include "ant_rx_chardev.h"
#include "ant_driver_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)
int readChannelMsg(ant_channel_info_t *pstChnlInfo)
{
int iRet = -1;
ANT_U8 aucRxBuffer[ANT_HCI_MAX_MSG_SIZE];
int iRxLenRead;
int iMutexResult;
ANT_FUNC_START();
while (((iRxLenRead = read(pstChnlInfo->iFd, aucRxBuffer, sizeof(aucRxBuffer))) < 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, iRxLenRead, 'R');
if (aucRxBuffer[CHIP_B_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET] == ANT_MESG_FLOW_CONTROL) {
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));
goto out;
}
ANT_DEBUG_V("got stFlowControlLock in %s", __FUNCTION__);
pstChnlInfo->ucFlowControlResp = aucRxBuffer[CHIP_B_HCI_DATA_OFFSET + ANT_MSG_DATA_OFFSET];
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);
} else {
if (pstChnlInfo->fnRxCallback != NULL) {
pstChnlInfo->fnRxCallback(aucRxBuffer[CHIP_B_HCI_SIZE_OFFSET], &aucRxBuffer[CHIP_B_HCI_DATA_OFFSET]);
} else {
ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath);
}
}
iRet = 0;
}
out:
ANT_FUNC_END();
return iRet;
}
int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo);
/*
* 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_ANT_CHANNELS];
enum ant_channel_type eChannel;
ant_channel_type eChannel;
ANT_FUNC_START();
stRxThreadInfo = (ant_rx_thread_info_t *)ant_rx_thread_info;
@@ -113,7 +65,9 @@ void *fnRxThread(void *ant_rx_thread_info)
astPollFd[eChannel].events = POLLIN | POLLRDNORM;
}
/* 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);
if (!iPollRet) {
ANT_DEBUG_V("poll timed out, checking exit cond");
@@ -127,15 +81,19 @@ void *fnRxThread(void *ant_rx_thread_info)
/* 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;
if (g_fnStateCallback) {
g_fnStateCallback(RADIO_STATUS_RESETTING);
}
goto reset;
} else if (astPollFd[eChannel].revents & (POLLIN | POLLRDNORM)) {
ANT_DEBUG_D("data on %s. reading it",
stRxThreadInfo->astChannels[eChannel].pcDevicePath);
if (readChannelMsg(&stRxThreadInfo->astChannels[eChannel]) < 0)
if (readChannelMsg(eChannel, &stRxThreadInfo->astChannels[eChannel]) < 0) {
goto out;
}
} else if (astPollFd[eChannel].revents) {
ANT_DEBUG_W("unhandled poll result %#x from %s",
astPollFd[eChannel].revents,
@@ -144,8 +102,10 @@ 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 */
@@ -157,13 +117,15 @@ out:
stRxThreadInfo->stRxThread = 0; /* spoof our handle as closed so we don't
* try to join ourselves in disable */
if (g_fnStateCallback)
if (g_fnStateCallback) {
g_fnStateCallback(RADIO_STATUS_DISABLING);
}
ant_do_disable();
ant_disable();
if (g_fnStateCallback)
if (g_fnStateCallback) {
g_fnStateCallback(ant_radio_enabled_status());
}
ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__);
pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock);
@@ -174,6 +136,10 @@ out:
} else {
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.
ANT_FUNC_END();
#ifdef ANDROID
return NULL;
@@ -181,6 +147,7 @@ out:
reset:
stRxThreadInfo->ucRunThread = 0;
ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__);
iMutexLockResult = pthread_mutex_lock(stRxThreadInfo->pstEnabledStatusLock);
if (iMutexLockResult < 0) {
@@ -189,25 +156,157 @@ reset:
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_do_disable();
if (ant_do_enable()) { /* failed */
if (g_fnStateCallback)
ant_disable();
if (ant_enable()) { /* failed */
if (g_fnStateCallback) {
g_fnStateCallback(RADIO_STATUS_DISABLED);
}
} else { /* success */
if (g_fnStateCallback)
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();
#ifdef ANDROID
return NULL;
#endif
}
////////////////////////////////////////////////////////////////////
// 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;
ANT_U8 aucRxBuffer[ANT_HCI_MAX_MSG_SIZE];
int iRxLenRead;
ANT_FUNC_START();
// Keep trying to read while there is an error, and that error is EAGAIN
while (((iRxLenRead = read(pstChnlInfo->iFd, aucRxBuffer, sizeof(aucRxBuffer))) < 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, iRxLenRead, 'R');
#if ANT_HCI_OPCODE_SIZE == 1 // Check the different message types by opcode
ANT_U8 opcode = aucRxBuffer[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
#ifdef ANT_MESG_FLOW_CONTROL
if (aucRxBuffer[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[ANT_HCI_DATA_OFFSET + ANT_MSG_DATA_OFFSET])) {
goto out;
}
} else
#endif // ANT_MESG_FLOW_CONTROL
{
if (pstChnlInfo->fnRxCallback != NULL) {
// TODO Allow HCI Size value to be larger than 1 byte
// This currently works as no size value is greater than 255, and little endian
pstChnlInfo->fnRxCallback(aucRxBuffer[ANT_HCI_SIZE_OFFSET], &aucRxBuffer[ANT_HCI_DATA_OFFSET]);
} else {
ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath);
}
}
}
iRet = 0;
}
out:
ANT_FUNC_END();
return iRet;
}

View File

@@ -20,7 +20,10 @@
* FILE NAME: ant_rx_chardev.h
*
* BRIEF:
* This file defines public members in ant_rx_chardev.c
* This file defines the receive thread function, the ant_rx_thread_info_t
* type for storing the -configuration- <state> 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).
*
*
\*******************************************************************************/
@@ -29,6 +32,14 @@
#define __ANT_RX_NATIVE_H
#include "ant_native.h"
#include "ant_driver_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 {
@@ -44,13 +55,23 @@ typedef struct {
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;
enum ant_channel_type {
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 */
@@ -65,6 +86,8 @@ typedef struct {
ant_channel_info_t astChannels[NUM_ANT_CHANNELS];
} 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);

View File

@@ -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

View File

@@ -0,0 +1,67 @@
/*
* 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
#define ANT_CHIP_NAME "TTY"
#define ANT_COMMANDS_DEVICE_NAME "/dev/smd5"
#define ANT_DATA_DEVICE_NAME "/dev/smd6"
// Hard reset not supported, don't define ANT_IOCTL_RESET
// -----------------------------------------
// | Header | Data | Footer |
// |----------------------|-----------------|
// |Optional| Data | Opt. | ... | Optional |
// | Opcode | Size | Sync | | Checksum |
#define ANT_HCI_OPCODE_SIZE 0
#define ANT_HCI_SIZE_SIZE 1
#define ANT_HCI_SYNC_SIZE 0
#define ANT_HCI_CHECKSUM_SIZE 0
#define ANT_MESG_FLOW_CONTROL ((ANT_U8)0xC9)
#define ANT_FLOW_GO ((ANT_U8)0x00)
// ---------------------- Not chip specific
#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_STOP ((ANT_U8)0x80)
#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10
#endif /* ifndef __VFS_PRERELEASE_H */

View File

@@ -0,0 +1,67 @@
/*
* 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 constants for the ST-E CG29XX implementation
*
*
\*******************************************************************************/
#ifndef __VFS_PRERELEASE_H
#define __VFS_PRERELEASE_H
#define ANT_CHIP_NAME "ST-E CG29XX"
#define ANT_COMMANDS_DEVICE_NAME "/dev/cg2900_antradio_cmd"
#define ANT_DATA_DEVICE_NAME "/dev/cg2900_antradio_data"
// TODO Must define ANT_IOCTL_RESET to value driver is expecting
#define ANT_IOCTL_RESET _IO('H', 160)
// -----------------------------------------
// | Header | Data | Footer |
// |----------------------|-----------------|
// |Optional| Data | Opt. | ... | Optional |
// | Opcode | Size | Sync | | Checksum |
#define ANT_HCI_OPCODE_SIZE 0
#define ANT_HCI_SIZE_SIZE 1
#define ANT_HCI_SYNC_SIZE 0
#define ANT_HCI_CHECKSUM_SIZE 0
#define ANT_MESG_FLOW_CONTROL ((ANT_U8)0xC9)
#define ANT_FLOW_GO ((ANT_U8)0x00)
// ---------------------- Not chip specific
#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_STOP ((ANT_U8)0x80)
#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10
#endif /* ifndef __VFS_PRERELEASE_H */