From e4f71eb3818673d5f9681bfb2ac2e99f14f73bb8 Mon Sep 17 00:00:00 2001 From: "jihwan.seo" Date: Thu, 21 Jan 2016 15:13:22 +0900 Subject: [PATCH] [IOT-931] Added send logic to check write/notify in BLE according to android BLE guide, I have modified transmission logic for BLE. when there is a big message to sent, next segmentation data has to wait for callback write/notify Characteristic for previous sent data. Change-Id: Idf543504d634ab4dfbc2fbd4bb90aa7e2ad1831e Signed-off-by: jihwan.seo Reviewed-on: https://gerrit.iotivity.org/gerrit/4841 Tested-by: jenkins-iotivity Reviewed-by: Jaehong Jo Reviewed-by: Hyuna Jo Reviewed-by: Jon A. Cruz --- .../src/bt_le_adapter/android/caleclient.c | 178 +++++++++++++++--- .../src/bt_le_adapter/android/caleclient.h | 10 +- .../src/bt_le_adapter/android/calenwmonitor.c | 14 +- .../src/bt_le_adapter/android/caleserver.c | 208 +++++++++++++++++++-- 4 files changed, 361 insertions(+), 49 deletions(-) diff --git a/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c b/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c index 41133cc..767cbce 100644 --- a/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c +++ b/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c @@ -40,12 +40,15 @@ #define TAG PCF("OIC_CA_LE_CLIENT") #define MICROSECS_PER_SEC 1000000 +#define WAIT_TIME_WRITE_CHARACTERISTIC 10 * MICROSECS_PER_SEC static const char METHODID_OBJECTNONPARAM[] = "()Landroid/bluetooth/BluetoothAdapter;"; static const char CLASSPATH_BT_ADAPTER[] = "android/bluetooth/BluetoothAdapter"; static const char CLASSPATH_BT_UUID[] = "java/util/UUID"; static const char CLASSPATH_BT_GATT[] = "android/bluetooth/BluetoothGatt"; +static ca_thread_pool_t g_threadPoolHandle = NULL; + JavaVM *g_jvm; static u_arraylist_t *g_deviceList = NULL; // device list to have same UUID static u_arraylist_t *g_gattObjectList = NULL; @@ -73,6 +76,9 @@ static ca_cond g_threadCond = NULL; static ca_cond g_deviceDescCond = NULL; static ca_mutex g_threadSendMutex = NULL; +static ca_mutex g_threadWriteCharacteristicMutex = NULL; +static ca_cond g_threadWriteCharacteristicCond = NULL; +static bool g_isSignalSetFlag = false; static ca_mutex g_bleReqRespClientCbMutex = NULL; static ca_mutex g_bleServerBDAddressMutex = NULL; @@ -224,6 +230,7 @@ CAResult_t CALEClientInitialize() // init mutex for send logic g_threadCond = ca_cond_new(); + g_threadWriteCharacteristicCond = ca_cond_new(); CALEClientCreateDeviceList(); CALEClientJNISetContext(); @@ -336,9 +343,12 @@ void CALEClientTerminate() ca_cond_free(g_deviceDescCond); ca_cond_free(g_threadCond); + ca_cond_free(g_threadWriteCharacteristicCond); g_deviceDescCond = NULL; g_threadCond = NULL; + g_threadWriteCharacteristicCond = NULL; + g_isSignalSetFlag = false; if (isAttached) { @@ -642,6 +652,7 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* if (g_sendBuffer) { (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; } jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen); (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data); @@ -729,6 +740,7 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data, if (g_sendBuffer) { (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; } if (0 == u_arraylist_length(g_deviceList)) @@ -915,10 +927,10 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device) return CA_STATUS_FAILED; } - CAResult_t ret = CALEClientWriteCharacteristic(env, gatt); + CAResult_t ret = CALESetValueAndWriteCharacteristic(env, gatt); if (CA_STATUS_OK != ret) { - OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed"); + OIC_LOG(ERROR, TAG, "CALESetValueAndWriteCharacteristic has failed"); (*env)->ReleaseStringUTFChars(env, jni_address, address); return ret; } @@ -1549,10 +1561,43 @@ CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt) return CA_STATUS_OK; } -CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt) +static void CALEWriteCharacteristicThread(void* object) +{ + VERIFY_NON_NULL(object, TAG, "object is null"); + + bool isAttached = false; + JNIEnv* env; + jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); + if (JNI_OK != res) + { + OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); + res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); + + if (JNI_OK != res) + { + OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed"); + return; + } + isAttached = true; + } + + jobject gatt = (jobject)object; + CAResult_t ret = CALESetValueAndWriteCharacteristic(env, gatt); + if (CA_STATUS_OK != ret) + { + OIC_LOG(ERROR, TAG, "CALESetValueAndWriteCharacteristic has failed"); + } + + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } +} + +CAResult_t CALESetValueAndWriteCharacteristic(JNIEnv* env, jobject gatt) { - VERIFY_NON_NULL(env, TAG, "env is null"); VERIFY_NON_NULL(gatt, TAG, "gatt is null"); + VERIFY_NON_NULL(env, TAG, "env is null"); // send data jobject jni_obj_character = CALEClientCreateGattCharacteristic(env, gatt, g_sendBuffer); @@ -1566,14 +1611,53 @@ CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt) if (CA_STATUS_OK != ret) { CALEClientSendFinish(env, gatt); - return ret; + return CA_STATUS_FAILED; + } + + // wait for callback for write Characteristic with success to sent data + OIC_LOG_V(DEBUG, TAG, "callback flag is %d", g_isSignalSetFlag); + ca_mutex_lock(g_threadWriteCharacteristicMutex); + if (!g_isSignalSetFlag) + { + OIC_LOG(DEBUG, TAG, "wait for callback to notify writeCharacteristic is success"); + if (CA_WAIT_SUCCESS != ca_cond_wait_for(g_threadWriteCharacteristicCond, + g_threadWriteCharacteristicMutex, + WAIT_TIME_WRITE_CHARACTERISTIC)) + { + OIC_LOG(ERROR, TAG, "there is no response. write has failed"); + g_isSignalSetFlag = false; + ca_mutex_unlock(g_threadWriteCharacteristicMutex); + return CA_STATUS_FAILED; + } } + // reset flag set by writeCharacteristic Callback + g_isSignalSetFlag = false; + ca_mutex_unlock(g_threadWriteCharacteristicMutex); + OIC_LOG(INFO, TAG, "writeCharacteristic success!!"); + return CA_STATUS_OK; +} + +CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt) +{ + OIC_LOG(DEBUG, TAG, "IN - CALEClientWriteCharacteristic"); + VERIFY_NON_NULL(env, TAG, "env is null"); + VERIFY_NON_NULL(gatt, TAG, "gatt is null"); + + jobject gattParam = (*env)->NewGlobalRef(env, gatt); + if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle, + CALEWriteCharacteristicThread, (void*)gattParam)) + { + OIC_LOG(ERROR, TAG, "Failed to create read thread!"); + return CA_STATUS_FAILED; + } + + OIC_LOG(DEBUG, TAG, "OUT - CALEClientWriteCharacteristic"); return CA_STATUS_OK; } CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt, - jobject gattCharacteristic) + jobject gattCharacteristic) { OIC_LOG(DEBUG, TAG, "WRITE GATT CHARACTERISTIC"); VERIFY_NON_NULL(env, TAG, "env is null"); @@ -1613,7 +1697,7 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt, gattCharacteristic); if (ret) { - OIC_LOG(DEBUG, TAG, "writeCharacteristic success"); + OIC_LOG(DEBUG, TAG, "writeCharacteristic is called successfully"); } else { @@ -3020,6 +3104,7 @@ void CALEClientUpdateSendCnt(JNIEnv *env) } // notity the thread ca_cond_signal(g_threadCond); + CALEClientSetSendFinishFlag(true); OIC_LOG(DEBUG, TAG, "set signal for send data"); } @@ -3119,6 +3204,16 @@ CAResult_t CALEClientInitGattMutexVaraibles() } } + if (NULL == g_threadWriteCharacteristicMutex) + { + g_threadWriteCharacteristicMutex = ca_mutex_new(); + if (NULL == g_threadWriteCharacteristicMutex) + { + OIC_LOG(ERROR, TAG, "ca_mutex_new has failed"); + return CA_STATUS_FAILED; + } + } + return CA_STATUS_OK; } @@ -3144,6 +3239,9 @@ void CALEClientTerminateGattMutexVariables() ca_mutex_free(g_scanMutex); g_scanMutex = NULL; + + ca_mutex_free(g_threadWriteCharacteristicMutex); + g_threadWriteCharacteristicMutex = NULL; } void CALEClientSetSendFinishFlag(bool flag) @@ -3212,7 +3310,13 @@ void CAStopLEGattClient() OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed"); } + ca_mutex_lock(g_threadMutex); ca_cond_signal(g_threadCond); + ca_mutex_unlock(g_threadMutex); + + ca_mutex_lock(g_threadWriteCharacteristicMutex); + ca_cond_signal(g_threadWriteCharacteristicCond); + ca_mutex_unlock(g_threadWriteCharacteristicMutex); if (isAttached) { @@ -3268,7 +3372,7 @@ void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback) void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle) { - OIC_LOG(INFO, TAG, "CASetLEClientThreadPoolHandle is not support"); + g_threadPoolHandle = handle; } CAResult_t CAGetLEAddress(char **local_address) @@ -3413,6 +3517,12 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J { OIC_LOG(ERROR, TAG, "CALEClientGattClose has failed"); } + + if (g_sendBuffer) + { + (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } } return; @@ -3487,11 +3597,14 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIE if (CA_STATUS_OK != res) { OIC_LOG_V(INFO, TAG, "Descriptor is not found : %d", res); - CAResult_t res = CALEClientWriteCharacteristic(env, gatt); - if (CA_STATUS_OK != res) + if (g_sendBuffer) { - OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed"); - goto error_exit; + CAResult_t res = CALEClientWriteCharacteristic(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed"); + goto error_exit; + } } } @@ -3558,20 +3671,34 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback( if (GATT_SUCCESS != status) // error case { OIC_LOG(ERROR, TAG, "send failure"); - CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET, - STATE_SEND_FAILED); + + // retry to write + CAResult_t res = CALEClientWriteCharacteristic(env, gatt); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); - } + OIC_LOG(ERROR, TAG, "WriteCharacteristic has failed"); + ca_mutex_lock(g_threadWriteCharacteristicMutex); + g_isSignalSetFlag = true; + ca_cond_signal(g_threadWriteCharacteristicCond); + ca_mutex_unlock(g_threadWriteCharacteristicMutex); - if (g_clientErrorCallback) - { - jint length = (*env)->GetArrayLength(env, data); - g_clientErrorCallback(address, data, length, CA_SEND_FAILED); - } + CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, + STATE_CHARACTER_SET, + STATE_SEND_FAILED); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); + } - CALEClientSendFinish(env, gatt); + if (g_clientErrorCallback) + { + jint length = (*env)->GetArrayLength(env, data); + g_clientErrorCallback(address, data, length, CA_SEND_FAILED); + } + + CALEClientSendFinish(env, gatt); + goto error_exit; + } } else { @@ -3582,6 +3709,13 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback( { OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); } + + ca_mutex_lock(g_threadWriteCharacteristicMutex); + OIC_LOG(DEBUG, TAG, "g_isSignalSetFlag is set true and signal"); + g_isSignalSetFlag = true; + ca_cond_signal(g_threadWriteCharacteristicCond); + ca_mutex_unlock(g_threadWriteCharacteristicMutex); + CALEClientUpdateSendCnt(env); } diff --git a/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.h b/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.h index 6656a0f..1a1d1e9 100644 --- a/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.h +++ b/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.h @@ -299,13 +299,21 @@ CAResult_t CALEClientDisconnectAll(JNIEnv *env); CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt); /** + * call CALESetValueAndWriteCharacteristic when connection is successful. + * @param[in] env JNI interface pointer. + * @param[in] gatt Gatt profile object. + * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h). + */ +CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt); + +/** * create GattCharacteristic and call CALEClientWriteCharacteristicImpl * for request to write gatt characteristic. * @param[in] env JNI interface pointer. * @param[in] gatt Gatt profile object. * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h). */ -CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt); +CAResult_t CALESetValueAndWriteCharacteristic(JNIEnv *env, jobject gatt); /** * request to write gatt characteristic. diff --git a/resource/csdk/connectivity/src/bt_le_adapter/android/calenwmonitor.c b/resource/csdk/connectivity/src/bt_le_adapter/android/calenwmonitor.c index 8b3c24f..1b9f836 100644 --- a/resource/csdk/connectivity/src/bt_le_adapter/android/calenwmonitor.c +++ b/resource/csdk/connectivity/src/bt_le_adapter/android/calenwmonitor.c @@ -237,22 +237,12 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeStateChangedCallback(JNIEnv *env, j CALEClientCreateDeviceList(); CALEServerCreateCachedDeviceList(); - CAResult_t res = CALEClientStartScan(); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - } - - res = CALEStartAdvertise(); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEStartAdvertise has failed"); - } - gCALEDeviceStateChangedCallback(newStatus); } else if (BT_STATE_OFF == status) // STATE_OFF:10 { + CALEClientStopMulticastServer(); + // remove obj for client CAResult_t res = CALEClientRemoveAllGattObjs(env); if (CA_STATUS_OK != res) diff --git a/resource/csdk/connectivity/src/bt_le_adapter/android/caleserver.c b/resource/csdk/connectivity/src/bt_le_adapter/android/caleserver.c index ff7a309..5a04a02 100644 --- a/resource/csdk/connectivity/src/bt_le_adapter/android/caleserver.c +++ b/resource/csdk/connectivity/src/bt_le_adapter/android/caleserver.c @@ -37,6 +37,8 @@ #define TAG PCF("OIC_CA_LE_SERVER") +#define WAIT_TIME_WRITE_CHARACTERISTIC 10000000 + static JavaVM *g_jvm = NULL; static jobject g_context = NULL; static jobject g_bluetoothGattServer = NULL; @@ -51,11 +53,18 @@ static u_arraylist_t *g_connectedDeviceList = NULL; static bool g_isStartServer = false; static bool g_isInitializedServer = false; +static jbyteArray g_sendBuffer = NULL; + static CABLEDataReceivedCallback g_CABLEServerDataReceivedCallback = NULL; static ca_mutex g_bleReqRespCbMutex = NULL; static ca_mutex g_bleClientBDAddressMutex = NULL; static ca_mutex g_connectedDeviceListMutex = NULL; +static ca_mutex g_threadSendMutex = NULL; +static ca_mutex g_threadSendNotifyMutex = NULL; +static ca_cond g_threadSendNotifyCond = NULL; +static bool g_isSignalSetFlag = false; + void CALEServerJNISetContext() { OIC_LOG(DEBUG, TAG, "CALEServerJNISetContext"); @@ -254,7 +263,7 @@ jobject CALEServerSetResponseData(JNIEnv *env, jbyteArray responseData) CAResult_t CALEServerSendResponseData(JNIEnv *env, jobject device, jobject responseData) { - OIC_LOG(DEBUG, TAG, "IN - CALEServerSendResponseData"); + OIC_LOG(DEBUG, TAG, "CALEServerSendResponseData"); VERIFY_NON_NULL(responseData, TAG, "responseData is null"); VERIFY_NON_NULL(device, TAG, "device is null"); VERIFY_NON_NULL(env, TAG, "env is null"); @@ -292,7 +301,23 @@ CAResult_t CALEServerSendResponseData(JNIEnv *env, jobject device, jobject respo return CA_SEND_FAILED; } - OIC_LOG(DEBUG, TAG, "OUT - CALEServerSendResponseData"); + OIC_LOG_V(DEBUG, TAG, "callback flag is %d", g_isSignalSetFlag); + ca_mutex_lock(g_threadSendNotifyMutex); + if (!g_isSignalSetFlag) + { + OIC_LOG(DEBUG, TAG, "wait for callback to notify notifyCharacteristic is success"); + if (0 != ca_cond_wait_for(g_threadSendNotifyCond, g_threadSendNotifyMutex, + WAIT_TIME_WRITE_CHARACTERISTIC)) + { + OIC_LOG(ERROR, TAG, "there is no response. notifyCharacteristic has failed"); + ca_mutex_unlock(g_threadSendNotifyMutex); + return CA_STATUS_FAILED; + } + } + // reset flag set by writeCharacteristic Callback + g_isSignalSetFlag = false; + ca_mutex_unlock(g_threadSendNotifyMutex); + OIC_LOG(INFO, TAG, "notifyCharacteristic success"); return CA_STATUS_OK; } @@ -1427,6 +1452,8 @@ CAResult_t CALEServerInitialize() return ret; } + g_threadSendNotifyCond = ca_cond_new(); + ret = CALEServerInitMutexVaraibles(); if (CA_STATUS_OK != ret) { @@ -1468,11 +1495,47 @@ void CALEServerTerminate() { OIC_LOG(DEBUG, TAG, "IN - CALEServerTerminate"); + if (!g_jvm) + { + OIC_LOG(ERROR, TAG, "g_jvm is null"); + return; + } + + bool isAttached = false; + JNIEnv* env; + jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); + if (JNI_OK != res) + { + OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); + res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); + + if (JNI_OK != res) + { + OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed"); + return; + } + isAttached = true; + } + + if (g_sendBuffer) + { + (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } + + ca_cond_free(g_threadSendNotifyCond); + g_threadSendNotifyCond = NULL; + CALEServerTerminateMutexVaraibles(); CALEServerTerminateConditionVaraibles(); g_isInitializedServer = false; + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + OIC_LOG(DEBUG, TAG, "OUT - CALEServerTerminate"); } @@ -1693,6 +1756,8 @@ CAResult_t CALEServerSendUnicastMessageImpl(JNIEnv *env, const char* address, co return CA_STATUS_FAILED; } + ca_mutex_lock(g_threadSendMutex); + jobject jni_obj_bluetoothDevice = NULL; uint32_t length = u_arraylist_length(g_connectedDeviceList); for (uint32_t index = 0; index < length; index++) @@ -1702,20 +1767,20 @@ CAResult_t CALEServerSendUnicastMessageImpl(JNIEnv *env, const char* address, co if (!jarrayObj) { OIC_LOG(ERROR, TAG, "jarrayObj is null"); - return CA_STATUS_FAILED; + goto error_exit; } jstring jni_setAddress = CALEGetAddressFromBTDevice(env, jarrayObj); if (!jni_setAddress) { OIC_LOG(ERROR, TAG, "jni_setAddress is null"); - return CA_STATUS_FAILED; + goto error_exit; } const char* setAddress = (*env)->GetStringUTFChars(env, jni_setAddress, NULL); if (!setAddress) { OIC_LOG(ERROR, TAG, "setAddress is null"); - return CA_STATUS_FAILED; + goto error_exit; } OIC_LOG_V(DEBUG, TAG, "setAddress : %s", setAddress); @@ -1733,23 +1798,42 @@ CAResult_t CALEServerSendUnicastMessageImpl(JNIEnv *env, const char* address, co if (jni_obj_bluetoothDevice) { - jbyteArray jni_bytearr_data = (*env)->NewByteArray(env, dataLen); - (*env)->SetByteArrayRegion(env, jni_bytearr_data, 0, dataLen, (jbyte*) data); + jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen); + (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data); + g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr); - CAResult_t res = CALEServerSend(env, jni_obj_bluetoothDevice, jni_bytearr_data); + CAResult_t res = CALEServerSend(env, jni_obj_bluetoothDevice, g_sendBuffer); if (CA_STATUS_OK != res) { OIC_LOG(ERROR, TAG, "send has failed"); - return CA_SEND_FAILED; + goto error_exit; } } else { OIC_LOG(ERROR, TAG, "There are no device to send in the list"); - return CA_STATUS_FAILED; + goto error_exit; } + if (g_sendBuffer) + { + (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } + + ca_mutex_unlock(g_threadSendMutex); + OIC_LOG(INFO, TAG, "unicast - send request is successful"); return CA_STATUS_OK; + +error_exit: + if (g_sendBuffer) + { + (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } + + ca_mutex_unlock(g_threadSendMutex); + return CA_SEND_FAILED; } CAResult_t CALEServerSendMulticastMessageImpl(JNIEnv *env, const uint8_t *data, uint32_t dataLen) @@ -1764,6 +1848,18 @@ CAResult_t CALEServerSendMulticastMessageImpl(JNIEnv *env, const uint8_t *data, return CA_STATUS_FAILED; } + ca_mutex_lock(g_threadSendMutex); + + OIC_LOG(DEBUG, TAG, "set data into g_sendBuffer for notify"); + if (g_sendBuffer) + { + (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } + jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen); + (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data); + g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr); + uint32_t length = u_arraylist_length(g_connectedDeviceList); for (uint32_t index = 0; index < length; index++) { @@ -1771,20 +1867,46 @@ CAResult_t CALEServerSendMulticastMessageImpl(JNIEnv *env, const uint8_t *data, if (!jarrayObj) { OIC_LOG(ERROR, TAG, "jarrayObj is null"); - return CA_STATUS_FAILED; + continue; } // send data for all device jbyteArray jni_bytearr_data = (*env)->NewByteArray(env, dataLen); (*env)->SetByteArrayRegion(env, jni_bytearr_data, 0, dataLen, (jbyte*) data); + + jstring jni_address = CALEGetAddressFromBTDevice(env, jarrayObj); + if (!jni_address) + { + OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); + continue; + } + + const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + continue; + } + CAResult_t res = CALEServerSend(env, jarrayObj, jni_bytearr_data); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "send has failed"); - return CA_SEND_FAILED; + OIC_LOG_V(ERROR, TAG, "send has failed for the device[%s]", address); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + continue; } + + OIC_LOG_V(INFO, TAG, "unicast - send request is successful for a device[%s]", address); + (*env)->ReleaseStringUTFChars(env, jni_address, address); } + if (g_sendBuffer) + { + (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } + + ca_mutex_unlock(g_threadSendMutex); return CA_STATUS_OK; } @@ -2206,8 +2328,36 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerNotificationSentCallback( VERIFY_NON_NULL_VOID(obj, TAG, "obj"); VERIFY_NON_NULL_VOID(device, TAG, "device"); - OIC_LOG_V(DEBUG, TAG, "Gatt Server Notification Sent Callback(%d)", + OIC_LOG_V(DEBUG, TAG, "Gatt Server Notification Sent Callback (status : %d)", status); + + if (GATT_SUCCESS != status) // error case + { + OIC_LOG(ERROR, TAG, "it will be sent again."); + + CAResult_t res = CALEServerSend(env, device, g_sendBuffer); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "send has failed"); + ca_mutex_lock(g_threadSendNotifyMutex); + g_isSignalSetFlag = true; + ca_cond_signal(g_threadSendNotifyCond); + ca_mutex_unlock(g_threadSendNotifyMutex); + return CA_SEND_FAILED; + } + } + else + { + OIC_LOG(DEBUG, TAG, "notify success"); + + // next data can be sent + ca_mutex_lock(g_threadSendNotifyMutex); + OIC_LOG(DEBUG, TAG, "g_isSignalSetFlag is set true and signal"); + g_isSignalSetFlag = true; + ca_cond_signal(g_threadSendNotifyCond); + ca_mutex_unlock(g_threadSendNotifyMutex); + } + } JNIEXPORT void JNICALL @@ -2314,6 +2464,10 @@ CAResult_t CAStopLEGattServer() (*env)->DeleteGlobalRef(env, g_bluetoothGattServerCallback); } + ca_mutex_lock(g_threadSendNotifyMutex); + ca_cond_signal(g_threadSendNotifyCond); + ca_mutex_unlock(g_threadSendNotifyMutex); + g_isStartServer = false; if (isAttached) @@ -2411,6 +2565,26 @@ CAResult_t CALEServerInitMutexVaraibles() } } + if (NULL == g_threadSendMutex) + { + g_threadSendMutex = ca_mutex_new(); + if (NULL == g_threadSendMutex) + { + OIC_LOG(ERROR, TAG, "ca_mutex_new has failed"); + return CA_STATUS_FAILED; + } + } + + if (NULL == g_threadSendNotifyMutex) + { + g_threadSendNotifyMutex = ca_mutex_new(); + if (NULL == g_threadSendNotifyMutex) + { + OIC_LOG(ERROR, TAG, "ca_mutex_new has failed"); + return CA_STATUS_FAILED; + } + } + return CA_STATUS_OK; } @@ -2424,6 +2598,12 @@ void CALEServerTerminateMutexVaraibles() ca_mutex_free(g_connectedDeviceListMutex); g_connectedDeviceListMutex = NULL; + + ca_mutex_free(g_threadSendMutex); + g_threadSendMutex = NULL; + + ca_mutex_free(g_threadSendNotifyMutex); + g_threadSendNotifyMutex = NULL; } void CALEServerTerminateConditionVaraibles() -- 2.7.4