X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fconnectivity%2Fsrc%2Fbt_le_adapter%2Fandroid%2Fcaleclient.c;h=8e7502fc9499fde1e32b630517575bbd13115ed4;hb=8fef6cff439e45dc7216fd0c963afea716ad8bdb;hp=38ae49a52ef4bb9a406354f7ee56c36d5dae5c3d;hpb=9d5949060f992881916284e39ccb44437aa44fc1;p=platform%2Fupstream%2Fiotivity.git 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 38ae49a..8e7502f 100644 --- a/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c +++ b/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c @@ -37,12 +37,12 @@ #include "uarraylist.h" #include "org_iotivity_ca_CaLeClientInterface.h" -#define TAG PCF("CA_LE_CLIENT") +#define TAG PCF("OIC_CA_LE_CLIENT") -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"; +#define MICROSECS_PER_SEC 1000000 +#define WAIT_TIME_WRITE_CHARACTERISTIC 10 * MICROSECS_PER_SEC + +static ca_thread_pool_t g_threadPoolHandle = NULL; JavaVM *g_jvm; static u_arraylist_t *g_deviceList = NULL; // device list to have same UUID @@ -51,7 +51,6 @@ static u_arraylist_t *g_deviceStateList = NULL; static CAPacketReceiveCallback g_packetReceiveCallback = NULL; static CABLEErrorHandleCallback g_clientErrorCallback; -static ca_thread_pool_t g_threadPoolHandle = NULL; static jobject g_leScanCallback = NULL; static jobject g_leGattCallback = NULL; static jobject g_context = NULL; @@ -69,8 +68,12 @@ static bool g_isFinishedSendData = false; static ca_mutex g_SendFinishMutex = NULL; static ca_mutex g_threadMutex = NULL; 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; @@ -79,8 +82,12 @@ static ca_mutex g_deviceListMutex = NULL; static ca_mutex g_gattObjectMutex = NULL; static ca_mutex g_deviceStateListMutex = NULL; +static ca_mutex g_scanMutex = NULL; + static CABLEDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL; +static jboolean g_autoConnectFlag = JNI_FALSE; + //getting jvm void CALEClientJniInit() { @@ -161,7 +168,7 @@ error_exit: return CA_STATUS_FAILED; } -CAResult_t CALEClientInitialize(ca_thread_pool_t handle) +CAResult_t CALEClientInitialize() { OIC_LOG(DEBUG, TAG, "CALEClientInitialize"); @@ -202,8 +209,6 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) return ret; } - g_threadPoolHandle = handle; - ret = CALEClientInitGattMutexVaraibles(); if (CA_STATUS_OK != ret) { @@ -218,8 +223,11 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) return ret; } + g_deviceDescCond = ca_cond_new(); + // init mutex for send logic g_threadCond = ca_cond_new(); + g_threadWriteCharacteristicCond = ca_cond_new(); CALEClientCreateDeviceList(); CALEClientJNISetContext(); @@ -251,6 +259,11 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) } g_isStartedLEClient = true; + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + return CA_STATUS_OK; } @@ -319,12 +332,21 @@ void CALEClientTerminate() } g_isStartedMulticastServer = false; - g_isStartedScan = false; + CALEClientSetScanFlag(false); CALEClientSetSendFinishFlag(false); CALEClientTerminateGattMutexVariables(); + CALEClientDestroyJniInterface(); + 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; + CALEClientSetAutoConnectFlag(JNI_FALSE); if (isAttached) { @@ -332,6 +354,77 @@ void CALEClientTerminate() } } +CAResult_t CALEClientDestroyJniInterface() +{ + OIC_LOG(DEBUG, TAG, "CALEClientDestroyJniInterface"); + + if (!g_jvm) + { + OIC_LOG(ERROR, TAG, "g_jvm is null"); + return CA_STATUS_FAILED; + } + + 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 CA_STATUS_FAILED; + } + isAttached = true; + } + + jclass jni_LeInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface"); + if (!jni_LeInterface) + { + OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface class"); + goto error_exit; + } + + jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_LeInterface, + "destroyLeInterface", + "()V"); + if (!jni_InterfaceDestroyMethod) + { + OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface destroy method"); + goto error_exit; + } + + (*env)->CallStaticVoidMethod(env, jni_LeInterface, jni_InterfaceDestroyMethod); + + if ((*env)->ExceptionCheck(env)) + { + OIC_LOG(ERROR, TAG, "destroyLeInterface has failed"); + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + goto error_exit; + } + + OIC_LOG(DEBUG, TAG, "Destroy instance for CaLeClientInterface"); + + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + + return CA_STATUS_OK; + +error_exit: + + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + + return CA_STATUS_FAILED; +} + void CALEClientSendFinish(JNIEnv *env, jobject gatt) { OIC_LOG(DEBUG, TAG, "CALEClientSendFinish"); @@ -482,6 +575,47 @@ void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback) g_clientErrorCallback = callback; } +CAResult_t CALEClientIsThereScannedDevices() +{ + if (!g_deviceList) + { + return CA_STATUS_FAILED; + } + + if (0 == u_arraylist_length(g_deviceList)) + { + // Wait for LE peripherals to be discovered. + + // Number of times to wait for discovery to complete. + static size_t const RETRIES = 5; + + static uint64_t const TIMEOUT = + 2 * MICROSECS_PER_SEC; // Microseconds + + bool devicesDiscovered = false; + for (size_t i = 0; + 0 == u_arraylist_length(g_deviceList) && i < RETRIES; + ++i) + { + if (ca_cond_wait_for(g_deviceDescCond, + g_threadSendMutex, + TIMEOUT) == CA_WAIT_SUCCESS) + { + devicesDiscovered = true; + break; + } + } + + // time out for scanning devices + if (!devicesDiscovered) + { + return CA_STATUS_FAILED; + } + } + + return CA_STATUS_OK; +} + CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* data, const uint32_t dataLen) { @@ -513,7 +647,15 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* ca_mutex_lock(g_threadSendMutex); - CAResult_t ret = CA_STATUS_OK; + CALEClientSetSendFinishFlag(false); + + CAResult_t ret = CALEClientIsThereScannedDevices(); + if (CA_STATUS_OK != ret) + { + OIC_LOG(INFO, TAG, "there is no scanned device"); + goto error_exit; + } + if (g_context && g_deviceList) { uint32_t length = u_arraylist_length(g_deviceList); @@ -557,11 +699,15 @@ 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); g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr); + // Target device to send message is just one. + g_targetCnt = 1; + ret = CALEClientSendData(env, jarrayObj); if (CA_STATUS_OK != ret) { @@ -576,16 +722,22 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* } } - if (isAttached) + OIC_LOG(DEBUG, TAG, "connection routine is finished for unicast"); + + // wait for finish to send data through "CALeGattServicesDiscoveredCallback" + // if there is no connection state. + ca_mutex_lock(g_threadMutex); + if (!g_isFinishedSendData) { - (*g_jvm)->DetachCurrentThread(g_jvm); + OIC_LOG(DEBUG, TAG, "waiting send finish signal"); + ca_cond_wait(g_threadCond, g_threadMutex); + OIC_LOG(DEBUG, TAG, "the data was sent"); } + ca_mutex_unlock(g_threadMutex); - ret = CALECheckSendState(address); - if(CA_STATUS_OK != ret) + if (isAttached) { - OIC_LOG(ERROR, TAG, "send has failed"); - goto error_exit; + (*g_jvm)->DetachCurrentThread(g_jvm); } // start LE Scan again @@ -598,8 +750,8 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* } ca_mutex_unlock(g_threadSendMutex); - OIC_LOG(INFO, TAG, "unicast - send success"); - return CA_STATUS_OK; + OIC_LOG(INFO, TAG, "unicast - send logic has finished"); + return CALECheckSendState(address); // error label. error_exit: @@ -610,6 +762,10 @@ error_exit: { OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); ca_mutex_unlock(g_threadSendMutex); + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } return res; } @@ -617,6 +773,11 @@ error_exit: { (*g_jvm)->DetachCurrentThread(g_jvm); } + + if (g_clientErrorCallback) + { + g_clientErrorCallback(address, data, dataLen, CA_SEND_FAILED); + } ca_mutex_unlock(g_threadSendMutex); return CA_SEND_FAILED; } @@ -642,26 +803,30 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data, if (g_sendBuffer) { (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } + + CAResult_t res = CALEClientIsThereScannedDevices(); + if (CA_STATUS_OK != res) + { + OIC_LOG(INFO, TAG, "there is no scanned device"); + goto error_exit; } - jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen); - (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data); - g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr); // connect to gatt server - CAResult_t res = CALEClientStopScan(); + res = CALEClientStopScan(); if (CA_STATUS_OK != res) { OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed"); ca_mutex_unlock(g_threadSendMutex); return res; } - uint32_t length = u_arraylist_length(g_deviceList); g_targetCnt = length; - if (0 == length) - { - goto error_exit; - } + + jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen); + (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data); + g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr); for (uint32_t index = 0; index < length; index++) { @@ -692,28 +857,20 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data, continue; } - res = CALECheckSendState(address); - if (CA_STATUS_OK != res) - { - OIC_LOG_V(INFO, TAG, "multicast : send has failed for this device[%s]", address); - g_clientErrorCallback(address, data, dataLen, res); - (*env)->ReleaseStringUTFChars(env, jni_address, address); - continue; - } - (*env)->ReleaseStringUTFChars(env, jni_address, address); } - OIC_LOG(DEBUG, TAG, "connection routine is finished"); + OIC_LOG(DEBUG, TAG, "connection routine is finished for multicast"); // wait for finish to send data through "CALeGattServicesDiscoveredCallback" + ca_mutex_lock(g_threadMutex); if (!g_isFinishedSendData) { - ca_mutex_lock(g_threadMutex); + OIC_LOG(DEBUG, TAG, "waiting send finish signal"); ca_cond_wait(g_threadCond, g_threadMutex); - OIC_LOG(DEBUG, TAG, "the data was sent for All devices"); - ca_mutex_unlock(g_threadMutex); + OIC_LOG(DEBUG, TAG, "the data was sent"); } + ca_mutex_unlock(g_threadMutex); // start LE Scan again res = CALEClientStartScan(); @@ -761,6 +918,8 @@ CAResult_t CALECheckSendState(const char* address) ca_mutex_unlock(g_deviceStateListMutex); return CA_SEND_FAILED; } + + OIC_LOG(INFO, TAG, "sendstate is STATE_SEND_SUCCESS"); ca_mutex_unlock(g_deviceStateListMutex); return CA_STATUS_OK; } @@ -771,32 +930,58 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device) VERIFY_NON_NULL(device, TAG, "device is null"); VERIFY_NON_NULL(env, TAG, "env is null"); - jstring jni_address = CALEGetAddressFromBTDevice(env, device); - if (!jni_address) + // get BLE address from bluetooth device object. + char* address = NULL; + CALEState_t* state = NULL; + jstring jni_address = CALEClientGetLEAddressFromBTDevice(env, device); + if (jni_address) { - OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); - return CA_STATUS_FAILED; - } - - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (!address) - { - OIC_LOG(ERROR, TAG, "address is not available"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "there is gatt object..it's not first connection"); + address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + return CA_STATUS_FAILED; + } + ca_mutex_lock(g_deviceStateListMutex); + state = CALEClientGetStateInfo(address); + ca_mutex_unlock(g_deviceStateListMutex); + (*env)->ReleaseStringUTFChars(env, jni_address, address); } - ca_mutex_lock(g_deviceStateListMutex); - CALEState_t* state = CALEClientGetStateInfo(address); - ca_mutex_unlock(g_deviceStateListMutex); if (!state) { OIC_LOG(DEBUG, TAG, "state is empty..start to connect LE"); - CAResult_t ret = CALEClientConnect(env, device, JNI_FALSE, g_leGattCallback); - if (CA_STATUS_OK != ret) + + // cancel previous connection request before connection + // if there is gatt object in g_gattObjectList. + if (jni_address) { - OIC_LOG(ERROR, TAG, "CALEClientConnect has failed"); + address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + return CA_STATUS_FAILED; + } + + jobject gatt = CALEClientGetGattObjInList(env, address); + if (gatt) + { + CAResult_t res = CALEClientDisconnect(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(INFO, TAG, "there is no gatt object"); + } + } (*env)->ReleaseStringUTFChars(env, jni_address, address); - return ret; + } + + // connection request + jobject newGatt = CALEClientConnect(env, device, CALEClientGetAutoConnectFlag()); + if (NULL == newGatt) + { + OIC_LOG(ERROR, TAG, "CALEClientConnect has failed"); + return CA_STATUS_FAILED; } } else @@ -804,6 +989,19 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device) if (STATE_CONNECTED == state->connectedState) { OIC_LOG(INFO, TAG, "GATT has already connected"); + if (!jni_address) + { + OIC_LOG(ERROR, TAG, "jni_address is not available"); + return CA_STATUS_FAILED; + } + + address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + return CA_STATUS_FAILED; + } + jobject gatt = CALEClientGetGattObjInList(env, address); if (!gatt) { @@ -812,28 +1010,52 @@ 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; } + (*env)->ReleaseStringUTFChars(env, jni_address, address); } else { + OIC_LOG(INFO, TAG, "STATE_DISCONNECTED - start to connect LE"); + + // cancel previous connection request before connection + // if there is gatt object in g_gattObjectList. + if (jni_address) + { + address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + return CA_STATUS_FAILED; + } + + jobject gatt = CALEClientGetGattObjInList(env, address); + if (gatt) + { + CAResult_t res = CALEClientDisconnect(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(INFO, TAG, "there is no gatt object"); + } + } + (*env)->ReleaseStringUTFChars(env, jni_address, address); + } + OIC_LOG(DEBUG, TAG, "start to connect LE"); - CAResult_t ret = CALEClientConnect(env, device, JNI_FALSE, g_leGattCallback); - if (CA_STATUS_OK != ret) + jobject gatt = CALEClientConnect(env, device, JNI_TRUE); + if (NULL == gatt) { OIC_LOG(ERROR, TAG, "CALEClientConnect has failed"); - (*env)->ReleaseStringUTFChars(env, jni_address, address); - return ret; + return CA_STATUS_FAILED; } } } - (*env)->ReleaseStringUTFChars(env, jni_address, address); return CA_STATUS_OK; } @@ -965,17 +1187,20 @@ CAResult_t CALEClientStartScan() { #ifdef UUID_SCAN ret = CALEClientStartScanWithUUIDImpl(env, g_uuidList, g_leScanCallback); - if(CA_STATUS_OK != ret) - { - OIC_LOG(ERROR, TAG, "CALEClientStartScanWithUUIDImpl has failed"); - } #else ret = CALEClientStartScanImpl(env, g_leScanCallback); +#endif if (CA_STATUS_OK != ret) { - OIC_LOG(ERROR, TAG, "CALEClientStartScanImpl has failed"); + if (CA_ADAPTER_NOT_ENABLED == ret) + { + OIC_LOG(DEBUG, TAG, "Adapter is disabled"); + } + else + { + OIC_LOG(ERROR, TAG, "start scan has failed"); + } } -#endif } if (isAttached) @@ -993,7 +1218,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback) if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1045,7 +1270,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback) else { OIC_LOG(DEBUG, TAG, "startLeScan is started"); - g_isStartedScan = true; + CALEClientSetScanFlag(true); } return CA_STATUS_OK; @@ -1059,7 +1284,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1110,7 +1335,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj else { OIC_LOG(DEBUG, TAG, "startLeScan With UUID is started"); - g_isStartedScan = true; + CALEClientSetScanFlag(true); } return CA_STATUS_OK; @@ -1182,11 +1407,18 @@ CAResult_t CALEClientStopScan() CAResult_t ret = CALEClientStopScanImpl(env, g_leScanCallback); if (CA_STATUS_OK != ret) { - OIC_LOG(ERROR, TAG, "CALEClientStopScanImpl has failed"); + if (CA_ADAPTER_NOT_ENABLED == ret) + { + OIC_LOG(DEBUG, TAG, "Adapter is disabled"); + } + else + { + OIC_LOG(ERROR, TAG, "CALEClientStopScanImpl has failed"); + } } else { - g_isStartedScan = false; + CALEClientSetScanFlag(false); } if (isAttached) @@ -1197,6 +1429,13 @@ CAResult_t CALEClientStopScan() return ret; } +void CALEClientSetScanFlag(bool flag) +{ + ca_mutex_lock(g_scanMutex); + g_isStartedScan = flag; + ca_mutex_unlock(g_scanMutex); +} + CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback) { OIC_LOG(DEBUG, TAG, "CALEClientStopScanImpl"); @@ -1205,7 +1444,7 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback) if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1260,25 +1499,94 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback) return CA_STATUS_OK; } -CAResult_t CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect, - jobject callback) +void CALEClientSetAutoConnectFlag(jboolean flag) +{ + OIC_LOG_V(INFO, TAG, "auto connect flag is set %d", flag); + g_autoConnectFlag = flag; +} + +jboolean CALEClientGetAutoConnectFlag() +{ + OIC_LOG_V(INFO, TAG, "auto connect flag is %d", g_autoConnectFlag); + return g_autoConnectFlag; +} + +jobject CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect) +{ + OIC_LOG(DEBUG, TAG, "CALEClientConnect"); + VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); + VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice is null", NULL); + + // get gatt object from Bluetooth Device object for closeProfileProxy(..) + jstring jni_address = CALEClientGetLEAddressFromBTDevice(env, bluetoothDevice); + if (jni_address) + { + const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + return NULL; + } + + // close the gatt service + jobject gatt = CALEClientGetGattObjInList(env, address); + if (gatt) + { + CAResult_t res = CALEClientCloseProfileProxy(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientCloseProfileProxy has failed"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + return NULL; + } + + // clean previous gatt object after close profile service + res = CALEClientRemoveGattObjForAddr(env, jni_address); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientRemoveGattObjForAddr has failed"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + return NULL; + } + } + (*env)->ReleaseStringUTFChars(env, jni_address, address); + } + + jobject newGatt = CALEClientGattConnect(env, bluetoothDevice, autoconnect); + if (!newGatt) + { + OIC_LOG(DEBUG, TAG, "re-connection will be started"); + return NULL; + } + + // add new gatt object into g_gattObjectList + CAResult_t res = CALEClientAddGattobjToList(env, newGatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientAddGattobjToList has failed"); + return NULL; + } + + return newGatt; +} + +jobject CALEClientGattConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect) { OIC_LOG(DEBUG, TAG, "GATT CONNECT"); - VERIFY_NON_NULL(env, TAG, "env is null"); - VERIFY_NON_NULL(bluetoothDevice, TAG, "bluetoothDevice is null"); - VERIFY_NON_NULL(callback, TAG, "callback is null"); + VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); + VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice is null", NULL); if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_ADAPTER_NOT_ENABLED; + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); + return NULL; } jstring jni_address = CALEGetAddressFromBTDevice(env, bluetoothDevice); if (!jni_address) { OIC_LOG(ERROR, TAG, "bleConnect: CALEGetAddressFromBTDevice is null"); - return CA_STATUS_FAILED; + return NULL; } // get BluetoothDevice class @@ -1287,7 +1595,7 @@ CAResult_t CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean auto if (!jni_cid_BluetoothDevice) { OIC_LOG(ERROR, TAG, "bleConnect: jni_cid_BluetoothDevice is null"); - return CA_STATUS_FAILED; + return NULL; } // get connectGatt method @@ -1299,40 +1607,111 @@ CAResult_t CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean auto if (!jni_mid_connectGatt) { OIC_LOG(ERROR, TAG, "bleConnect: jni_mid_connectGatt is null"); - return CA_STATUS_FAILED; + return NULL; } - OIC_LOG(DEBUG, TAG, "Call object method - connectGatt"); + OIC_LOG(INFO, TAG, "CALL API - connectGatt"); jobject jni_obj_connectGatt = (*env)->CallObjectMethod(env, bluetoothDevice, jni_mid_connectGatt, NULL, - autoconnect, callback); + autoconnect, g_leGattCallback); if (!jni_obj_connectGatt) { - OIC_LOG(ERROR, TAG, "CALL API - connectGatt was failed..it will be removed"); + OIC_LOG(ERROR, TAG, "connectGatt was failed..it will be removed"); CALEClientRemoveDeviceInScanDeviceList(env, jni_address); CALEClientUpdateSendCnt(env); - return CA_STATUS_FAILED; + return NULL; } else { OIC_LOG(DEBUG, TAG, "le connecting..please wait.."); } + return jni_obj_connectGatt; +} + +CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt) +{ + OIC_LOG(DEBUG, TAG, "IN - CALEClientCloseProfileProxy"); + + VERIFY_NON_NULL(env, TAG, "env is null"); + VERIFY_NON_NULL(gatt, TAG, "gatt is null"); + + jclass jni_cid_BTAdapter = (*env)->FindClass(env, CLASSPATH_BT_ADAPTER); + if (!jni_cid_BTAdapter) + { + OIC_LOG(ERROR, TAG, "jni_cid_BTAdapter is null"); + return CA_STATUS_FAILED; + } + + // get remote bt adapter method + jmethodID jni_mid_getDefaultAdapter = (*env)->GetStaticMethodID(env, jni_cid_BTAdapter, + "getDefaultAdapter", + METHODID_OBJECTNONPARAM); + if (!jni_mid_getDefaultAdapter) + { + OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null"); + return CA_STATUS_FAILED; + } + + // gat bt adapter object + jobject jni_obj_BTAdapter = (*env)->CallStaticObjectMethod(env, jni_cid_BTAdapter, + jni_mid_getDefaultAdapter); + if (!jni_obj_BTAdapter) + { + OIC_LOG(ERROR, TAG, "jni_obj_BTAdapter is null"); + return CA_STATUS_FAILED; + } + + // get closeProfileProxy method + jmethodID jni_mid_closeProfileProxy = (*env)->GetMethodID(env, jni_cid_BTAdapter, + "closeProfileProxy", + "(ILandroid/bluetooth/" + "BluetoothProfile;)V"); + if (!jni_mid_closeProfileProxy) + { + OIC_LOG(ERROR, TAG, "jni_mid_closeProfileProxy is null"); + return CA_STATUS_FAILED; + } + + jclass jni_cid_BTProfile = (*env)->FindClass(env, CLASSPATH_BT_PROFILE); + if (!jni_cid_BTProfile) + { + OIC_LOG(ERROR, TAG, "jni_cid_BTProfile is null"); + return CA_STATUS_FAILED; + } + + // GATT - Constant value : 7 (0x00000007) + jfieldID id_gatt = (*env)->GetStaticFieldID(env, jni_cid_BTProfile, + "GATT", "I"); + if (!id_gatt) + { + OIC_LOG(ERROR, TAG, "id_gatt is null"); + return CA_STATUS_FAILED; + } + + jint jni_gatt = (*env)->GetStaticIntField(env, jni_cid_BTProfile, id_gatt); + + OIC_LOG(DEBUG, TAG, "CALL API - close the connection of the profile proxy to the Service"); + (*env)->CallVoidMethod(env, jni_obj_BTAdapter, jni_mid_closeProfileProxy, jni_gatt, gatt); + if ((*env)->ExceptionCheck(env)) + { + OIC_LOG(ERROR, TAG, "closeProfileProxy has failed"); + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + return CA_STATUS_FAILED; + } + + OIC_LOG(DEBUG, TAG, "OUT - CALEClientCloseProfileProxy"); return CA_STATUS_OK; } + CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt) { OIC_LOG(DEBUG, TAG, "GATT DISCONNECT"); VERIFY_NON_NULL(env, TAG, "env is null"); VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null"); - if (!CALEIsEnableBTAdapter(env)) - { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_ADAPTER_NOT_ENABLED; - } - // get BluetoothGatt class jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); if (!jni_cid_BluetoothGatt) @@ -1351,6 +1730,7 @@ CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt) } // call disconnect gatt method + OIC_LOG(DEBUG, TAG, "CALL API - request disconnect gatt"); (*env)->CallVoidMethod(env, bluetoothGatt, jni_mid_disconnectGatt); if ((*env)->ExceptionCheck(env)) { @@ -1372,13 +1752,15 @@ CAResult_t CALEClientDisconnectAll(JNIEnv *env) if (!g_gattObjectList) { - OIC_LOG(ERROR, TAG, "g_gattObjectList is null"); - return CA_STATUS_FAILED; + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); + return CA_STATUS_OK; } uint32_t length = u_arraylist_length(g_gattObjectList); + OIC_LOG_V(DEBUG, TAG, "list length : %d", length); for (uint32_t index = 0; index < length; index++) { + OIC_LOG(DEBUG, TAG, "start CALEClientDisconnectAll"); jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index); if (!jarrayObj) { @@ -1393,9 +1775,73 @@ CAResult_t CALEClientDisconnectAll(JNIEnv *env) } } - OICFree(g_gattObjectList); - g_gattObjectList = NULL; + return CA_STATUS_OK; +} + +CAResult_t CALEClientDisconnectforAddress(JNIEnv *env, jstring remote_address) +{ + OIC_LOG(DEBUG, TAG, "IN-CALEClientDisconnectforAddress"); + VERIFY_NON_NULL(env, TAG, "env is null"); + + if (!g_gattObjectList) + { + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); + return CA_STATUS_OK; + } + + char* address = (char*)(*env)->GetStringUTFChars(env, remote_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is null"); + return CA_STATUS_FAILED; + } + + uint32_t length = u_arraylist_length(g_gattObjectList); + for (uint32_t index = 0; index < length; index++) + { + jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index); + if (!jarrayObj) + { + OIC_LOG(ERROR, TAG, "jarrayObj is null"); + continue; + } + + jstring jni_setAddress = CALEClientGetAddressFromGattObj(env, jarrayObj); + if (!jni_setAddress) + { + OIC_LOG(ERROR, TAG, "jni_setAddress is null"); + (*env)->ReleaseStringUTFChars(env, remote_address, address); + return CA_STATUS_FAILED; + } + + const char* setAddress = (*env)->GetStringUTFChars(env, jni_setAddress, NULL); + if (!setAddress) + { + OIC_LOG(ERROR, TAG, "setAddress is null"); + (*env)->ReleaseStringUTFChars(env, remote_address, address); + return CA_STATUS_FAILED; + } + OIC_LOG_V(DEBUG, TAG, "target address : %s, set address : %s", address, setAddress); + if (!strcmp(address, setAddress)) + { + CAResult_t res = CALEClientDisconnect(env, jarrayObj); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); + (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + (*env)->ReleaseStringUTFChars(env, remote_address, address); + return CA_STATUS_FAILED; + } + (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + (*env)->ReleaseStringUTFChars(env, remote_address, address); + return CA_STATUS_OK; + } + (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + } + (*env)->ReleaseStringUTFChars(env, remote_address, address); + + OIC_LOG(DEBUG, TAG, "OUT-CALEClientDisconnectforAddress"); return CA_STATUS_OK; } @@ -1406,7 +1852,7 @@ CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt) if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1419,30 +1865,63 @@ CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt) return CA_STATUS_FAILED; } - OIC_LOG(DEBUG, TAG, "discovery gatt services method"); - jmethodID jni_mid_discoverServices = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "discoverServices", "()Z"); - if (!jni_mid_discoverServices) + OIC_LOG(DEBUG, TAG, "discovery gatt services method"); + jmethodID jni_mid_discoverServices = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, + "discoverServices", "()Z"); + if (!jni_mid_discoverServices) + { + OIC_LOG(ERROR, TAG, "jni_mid_discoverServices is null"); + return CA_STATUS_FAILED; + } + // call disconnect gatt method + OIC_LOG(DEBUG, TAG, "CALL API - request discovery gatt services"); + jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_discoverServices); + if (!ret) + { + OIC_LOG(ERROR, TAG, "discoverServices has not been started"); + return CA_STATUS_FAILED; + } + + return CA_STATUS_OK; +} + +static void CALEWriteCharacteristicThread(void* object) +{ + VERIFY_NON_NULL_VOID(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, "jni_mid_discoverServices is null"); - return CA_STATUS_FAILED; + OIC_LOG(ERROR, TAG, "CALESetValueAndWriteCharacteristic has failed"); } - // call disconnect gatt method - OIC_LOG(DEBUG, TAG, "CALL API - request discovery gatt services"); - jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_discoverServices); - if (!ret) + + if (isAttached) { - OIC_LOG(ERROR, TAG, "discoverServices has not been started"); - return CA_STATUS_FAILED; + (*g_jvm)->DetachCurrentThread(g_jvm); } - - return CA_STATUS_OK; } -CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt) +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); @@ -1456,14 +1935,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"); @@ -1472,7 +1990,7 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt, if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_STATUS_FAILED; } @@ -1503,7 +2021,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 { @@ -1521,7 +2039,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt) if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_STATUS_FAILED; } @@ -1583,7 +2101,7 @@ CAResult_t CALEClientSetCharacteristicNotification(JNIEnv *env, jobject bluetoot if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1630,7 +2148,7 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return NULL; } @@ -1723,7 +2241,7 @@ jobject CALEClientCreateGattCharacteristic(JNIEnv *env, jobject bluetoothGatt, j if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return NULL; } @@ -1802,7 +2320,7 @@ jbyteArray CALEClientGetValueFromCharacteristic(JNIEnv *env, jobject characteris if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return NULL; } @@ -1905,7 +2423,7 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt, if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1941,8 +2459,8 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt, jni_mid_getDescriptor, jni_obj_cc_uuid); if (!jni_obj_descriptor) { - OIC_LOG(ERROR, TAG, "jni_obj_descriptor is null"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "jni_obj_descriptor is null"); + return CA_NOT_SUPPORTED; } OIC_LOG(DEBUG, TAG, "set value in descriptor"); @@ -2035,7 +2553,6 @@ void CALEClientCreateScanDeviceList(JNIEnv *env) CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device) { - OIC_LOG(DEBUG, TAG, "IN - CALEClientAddScanDeviceToList"); VERIFY_NON_NULL(device, TAG, "device is null"); VERIFY_NON_NULL(env, TAG, "env is null"); @@ -2068,19 +2585,18 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device) { jobject gdevice = (*env)->NewGlobalRef(env, device); u_arraylist_add(g_deviceList, gdevice); - OIC_LOG(DEBUG, TAG, "Set Object to Array as Element"); + ca_cond_signal(g_deviceDescCond); + OIC_LOG_V(DEBUG, TAG, "Added this BT Device[%s] in the List", remoteAddress); } (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress); ca_mutex_unlock(g_deviceListMutex); - OIC_LOG(DEBUG, TAG, "OUT - CALEClientAddScanDeviceToList"); return CA_STATUS_OK; } bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress) { - OIC_LOG(DEBUG, TAG, "IN - CALEClientIsDeviceInScanDeviceList"); VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", true); @@ -2116,7 +2632,6 @@ bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress) if (!strcmp(remoteAddress, setAddress)) { - OIC_LOG(DEBUG, TAG, "the device is already set"); (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); return true; } @@ -2124,7 +2639,6 @@ bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress) (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); } - OIC_LOG(DEBUG, TAG, "OUT - CALEClientIsDeviceInScanDeviceList"); OIC_LOG(DEBUG, TAG, "there are no the device in list. we can add"); return false; @@ -2221,7 +2735,12 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address) (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, address, remoteAddress); - CALEClientReorderingList(index, g_deviceList); + if (NULL == u_arraylist_remove(g_deviceList, index)) + { + OIC_LOG(ERROR, TAG, "List removal failed."); + ca_mutex_unlock(g_deviceListMutex); + return CA_STATUS_FAILED; + } ca_mutex_unlock(g_deviceListMutex); return CA_STATUS_OK; } @@ -2241,12 +2760,19 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address) CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt) { - OIC_LOG(DEBUG, TAG, "CALEClientAddGattobjToList"); + OIC_LOG(INFO, TAG, "CALEClientAddGattobjToList"); VERIFY_NON_NULL(env, TAG, "env is null"); VERIFY_NON_NULL(gatt, TAG, "gatt is null"); ca_mutex_lock(g_gattObjectMutex); + if (!g_gattObjectList) + { + OIC_LOG(ERROR, TAG, "g_gattObjectList is not available"); + ca_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_FAILED; + } + jstring jni_remoteAddress = CALEClientGetAddressFromGattObj(env, gatt); if (!jni_remoteAddress) { @@ -2263,11 +2789,12 @@ CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt) return CA_STATUS_FAILED; } + OIC_LOG_V(INFO, TAG, "remote address : %s", remoteAddress); if (!CALEClientIsGattObjInList(env, remoteAddress)) { jobject newGatt = (*env)->NewGlobalRef(env, gatt); u_arraylist_add(g_gattObjectList, newGatt); - OIC_LOG(DEBUG, TAG, "Set GATT Object to Array as Element"); + OIC_LOG(INFO, TAG, "Set GATT Object to Array as Element"); } (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress); @@ -2380,9 +2907,9 @@ CAResult_t CALEClientRemoveAllGattObjs(JNIEnv *env) ca_mutex_lock(g_gattObjectMutex); if (!g_gattObjectList) { - OIC_LOG(ERROR, TAG, "g_gattObjectList is null"); + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); ca_mutex_unlock(g_gattObjectMutex); - return CA_STATUS_FAILED; + return CA_STATUS_OK; } uint32_t length = u_arraylist_length(g_gattObjectList); @@ -2399,6 +2926,7 @@ CAResult_t CALEClientRemoveAllGattObjs(JNIEnv *env) OICFree(g_gattObjectList); g_gattObjectList = NULL; + OIC_LOG(INFO, TAG, "g_gattObjectList is removed"); ca_mutex_unlock(g_gattObjectMutex); return CA_STATUS_OK; } @@ -2412,9 +2940,9 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt) ca_mutex_lock(g_gattObjectMutex); if (!g_gattObjectList) { - OIC_LOG(ERROR, TAG, "g_gattObjectList is null"); + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); ca_mutex_unlock(g_gattObjectMutex); - return CA_STATUS_FAILED; + return CA_STATUS_OK; } uint32_t length = u_arraylist_length(g_gattObjectList); @@ -2468,8 +2996,15 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt) (*env)->DeleteGlobalRef(env, jarrayObj); (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress); + + if (NULL == u_arraylist_remove(g_gattObjectList, index)) + { + OIC_LOG(ERROR, TAG, "List removal failed."); + ca_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_FAILED; + } ca_mutex_unlock(g_gattObjectMutex); - return CALEClientReorderingList(index, g_gattObjectList); + return CA_STATUS_OK; } (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress); @@ -2489,9 +3024,9 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr) ca_mutex_lock(g_gattObjectMutex); if (!g_gattObjectList) { - OIC_LOG(ERROR, TAG, "g_gattObjectList is null"); + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); ca_mutex_unlock(g_gattObjectMutex); - return CA_STATUS_FAILED; + return CA_STATUS_OK; } uint32_t length = u_arraylist_length(g_gattObjectList); @@ -2537,8 +3072,14 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr) (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, addr, remoteAddress); + if (NULL == u_arraylist_remove(g_gattObjectList, index)) + { + OIC_LOG(ERROR, TAG, "List removal failed."); + ca_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_FAILED; + } ca_mutex_unlock(g_gattObjectMutex); - return CALEClientReorderingList(index, g_gattObjectList); + return CA_STATUS_OK; } (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, addr, remoteAddress); @@ -2549,6 +3090,109 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr) return CA_STATUS_FAILED; } +jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice) +{ + OIC_LOG(DEBUG, TAG, "IN - CALEClientGetLEAddressFromBTDevice"); + + VERIFY_NON_NULL_RET(env, TAG, "env", NULL); + VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice", NULL); + + // get Bluetooth Address + jstring jni_btTargetAddress = CALEGetAddressFromBTDevice(env, bluetoothDevice); + if (!jni_btTargetAddress) + { + OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); + return NULL; + } + + const char* targetAddress = (*env)->GetStringUTFChars(env, jni_btTargetAddress, NULL); + if (!targetAddress) + { + OIC_LOG(ERROR, TAG, "targetAddress is not available"); + return NULL; + } + + // get method ID of getDevice() + jclass jni_cid_gattdevice_list = (*env)->FindClass(env, CLASSPATH_BT_GATT); + if (!jni_cid_gattdevice_list) + { + OIC_LOG(ERROR, TAG, "jni_cid_gattdevice_list is null"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; + } + + jmethodID jni_mid_getDevice = (*env)->GetMethodID(env, jni_cid_gattdevice_list, "getDevice", + METHODID_BT_DEVICE); + if (!jni_mid_getDevice) + { + OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; + } + + size_t length = u_arraylist_length(g_gattObjectList); + for (size_t index = 0; index < length; index++) + { + jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index); + if (!jarrayObj) + { + OIC_LOG(ERROR, TAG, "jarrayObj is null"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; + } + + OIC_LOG(DEBUG, TAG, "CALL API - bluetoothGatt.getDevice()"); + jobject jni_obj_device = (*env)->CallObjectMethod(env, jarrayObj, jni_mid_getDevice); + if (!jni_obj_device) + { + OIC_LOG(ERROR, TAG, "jni_obj_device is null"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; + } + + jstring jni_btAddress = CALEGetAddressFromBTDevice(env, jni_obj_device); + if (!jni_btAddress) + { + OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; + } + + const char* btAddress = (*env)->GetStringUTFChars(env, jni_btAddress, NULL); + if (!btAddress) + { + OIC_LOG(ERROR, TAG, "btAddress is not available"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; + } + + OIC_LOG_V(DEBUG, TAG, "targetAddress : %s", targetAddress); + OIC_LOG_V(DEBUG, TAG, "btAddress : %s", btAddress); + if (!strcmp(targetAddress, btAddress)) + { + OIC_LOG(DEBUG, TAG, "Found Gatt object from BT device"); + + // get LE address + jstring jni_LEAddress = CALEClientGetAddressFromGattObj(env, jarrayObj); + if (!jni_LEAddress) + { + OIC_LOG(ERROR, TAG, "jni_LEAddress is null"); + } + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + (*env)->ReleaseStringUTFChars(env, jni_btAddress, btAddress); + (*env)->DeleteLocalRef(env, jni_btAddress); + (*env)->DeleteLocalRef(env, jni_obj_device); + return jni_LEAddress; + } + (*env)->ReleaseStringUTFChars(env, jni_btAddress, btAddress); + (*env)->DeleteLocalRef(env, jni_btAddress); + (*env)->DeleteLocalRef(env, jni_obj_device); + } + + OIC_LOG(DEBUG, TAG, "OUT - CALEClientGetLEAddressFromBTDevice"); + return NULL; +} + /** * BT State List */ @@ -2617,8 +3261,8 @@ CAResult_t CALEClientAddDeviceStateToList(CALEState_t* state) } } u_arraylist_add(g_deviceStateList, state); // update new state - OIC_LOG_V(DEBUG, TAG, "Set State Info to List : %d, %d", - state->connectedState, state->notificationState); + OIC_LOG_V(INFO, TAG, "Set State Info to List : %d, %d, %s", + state->connectedState, state->notificationState, state->address); ca_mutex_unlock(g_deviceStateListMutex); return CA_STATUS_OK; @@ -2661,7 +3305,7 @@ bool CALEClientIsDeviceInList(const char* remoteAddress) CAResult_t CALEClientRemoveAllDeviceState() { - OIC_LOG(DEBUG, TAG, "CALENativeRemoveAllDevices"); + OIC_LOG(DEBUG, TAG, "CALEClientRemoveAllDeviceState"); ca_mutex_lock(g_deviceStateListMutex); if (!g_deviceStateList) @@ -2713,20 +3357,22 @@ CAResult_t CALEClientRemoveDeviceState(const char* remoteAddress) if (!strcmp(state->address, remoteAddress)) { - OIC_LOG_V(DEBUG, TAG, "remove state : %s", remoteAddress); - OICFree(state); + OIC_LOG_V(DEBUG, TAG, "remove state : %s", state->address); - CAResult_t res = CALEClientReorderingList(index, g_deviceStateList); - if(CA_STATUS_OK != res) + CALEState_t* targetState = (CALEState_t*)u_arraylist_remove(g_deviceStateList, + index); + if (NULL == targetState) { - OIC_LOG(ERROR, TAG, "CALEClientReorderingList has failed"); - return res; + OIC_LOG(ERROR, TAG, "List removal failed."); + return CA_STATUS_FAILED; } + + OICFree(targetState); return CA_STATUS_OK; } } - return CA_STATUS_FAILED; + return CA_STATUS_OK; } CALEState_t* CALEClientGetStateInfo(const char* remoteAddress) @@ -2741,6 +3387,8 @@ CALEState_t* CALEClientGetStateInfo(const char* remoteAddress) } uint32_t length = u_arraylist_length(g_deviceStateList); + OIC_LOG_V(DEBUG, TAG, "CALEClientGetStateInfo : %d", length); + for (uint32_t index = 0; index < length; index++) { CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index); @@ -2750,6 +3398,9 @@ CALEState_t* CALEClientGetStateInfo(const char* remoteAddress) continue; } + OIC_LOG_V(DEBUG, TAG, "target address : %s", remoteAddress); + OIC_LOG_V(DEBUG, TAG, "state address : %s", state->address); + if (!strcmp(state->address, remoteAddress)) { OIC_LOG_V(DEBUG, TAG, "get state : %s", remoteAddress); @@ -2873,37 +3524,13 @@ void CALEClientCreateDeviceList() } } -CAResult_t CALEClientReorderingList(uint32_t index, u_arraylist_t *list) -{ - if (!list) - { - OIC_LOG(ERROR, TAG, "list is null"); - return CA_STATUS_FAILED; - } - - if (index >= list->length) - { - OIC_LOG(ERROR, TAG, "index is not available"); - return CA_STATUS_FAILED; - } - - if (index < list->length - 1) - { - memmove(&list->data[index], &list->data[index + 1], - (list->length - index - 1) * sizeof(void *)); - } - - list->size--; - list->length--; - - return CA_STATUS_OK; -} - /** * Check Sent Count for remove g_sendBuffer */ void CALEClientUpdateSendCnt(JNIEnv *env) { + OIC_LOG(DEBUG, TAG, "CALEClientUpdateSendCnt"); + VERIFY_NON_NULL_VOID(env, TAG, "env is null"); // mutex lock ca_mutex_lock(g_threadMutex); @@ -2922,6 +3549,7 @@ void CALEClientUpdateSendCnt(JNIEnv *env) } // notity the thread ca_cond_signal(g_threadCond); + CALEClientSetSendFinishFlag(true); OIC_LOG(DEBUG, TAG, "set signal for send data"); } @@ -2931,8 +3559,6 @@ void CALEClientUpdateSendCnt(JNIEnv *env) CAResult_t CALEClientInitGattMutexVaraibles() { - OIC_LOG(DEBUG, TAG, "IN"); - if (NULL == g_bleReqRespClientCbMutex) { g_bleReqRespClientCbMutex = ca_mutex_new(); @@ -3013,14 +3639,31 @@ CAResult_t CALEClientInitGattMutexVaraibles() } } - OIC_LOG(DEBUG, TAG, "OUT"); + if (NULL == g_scanMutex) + { + g_scanMutex = ca_mutex_new(); + if (NULL == g_scanMutex) + { + OIC_LOG(ERROR, TAG, "ca_mutex_new has failed"); + return CA_STATUS_FAILED; + } + } + + 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; } void CALEClientTerminateGattMutexVariables() { - OIC_LOG(DEBUG, TAG, "IN"); - ca_mutex_free(g_bleReqRespClientCbMutex); g_bleReqRespClientCbMutex = NULL; @@ -3039,7 +3682,11 @@ void CALEClientTerminateGattMutexVariables() ca_mutex_free(g_SendFinishMutex); g_SendFinishMutex = NULL; - OIC_LOG(DEBUG, TAG, "OUT"); + ca_mutex_free(g_scanMutex); + g_scanMutex = NULL; + + ca_mutex_free(g_threadWriteCharacteristicMutex); + g_threadWriteCharacteristicMutex = NULL; } void CALEClientSetSendFinishFlag(bool flag) @@ -3108,7 +3755,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) { @@ -3117,9 +3770,17 @@ void CAStopLEGattClient() } +CAResult_t CAInitializeLEGattClient() +{ + OIC_LOG(DEBUG, TAG, "Initialize GATT Client"); + CALEClientInitialize(); + return CA_STATUS_OK; +} + void CATerminateLEGattClient() { OIC_LOG(DEBUG, TAG, "Terminate GATT Client"); + CAStopLEGattClient(); CALEClientTerminate(); } @@ -3150,22 +3811,14 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback) { - OIC_LOG(DEBUG, TAG, "IN"); - ca_mutex_lock(g_bleReqRespClientCbMutex); g_CABLEClientDataReceivedCallback = callback; ca_mutex_unlock(g_bleReqRespClientCbMutex); - - OIC_LOG(DEBUG, TAG, "OUT"); } void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle) { - OIC_LOG(DEBUG, TAG, "IN"); - - CALEClientInitialize(handle); - - OIC_LOG(DEBUG, TAG, "OUT"); + g_threadPoolHandle = handle; } CAResult_t CAGetLEAddress(char **local_address) @@ -3232,7 +3885,11 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); - if (GATT_SUCCESS == status && STATE_CONNECTED == newstate) // le connected + jint state_connected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_CONNECTED"); + jint state_disconnected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_DISCONNECTED"); + jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS"); + + if (gatt_success == status && state_connected == newstate) // le connected { jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); if (!jni_address) @@ -3252,6 +3909,8 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J (*env)->ReleaseStringUTFChars(env, jni_address, address); goto error_exit; } + OIC_LOG_V(INFO, TAG, "ConnectionStateCB - remote address : %s", address); + (*env)->ReleaseStringUTFChars(env, jni_address, address); } @@ -3269,30 +3928,48 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J goto error_exit; } } - else if (GATT_SUCCESS == status && STATE_DISCONNECTED == newstate) // le disconnected + else if (GATT_ERROR == status && state_disconnected == newstate) + { + OIC_LOG(INFO, TAG, "Background connection running.. please wait"); + } + else // le disconnected { CAResult_t res = CALEClientStartScan(); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); + if (CA_ADAPTER_NOT_ENABLED == res) + { + // scan will be started with start server when adapter is enabled + OIC_LOG(INFO, TAG, "Adapter was disabled"); + } + else + { + OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); + goto error_exit; + } } jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); if (!jni_address) { OIC_LOG(ERROR, TAG, "CALEClientGetAddressFromGattObj has failed"); + goto error_exit; } const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); if (address) { - res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED, - STATE_CHARACTER_NO_CHANGE, - STATE_SEND_NONE); + CAResult_t res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED, + STATE_CHARACTER_UNSET, + STATE_SEND_NONE); if (CA_STATUS_OK != res) { OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + goto error_exit; } + OIC_LOG_V(INFO, TAG, "ConnectionStateCB - remote address : %s", address); + (*env)->ReleaseStringUTFChars(env, jni_address, address); } @@ -3301,38 +3978,12 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J { OIC_LOG(ERROR, TAG, "CALEClientGattClose has failed"); } - } - else // error - { - // update state - jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); - if (!jni_address) - { - OIC_LOG(ERROR, TAG, "jni_address is null"); - goto error_exit; - - } - - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (address) - { - CAResult_t res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED, - STATE_CHARACTER_NO_CHANGE, - STATE_SEND_FAILED); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); - } - } - (*env)->ReleaseStringUTFChars(env, jni_address, address); - CAResult_t res = CALEClientGattClose(env, gatt); - if (CA_STATUS_OK != res) + if (g_sendBuffer) { - OIC_LOG(ERROR, TAG, "CALEClientGattClose has failed"); + (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; } - - goto error_exit; } return; @@ -3406,12 +4057,15 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIE res = CALEClientSetUUIDToDescriptor(env, gatt, jni_obj_GattCharacteristic); if (CA_STATUS_OK != res) { - OIC_LOG(INFO, TAG, "Descriptor of the uuid is not found"); - CAResult_t res = CALEClientWriteCharacteristic(env, gatt); - if (CA_STATUS_OK != res) + OIC_LOG_V(INFO, TAG, "Descriptor is not found : %d", 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; + } } } @@ -3432,11 +4086,13 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIE goto error_exit; } } + OIC_LOG(INFO, TAG, "ServicesDiscovery is successful"); (*env)->ReleaseStringUTFChars(env, jni_address, address); return; // error label. error_exit: + OIC_LOG(ERROR, TAG, "ServicesDiscovery has failed"); (*env)->ReleaseStringUTFChars(env, jni_address, address); CALEClientSendFinish(env, gatt); return; @@ -3475,16 +4131,38 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback( goto error_exit; } - if (GATT_SUCCESS != status) // error case + jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS"); + 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); + + 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"); + } + + if (g_clientErrorCallback) + { + jint length = (*env)->GetArrayLength(env, data); + g_clientErrorCallback(address, data, length, CA_SEND_FAILED); + } + + CALEClientSendFinish(env, gatt); + goto error_exit; } - CALEClientSendFinish(env, gatt); } else { @@ -3495,6 +4173,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); } @@ -3585,12 +4270,21 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattDescriptorWriteCallback(JNIEnv VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); - CAResult_t res = CALEClientWriteCharacteristic(env, gatt); - if (CA_STATUS_OK != res) + jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS"); + if (gatt_success != status) // error { - OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed"); goto error_exit; } + + if (g_sendBuffer) + { + CAResult_t res = CALEClientWriteCharacteristic(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed"); + goto error_exit; + } + } return; // error label.