diff options
author | Rohan Martin <rohan.martin@thisisant.com> | 2012-11-01 15:20:17 -0600 |
---|---|---|
committer | Rohan Martin <rohan.martin@thisisant.com> | 2012-11-01 15:20:17 -0600 |
commit | 95c4bdb20e2823f28df739902947c98b11ddc03e (patch) | |
tree | e0ef46bac8dfddec9df9009880bdce503b6389ba | |
parent | 6baccbbe08b8b5174fb1e49b8511f522b551f463 (diff) | |
download | android_external_ant-wireless_ant_native-95c4bdb20e2823f28df739902947c98b11ddc03e.tar.gz android_external_ant-wireless_ant_native-95c4bdb20e2823f28df739902947c98b11ddc03e.tar.bz2 android_external_ant-wireless_ant_native-95c4bdb20e2823f28df739902947c98b11ddc03e.zip |
Broke Android_System_package in to individual repositories
31 files changed, 5030 insertions, 1 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..801a40c --- /dev/null +++ b/Android.mk @@ -0,0 +1,70 @@ +# +# Copyright (C) 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. +# + +ifneq ($(BOARD_ANT_WIRELESS_DEVICE),) + +# +# ANT native library +# + +include $(CLEAR_VARS) + +ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"wl12xx") + +include $(LOCAL_PATH)/hal/bluez_hci/Android.mk + +else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"chip-B") + +include $(LOCAL_PATH)/hal/chip-B/Android.mk + +else ifeq ($(BOARD_ANT_WIRELESS_DEVICE),"chip-C") + +include $(LOCAL_PATH)/hal/chip-C/Android.mk + +else + +$(error Unsupported BOARD_ANT_WIRELESS_DEVICE := $(BOARD_ANT_WIRELESS_DEVICE)) + +endif # BOARD_ANT_WIRELESS_DEVICE type + + +# +# ANT Application +# + +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES:= \ + $(LOCAL_PATH)/src/common/inc \ + $(LOCAL_PATH)/app + +LOCAL_CFLAGS:= -g -c -W -Wall -O2 + +LOCAL_SRC_FILES:= \ + $(LOCAL_PATH)/app/ant_app.c + +LOCAL_SHARED_LIBRARIES := \ + libantradio \ + libcutils + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := debug +LOCAL_MODULE:=antradio_app + +include $(BUILD_EXECUTABLE) + + +endif # BOARD_ANT_WIRELESS_DEVICE defined diff --git a/JAntNative.cpp b/JAntNative.cpp new file mode 100644 index 0000000..2e3beb0 --- /dev/null +++ b/JAntNative.cpp @@ -0,0 +1,366 @@ +/* + * 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: JAntNative.cpp +* +* BRIEF: +* This file provides the implementation of the native interface functions for ANT +* +* +\*******************************************************************************/ + +#include "android_runtime/AndroidRuntime.h" +#include "jni.h" +#include "nativehelper/JNIHelp.h" + +static JNIEnv *g_jEnv = NULL; +static JavaVM *g_jVM = NULL; +static jclass g_sJClazz; +static jmethodID g_sMethodId_nativeCb_AntRxMessage; +static jmethodID g_sMethodId_nativeCb_AntStateChange; + +extern "C" +{ + #include "ant_native.h" + #include "ant_log.h" + #undef LOG_TAG + #define LOG_TAG "JAntNative" + + void nativeJAnt_RxCallback(ANT_U8 ucLen, ANT_U8* pucData); + void nativeJAnt_StateCallback(ANTRadioEnabledStatus uiNewState); +} + +static jint nativeJAnt_Create(JNIEnv *env, jobject obj) +{ + ANTStatus antStatus = ANT_STATUS_FAILED; + (void)env; //unused warning + (void)obj; //unused warning + + ANT_FUNC_START(); + + antStatus = ant_init(); + if (antStatus) + { + ANT_DEBUG_D("failed to init ANT stack"); + goto CLEANUP; + } + + antStatus = set_ant_rx_callback(nativeJAnt_RxCallback); + if (antStatus) + { + ANT_DEBUG_D("failed to set ANT rx callback"); + goto CLEANUP; + } + + antStatus = set_ant_state_callback(nativeJAnt_StateCallback); + if (antStatus) + { + ANT_DEBUG_D("failed to set ANT state callback"); + goto CLEANUP; + } + +CLEANUP: + ANT_FUNC_END(); + return antStatus; +} + +static jint nativeJAnt_Destroy(JNIEnv *env, jobject obj) +{ + (void)env; //unused warning + (void)obj; //unused warning + ANTStatus status; + ANT_FUNC_START(); + + ANT_DEBUG_D("nativeJAnt_Destroy(): calling ant_deinit"); + status = ant_deinit(); + if (status) + { + ANT_DEBUG_D("failed to deinit ANT stack returned %d",(int)status); + return status; + } + else + { + ANT_DEBUG_D("deinit ANT stack Success"); + } + + ANT_FUNC_END(); + return status; +} + +static jint nativeJAnt_Enable(JNIEnv *env, jobject obj) +{ + (void)env; //unused warning + (void)obj; //unused warning + ANT_FUNC_START(); + + ANTStatus status = ant_enable_radio(); + + ANT_FUNC_END(); + return status; +} + +static jint nativeJAnt_Disable(JNIEnv *env, jobject obj) +{ + (void)env; //unused warning + (void)obj; //unused warning + ANT_FUNC_START(); + + ANTStatus status = ant_disable_radio(); + + ANT_FUNC_END(); + return status; +} + +static jint nativeJAnt_GetRadioEnabledStatus(JNIEnv *env, jobject obj) +{ + (void)env; //unused warning + (void)obj; //unused warning + ANT_FUNC_START(); + + jint status = ant_radio_enabled_status(); + + ANT_FUNC_END(); + return status; +} + +static jint nativeJAnt_TxMessage(JNIEnv *env, jobject obj, jbyteArray msg) +{ + (void)obj; //unused warning + ANT_FUNC_START(); + + if (msg == NULL) + { + if (jniThrowException(env, "java/lang/NullPointerException", NULL)) + { + ANT_ERROR("Unable to throw NullPointerException"); + } + return -1; + } + + jbyte* msgBytes = env->GetByteArrayElements(msg, NULL); + jint msgLength = env->GetArrayLength(msg); + + ANTStatus status = ant_tx_message((ANT_U8) msgLength, (ANT_U8 *)msgBytes); + ANT_DEBUG_D("nativeJAnt_TxMessage: ant_tx_message() returned %d", (int)status); + + env->ReleaseByteArrayElements(msg, msgBytes, JNI_ABORT); + + ANT_FUNC_END(); + return status; +} + +static jint nativeJAnt_HardReset(JNIEnv *env, jobject obj) +{ + (void)env; //unused warning + (void)obj; //unused warning + ANT_FUNC_START(); + + ANTStatus status = ant_radio_hard_reset(); + + ANT_FUNC_END(); + return status; +} + +extern "C" +{ + + /********************************************************************** + * Callback registration + ***********************************************************************/ + void nativeJAnt_RxCallback(ANT_U8 ucLen, ANT_U8* pucData) + { + JNIEnv* env = NULL; + jbyteArray jAntRxMsg = NULL; + ANT_FUNC_START(); + + ANT_DEBUG_D( "got message %d bytes", ucLen); + + g_jVM->AttachCurrentThread((&env), NULL); + + if (env == NULL) + { + ANT_DEBUG_D("nativeJAnt_RxCallback: Entered, env is null"); + return; // log error? cleanup? + } + else + { + ANT_DEBUG_D("nativeJAnt_RxCallback: jEnv %p", env); + } + + jAntRxMsg = env->NewByteArray(ucLen); + + if (jAntRxMsg == NULL) + { + ANT_ERROR("nativeJAnt_RxCallback: Failed creating java byte[]"); + goto CLEANUP; + } + + env->SetByteArrayRegion(jAntRxMsg,0,ucLen,(jbyte*)pucData); + + if (env->ExceptionOccurred()) + { + ANT_ERROR("nativeJAnt_RxCallback: ExceptionOccurred during byte[] copy"); + goto CLEANUP; + } + ANT_DEBUG_V("nativeJAnt_RxCallback: Calling java rx callback"); + env->CallStaticVoidMethod(g_sJClazz, g_sMethodId_nativeCb_AntRxMessage, jAntRxMsg); + ANT_DEBUG_V("nativeJAnt_RxCallback: Called java rx callback"); + + if (env->ExceptionOccurred()) + { + ANT_ERROR("nativeJAnt_RxCallback: Calling Java nativeCb_AntRxMessage failed"); + goto CLEANUP; + } + + //Delete the local references + if (jAntRxMsg != NULL) + { + env->DeleteLocalRef(jAntRxMsg); + } + + ANT_DEBUG_D("nativeJAnt_RxCallback: Exiting, Calling DetachCurrentThread at the END"); + + g_jVM->DetachCurrentThread(); + + ANT_FUNC_END(); + return; + + CLEANUP: + ANT_ERROR("nativeJAnt_RxCallback: Exiting due to failure"); + if (jAntRxMsg != NULL) + { + env->DeleteLocalRef(jAntRxMsg); + } + + if (env->ExceptionOccurred()) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + g_jVM->DetachCurrentThread(); + + return; + } + + void nativeJAnt_StateCallback(ANTRadioEnabledStatus uiNewState) + { + JNIEnv* env = NULL; + jint jNewState = uiNewState; + ANT_BOOL iShouldDetach = ANT_FALSE; + ANT_FUNC_START(); + + g_jVM->GetEnv((void**) &env, JNI_VERSION_1_4); + if (env == NULL) + { + ANT_DEBUG_D("nativeJAnt_StateCallback: called from rx thread, attaching to VM"); + g_jVM->AttachCurrentThread((&env), NULL); + if (env == NULL) + { + ANT_DEBUG_E("nativeJAnt_StateCallback: failed to attach rx thread to VM"); + return; + } + iShouldDetach = ANT_TRUE; + } + else + { + ANT_DEBUG_D("nativeJAnt_StateCallback: called from java enable/disable" + ", already attached, don't detach"); + } + + ANT_DEBUG_V("nativeJAnt_StateCallback: Calling java state callback"); + env->CallStaticVoidMethod(g_sJClazz, g_sMethodId_nativeCb_AntStateChange, jNewState); + ANT_DEBUG_V("nativeJAnt_StateCallback: Called java state callback"); + + if (env->ExceptionOccurred()) + { + ANT_ERROR("nativeJAnt_StateCallback: Calling Java nativeCb_AntStateChange failed"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + if (iShouldDetach) + { + ANT_DEBUG_D("nativeJAnt_StateCallback: env was attached, detaching"); + g_jVM->DetachCurrentThread(); + } + + ANT_FUNC_END(); + return; + } +} + +static JNINativeMethod g_sMethods[] = +{ + /* name, signature, funcPtr */ + {"nativeJAnt_Create", "()I", (void*)nativeJAnt_Create}, + {"nativeJAnt_Destroy", "()I", (void*)nativeJAnt_Destroy}, + {"nativeJAnt_Enable", "()I", (void*)nativeJAnt_Enable}, + {"nativeJAnt_Disable", "()I", (void*)nativeJAnt_Disable}, + {"nativeJAnt_GetRadioEnabledStatus", "()I", (void*)nativeJAnt_GetRadioEnabledStatus}, + {"nativeJAnt_TxMessage","([B)I", (void*)nativeJAnt_TxMessage}, + {"nativeJAnt_HardReset", "()I", (void *)nativeJAnt_HardReset} +}; + +jint JNI_OnLoad(JavaVM* vm, void* reserved) { + ANT_FUNC_START(); + (void)reserved; //unused warning + + g_jVM = vm; + if (g_jVM->GetEnv((void**) &g_jEnv, JNI_VERSION_1_4) != JNI_OK) { + ANT_ERROR("GetEnv failed"); + return -1; + } + if (NULL == g_jEnv) { + ANT_ERROR("env is null"); + return -1; + } + + g_sJClazz = g_jEnv->FindClass("com/dsi/ant/core/JAntJava"); + if (NULL == g_sJClazz) { + ANT_ERROR("could not find class \"com/dsi/ant/core/JAntJava\""); + return -1; + } + + /* Save class information in global reference to prevent class unloading */ + g_sJClazz = (jclass)g_jEnv->NewGlobalRef(g_sJClazz); + + if (g_jEnv->RegisterNatives(g_sJClazz, g_sMethods, NELEM(g_sMethods)) != JNI_OK) { + ANT_ERROR("failed to register methods"); + return -1; + } + + g_sMethodId_nativeCb_AntRxMessage = g_jEnv->GetStaticMethodID(g_sJClazz, + "nativeCb_AntRxMessage", "([B)V"); + if (NULL == g_sMethodId_nativeCb_AntRxMessage) { + ANT_ERROR("VerifyMethodId: Failed getting method id of \"void nativeCb_AntRxMessage(byte[])\""); + return -1; + } + + g_sMethodId_nativeCb_AntStateChange = g_jEnv->GetStaticMethodID(g_sJClazz, + "nativeCb_AntStateChange", "(I)V"); + if (NULL == g_sMethodId_nativeCb_AntStateChange) { + ANT_ERROR("VerifyMethodId: Failed getting method id of \"void nativeCb_AntStateChange(int)\""); + return -1; + } + + ANT_FUNC_END(); + return JNI_VERSION_1_4; +} + @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. @@ -0,0 +1,5 @@ +ANT Android System Package +Copyright 2009-2012 Dynastream Innovations + +This product includes software developed at +Dynastream Innovations (http://www.dynastream.com/).
\ No newline at end of file @@ -1,2 +1,2 @@ -Linux_commandline-app +Linux ANT HAL library =====================
\ No newline at end of file diff --git a/app/ant_app.c b/app/ant_app.c new file mode 100644 index 0000000..b0090ba --- /dev/null +++ b/app/ant_app.c @@ -0,0 +1,326 @@ +/* + * ANT Stack testing appication + * + * 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. + */ + + +#define _GNU_SOURCE + +#include <stdio.h> +#include <pthread.h> +#include <string.h> +#include <errno.h> +#include <math.h> +#include <signal.h> + +#include "ant_native.h" +#include "ant_types.h" +#include "ant_log.h" +#undef LOG_TAG +#define LOG_TAG "antradio_app" + +/* transient stage */ +typedef ANTStatus ant_status; + +void app_ANT_rx_callback(ANT_U8 ucLen, ANT_U8* pucData); +void app_ANT_state_callback(ANTRadioEnabledStatus uiNewState); + +static int Ant_Create(void) +{ + ANTStatus antStatus; + + //register_antsig_handlers(); + + antStatus = ant_init(); + if (antStatus) + { + printf("failed to init ANT rx stacki\n"); + goto CLEANUP; + } + + antStatus = set_ant_rx_callback(app_ANT_rx_callback); + if (antStatus) + { + printf("failed to set ANT rx callback"); + goto CLEANUP; + } + + antStatus = set_ant_state_callback(app_ANT_state_callback); + if (antStatus) + { + printf("failed to set ANT rx callback"); + goto CLEANUP; + } + return antStatus; + +CLEANUP: + return ANT_STATUS_FAILED; +} + +void ProcessCommand(char cCmd) +{ + ANT_U8 TxMessage[256]; + switch (cCmd) + { + case 'V': + TxMessage[0] = 0x02; //Size + TxMessage[1] = 0x4D; //MESG_REQUEST_ID + TxMessage[2] = 0x00; //Ch0 + TxMessage[3] = 0x3E; + ant_tx_message(4,TxMessage); + break; + case 'R': + TxMessage[0] = 0x01; //Size + TxMessage[1] = 0x4A; //MESG_RESET_ID + TxMessage[2] = 0x00; //Ch0 + ant_tx_message(3,TxMessage); + break; + case 'K': + printf("Hard Reset returned: %d\n", ant_radio_hard_reset()); + break; + + case 'H': + //Normally we will not blindly send commands like this and actually check for responses before sending the next command, but this is just for a quick test. + ProcessCommand('R'); //Reset chip + ProcessCommand('A'); //Assign channel + ProcessCommand('F'); //Set RF Freq + ProcessCommand('I'); //Set Channel ID + ProcessCommand('P'); //Set Channel Period + ProcessCommand('O'); //Open Channel + break; + + case 'A': + TxMessage[0] = 0x03; //Size + TxMessage[1] = 0x42; //MESG_ASSIGN_ID + TxMessage[2] = 0x00; //Ch0 + TxMessage[3] = 0x00; //Assignment Params (Rx channel) + TxMessage[4] = 0x01; //Network 1 (ANT+) + ant_tx_message(5,TxMessage); + break; + + case 'F': + TxMessage[0] = 0x02; //Size + TxMessage[1] = 0x45; //MESG_CHANNEL_RADIO_FREQ_ID + TxMessage[2] = 0x00; //Ch0 + TxMessage[3] = 57; //2.457GHz + ant_tx_message(4,TxMessage); + break; + + case 'I': + TxMessage[0] = 0x05; //Size + TxMessage[1] = 0x51; //MESG_CHANNEL_ID_ID + TxMessage[2] = 0x00; //Ch0 + TxMessage[3] = 0x00; //Wildcard Device Number + TxMessage[4] = 0x00; //Wildcard Device Number + TxMessage[5] = 0x78; //Set HRM Device Type + TxMessage[6] = 0x00; //Wildcard Transmission Type + ant_tx_message(7,TxMessage); + break; + + case 'P': + TxMessage[0] = 0x03; //Size + TxMessage[1] = 0x43; //MESG_CHANNEL_MESG_PERIOD_ID + TxMessage[2] = 0x00; //Ch0 + TxMessage[3] = 0x86; // + TxMessage[4] = 0x1F; // HRM MESG Peroid 0x1F86 (8070) + ant_tx_message(5,TxMessage); + break; + + case 'O': + TxMessage[0] = 0x01; //Size + TxMessage[1] = 0x4B; //MESG_OPEN_CHANNEL__ID + TxMessage[2] = 0x00; //Ch0 + ant_tx_message(3,TxMessage); + break; + case 'E': + printf("Enable returned: %d\n", ant_enable_radio()); + break; + case 'D': + printf("Disable returned: %d\n", ant_disable_radio()); + break; + case 'S': + printf("State is: %d\n", ant_radio_enabled_status()); + break; + case '1': + TxMessage[0] = 0x0A; //Size + TxMessage[1] = 0x01; //Enable + TxMessage[2] = 0x00; //Code upload + TxMessage[3] = 0x00; + TxMessage[4] = 0x00; + TxMessage[5] = 0x00; + TxMessage[6] = 0x00; + TxMessage[7] = 0x00; + TxMessage[8] = 0x00; + TxMessage[9] = 0x00; + TxMessage[10] = 0x00; + //ANT_CORE_Send_VS_Command(0xFDD0, 11, TxMessage); + printf("Not Implemented\n"); + break; + + case '2': + TxMessage[0] = 0x00; //Size + //ANT_CORE_Send_VS_Command(0xFF22, 1, TxMessage); + printf("Not Implemented\n"); + break; + + + case 'X': + printf("Exiting\n"); + break; + + default: + printf("Invalid command: %#02x\n", cCmd); + break; + } +} + + +void app_ANT_rx_callback(ANT_U8 ucLen, ANT_U8* pucData) +{ + ANT_U8 i; + + for(i=0; i <ucLen; i++) + printf("[%02X]",pucData[i]); + switch (pucData[1]) + { + case 0x3E: + printf(" ANT FW Version:%s\n", &(pucData[2])); + break; + case 0x6F: + printf(" Chip Reset\n"); + break; + case 0x40: + if (pucData[3] != 0x01) + { + printf(" Response (Ch:%d Mesg:%02X) ", pucData[2], pucData[3]); + if (pucData[4] == 0) + printf("Success\n"); + else + printf("Error - %02X\n", pucData[4]); + } + else + { + printf(" Event (Ch:%d) %02X\n", pucData[2], pucData[4]); + } + break; + case 0x4E: + if (pucData[2] == 0) //we are using channel 0 for HRM + { + // We are just assuming this is a HRM message and pulling the BPM out, refer to the ANT+ HRM profile documentation for proper/complete decoding instructions. + printf(" BPM: %u\n", pucData[10]); + } + break; + + default: + + break; + } + return; +} + +void app_ANT_state_callback(ANTRadioEnabledStatus uiNewState) +{ + const char *pcState; + switch (uiNewState) { + case RADIO_STATUS_UNKNOWN: + pcState = "UNKNOWN"; + break; + case RADIO_STATUS_ENABLING: + pcState = "ENABLING"; + break; + case RADIO_STATUS_ENABLED: + pcState = "ENABLED"; + break; + case RADIO_STATUS_DISABLING: + pcState = "DISABLING"; + break; + case RADIO_STATUS_DISABLED: + pcState = "DISABLED"; + break; + case RADIO_STATUS_NOT_SUPPORTED: + pcState = "NOT SUPPORTED"; + break; + case RADIO_STATUS_SERVICE_NOT_INSTALLED: + pcState = "SERVICE NOT INSTALLED"; + break; + case RADIO_STATUS_SERVICE_NOT_CONNECTED: + pcState = "SERVICE NOT CONNECTED"; + break; + case RADIO_STATUS_RESETTING: + pcState = "RESETTING"; + break; + case RADIO_STATUS_RESET: + pcState = "RESET"; + break; + default: + printf("State change to: %d is an undefined state\n", uiNewState); + return; + } + printf("State change to: %s\n", pcState); +} + +int main(void) +{ + char buffer[1024]; + int ret = 0; + + if (Ant_Create()) + { + printf("failed to init ANT\n"); + goto out; + } + + printf("===ANT Test===\n"); + printf("Using libantradio version:\n"); + printf("%s\n", ant_get_lib_version()); + printf("\n"); + printf("Press V to get Version\n"); + printf("Press R to Reset\n"); + printf("Press K to hard reset\n"); + printf("Press H to setup an ANT+ HRM rx channel\n"); + printf("\n"); + printf("Press A to Assign channel\n"); + printf("Press F to set radio Frequency\n"); + printf("Press I to set channel Id\n"); + printf("Press P to set channel Peroid\n"); + printf("Press O to Open channel\n"); + printf("\n"); + printf("Press E to Enable ANT\n"); + printf("Press D to Disable ANT\n"); + printf("Press S to get State\n"); + printf("\n"); + printf("Press X to eXit\n"); + + while (1) + { + memset(&buffer,0,sizeof(buffer)); + fgets(buffer, sizeof(buffer), stdin); + ProcessCommand(buffer[0]); + if (buffer[0] == 'X') + goto done; + } + +done: + ProcessCommand('R'); + sleep(1); + ProcessCommand('D'); + ant_deinit(); + + +out: + return ret; +} + diff --git a/app/ant_app.h b/app/ant_app.h new file mode 100644 index 0000000..1806975 --- /dev/null +++ b/app/ant_app.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + + +#ifndef __ANT_APP_H +#define __ANT_APP_H + + + +#endif diff --git a/src/bluez_hci/Android.mk b/src/bluez_hci/Android.mk new file mode 100644 index 0000000..0320a39 --- /dev/null +++ b/src/bluez_hci/Android.mk @@ -0,0 +1,67 @@ +# +# Copyright (C) 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. +# + +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_C_INCLUDES := \ + $(LOCAL_PATH)/../common/inc \ + $(LOCAL_PATH)/inc \ + system/bluetooth/bluez-clean-headers \ + +ifeq ($(BOARD_ANT_WIRELESS_POWER),"bluedroid") +LOCAL_CFLAGS += -DBOARD_HAVE_ANT_WIRELESS +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 \ + +# jni +LOCAL_SHARED_LIBRARIES += \ + libnativehelper \ + +# chip power +LOCAL_SHARED_LIBRARIES += \ + libbluedroid \ + +# 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 = "wl12xx" + diff --git a/src/bluez_hci/ant_native_hci.c b/src/bluez_hci/ant_native_hci.c new file mode 100644 index 0000000..4650f62 --- /dev/null +++ b/src/bluez_hci/ant_native_hci.c @@ -0,0 +1,823 @@ +/* +* 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 +* +* +\******************************************************************************/ + +#include <pthread.h> +#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" + +#include "ant_rx.h" +#include "ant_tx.h" +#include "ant_hciutils.h" +#include "ant_log.h" + +static pthread_mutex_t txLock; +pthread_mutex_t enableLock; + +static ANTRadioEnabledStatus radio_status = RADIO_STATUS_DISABLED; +ANTRadioEnabledStatus get_and_set_radio_status(void); + +//////////////////////////////////////////////////////////////////// +// ant_init +// +// Initialises the native environment. +// +// Parameters: +// - +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failures: +// ANT_STATUS_FAILED if could not initialize mutex +// +// Psuedocode: +/* +LOCK antdevice_LOCK + CREATE mutex for locking Tx attempt + IF could not create mutex + RESULT = ANT_STATUS_FAILED + ELSE + CREATE mutex for locking enable/disable + IF could not create mutex + RESULT = ANT_STATUS_FAILED + ELSE + RESULT = ANT_STATUS_SUCCESS + ENDIF + ENDIF +UNLOCK +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_init(void) +{ + int mutexResult; + ANTStatus status = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + mutexResult = pthread_mutex_init(&txLock, NULL); //use default attr + if (mutexResult) + { + ANT_ERROR("Tx Lock mutex initialization failed: %s", strerror(mutexResult)); + } + else + { + mutexResult = pthread_mutex_init(&enableLock, NULL); + if (mutexResult) + { + ANT_ERROR("Enable Lock mutex init failed %s", strerror(mutexResult)); + } + else + { + status = ANT_STATUS_SUCCESS; + } + } + + ANT_FUNC_END(); + return status; +} + + +//////////////////////////////////////////////////////////////////// +// ant_deinit +// +// De-initialises the native environment. +// +// Parameters: +// - +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failures: +// ANT_STATUS_FAILED if could not de-initialize mutex +// +// Psuedocode: +/* +LOCK antdevice_LOCK (also Init and Tx) + DESTROY mutex for locking Tx attempt + IF could not destroy mutex + RESULT = ANT_STATUS_FAILED + ELSE + DESTROY mutex for locking enable/disable + IF coult not destroy mutex + RESULT = ANT_STATUS_FAILED + ELSE + RESULT = ANT_STATUS_SUCCESS + ENDIF + ENDIF +UNLOCK +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_deinit(void) +{ + int mutexResult; + ANTStatus result_status = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + mutexResult = pthread_mutex_destroy(&txLock); + if (mutexResult) + { + ANT_ERROR("Tx Lock mutex destroy failed: %s", strerror(mutexResult)); + } + else + { + mutexResult = pthread_mutex_destroy(&enableLock); + if (mutexResult) + { + ANT_ERROR("Enable Lock mutex destroy failed: %s", strerror(mutexResult)); + } + else + { + 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 +// On Android this is in the Bluedroid module. +// On Linux this is device specific +// +// 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 + LOCK tx_LOCK + IF state is not enabled + STATE = ENABLING + ENDIF + ant enable + IF ant_enable success + IF rx thread is running + STATE = ENABLED + RESULT = SUCCESS + ELSE + start rx thread + IF starting rx thread fails + ant disable + get state + IF state is enabled + log a serious error + ENDIF + RESULT = FAILED + ELSE + STATE = ENABLED + RESULT = SUCCESS + ENDIF + ENDIF + ELSE + get state + IF state is enabled + log a serious error + ENDIF + RESULT = FAILURE + ENDIF + UNLOCK +UNLOCK +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_enable_radio(void) +{ + int result; + int lockResult; + ANTStatus result_status = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + ANT_DEBUG_V("getting enableLock in %s", __FUNCTION__); + lockResult = pthread_mutex_lock(&enableLock); + if(lockResult) + { + ANT_ERROR("Enable failed to get enableLock mutex: %s", strerror(lockResult)); + return ANT_STATUS_FAILED; + } + ANT_DEBUG_V("got enableLock in %s", __FUNCTION__); + + ANT_DEBUG_V("getting txLock in %s", __FUNCTION__); + lockResult = pthread_mutex_lock(&txLock); + if (lockResult) + { + ANT_ERROR("Enable txLock failed: %s", strerror(lockResult)); + pthread_mutex_unlock(&enableLock); + return ANT_STATUS_FAILED; + } + ANT_DEBUG_V("got txLock in %s", __FUNCTION__); + + if (get_and_set_radio_status() != RADIO_STATUS_ENABLED) + { + if (RxParams.thread) + { + ANT_WARN("in enable call: rx thread still exists but radio crashed. trying to recover"); + ANT_DEBUG_V("radio crashed, letting rx thread join"); + pthread_join(RxParams.thread, NULL); + 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 (RxParams.pfStateCallback) + RxParams.pfStateCallback(radio_status); + } + + result = ant_enable(); + ANT_DEBUG_D("ant_enable() result is %d", result); + if (result == 0) + { + if (RxParams.thread) + { + result_status = ANT_STATUS_SUCCESS; + radio_status = RADIO_STATUS_ENABLED; // sanity assign, cant be enabling + ANT_DEBUG_D("ANT radio re-enabled"); + } + else + { + result = pthread_create(&RxParams.thread, NULL, ANTHCIRxThread, NULL); + if (result) + { + ANT_ERROR("Thread initialization failed: %s", strerror(result)); + result_status = ANT_STATUS_FAILED; + } + else + { + result_status = ANT_STATUS_SUCCESS; + if (radio_status == RADIO_STATUS_ENABLING) + { + ANT_DEBUG_I("radio_status (%d -> %d)", radio_status, RADIO_STATUS_ENABLED); + radio_status = RADIO_STATUS_ENABLED; + + if (RxParams.pfStateCallback) + RxParams.pfStateCallback(radio_status); + } + else + { + ANT_WARN("radio was already enabled but rx thread was not running"); + } + } + } + } + else + { + result_status = ANT_STATUS_TRANSPORT_INIT_ERR; + } + + if (result_status != ANT_STATUS_SUCCESS) + { + ant_disable(); + + switch (get_and_set_radio_status()) + { + case RADIO_STATUS_ENABLED: + ANT_ERROR("SERIOUS: enable failed, but ANT is enabled without a rx thread"); + break; + default: + ANT_DEBUG_D("Enable failed, after cleanup chip is not enabled"); + break; + } + } + + ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); + pthread_mutex_unlock(&txLock); + ANT_DEBUG_V("released txLock in %s", __FUNCTION__); + + ANT_DEBUG_V("releasing enableLock in %s", __FUNCTION__); + pthread_mutex_unlock(&enableLock); + ANT_DEBUG_V("released enableLock in %s", __FUNCTION__); + + ANT_FUNC_END(); + return result_status; +} + +ANTStatus ant_radio_hard_reset(void) +{ + ANTStatus result_status = ANT_STATUS_NOT_SUPPORTED; + ANT_FUNC_START(); + ANT_FUNC_END(); + return result_status; +} + +//////////////////////////////////////////////////////////////////// +// ant_disable_radio +// +// Disables the HCI transport and powers off the ANT part. +// +// Parameters: +// - +// +// Returns: +// Success: +// ANT_STATUS_SUCCESS +// Failures: +// ANT_STATUS_FAILED if could not get mutex +// ANT_STATUS_NOT_DE_INITIALIZED if ant_disable failed +// +// Psuedocode: +/* +LOCK enable_LOCK + LOCK tx_LOCK + IF not disabled + STATE = DISABLING + ENDIF + ant disable + IF rx thread is running + wait for rx thread to terminate + ENDIF + get radio status + IF radio is disabled + RESULT = SUCCESS + ELSE IF radio is enabled + log a serious error + RESULT = FAILURE + ELSE + RESULT = FAILURE + ENDIF + UNLOCK +UNLOCK +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_disable_radio(void) +{ + int result; + int lockResult; + ANTStatus ret = ANT_STATUS_FAILED; + ANT_FUNC_START(); + + ANT_DEBUG_V("getting enableLock in %s", __FUNCTION__); + lockResult = pthread_mutex_lock(&enableLock); + if(lockResult) + { + ANT_ERROR("Disable failed to get enableLock mutex: %s", strerror(lockResult)); + return ANT_STATUS_FAILED; + } + ANT_DEBUG_V("got enableLock in %s", __FUNCTION__); + + ANT_DEBUG_V("getting txLock in %s", __FUNCTION__); + lockResult = pthread_mutex_lock(&txLock); + if (lockResult) + { + ANT_ERROR("Disable txLock failed: %s", strerror(lockResult)); + pthread_mutex_unlock(&enableLock); + return ANT_STATUS_FAILED; + } + ANT_DEBUG_V("got txLock in %s", __FUNCTION__); + + if (get_and_set_radio_status() != RADIO_STATUS_DISABLED) + { + ANT_DEBUG_I("radio_status (%d -> %d)", radio_status, RADIO_STATUS_DISABLING); + radio_status = RADIO_STATUS_DISABLING; + + if (RxParams.pfStateCallback) + RxParams.pfStateCallback(radio_status); + } + + result = ant_disable(); + ANT_DEBUG_D("ant_disable() result is %d", result); + + // If rx thread exists ( != 0) + if (RxParams.thread) + { + ANT_DEBUG_V("quit rx thread, joining"); + pthread_join(RxParams.thread, NULL); + RxParams.thread = 0; + ANT_DEBUG_V("joined by rx thread"); + } + else + { + ANT_DEBUG_W("rx thread is 0 (not created?)"); + } + + switch (get_and_set_radio_status()) + { + case RADIO_STATUS_DISABLED: + ret = ANT_STATUS_SUCCESS; + break; + case RADIO_STATUS_ENABLED: + ANT_ERROR("SERIOUS: ANT was disabled, rx thread quit, but ANT is enabled"); + ret = ANT_STATUS_FAILED; + break; + default: + ret = ANT_STATUS_NOT_DE_INITIALIZED; + break; + } + + ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); + pthread_mutex_unlock(&txLock); + ANT_DEBUG_V("released txLock in %s", __FUNCTION__); + + ANT_DEBUG_V("releasing enableLock in %s", __FUNCTION__); + pthread_mutex_unlock(&enableLock); + ANT_DEBUG_V("released enableLock in %s", __FUNCTION__); + + ANT_FUNC_END(); + return ret; +} + + +//////////////////////////////////////////////////////////////////// +// ant_radio_enabled_status +// +// Returns if the chip/transport is disabled/disabling/enabling/enabled. This +// function will NOT overwrite internal state variable enabling or disabling. +// It will call get_and_set_radio_status() if not enabling/disabling which can +// change internal state on errors. +// +// Parameters: +// - +// +// Returns: +// The current radio status (ANTRadioEnabledStatus) +// +// Psuedocode: +/* +IF Enabling + RESULT = Enabling +ELSE IF Disabling + RESULT = Disabling +ELSE + IF ant_is_enabled + Enabled + RESULT = Enabled + ELSE + Disabled + RESULT = Disabled + ENDIF +ENDIF +*/ +//////////////////////////////////////////////////////////////////// +ANTRadioEnabledStatus ant_radio_enabled_status(void) +{ + ANT_FUNC_START(); + + if ((RADIO_STATUS_ENABLING != radio_status) && + (RADIO_STATUS_DISABLING != radio_status)) + { + get_and_set_radio_status(); + } + + ANT_FUNC_END(); + return radio_status; +} + +//////////////////////////////////////////////////////////////////// +// get_and_set_radio_status +// +// Returns if the chip/transport is disabled/enabled/unknown This function WILL +// overwrite what it thinks the state is with what the BlueZ core (kernel) +// thinks it is. It will overwrite enabling or disabling states, and might +// change internal state from enabled, disabled, or unknown to any of these +// three on errors. +// +// Paramerters: +// - +// +// Returns: +// The current radio status (ANTRadioEnabledStatus) +// +//////////////////////////////////////////////////////////////////// +ANTRadioEnabledStatus get_and_set_radio_status(void) +{ + ANTRadioEnabledStatus orig_status = radio_status; + ANT_FUNC_START(); + + switch (ant_is_enabled()) + { + case 0: + radio_status = RADIO_STATUS_DISABLED; + break; + case 1: + radio_status = RADIO_STATUS_ENABLED; + break; + default: + ANT_ERROR("getting chip state returned an error"); + radio_status = RADIO_STATUS_UNKNOWN; + break; + } + if (orig_status != radio_status) + { + ANT_DEBUG_I("radio_status (%d -> %d)", orig_status, radio_status); + + if (RxParams.pfStateCallback) + RxParams.pfStateCallback(radio_status); + } + + ANT_FUNC_END(); + return radio_status; +} + +//////////////////////////////////////////////////////////////////// +// 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 recieved messages. +// +// Returns: +// ANT_STATUS_SUCCESS +// +// Psuedocode: +/* + Rx Callback = rx_callback_func +*/ +//////////////////////////////////////////////////////////////////// +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; +} + +//////////////////////////////////////////////////////////////////// +// 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 recieved 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(); + + RxParams.pfStateCallback = state_callback_func; + + ANT_FUNC_END(); + + return status; +} + +//////////////////////////////////////////////////////////////////// +// ant_tx_message +// +// Sends an 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 = NOT ENABLED +ELSE + Lock + IF Lock failed + RESULT = FAILED + ELSE + STORE length (little endian) in send buffer + STORE data in send buffer + ENDIF +ENDIF +*/ +//////////////////////////////////////////////////////////////////// +ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) +{ + ANTStatus status; + + /* Socket for sending HCI commands */ + int tx_socket = -1; + + int lockResult; + + ANT_FUNC_START(); + + ANT_DEBUG_V("getting txLock in %s", __FUNCTION__); + lockResult = pthread_mutex_lock(&txLock); + if (lockResult) + { + ANT_ERROR("ant_tx_message, could not get txLock: %s", strerror(lockResult)); + return ANT_STATUS_FAILED; + } + + ANT_DEBUG_V("got txLock in %s", __FUNCTION__); + + if(RADIO_STATUS_ENABLED != get_and_set_radio_status()) + { + ANT_DEBUG_E("ant_tx_message, ANT not enabled - ABORTING. Radio status = %d", + radio_status); + ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); + pthread_mutex_unlock(&txLock); + ANT_DEBUG_V("released txLock in %s", __FUNCTION__); + return ANT_STATUS_FAILED_BT_NOT_INITIALIZED; + } + + // Open socket + tx_socket = ant_open_tx_transport(); + + if(tx_socket < 0) + { + ANT_ERROR("Could not open Tx socket"); + ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); + pthread_mutex_unlock(&txLock); + ANT_DEBUG_V("released txLock in %s", __FUNCTION__); + return ANT_STATUS_FAILED; + } + + // Send HCI packet + ANT_BOOL retryRx; + ANT_BOOL retryTx; + status = ANT_STATUS_FAILED; + + int MAX_RETRIES_WRITE_FAIL = 10; + int MAX_RETRY_TIME_SECS = 10; + int commandWriteFailRetries = 0; + + // Start New timed retry code: + time_t startTime = time(NULL); + time_t endTime = 0; + if((time_t)-1 != startTime) + { + endTime = startTime + MAX_RETRY_TIME_SECS; + } + else + { + ANT_ERROR("failed to get current time"); + } + + do // while (retryTx) + { + retryTx = ANT_FALSE; + + if(ANT_STATUS_SUCCESS == write_data(pucMesg, ucLen)) + { + do // while (retryRx) + { + retryRx = ANT_FALSE; + + if(ANT_TRUE == wait_for_message(tx_socket)) + { + ANT_DEBUG_D("New HCI data available, reading..."); + + status = get_command_complete_result(tx_socket); + switch (status) + { + case ANT_STATUS_NO_VALUE_AVAILABLE: + { + ANT_WARN("Did not get an expected response for write, trying again"); + retryRx = ANT_TRUE; + break; + } + case ANT_STATUS_FAILED: + { + ANT_ERROR("Command Complete: ANT_STATUS_FAILED"); + break; + } + case ANT_STATUS_COMMAND_WRITE_FAILED: + { + ANT_ERROR("Command Complete: ANT_STATUS_WRITE_FAILED"); + + if(++commandWriteFailRetries < MAX_RETRIES_WRITE_FAIL) + { + ANT_DEBUG_D("Retrying. Retry count = %d", + commandWriteFailRetries); + + retryTx = ANT_TRUE; + } + else + { + ANT_ERROR("Aborting. Retry count = %d. Max retries = %d", + commandWriteFailRetries, MAX_RETRIES_WRITE_FAIL); + } + break; + } + case ANT_STATUS_TRANSPORT_UNSPECIFIED_ERROR: + { + ANT_DEBUG_D("Command Complete: ANT_STATUS_UNSPECIFIED_ERROR"); + + time_t currentTime = time(NULL); + + if((time_t)-1 != currentTime) + { + if(currentTime < endTime) + { + ANT_DEBUG_V("Retrying. Current time = %d. " + "End time = %d", (int)currentTime, (int)endTime); + + retryTx = ANT_TRUE; + } + else + { + ANT_ERROR("Command Complete: ANT_STATUS_UNSPECIFIED_ERROR"); + ANT_ERROR("Aborting. Current time = %d. End Time = %d", + (int)currentTime, (int)endTime); + } + } + else + { + ANT_ERROR("Command Complete: failed to get current time"); + } + + break; + } + case ANT_STATUS_SUCCESS: + { + break; + } + default: + { + ANT_ERROR("Unhandled command complete status"); + break; + } + } + } + else + { + ANT_WARN("Command Complete: wait for message failed"); + } + } while (retryRx); + } + else + { + ANT_ERROR("write failed"); + retryRx = ANT_FALSE; + + status = ANT_STATUS_FAILED; + } + } while(retryTx); + + ant_close_tx_transport(tx_socket); + + ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); + pthread_mutex_unlock(&txLock); + ANT_DEBUG_V("released txLock in %s", __FUNCTION__); + + ANT_FUNC_END(); + + return status; +} + +const char *ant_get_lib_version() +{ + return "libantradio.so Bluez HCI Transport Version " + LIBANT_STACK_MAJOR "." LIBANT_STACK_MINOR "." LIBANT_STACK_INCRE; +} + diff --git a/src/bluez_hci/ant_rx.c b/src/bluez_hci/ant_rx.c new file mode 100644 index 0000000..76d29ff --- /dev/null +++ b/src/bluez_hci/ant_rx.c @@ -0,0 +1,275 @@ +/* + * ANT Stack + * + * Copyright 2009 Dynastream Innovations + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/******************************************************************************\ +* +* FILE NAME: ant_rx.c +* +* BRIEF: +* This file Implements the receive thread for an HCI implementation +* using Vendor Specific messages. +* +* +\******************************************************************************/ + + +#define _GNU_SOURCE /* needed for PTHREAD_MUTEX_RECURSIVE */ + +#include <errno.h> +#include <poll.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/un.h> + +#include "antradio_power.h" + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#include "ant_rx.h" +#include "ant_hciutils.h" +#include "ant_types.h" +#include "ant_framing.h" +#include "ant_log.h" +#undef LOG_TAG +#define LOG_TAG "antradio_rx" + +static char EVT_PKT_VENDOR_FILTER[] = {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x05,0x00,0x00}; + +/* Global Options */ +ANTHCIRxParams RxParams = { + .pfRxCallback = NULL, + .pfStateCallback = NULL, + .thread = 0 +}; + +extern pthread_mutex_t enableLock; +extern ANTRadioEnabledStatus get_and_set_radio_status(void); +/* + * This thread opens a Bluez HCI socket and waits for ANT messages. + */ +void *ANTHCIRxThread(void *pvHCIDevice) +{ + int ret = ANT_STATUS_SUCCESS; + int rxSocket; + int len; + unsigned char buf[HCI_MAX_EVENT_SIZE]; + int result; + ANT_FUNC_START(); + + (void)pvHCIDevice; //unused waring + + ANT_DEBUG_D("Entering ANTHCIRxThread"); + + rxSocket = create_hci_sock(); + if (rxSocket < 0) + { + ANT_DEBUG_E("can't open HCI socket in rx thread: %s", strerror(errno)); + + ret = ANT_STATUS_FAILED; + goto out; + } + + if (setsockopt(rxSocket, SOL_HCI, HCI_FILTER, &EVT_PKT_VENDOR_FILTER, + sizeof(EVT_PKT_VENDOR_FILTER)) < 0) + { + ANT_ERROR("failed to set socket options: %s", strerror(errno)); + + ret = ANT_STATUS_FAILED; + goto close; + } + + /* continue running as long as not terminated */ + while (get_and_set_radio_status() == RADIO_STATUS_ENABLED) + { + struct pollfd p; + int n; + + p.fd = rxSocket; + p.events = POLLIN; + + ANT_DEBUG_V(" RX: Polling HCI for data..."); + + /* poll socket, wait for ANT messages */ + while ((n = poll(&p, 1, 2500)) == -1) + { + if (errno == EAGAIN || errno == EINTR) + continue; + + ANT_ERROR("failed to poll socket: %s", strerror(errno)); + + ret = ANT_STATUS_FAILED; + goto close; + } + + /* we timeout once in a while */ + /* this let's us the chance to check if we were terminated */ + if (0 == n) + { + ANT_DEBUG_V(" RX: Timeout"); + continue; + } + + ANT_DEBUG_D("New HCI data available, reading..."); + + /* read newly arrived data */ + /* TBD: rethink assumption about single arrival */ + while ((len = read(rxSocket, buf, sizeof(buf))) < 0) + { + if (errno == EAGAIN || errno == EINTR) + continue; + + ANT_ERROR("failed to read socket: %s", strerror(errno)); + + ret = ANT_STATUS_FAILED; + goto close; + } + + // 0 = packet type eg. HCI_EVENT_PKT + // FOR EVENT: + // 1 = event code eg. EVT_VENDOR, EVT_CMD_COMPLETE + // 2 = Parameter total length + // 3... parameters + // FOR CC + // 3 = Num HCI Command packets allowed to be sent + // 4+5 = ANT Opcode + // 6 = Result ?? + // FOR VS + // 3+4 = ANT Opcode + // 5 = length + // 6 ? MSB of length ? + // 7... ant message + + if (len >= 7) + { + ANT_DEBUG_V("HCI Data: [%02X][%02X][%02X][%02X][%02X][%02X][%02X]...", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + } + else + { + ANT_ERROR("Failed to read full header off socket. len = %d", len); + continue; + } + + if (len != (buf[2] + 3)) + { + ANT_WARN("HCI packet length(%d) and bytes read(%d) dont match", buf[2] + 3, len); + } + + if(HCI_EVENT_PKT == buf[0]) + { + ANT_DEBUG_D("Received Event Packet"); + + if (EVT_VENDOR == buf[1]) + { + if ((HCI_VSOP_ANT_LSB == buf[3]) && (HCI_VSOP_ANT_MSB == buf[4])) + { + ANT_DEBUG_D("Received ANT VS Message"); + + if (len < 9) + { + ANT_ERROR("Malformed ANT header"); + ret = ANT_STATUS_FAILED; + goto close; + } + + ANT_DEBUG_V("ANT Mesg: ANTMesgSize:%d ANTMesgID:0x%02X ...", + buf[7], buf[8]); + + ANT_SERIAL(&(buf[7]), buf[5], 'R'); + + if(RxParams.pfRxCallback != NULL) + { + RxParams.pfRxCallback(buf[5], &(buf[7])); + } + else + { + ANT_ERROR("Can't send rx message - no callback registered"); + } + + continue; + } + else + { + ANT_DEBUG_W("Vendor Specific message for another vendor. " + "Should filter out"); + } + } + else + { + ANT_DEBUG_V("Other Event Packet, Ignoring"); + } + } + else + { + ANT_DEBUG_V("Non-Event Packet, Ignoring"); + } + } + +close: + result = pthread_mutex_trylock(&enableLock); + ANT_DEBUG_D("rx thread close: trylock enableLock returned %d", result); + + if (result == 0) + { + ANT_DEBUG_W("rx thread socket has unexpectedly crashed"); + if (RxParams.pfStateCallback) + RxParams.pfStateCallback(RADIO_STATUS_DISABLING); + ant_disable(); + get_and_set_radio_status(); + RxParams.thread = 0; + pthread_mutex_unlock(&enableLock); + } + else if (result == EBUSY) + { + ANT_DEBUG_V("rx thread socket was closed"); + } + else + { + ANT_ERROR("rx thread close: trylock failed: %s", strerror(result)); + } + + if (-1 == close(rxSocket)) + { + ANT_ERROR("failed to close hci device (socket handle=%#x): %s", rxSocket, strerror(errno)); + } + else + { + ANT_DEBUG_D("closed hci device (socket handle=%#x)", rxSocket); + } + +out: + ANT_FUNC_END(); + + pthread_exit((void *)ret); + +#if defined(ANDROID) + return 0; +#endif +} + diff --git a/src/bluez_hci/ant_tx.c b/src/bluez_hci/ant_tx.c new file mode 100644 index 0000000..2757a3b --- /dev/null +++ b/src/bluez_hci/ant_tx.c @@ -0,0 +1,358 @@ +/* + * 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_tx.c +* +* BRIEF: +* This file Implements the transmit functionality for an HCI implementation +* using Vendor Specific messages. +* +* +\******************************************************************************/ + +#include <errno.h> +#include <poll.h> +#include <sys/uio.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#include "ant_types.h" +#include "ant_hciutils.h" +#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; + ANT_FUNC_START(); + + socket = create_hci_sock(); + + 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_ERROR("failed to set socket options: %s", strerror(errno)); + close(socket); + socket = -1; + } + } + + ANT_FUNC_END(); + return socket; +} + +void ant_close_tx_transport(int socket) +{ + ANT_FUNC_START(); + + if(0 < socket) + { + if (0 == close(socket)) + { + ANT_DEBUG_D("closed hci device (socket handle=%#x)", socket); + } + else + { + ANT_ERROR("failed to close hci device (socket handle=%#x): %s", socket, strerror(errno)); + } + } + else + { + ANT_DEBUG_E("requested close on socket %#x. invalid param", socket); + } + + ANT_FUNC_END(); +} + +/* +Format of an HCI WRITE command to ANT chip: + +HCI Header: +---------- +- HCI Packet Type: 1 byte + +- HCI Opcode: 2 bytes + (LSB, MSB - LE) +- HCI Parameters Total Len (total length of all subsequent fields): 1 byte + +HCI Parameters: +-------------- +- VS Parameters Len (total length of ANT Mesg inculding Len/ID) 2 bytes + (LSB, MSB - LE) +- ANT Mesg Len (N = number of bytes in ANT Mesg Data): 1 byte +- ANT Mesg ID: 1 byte +- ANT Mesg Data: N bytes +*/ + +ANT_BOOL wait_for_message(int socket) +{ + struct pollfd p; + int n; + + ANT_BOOL bReturn = ANT_FALSE; + ANT_BOOL bRetry = ANT_FALSE; + + ANT_FUNC_START(); + + p.fd = socket; + p.events = POLLIN; + + do + { + bRetry = ANT_FALSE; + + ANT_DEBUG_V(" CC: Polling HCI for data..."); + + /* poll socket, wait for ANT messages */ + n = poll(&p, 1, 2500); + if (0 > n) + { + if (errno == EAGAIN || errno == EINTR) + { + ANT_DEBUG_W(" CC: error: %s", strerror(errno)); + bRetry = ANT_TRUE; + } + else + { + ANT_ERROR("failed to poll socket. error: %s", strerror(errno)); + } + } + + /* timeout */ + else if (0 == n) + { + ANT_ERROR("SERIOUS: Timeouted getting Command Complete"); + } + else if(0 < n) + { + // There is data to read. + bReturn = ANT_TRUE; + } + + } while(ANT_TRUE == bRetry); + + ANT_FUNC_END(); + + return bReturn; +} + +ANTStatus write_data(ANT_U8 ant_message[], int ant_message_len) +{ + ANTStatus ret = ANT_STATUS_FAILED; + ANT_BOOL retry = ANT_FALSE; + int bytes_written; + struct iovec iov[2]; + hci_vendor_cmd_packet_t hci_header; + ANT_U16 hci_opcode; + + 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); + + iov[0].iov_base = &hci_header; + iov[0].iov_len = sizeof(hci_header); + iov[1].iov_base = ant_message; + iov[1].iov_len = ant_message_len; + + do //while retry + { + retry = ANT_FALSE; + + if (g_ant_cmd_socket < 0) + { + ANT_DEBUG_E("bad socket handle %#x", g_ant_cmd_socket); + return ANT_STATUS_INTERNAL_ERROR; + } + + ANT_SERIAL(ant_message, ant_message_len, 'T'); + + bytes_written = writev(g_ant_cmd_socket, iov, 2); + + ANT_DEBUG_D("writing to socket %#x returned %d", g_ant_cmd_socket, + bytes_written); + +// bytes_written < 0 = error (check errno) +// bytes_written = 0 = No data written +// bytes_written < sizeof(hci_message) = not all data written +// bytes_written = sizeof(hci_message) = all data written + + if(bytes_written < 0) + { + ANT_ERROR("write to HCI failed: %s", strerror(errno)); + + if (errno == EAGAIN || errno == EINTR) + { + ANT_DEBUG_D("Retrying write to HCI"); + retry = ANT_TRUE; + } + else + { + ret = ANT_STATUS_FAILED; + } + } + else if(bytes_written < ((int)sizeof(hci_header) + ant_message_len)) + { + ANT_DEBUG_D("Only %d bytes written to HCI.", bytes_written); + ret = ANT_STATUS_FAILED; + } + else + { + ANT_DEBUG_V("writev successful"); + ret = ANT_STATUS_SUCCESS; + } + } while(retry); + + ANT_FUNC_END(); + + return ret; +} + +// Returns: +// ANT_STATUS_NO_VALUE_AVAILABLE if not a CC packet +// ANT_STATUS_FAILED if could not read socket or not a +// valid length CC packet +// ANT_STATUS_TRANSPORT_UNSPECIFIED_ERROR if CC indicates an unspecified error +// ANT_STATUS_COMMAND_WRITE_FAILED if CC indicates a failure +// ANT_STATUS_SUCCESS if CC indicates message was received +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_FUNC_START(); + ANT_DEBUG_V("reading off socket %#x", socket); + + /* read newly arrived data */ + while ((len = read(socket, buf, sizeof(buf))) < 0) + { + if (errno == EAGAIN || errno == EINTR) + continue; + + ANT_ERROR("failed to read socket. error: %s", strerror(errno)); + + ret = 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]) + { + ANT_DEBUG_D("Received Event Packet"); + + if(EVT_CMD_COMPLETE == buf[1]) + { + if(len < HCI_EVENT_OVERHEAD_SIZE) + { + status = ANT_STATUS_FAILED; + } + else + { + if((HCI_CMD_OPCODE_ANT_LSB == buf[4]) && + (HCI_CMD_OPCODE_ANT_MSB == buf[5])) + { + ucResult = buf[6]; + + ANT_DEBUG_V("Received COMMAND COMPLETE"); + } + else + { + ANT_DEBUG_V("Command complete has wrong opcode"); + } + } + + /* + * if got a status byte, pass it forward, otherwise pass a failure + * status + */ + if(status != ANT_STATUS_FAILED) + { + if(ucResult == 0) + { + ANT_DEBUG_D("Command Complete = SUCCESS"); + status = ANT_STATUS_SUCCESS; + } + else if(ucResult == HCI_UNSPECIFIED_ERROR) + { + ANT_DEBUG_D("Command Complete = UNSPECIFIED_ERROR"); + + status = ANT_STATUS_TRANSPORT_UNSPECIFIED_ERROR; + } + else + { + status = ANT_STATUS_COMMAND_WRITE_FAILED; + ANT_DEBUG_D("Command Complete = WRITE_FAILED"); + } + } + } + else + { + ANT_DEBUG_W("Other Event Packet, Should filter out"); + } + } + +close: + ANT_FUNC_END(); + return status; +} + diff --git a/src/bluez_hci/inc/ant_framing.h b/src/bluez_hci/inc/ant_framing.h new file mode 100644 index 0000000..7d01844 --- /dev/null +++ b/src/bluez_hci/inc/ant_framing.h @@ -0,0 +1,50 @@ +/* + * 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_Framing.h +* +* BRIEF: +* This file defines ANT specific HCI values used by the ANT chip. +* +* +\******************************************************************************/ + +#ifndef __ANT_HCIFRAMING_H +#define __ANT_HCIFRAMING_H + +#ifdef BOARD_ANT_DEVICE_WILINK + +/* Number to used by the VS Parameters Len field */ +#define ANT_NATIVE_HCI_VS_PARMS_LEN_FIELD_LEN (2) + +#define HCI_CMD_ANT_MESSAGE_WRITE ((ANT_U16)0x01D1) + +#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 + +#else + +#error "Board ANT Device Type not recognised" + +#endif + +#endif /* __ANT_HCIFRAMING_H */ diff --git a/src/bluez_hci/inc/ant_hciutils.h b/src/bluez_hci/inc/ant_hciutils.h new file mode 100644 index 0000000..f8cf579 --- /dev/null +++ b/src/bluez_hci/inc/ant_hciutils.h @@ -0,0 +1,121 @@ +/* + * 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_hciuntils.h +* +* BRIEF: +* This file defines the utility functions for an HCI implementation +* +* +\******************************************************************************/ + +#ifndef __ANT_HCIUTILS_H +#define __ANT_HCIUTILS_H + +#include <errno.h> +#include <sys/socket.h> +#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); + if (sk < 0) + { + ANT_ERROR("Failed to create bluetooth hci socket: %s", strerror(errno)); + } + else + { + memset(&sa, 0, sizeof(sa)); + // sockaddr_hci changed from kernel 2.6.37 to 2.6.38 adding member hci_channel + // In order to be backwards compatible set it to 0 if it exists (HCI_CHANNEL_RAW) + sa.hci_family = AF_BLUETOOTH; + sa.hci_dev = 0; + if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) + { + ANT_ERROR("Failed to bind socket %#x to hci0: %s", sk, strerror(errno)); + close(sk); + sk = -1; + } + } + return sk; +} + +#endif /* __ANT_HCIUTILS_H */ + + diff --git a/src/bluez_hci/inc/ant_rx.h b/src/bluez_hci/inc/ant_rx.h new file mode 100644 index 0000000..c914bb6 --- /dev/null +++ b/src/bluez_hci/inc/ant_rx.h @@ -0,0 +1,54 @@ +/* + * ANT Stack + * + * Copyright 2009 Dynastream Innovations + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/******************************************************************************\ +* +* FILE NAME: ant_rx.h +* +* BRIEF: +* This file defines the receive thread function +* +* +\******************************************************************************/ + +#ifndef __ANT_OS_H +#define __ANT_OS_H + +#include <pthread.h> +#include "ant_types.h" +#include "ant_native.h" + +typedef struct +{ + //The function to call back with received data + ANTNativeANTEventCb pfRxCallback; + + //The function to call back with state changes + ANTNativeANTStateCb pfStateCallback; + + //The thread object itself + pthread_t thread; + +} ANTHCIRxParams; + +extern ANTHCIRxParams RxParams; + +//The message receive thread +void* ANTHCIRxThread(void* pvHCIDevice); + +#endif /* __ANT_OS_H */ + diff --git a/src/bluez_hci/inc/ant_tx.h b/src/bluez_hci/inc/ant_tx.h new file mode 100644 index 0000000..5057011 --- /dev/null +++ b/src/bluez_hci/inc/ant_tx.h @@ -0,0 +1,42 @@ +/* + * 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_tx.h +* +* BRIEF: +* This file defines the transmit function +* +* +\******************************************************************************/ + +#ifndef __ANT_TX_H +#define __ANT_TX_H + +#include "ant_types.h" +#include "ant_hciutils.h" + +int ant_open_tx_transport(void); +void ant_close_tx_transport(int socket); +ANT_BOOL wait_for_message(int socket); +ANTStatus write_data(ANT_U8 ant_message[], int ant_message_len); + +ANTStatus get_command_complete_result(int socket); + +#endif /* __ANT_TX_H */ + diff --git a/src/chip-B/Android.mk b/src/chip-B/Android.mk new file mode 100644 index 0000000..5b030ff --- /dev/null +++ b/src/chip-B/Android.mk @@ -0,0 +1,50 @@ +# +# 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-B") + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_CFLAGS := -g -c -W -Wall -O2 + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../common/inc \ + $(LOCAL_PATH)/inc \ + +LOCAL_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-B" diff --git a/src/chip-B/ant_native_chardev.c b/src/chip-B/ant_native_chardev.c new file mode 100644 index 0000000..39e61d7 --- /dev/null +++ b/src/chip-B/ant_native_chardev.c @@ -0,0 +1,424 @@ +/* + * 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 new file mode 100644 index 0000000..c4aedac --- /dev/null +++ b/src/chip-B/ant_rx_chardev.c @@ -0,0 +1,213 @@ +/* + * 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 new file mode 100644 index 0000000..1173f08 --- /dev/null +++ b/src/chip-B/inc/ant_native_chardev.h @@ -0,0 +1,48 @@ +/* + * 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-B/inc/ant_rx_chardev.h b/src/chip-B/inc/ant_rx_chardev.h new file mode 100644 index 0000000..6721222 --- /dev/null +++ b/src/chip-B/inc/ant_rx_chardev.h @@ -0,0 +1,73 @@ +/* + * 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/src/chip-C/Android.mk b/src/chip-C/Android.mk new file mode 100644 index 0000000..1f75535 --- /dev/null +++ b/src/chip-C/Android.mk @@ -0,0 +1,50 @@ +# +# 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 new file mode 100644 index 0000000..fe10382 --- /dev/null +++ b/src/chip-C/ant_native_chardev.c @@ -0,0 +1,389 @@ +/* + * 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/ant_rx_chardev.c b/src/chip-C/ant_rx_chardev.c new file mode 100644 index 0000000..2c0c6bd --- /dev/null +++ b/src/chip-C/ant_rx_chardev.c @@ -0,0 +1,213 @@ +/* + * ANT Stack + * + * Copyright 2011 Dynastream Innovations + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*******************************************************************************\ +* +* FILE NAME: ant_rx_chardev.c +* +* BRIEF: +* This file provides the rx function which will loop reading ANT messages +* until told to exit. +* +* +\*******************************************************************************/ + +#include <errno.h> +#include <poll.h> +#include <pthread.h> + +#include "ant_rx_chardev.h" +#include "ant_native_chardev.h" + +#include "ant_native.h" +#include "ant_types.h" +#include "ant_log.h" +#undef LOG_TAG +#define LOG_TAG "antradio_rx" + +#define ANT_POLL_TIMEOUT ((int)30000) + +int readChannelMsg(ant_channel_info_t *pstChnlInfo) +{ + int iRet = -1; + ANT_U8 aucRxBuffer[ANT_HCI_MAX_MSG_SIZE]; + int iRxLenRead; + int iMutexResult; + ANT_FUNC_START(); + + while (((iRxLenRead = read(pstChnlInfo->iFd, aucRxBuffer, sizeof(aucRxBuffer))) < 0) + && errno == EAGAIN) + ; + + if (iRxLenRead < 0) { + if (errno == ENODEV) { + ANT_ERROR("%s not enabled, exiting rx thread", + pstChnlInfo->pcDevicePath); + goto out; + } else if (errno == ENXIO) { + ANT_ERROR("%s there is no physical ANT device connected", + pstChnlInfo->pcDevicePath); + goto out; + } else { + ANT_ERROR("%s read thread exiting, unhandled error: %s", + pstChnlInfo->pcDevicePath, strerror(errno)); + goto out; + } + } else { + ANT_SERIAL(aucRxBuffer, iRxLenRead, 'R'); + if (aucRxBuffer[CHIP_C_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET] == ANT_MESG_FLOW_CONTROL) { + ANT_DEBUG_V("getting stFlowControlLock in %s", __FUNCTION__); + iMutexResult = pthread_mutex_lock(pstChnlInfo->pstFlowControlLock); + if (iMutexResult) { + ANT_ERROR("failed to lock flow control mutex during response: %s", strerror(iMutexResult)); + goto out; + } + ANT_DEBUG_V("got stFlowControlLock in %s", __FUNCTION__); + + pstChnlInfo->ucFlowControlResp = aucRxBuffer[CHIP_C_HCI_DATA_OFFSET + ANT_MSG_DATA_OFFSET]; + + ANT_DEBUG_V("releasing stFlowControlLock in %s", __FUNCTION__); + pthread_mutex_unlock(pstChnlInfo->pstFlowControlLock); + ANT_DEBUG_V("released stFlowControlLock in %s", __FUNCTION__); + pthread_cond_signal(pstChnlInfo->pstFlowControlCond); + } else { + if (pstChnlInfo->fnRxCallback != NULL) { + pstChnlInfo->fnRxCallback(aucRxBuffer[CHIP_C_HCI_SIZE_OFFSET], &aucRxBuffer[CHIP_C_HCI_DATA_OFFSET]); + } else { + ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath); + } + } + iRet = 0; + } +out: + ANT_FUNC_END(); + return iRet; +} + +void *fnRxThread(void *ant_rx_thread_info) +{ + int iMutexLockResult; + int iPollRet; + ant_rx_thread_info_t *stRxThreadInfo; + struct pollfd astPollFd[NUM_ANT_CHANNELS]; + enum ant_channel_type eChannel; + ANT_FUNC_START(); + + stRxThreadInfo = (ant_rx_thread_info_t *)ant_rx_thread_info; + for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { + astPollFd[eChannel].fd = stRxThreadInfo->astChannels[eChannel].iFd; + astPollFd[eChannel].events = POLLIN | POLLRDNORM; + } + + while (stRxThreadInfo->ucRunThread) { + iPollRet = poll(astPollFd, NUM_ANT_CHANNELS, ANT_POLL_TIMEOUT); + if (!iPollRet) { + ANT_DEBUG_V("poll timed out, checking exit cond"); + } else if (iPollRet < 0) { + ANT_ERROR("read thread exiting, unhandled error: %s", strerror(errno)); + } else { + for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { + if (astPollFd[eChannel].revents & (POLLERR | POLLPRI | POLLRDHUP)) { + ANT_ERROR("poll error from %s. exiting rx thread", + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + /* Chip was reset or other error, only way to recover is to + * close and open ANT chardev */ + stRxThreadInfo->ucChipResetting = 1; + if (g_fnStateCallback) + g_fnStateCallback(RADIO_STATUS_RESETTING); + goto reset; + + } else if (astPollFd[eChannel].revents & (POLLIN | POLLRDNORM)) { + ANT_DEBUG_D("data on %s. reading it", + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + if (readChannelMsg(&stRxThreadInfo->astChannels[eChannel]) < 0) + goto out; + } else if (astPollFd[eChannel].revents) { + ANT_DEBUG_W("unhandled poll result %#x from %s", + astPollFd[eChannel].revents, + stRxThreadInfo->astChannels[eChannel].pcDevicePath); + } + } + } + } +out: + stRxThreadInfo->ucRunThread = 0; + /* Try to get stEnabledStatusLock. + * if you get it then noone is enabling or disabling + * if you can't get it assume something made you exit */ + ANT_DEBUG_V("try getting stEnabledStatusLock in %s", __FUNCTION__); + iMutexLockResult = pthread_mutex_trylock(stRxThreadInfo->pstEnabledStatusLock); + if (!iMutexLockResult) { + ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); + ANT_WARN("rx thread has unexpectedly crashed, cleaning up"); + stRxThreadInfo->stRxThread = 0; /* spoof our handle as closed so we don't + * try to join ourselves in disable */ + + if (g_fnStateCallback) + g_fnStateCallback(RADIO_STATUS_DISABLING); + + ant_do_disable(); + + if (g_fnStateCallback) + g_fnStateCallback(ant_radio_enabled_status()); + + ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); + pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock); + ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); + } else if (iMutexLockResult != EBUSY) { + ANT_ERROR("rx thread closing code, trylock on state lock failed: %s", + strerror(iMutexLockResult)); + } else { + ANT_DEBUG_V("stEnabledStatusLock busy"); + } + ANT_FUNC_END(); +#ifdef ANDROID + return NULL; +#endif + +reset: + stRxThreadInfo->ucRunThread = 0; + ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); + iMutexLockResult = pthread_mutex_lock(stRxThreadInfo->pstEnabledStatusLock); + if (iMutexLockResult < 0) { + ANT_ERROR("chip was reset, getting state mutex failed: %s", + strerror(iMutexLockResult)); + stRxThreadInfo->stRxThread = 0; + } else { + ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); + stRxThreadInfo->stRxThread = 0; /* spoof our handle as closed so we don't + * try to join ourselves in disable */ + ant_do_disable(); + + if (ant_do_enable()) { /* failed */ + if (g_fnStateCallback) + g_fnStateCallback(RADIO_STATUS_DISABLED); + } else { /* success */ + if (g_fnStateCallback) + g_fnStateCallback(RADIO_STATUS_RESET); + } + ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); + pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock); + ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); + } + stRxThreadInfo->ucChipResetting = 0; + ANT_FUNC_END(); +#ifdef ANDROID + return NULL; +#endif +} + diff --git a/src/chip-C/inc/ant_native_chardev.h b/src/chip-C/inc/ant_native_chardev.h new file mode 100644 index 0000000..c72ac0e --- /dev/null +++ b/src/chip-C/inc/ant_native_chardev.h @@ -0,0 +1,48 @@ +/* + * 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 new file mode 100644 index 0000000..6721222 --- /dev/null +++ b/src/chip-C/inc/ant_rx_chardev.h @@ -0,0 +1,73 @@ +/* + * 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/src/common/ant_utils.c b/src/common/ant_utils.c new file mode 100644 index 0000000..65b35de --- /dev/null +++ b/src/common/ant_utils.c @@ -0,0 +1,57 @@ +/* + * 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_utils.c +* +* BRIEF: +* This file contains utility functions +* +* +\******************************************************************************/ + +#include "ant_types.h" +#include "ant_utils.h" + + +ANT_U16 ANT_UTILS_BEtoHost16(ANT_U8 * num) +{ + return (ANT_U16)(((ANT_U16) *(num) << 8) | ((ANT_U16) *(num+1))); +} +ANT_U16 ANT_UTILS_LEtoHost16(ANT_U8 * num) +{ + return (ANT_U16)(((ANT_U16) *(num+1) << 8) | ((ANT_U16) *(num))); +} +void ANT_UTILS_StoreBE16(ANT_U8 *buff, ANT_U16 be_value) +{ + buff[0] = (ANT_U8)(be_value>>8); + buff[1] = (ANT_U8)be_value; +} +void ANT_UTILS_StoreLE16(ANT_U8 *buff, ANT_U16 le_value) +{ + buff[1] = (ANT_U8)(le_value>>8); + buff[0] = (ANT_U8)le_value; +} + +void ANT_UTILS_StoreBE32(ANT_U8 *buff, ANT_U32 be_value) +{ + buff[0] = (ANT_U8)(be_value>>24); + buff[1] = (ANT_U8)(be_value>>16); + buff[2] = (ANT_U8)(be_value>>8); + buff[3] = (ANT_U8)be_value; +} diff --git a/src/common/inc/ant_log.h b/src/common/inc/ant_log.h new file mode 100644 index 0000000..f2d09b5 --- /dev/null +++ b/src/common/inc/ant_log.h @@ -0,0 +1,174 @@ +/* + * 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 +* +* BRIEF: +* This file defines logging functions +* +* +\******************************************************************************/ + +#ifndef __ANT_LOG_H +#define __ANT_LOG_H + +#include <unistd.h> +#include "ant_types.h" + +#define LEVEL_NONE 0 +#define LEVEL_ERROR 1 +#define LEVEL_WARNING 2 +#define LEVEL_INFO 3 +#define LEVEL_DEBUG 4 +#define LEVEL_VERBOSE 5 + +#define STREAM_STDOUT 16 +#define STREAM_LOGCAT 17 + +/* Define what stream output should go to depending on platform */ +#if defined(__ANDROID__) || defined(ANDROID) + #define ANT_OUTPUT_STREAM STREAM_LOGCAT +#elif defined(__linux__) || defined(__linux) || defined(linux) + #define ANT_OUTPUT_STREAM STREAM_STDOUT +#endif + +/* If no debug level defined, set default as none */ +#if !defined(ANT_DEBUG) + #define ANT_DEBUG LEVEL_NONE +#endif + +/* Define to show function entry and exit */ +//#define ANT_STACK_TRACE + +/* Define to show message in byte form */ +//#define ANT_LOG_SERIAL + +/* Define to write serial log to file instead of logcat */ +//#define ANT_LOG_SERIAL_FILE "/data/system/antseriallog.txt" + +#undef LOG_TAG +#define LOG_TAG "antradio" + +#if ANT_DEBUG == LEVEL_NONE + #undef ANT_STACK_TRACE + #undef ANT_LOG_SERIAL +#endif + +#if ANT_DEBUG >= LEVEL_ERROR + #define OUTPUT_LEVEL_ERROR(...) OUTPUT_ERROR(__VA_ARGS__) +#else + #define OUTPUT_LEVEL_ERROR(...) ((void)0) +#endif +#if ANT_DEBUG >= LEVEL_WARNING + #define OUTPUT_LEVEL_WARNING(...) OUTPUT_WARNING(__VA_ARGS__) +#else + #define OUTPUT_LEVEL_WARNING(...) ((void)0) +#endif +#if ANT_DEBUG >= LEVEL_INFO + #define OUTPUT_LEVEL_INFO(...) OUTPUT_INFO(__VA_ARGS__) +#else + #define OUTPUT_LEVEL_INFO(...) ((void)0) +#endif +#if ANT_DEBUG >= LEVEL_DEBUG + #define OUTPUT_LEVEL_DEBUG(...) OUTPUT_DEBUG(__VA_ARGS__) +#else + #define OUTPUT_LEVEL_DEBUG(...) ((void)0) +#endif +#if ANT_DEBUG >= LEVEL_VERBOSE + #define OUTPUT_LEVEL_VERBOSE(...) OUTPUT_VERBOSE(__VA_ARGS__) +#else + #define OUTPUT_LEVEL_VERBOSE(...) ((void)0) +#endif + +#if ANT_OUTPUT_STREAM == STREAM_STDOUT + #include <stdio.h> + #define OUTPUT_VERBOSE(fmt, ...) fprintf(stdout, LOG_TAG "<V>: " fmt "\n", ##__VA_ARGS__) + #define OUTPUT_DEBUG(fmt, ...) fprintf(stdout, LOG_TAG "<D>: " fmt "\n", ##__VA_ARGS__) + #define OUTPUT_INFO(fmt, ...) fprintf(stdout, LOG_TAG "<I>: " fmt "\n", ##__VA_ARGS__) + #define OUTPUT_WARNING(fmt, ...) fprintf(stdout, LOG_TAG "<W>: " fmt "\n", ##__VA_ARGS__) + #define OUTPUT_ERROR(fmt, ...) fprintf(stdout, LOG_TAG "<E>: " fmt "\n", ##__VA_ARGS__) +#elif ANT_OUTPUT_STREAM == STREAM_LOGCAT + #if (ANT_DEBUG >= LEVEL_VERBOSE) || (defined(ANT_LOG_SERIAL) && !defined(ANT_LOG_SERIAL_FILE)) + #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__) +#endif + +#define ANT_WARN(...) OUTPUT_WARNING(__VA_ARGS__) +#define ANT_ERROR(...) OUTPUT_ERROR(__VA_ARGS__) + +#define ANT_DEBUG_V(...) OUTPUT_LEVEL_VERBOSE(__VA_ARGS__) +#define ANT_DEBUG_D(...) OUTPUT_LEVEL_DEBUG(__VA_ARGS__) +#define ANT_DEBUG_I(...) OUTPUT_LEVEL_INFO(__VA_ARGS__) +#define ANT_DEBUG_W(...) OUTPUT_LEVEL_WARNING(__VA_ARGS__) +#define ANT_DEBUG_E(...) OUTPUT_LEVEL_ERROR(__VA_ARGS__) + +#if defined(ANT_STACK_TRACE) + #define ANT_FUNC_START() OUTPUT_DEBUG("-> FUNC start %s", __FUNCTION__) + #define ANT_FUNC_END() OUTPUT_DEBUG("<- FUNC end %s", __FUNCTION__) +#else + #define ANT_FUNC_START() ((void)0) + #define ANT_FUNC_END() ((void)0) +#endif + +#if defined(ANT_LOG_SERIAL) +static inline void ANT_SERIAL(ANT_U8 *buf, ANT_U8 len, char dir) +{ + static const char hexToChar[] = {'0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F'}; + int i; + static char log[1024]; + char *ptr = log; + + *(ptr++) = dir; + *(ptr++) = 'x'; + *(ptr++) = ' '; + for (i = 0; i < len; i++) { + *(ptr++) = '['; + *(ptr++) = hexToChar[(buf[i] & 0xF0) >> 4]; + *(ptr++) = hexToChar[(buf[i] & 0x0F) >> 0]; + *(ptr++) = ']'; + } +#if defined(ANT_LOG_SERIAL_FILE) + *(ptr++) = '\n'; + FILE *fd = NULL; + fd = fopen(ANT_LOG_SERIAL_FILE, "a"); + if (NULL == fd) { + LOGW("Could not open %s for serial output. %s", ANT_LOG_SERIAL_FILE, strerror(errno)); + } else { + fwrite(log, 1, (ptr - log), fd); + if (fclose(fd)) { + LOGW("Could not close file for serial output. %s", strerror(errno)); + } + } +#else + *(ptr++) = '\0'; + OUTPUT_VERBOSE("%s", log); +#endif +} +#else + #define ANT_SERIAL(...) ((void)0) +#endif + +#endif /* __ANT_LOG_H */ diff --git a/src/common/inc/ant_native.h b/src/common/inc/ant_native.h new file mode 100644 index 0000000..eedec50 --- /dev/null +++ b/src/common/inc/ant_native.h @@ -0,0 +1,142 @@ +/* + * 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.h +* +* BRIEF: +* This file defines the interface to the ANT transport layer +* +* +\******************************************************************************/ + +#ifndef __ANT_NATIVE_H +#define __ANT_NATIVE_H + +/******************************************************************************* + * + * Include files + * + ******************************************************************************/ +#include "ant_types.h" + +/******************************************************************************* + * + * 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) + +/******************************************************************************* + * + * Types + * + ******************************************************************************/ +typedef void (*ANTNativeANTEventCb)(ANT_U8 ucLen, ANT_U8* pucData); +typedef void (*ANTNativeANTStateCb)(ANTRadioEnabledStatus uiNewState); + +/******************************************************************************* + * + * Data Structures + * + ******************************************************************************/ + +/******************************************************************************* + * + * Function declarations + * + ******************************************************************************/ + +/*------------------------------------------------------------------------------ + * ant_init() + * + * Called to initialize the ANT stack + */ +ANTStatus ant_init(void); + +/*------------------------------------------------------------------------------ + * ant_deinit() + * + * Called to de-initialize the ANT stack + */ +ANTStatus ant_deinit(void); + +/*------------------------------------------------------------------------------ + * ant_enable_radio() + * + * Power on the chip and set it to a state which can read / write to it + */ +ANTStatus ant_enable_radio(void); + +/*------------------------------------------------------------------------------ + * ant_disable_radio() + * + * Kill power to the ANT chip and set state which doesnt allow read / write + */ +ANTStatus ant_disable_radio(void); + +/*------------------------------------------------------------------------------ + * ant_radio_enabled_status() + * + * Gets if the chip/transport is disabled/disabling/enabling/enabled + */ +ANTRadioEnabledStatus ant_radio_enabled_status(void); + +/*------------------------------------------------------------------------------ + * set_ant_rx_callback() + * + * Sets the callback function for receiving ANT messages + */ +ANTStatus set_ant_rx_callback(ANTNativeANTEventCb rx_callback_func); + +/*------------------------------------------------------------------------------ + * set_ant_state_callback() + * + * Sets the callback function for any ANT radio enabled status state changes + */ +ANTStatus set_ant_state_callback(ANTNativeANTStateCb state_callback_func); + +/*------------------------------------------------------------------------------ + * ant_tx_message() + * + * Sends an ANT message command to the chip. + */ +ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg); + +/*------------------------------------------------------------------------------ + * ant_radio_hard_reset() + * + * If supported, forces the chip to do a power cycle reset + */ +ANTStatus ant_radio_hard_reset(void); + +/*------------------------------------------------------------------------------ + * ant_get_lib_version() + * + * Gets the current version and transport type of libantradio.so + */ +const char *ant_get_lib_version(void); + +#endif /* ifndef __ANT_NATIVE_H */ + diff --git a/src/common/inc/ant_types.h b/src/common/inc/ant_types.h new file mode 100644 index 0000000..bc896b6 --- /dev/null +++ b/src/common/inc/ant_types.h @@ -0,0 +1,125 @@ +/* + * 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_types.h +* +* BRIEF: +* This file defines types used in the ANT stack +* +* +\******************************************************************************/ + +#ifndef __ANT_TYPES_H +#define __ANT_TYPES_H + +#include <stdint.h> + +/* ------------------------------------------------------------- + * 8 Bits Types + */ +typedef uint8_t ANT_U8; +typedef int8_t ANT_S8; + +/* ------------------------------------------------------------- + * 16 Bits Types + */ +typedef uint16_t ANT_U16; +typedef int8_t ANT_S16; + +/* ------------------------------------------------------------- + * 32 Bits Types + */ +typedef uint32_t ANT_U32; +typedef int32_t ANT_S32; + + +/* ------------------------------------------------------------- + * Native Integer Types (# of bits irrelevant) + */ +typedef int ANT_INT; +typedef unsigned int ANT_UINT; + + +/* -------------------------------------------------------------- + * Boolean Definitions + */ +typedef ANT_INT ANT_BOOL; + +#define ANT_TRUE (1 == 1) +#define ANT_FALSE (1 == 0) + +/* +*/ +#define ANT_NO_VALUE ((ANT_U32)0xFFFFFFFFUL) + + +/* ------------------------------------------------------------- + * ANTRadioEnabledStatus Type + */ +typedef ANT_UINT ANTRadioEnabledStatus; + +#define RADIO_STATUS_UNKNOWN ((ANTRadioEnabledStatus)0) +#define RADIO_STATUS_ENABLING ((ANTRadioEnabledStatus)1) +#define RADIO_STATUS_ENABLED ((ANTRadioEnabledStatus)2) +#define RADIO_STATUS_DISABLING ((ANTRadioEnabledStatus)3) +#define RADIO_STATUS_DISABLED ((ANTRadioEnabledStatus)4) +#define RADIO_STATUS_NOT_SUPPORTED ((ANTRadioEnabledStatus)5) +#define RADIO_STATUS_SERVICE_NOT_INSTALLED ((ANTRadioEnabledStatus)6) +#define RADIO_STATUS_SERVICE_NOT_CONNECTED ((ANTRadioEnabledStatus)7) +#define RADIO_STATUS_RESETTING ((ANTRadioEnabledStatus)8) +#define RADIO_STATUS_RESET ((ANTRadioEnabledStatus)9) + +/*------------------------------------------------------------------------------ + * ANTStatus Type + * + */ +typedef ANT_UINT ANTStatus; + +#define ANT_STATUS_SUCCESS ((ANTStatus)0) +#define ANT_STATUS_FAILED ((ANTStatus)1) +#define ANT_STATUS_PENDING ((ANTStatus)2) +#define ANT_STATUS_INVALID_PARM ((ANTStatus)3) +#define ANT_STATUS_IN_PROGRESS ((ANTStatus)4) +#define ANT_STATUS_NOT_APPLICABLE ((ANTStatus)5) +#define ANT_STATUS_NOT_SUPPORTED ((ANTStatus)6) +#define ANT_STATUS_INTERNAL_ERROR ((ANTStatus)7) +#define ANT_STATUS_TRANSPORT_INIT_ERR ((ANTStatus)8) +#define ANT_STATUS_HARDWARE_ERR ((ANTStatus)9) +#define ANT_STATUS_NO_VALUE_AVAILABLE ((ANTStatus)10) +#define ANT_STATUS_CONTEXT_DOESNT_EXIST ((ANTStatus)11) +#define ANT_STATUS_CONTEXT_NOT_DESTROYED ((ANTStatus)12) +#define ANT_STATUS_CONTEXT_NOT_ENABLED ((ANTStatus)13) +#define ANT_STATUS_CONTEXT_NOT_DISABLED ((ANTStatus)14) +#define ANT_STATUS_NOT_DE_INITIALIZED ((ANTStatus)15) +#define ANT_STATUS_NOT_INITIALIZED ((ANTStatus)16) +#define ANT_STATUS_TOO_MANY_PENDING_CMDS ((ANTStatus)17) +#define ANT_STATUS_DISABLING_IN_PROGRESS ((ANTStatus)18) + +#define ANT_STATUS_COMMAND_WRITE_FAILED ((ANTStatus)20) +#define ANT_STATUS_SCRIPT_EXEC_FAILED ((ANTStatus)21) + +#define ANT_STATUS_FAILED_BT_NOT_INITIALIZED ((ANTStatus)23) +#define ANT_STATUS_AUDIO_OPERATION_UNAVAILIBLE_RESOURCES ((ANTStatus)24) + +#define ANT_STATUS_TRANSPORT_UNSPECIFIED_ERROR ((ANTStatus)30) + +#define ANT_STATUS_NO_VALUE ((ANTStatus)100) + +#endif /* __ANT_TYPES_H */ + diff --git a/src/common/inc/ant_utils.h b/src/common/inc/ant_utils.h new file mode 100644 index 0000000..60abe8c --- /dev/null +++ b/src/common/inc/ant_utils.h @@ -0,0 +1,139 @@ +/* + * 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_utils.h +* +* BRIEF: +* This file defines utility functions +* +* +\******************************************************************************/ +#ifndef __ANT_UTILS_H +#define __ANT_UTILS_H + +#include "ant_types.h" + +/**************************************************************************** + * + * Type Definitions + * + ****************************************************************************/ + + + +/*------------------------------------------------------------------------------ + * ANT_xxx() + * + * Brief: + * xxx + * + * Description: + * xxx + * + * Type: + * Syxxx/As + * + * Parameters: + * xxx [in] - + * + * Returns: + * xxx + */ +ANT_U16 ANT_UTILS_BEtoHost16(ANT_U8 * num); +/*------------------------------------------------------------------------------ + * ANT_xxx() + * + * Brief: + * xxx + * + * Description: + * xxx + * + * Type: + * Syxxx/As + * + * Parameters: + * xxx [in] - + * + * Returns: + * xxx + */ +ANT_U16 ANT_UTILS_LEtoHost16(ANT_U8 * num); +/*------------------------------------------------------------------------------ + * ANT_xxx() + * + * Brief: + * xxx + * + * Description: + * xxx + * + * Type: + * Syxxx/As + * + * Parameters: + * xxx [in] - + * + * Returns: + * xxx + */ +void ANT_UTILS_StoreBE16(ANT_U8 *buff, ANT_U16 be_value) ; +/*------------------------------------------------------------------------------ + * ANT_xxx() + * + * Brief: + * xxx + * + * Description: + * xxx + * + * Type: + * Syxxx/As + * + * Parameters: + * xxx [in] - + * + * Returns: + * xxx + */ +void ANT_UTILS_StoreLE16(ANT_U8 *buff, ANT_U16 le_value) ; +/*------------------------------------------------------------------------------ + * ANT_xxx() + * + * Brief: + * xxx + * + * Description: + * xxx + * + * Type: + * Syxxx/As + * + * Parameters: + * xxx [in] - + * + * Returns: + * xxx + */ +void ANT_UTILS_StoreBE32(ANT_U8 *buff, ANT_U32 be_value) ; + + + +#endif /* __ANT_UTILS_H */ + diff --git a/src/common/inc/ant_version.h b/src/common/inc/ant_version.h new file mode 100644 index 0000000..bc1f239 --- /dev/null +++ b/src/common/inc/ant_version.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef __ANT_VERSION_H +#define __ANT_VERSION_H + +#define LIBANT_STACK_MAJOR "0" +#define LIBANT_STACK_MINOR "7" +#define LIBANT_STACK_INCRE "0" + +#endif // __ANT_VERSION_H + |