diff options
author | Rohan Martin <rohan.martin@dynastream.com> | 2012-11-16 20:22:22 -0800 |
---|---|---|
committer | Rohan Martin <rohan.martin@dynastream.com> | 2012-11-16 20:22:22 -0800 |
commit | a547b89995ec490063c6c9bd59d21fe88d4db7cf (patch) | |
tree | f23f0fad3dd4327353d6d14b6bf27c082300e0ef | |
parent | 95c4bdb20e2823f28df739902947c98b11ddc03e (diff) | |
parent | af8cf68354a02aad9e12a26f69355226eec7ac61 (diff) | |
download | android_external_ant-wireless_ant_native-a547b89995ec490063c6c9bd59d21fe88d4db7cf.tar.gz android_external_ant-wireless_ant_native-a547b89995ec490063c6c9bd59d21fe88d4db7cf.tar.bz2 android_external_ant-wireless_ant_native-a547b89995ec490063c6c9bd59d21fe88d4db7cf.zip |
Merge pull request #1 from rohan-martin/dsicvs
Pull in Android_System_ANT-HAL_1-2-1
26 files changed, 1619 insertions, 1659 deletions
@@ -16,6 +16,8 @@ ifneq ($(BOARD_ANT_WIRELESS_DEVICE),) +LOCAL_PATH := $(call my-dir) + # # ANT native library # @@ -24,15 +26,15 @@ 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),"vfs-prerelease") -include $(LOCAL_PATH)/hal/chip-C/Android.mk +ANT_DIR := src/vfs else @@ -40,6 +42,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 +59,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 \ diff --git a/src/bluez_hci/Android.mk b/src/bluez_hci/Android.mk index 0320a39..2a7687b 100644 --- a/src/bluez_hci/Android.mk +++ b/src/bluez_hci/Android.mk @@ -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_C_INCLUDE += $(JNI_H_INCLUDE) - LOCAL_SRC_FILES := \ - ../../JAntNative.cpp \ - ../common/ant_utils.c \ - ant_native_hci.c \ - ant_rx.c \ - ant_tx.c \ + $(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_SHARED_LIBRARIES += \ +# JNI +LOCAL_C_INCLUDE += $(JNI_H_INCLUDE) + +LOCAL_SHARED_LIBRARIES += \ libnativehelper \ # chip power @@ -63,5 +65,3 @@ LOCAL_MODULE := libantradio include $(BUILD_SHARED_LIBRARY) -endif # BOARD_ANT_WIRELESS_DEVICE = "wl12xx" - diff --git a/src/bluez_hci/ant_native_hci.c b/src/bluez_hci/ant_native_hci.c index 4650f62..c2c453f 100644 --- a/src/bluez_hci/ant_native_hci.c +++ b/src/bluez_hci/ant_native_hci.c @@ -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; diff --git a/src/bluez_hci/ant_rx.c b/src/bluez_hci/ant_rx.c index 76d29ff..3894cd6 100644 --- a/src/bluez_hci/ant_rx.c +++ b/src/bluez_hci/ant_rx.c @@ -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) - { - 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 + 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_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_WARN("HCI packet length(%d) and bytes read(%d) dont match", buf[2] + 3, len); - } + ANT_SERIAL(event_packet->hci_payload, hci_payload_len, 'R'); - if(HCI_EVENT_PKT == buf[0]) + if(RxParams.pfRxCallback != NULL) { - 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); } diff --git a/src/bluez_hci/ant_tx.c b/src/bluez_hci/ant_tx.c index 2757a3b..e1efa7f 100644 --- a/src/bluez_hci/ant_tx.c +++ b/src/bluez_hci/ant_tx.c @@ -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) - { - status = ANT_STATUS_FAILED; - } - else + ANT_DEBUG_D("Received Event Packet"); + + if(command_complete->event_header.evt == EVT_CMD_COMPLETE) { - if((HCI_CMD_OPCODE_ANT_LSB == buf[4]) && - (HCI_CMD_OPCODE_ANT_MSB == buf[5])) + ANT_U16 opcode = ANT_UTILS_LEtoHost16((ANT_U8 *)&command_complete->command_complete_hdr.opcode); + if(opcode == ANT_COMMAND_OPCODE) { - ucResult = buf[6]; - 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_V("Command complete has wrong opcode"); + ANT_DEBUG_W("Command complete has wrong opcode, this should have been filtered out"); } } - - /* - * if got a status byte, pass it forward, otherwise pass a failure - * status - */ - if(status != ANT_STATUS_FAILED) + else { - 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"); } } diff --git a/src/bluez_hci/inc/ant_framing.h b/src/bluez_hci/inc/ant_framing.h index 7d01844..59c16ca 100644 --- a/src/bluez_hci/inc/ant_framing.h +++ b/src/bluez_hci/inc/ant_framing.h @@ -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) + +#define ANT_COMMAND_OPCODE 0xFDD1 +#define ANT_EVENT_VENDOR_CODE 0x0500 + +typedef struct { + ANT_U16 vendor_msg_len; +} __attribute__ ((packed)) hci_cmd_vendor_hdr_t; +#define HCI_COMMAND_VENDOR_HDR_SIZE 2 + +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 + +#elif defined(BOARD_ANT_DEVICE_BCM433X) + +#define ANT_COMMAND_OPCODE 0xFCEC +#define ANT_EVENT_VENDOR_CODE 0x2D + +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" -/* Number to used by the VS Parameters Len field */ -#define ANT_NATIVE_HCI_VS_PARMS_LEN_FIELD_LEN (2) +#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 HCI_CMD_ANT_MESSAGE_WRITE ((ANT_U16)0x01D1) +#define TYPE_MASK_EVENT_PACKET 0x00000010 +#define EVENT_MASK_0_COMMAND_COMPLETE 0x00004000 +#define EVENT_MASK_1_EVENT_VENDOR 0x80000000 -#define HCI_CMD_OPCODE_ANT_LSB 0xD1 -#define HCI_CMD_OPCODE_ANT_MSB 0xFD +// ------------------------------------------------- -#define HCI_VSOP_ANT_LSB 0x00 -#define HCI_VSOP_ANT_MSB 0x05 +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; -#else -#error "Board ANT Device Type not recognised" +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 */ diff --git a/src/bluez_hci/inc/ant_hciutils.h b/src/bluez_hci/inc/ant_hciutils.h index f8cf579..d654ce9 100644 --- a/src/bluez_hci/inc/ant_hciutils.h +++ b/src/bluez_hci/inc/ant_hciutils.h @@ -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); diff --git a/src/bluez_hci/inc/ant_rx.h b/src/bluez_hci/inc/ant_rx.h index c914bb6..aff076d 100644 --- a/src/bluez_hci/inc/ant_rx.h +++ b/src/bluez_hci/inc/ant_rx.h @@ -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 diff --git a/src/bluez_hci/inc/ant_tx.h b/src/bluez_hci/inc/ant_tx.h index 5057011..0c85a5a 100644 --- a/src/bluez_hci/inc/ant_tx.h +++ b/src/bluez_hci/inc/ant_tx.h @@ -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. * * \******************************************************************************/ diff --git a/src/chip-B/ant_native_chardev.c b/src/chip-B/ant_native_chardev.c deleted file mode 100644 index 39e61d7..0000000 --- a/src/chip-B/ant_native_chardev.c +++ /dev/null @@ -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; -} - diff --git a/src/chip-B/ant_rx_chardev.c b/src/chip-B/ant_rx_chardev.c deleted file mode 100644 index c4aedac..0000000 --- a/src/chip-B/ant_rx_chardev.c +++ /dev/null @@ -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_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; -} - -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 -} - diff --git a/src/chip-B/inc/ant_native_chardev.h b/src/chip-B/inc/ant_native_chardev.h deleted file mode 100644 index 1173f08..0000000 --- a/src/chip-B/inc/ant_native_chardev.h +++ /dev/null @@ -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 */ - diff --git a/src/chip-C/Android.mk b/src/chip-C/Android.mk deleted file mode 100644 index 1f75535..0000000 --- a/src/chip-C/Android.mk +++ /dev/null @@ -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" diff --git a/src/chip-C/ant_native_chardev.c b/src/chip-C/ant_native_chardev.c deleted file mode 100644 index fe10382..0000000 --- a/src/chip-C/ant_native_chardev.c +++ /dev/null @@ -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; -} - diff --git a/src/chip-C/inc/ant_native_chardev.h b/src/chip-C/inc/ant_native_chardev.h deleted file mode 100644 index c72ac0e..0000000 --- a/src/chip-C/inc/ant_native_chardev.h +++ /dev/null @@ -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 */ - diff --git a/src/chip-C/inc/ant_rx_chardev.h b/src/chip-C/inc/ant_rx_chardev.h deleted file mode 100644 index 6721222..0000000 --- a/src/chip-C/inc/ant_rx_chardev.h +++ /dev/null @@ -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 */ - diff --git a/JAntNative.cpp b/src/common/JAntNative.cpp index 2e3beb0..2e3beb0 100644 --- a/JAntNative.cpp +++ b/src/common/JAntNative.cpp diff --git a/src/common/inc/ant_log.h b/src/common/inc/ant_log.h index f2d09b5..bc45462 100644 --- a/src/common/inc/ant_log.h +++ b/src/common/inc/ant_log.h @@ -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__) diff --git a/src/common/inc/ant_native.h b/src/common/inc/ant_native.h index eedec50..6fe106d 100644 --- a/src/common/inc/ant_native.h +++ b/src/common/inc/ant_native.h @@ -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) /******************************************************************************* * diff --git a/src/common/inc/ant_version.h b/src/common/inc/ant_version.h index bc1f239..8f1eb7a 100644 --- a/src/common/inc/ant_version.h +++ b/src/common/inc/ant_version.h @@ -19,9 +19,9 @@ #ifndef __ANT_VERSION_H #define __ANT_VERSION_H -#define LIBANT_STACK_MAJOR "0" -#define LIBANT_STACK_MINOR "7" -#define LIBANT_STACK_INCRE "0" +#define LIBANT_STACK_MAJOR "1" +#define LIBANT_STACK_MINOR "2" +#define LIBANT_STACK_INCRE "1" #endif // __ANT_VERSION_H diff --git a/src/chip-B/Android.mk b/src/vfs/Android.mk index 5b030ff..3090520 100644 --- a/src/chip-B/Android.mk +++ b/src/vfs/Android.mk @@ -14,32 +14,38 @@ # limitations under the License. # -ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"chip-B") +# Check for all VFS transport chip types: +ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"vfs-prerelease") -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),"vfs-prerelease") +LOCAL_C_INCLUDES += \ + $(ANT_DIR)/prerelease \ -#JNI +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 @@ -47,4 +53,4 @@ LOCAL_MODULE := libantradio include $(BUILD_SHARED_LIBRARY) -endif # BOARD_ANT_WIRELESS_DEVICE = "chip-B" +endif # BOARD_ANT_WIRELESS_DEVICE VFS diff --git a/src/vfs/ant_native_chardev.c b/src/vfs/ant_native_chardev.c new file mode 100644 index 0000000..80ca0d1 --- /dev/null +++ b/src/vfs/ant_native_chardev.c @@ -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; +} diff --git a/src/chip-C/ant_rx_chardev.c b/src/vfs/ant_rx_chardev.c index 2c0c6bd..5a4a255 100644 --- a/src/chip-C/ant_rx_chardev.c +++ b/src/vfs/ant_rx_chardev.c @@ -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_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; -} +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) + + if (g_fnStateCallback) { g_fnStateCallback(RADIO_STATUS_RESETTING); - goto reset; + } + 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; +} diff --git a/src/chip-B/inc/ant_rx_chardev.h b/src/vfs/inc/ant_rx_chardev.h index 6721222..526070c 100644 --- a/src/chip-B/inc/ant_rx_chardev.h +++ b/src/vfs/inc/ant_rx_chardev.h @@ -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); diff --git a/src/vfs/inc/antradio_power.h b/src/vfs/inc/antradio_power.h new file mode 100644 index 0000000..1aa0b24 --- /dev/null +++ b/src/vfs/inc/antradio_power.h @@ -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 diff --git a/src/vfs/prerelease/ant_driver_defines.h b/src/vfs/prerelease/ant_driver_defines.h new file mode 100644 index 0000000..7b6b58b --- /dev/null +++ b/src/vfs/prerelease/ant_driver_defines.h @@ -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 */ |