X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=resource%2Fcsdk%2Fconnectivity%2Fsrc%2Fbt_le_adapter%2Fandroid%2Fcaleclient.c;h=dd953de6604487cb7e123223aa3ebaf407e147a1;hb=390866079e285d2c74918432c0d597d5da52f8a0;hp=06c1c05e9c3d358f32d228c98b809c981555902e;hpb=935fdb9b67b6c10d007e652e9e2e028fd6ccfe09;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 06c1c05..dd953de 100644 --- a/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c +++ b/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c @@ -31,17 +31,28 @@ #include "logger.h" #include "oic_malloc.h" +#include "oic_string.h" #include "cathreadpool.h" /* for thread pool */ #include "camutex.h" #include "uarraylist.h" -#include "org_iotivity_jar_caleclientinterface.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 + +#define GATT_CONNECTION_PRIORITY_BALANCED 0 +#define GATT_FAILURE 257 +#define GATT_INSUFFICIENT_AUTHENTICATION 5 +#define GATT_INSUFFICIENT_ENCRYPTION 15 +#define GATT_INVALID_ATTRIBUTE_LENGTH 13 +#define GATT_INVALID_OFFSET 7 +#define GATT_READ_NOT_PERMITTED 2 +#define GATT_REQUEST_NOT_SUPPORTED 6 +#define GATT_WRITE_NOT_PERMITTED 3 + +static ca_thread_pool_t g_threadPoolHandle = NULL; JavaVM *g_jvm; static u_arraylist_t *g_deviceList = NULL; // device list to have same UUID @@ -49,7 +60,7 @@ static u_arraylist_t *g_gattObjectList = NULL; static u_arraylist_t *g_deviceStateList = NULL; static CAPacketReceiveCallback g_packetReceiveCallback = NULL; -static ca_thread_pool_t g_threadPoolHandle = NULL; +static CABLEErrorHandleCallback g_clientErrorCallback; static jobject g_leScanCallback = NULL; static jobject g_leGattCallback = NULL; static jobject g_context = NULL; @@ -57,26 +68,21 @@ static jobjectArray g_uuidList = NULL; // it will be prevent to start send logic when adapter has stopped. static bool g_isStartedLEClient = false; -static bool g_isStartedMulticastServer = false; static bool g_isStartedScan = false; static jbyteArray g_sendBuffer = NULL; static uint32_t g_targetCnt = 0; static uint32_t g_currentSentCnt = 0; static bool g_isFinishedSendData = false; -static ca_mutex g_SendFinishMutex = false; +static ca_mutex g_SendFinishMutex = NULL; static ca_mutex g_threadMutex = NULL; static ca_cond g_threadCond = NULL; - -static bool g_isRequestedSend = false; -static bool g_isReceivedWriteCB = false; -static ca_mutex g_writeCharacteristicCBMutex = false; -static ca_mutex g_theSendRequestMutex = false; -static ca_mutex g_threadSendCBMutex = NULL; -static ca_cond g_threadSendCBCond = NULL; +static ca_cond g_deviceDescCond = NULL; static ca_mutex g_threadSendMutex = NULL; -static ca_cond g_threadSendCond = 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; @@ -85,7 +91,38 @@ static ca_mutex g_deviceListMutex = NULL; static ca_mutex g_gattObjectMutex = NULL; static ca_mutex g_deviceStateListMutex = NULL; -static CABLEClientDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL; +static ca_mutex g_deviceScanRetryDelayMutex = NULL; +static ca_cond g_deviceScanRetryDelayCond = NULL; + +static ca_mutex g_scanMutex = NULL; + +static CABLEDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL; + +/** + * check if retry logic for connection routine has to be stopped or not. + * in case of error value including this method, connection routine has to be stopped. + * since there is no retry logic for this error reason in this client. + * @param state constant value of bluetoothgatt. + * @return true - waiting for background connection in BT platform. + * false - connection routine has to be stopped. + */ +static bool CALECheckConnectionStateValue(jint state) +{ + switch(state) + { + case GATT_CONNECTION_PRIORITY_BALANCED: + case GATT_FAILURE: + case GATT_INSUFFICIENT_AUTHENTICATION: + case GATT_INSUFFICIENT_ENCRYPTION: + case GATT_INVALID_ATTRIBUTE_LENGTH: + case GATT_INVALID_OFFSET: + case GATT_READ_NOT_PERMITTED: + case GATT_REQUEST_NOT_SUPPORTED: + case GATT_WRITE_NOT_PERMITTED: + return true; + } + return false; +} //getting jvm void CALEClientJniInit() @@ -132,10 +169,10 @@ CAResult_t CALECreateJniInterfaceObject() isAttached = true; } - jclass jni_LEInterface = (*env)->FindClass(env, "org/iotivity/jar/caleclientinterface"); + jclass jni_LEInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface"); if (!jni_LEInterface) { - OIC_LOG(ERROR, TAG, "Could not get caleclientinterface class"); + OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface class"); goto error_exit; } @@ -143,12 +180,12 @@ CAResult_t CALECreateJniInterfaceObject() "(Landroid/content/Context;)V"); if (!LeInterfaceConstructorMethod) { - OIC_LOG(ERROR, TAG, "Could not get caleclientinterface constructor method"); + OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface constructor method"); goto error_exit; } (*env)->NewObject(env, jni_LEInterface, LeInterfaceConstructorMethod, g_context); - OIC_LOG(DEBUG, TAG, "Create instance for caleclientinterface"); + OIC_LOG(DEBUG, TAG, "Create instance for CaLeClientInterface"); if (isAttached) { @@ -167,7 +204,7 @@ error_exit: return CA_STATUS_FAILED; } -CAResult_t CALEClientInitialize(ca_thread_pool_t handle) +CAResult_t CALEClientInitialize() { OIC_LOG(DEBUG, TAG, "CALEClientInitialize"); @@ -208,8 +245,6 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) return ret; } - g_threadPoolHandle = handle; - ret = CALEClientInitGattMutexVaraibles(); if (CA_STATUS_OK != ret) { @@ -224,10 +259,12 @@ 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_threadSendCond = ca_cond_new(); - g_threadSendCBCond = ca_cond_new(); + g_threadWriteCharacteristicCond = ca_cond_new(); + g_deviceScanRetryDelayCond = ca_cond_new(); CALEClientCreateDeviceList(); CALEClientJNISetContext(); @@ -259,6 +296,11 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) } g_isStartedLEClient = true; + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + return CA_STATUS_OK; } @@ -291,21 +333,25 @@ void CALEClientTerminate() if (g_leScanCallback) { (*env)->DeleteGlobalRef(env, g_leScanCallback); + g_leScanCallback = NULL; } if (g_leGattCallback) { (*env)->DeleteGlobalRef(env, g_leGattCallback); + g_leGattCallback = NULL; } if (g_sendBuffer) { (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; } if (g_uuidList) { (*env)->DeleteGlobalRef(env, g_uuidList); + g_uuidList = NULL; } CAResult_t ret = CALEClientRemoveAllDeviceState(); @@ -326,54 +372,33 @@ void CALEClientTerminate() OIC_LOG(ERROR, TAG, "CALEClientRemoveAllGattObjs has failed"); } - g_isStartedMulticastServer = false; - g_isStartedScan = false; - CALEClientSetSendFinishFlag(false); - CALEClientSetTheSendRequestFlag(false); - CALEClientSetWriteCharacteristicCBFlag(false); + CALEClientSetScanFlag(false); + CALEClientSetSendFinishFlag(true); CALEClientTerminateGattMutexVariables(); + CALEClientDestroyJniInterface(); + ca_cond_free(g_deviceDescCond); ca_cond_free(g_threadCond); - ca_cond_free(g_threadSendCond); - ca_cond_free(g_threadSendCBCond); + ca_cond_free(g_threadWriteCharacteristicCond); + ca_cond_free(g_deviceScanRetryDelayCond); - if (isAttached) - { - (*g_jvm)->DetachCurrentThread(g_jvm); - } -} + g_deviceDescCond = NULL; + g_threadCond = NULL; + g_threadWriteCharacteristicCond = NULL; + g_deviceScanRetryDelayCond = NULL; -void CALEClientSendFinish(JNIEnv *env, jobject gatt) -{ - OIC_LOG(DEBUG, TAG, "CALEClientSendFinish"); - VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + g_isSignalSetFlag = false; - if (gatt) + if (isAttached) { - CAResult_t res = CALEClientDisconnect(env, gatt); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); - } + (*g_jvm)->DetachCurrentThread(g_jvm); } - CALEClientUpdateSendCnt(env); -} - -CAResult_t CALEClientSendUnicastMessage(const char* address, const char* data, - const uint32_t dataLen) -{ - OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessage(%s, %s)", address, data); - VERIFY_NON_NULL(address, TAG, "address is null"); - VERIFY_NON_NULL(data, TAG, "data is null"); - - return CALEClientSendUnicastMessageImpl(address, data, dataLen); } -CAResult_t CALEClientSendMulticastMessage(const char* data, const uint32_t dataLen) +CAResult_t CALEClientDestroyJniInterface() { - OIC_LOG_V(DEBUG, TAG, "CALEClientSendMulticastMessage(%s)", data); - VERIFY_NON_NULL(data, TAG, "data is null"); + OIC_LOG(DEBUG, TAG, "CALEClientDestroyJniInterface"); if (!g_jvm) { @@ -397,36 +422,83 @@ CAResult_t CALEClientSendMulticastMessage(const char* data, const uint32_t dataL isAttached = true; } - CAResult_t ret = CALEClientSendMulticastMessageImpl(env, data, dataLen); - if (CA_STATUS_OK != ret) + jclass jni_LeInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface"); + if (!jni_LeInterface) { - OIC_LOG(ERROR, TAG, "CALEClientSendMulticastMessageImpl has failed"); + 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 ret; -} + return CA_STATUS_OK; -CAResult_t CALEClientStartUnicastServer(const char* address) -{ - OIC_LOG_V(DEBUG, TAG, "it is not needed in this platform (%s)", address); +error_exit: - return CA_NOT_SUPPORTED; + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + + return CA_STATUS_FAILED; } -CAResult_t CALEClientStartMulticastServer() +void CALEClientSendFinish(JNIEnv *env, jobject gatt) { - OIC_LOG(DEBUG, TAG, "CALEClientStartMulticastServer"); + OIC_LOG(DEBUG, TAG, "CALEClientSendFinish"); + VERIFY_NON_NULL_VOID(env, TAG, "env is null"); - if (g_isStartedMulticastServer) + if (gatt) { - OIC_LOG(ERROR, TAG, "server is already started..it will be skipped"); - return CA_STATUS_FAILED; + CAResult_t res = CALEClientDisconnect(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); + } } + CALEClientUpdateSendCnt(env); +} + +CAResult_t CALEClientSendUnicastMessage(const char* address, + const uint8_t* data, + const uint32_t dataLen) +{ + OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessage(%s, %p)", address, data); + VERIFY_NON_NULL(address, TAG, "address is null"); + VERIFY_NON_NULL(data, TAG, "data is null"); + + return CALEClientSendUnicastMessageImpl(address, data, dataLen); +} + +CAResult_t CALEClientSendMulticastMessage(const uint8_t* data, + const uint32_t dataLen) +{ + OIC_LOG_V(DEBUG, TAG, "CALEClientSendMulticastMessage(%p)", data); + VERIFY_NON_NULL(data, TAG, "data is null"); if (!g_jvm) { @@ -450,11 +522,10 @@ CAResult_t CALEClientStartMulticastServer() isAttached = true; } - g_isStartedMulticastServer = true; - CAResult_t ret = CALEClientStartScan(); + CAResult_t ret = CALEClientSendMulticastMessageImpl(env, data, dataLen); if (CA_STATUS_OK != ret) { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); + OIC_LOG(ERROR, TAG, "CALEClientSendMulticastMessageImpl has failed"); } if (isAttached) @@ -465,6 +536,20 @@ CAResult_t CALEClientStartMulticastServer() return ret; } +CAResult_t CALEClientStartUnicastServer(const char* address) +{ + OIC_LOG_V(DEBUG, TAG, "it is not needed in this platform (%s)", address); + + return CA_NOT_SUPPORTED; +} + +CAResult_t CALEClientStartMulticastServer() +{ + OIC_LOG(DEBUG, TAG, "it is not needed in this platform"); + + return CA_NOT_SUPPORTED; +} + void CALEClientStopUnicastServer() { OIC_LOG(DEBUG, TAG, "CALEClientStopUnicastServer"); @@ -473,13 +558,6 @@ void CALEClientStopUnicastServer() void CALEClientStopMulticastServer() { OIC_LOG(DEBUG, TAG, "CALEClientStopMulticastServer"); - g_isStartedMulticastServer = false; - CAResult_t res = CALEClientStopScan(); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - return; - } } void CALEClientSetCallback(CAPacketReceiveCallback callback) @@ -487,16 +565,96 @@ void CALEClientSetCallback(CAPacketReceiveCallback callback) g_packetReceiveCallback = callback; } -CAResult_t CALEClientGetInterfaceInfo(char **address) +void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback) { - OIC_LOG(INFO, TAG, "CALEClientGetInterfaceInfo is not supported"); - return CA_NOT_SUPPORTED; + g_clientErrorCallback = callback; +} + +CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address) +{ + VERIFY_NON_NULL(env, TAG, "env"); + + if (!g_deviceList) + { + return CA_STATUS_FAILED; + } + + if (0 == u_arraylist_length(g_deviceList) // multicast + || (address && !CALEClientIsDeviceInScanDeviceList(env, address))) // unicast + { + // 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; i < RETRIES; ++i) + { + OIC_LOG(DEBUG, TAG, "waiting for target device"); + if (ca_cond_wait_for(g_deviceDescCond, + g_threadSendMutex, + TIMEOUT) == CA_WAIT_SUCCESS) + { + ca_mutex_lock(g_deviceListMutex); + size_t scannedDeviceLen = u_arraylist_length(g_deviceList); + ca_mutex_unlock(g_deviceListMutex); + + if (0 < scannedDeviceLen) + { + if (!address // multicast + || (address && CALEClientIsDeviceInScanDeviceList(env, address))) // unicast + { + devicesDiscovered = true; + break; + } + else + { + if (address) + { + OIC_LOG(INFO, TAG, "waiting.."); + + ca_mutex_lock(g_deviceScanRetryDelayMutex); + if (ca_cond_wait_for(g_deviceScanRetryDelayCond, + g_deviceScanRetryDelayMutex, + MICROSECS_PER_SEC) == CA_WAIT_SUCCESS) + { + OIC_LOG(INFO, TAG, "finish to waiting for target device"); + ca_mutex_unlock(g_deviceScanRetryDelayMutex); + break; + } + ca_mutex_unlock(g_deviceScanRetryDelayMutex); + // time out + + // checking whether a target device is found while waiting for time-out. + if (CALEClientIsDeviceInScanDeviceList(env, address)) + { + 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 char* data, + +CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* data, const uint32_t dataLen) { - OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessageImpl, address: %s, data: %s", address, + OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessageImpl, address: %s, data: %p", address, data); VERIFY_NON_NULL(address, TAG, "address is null"); VERIFY_NON_NULL(data, TAG, "data is null"); @@ -524,7 +682,15 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat ca_mutex_lock(g_threadSendMutex); - CAResult_t ret = CA_STATUS_OK; + CALEClientSetSendFinishFlag(false); + + CAResult_t ret = CALEClientIsThereScannedDevices(env, address); + 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); @@ -568,32 +734,21 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat 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) { OIC_LOG(ERROR, TAG, "CALEClientSendData in unicast is failed"); goto error_exit; } - else - { - CALEClientSetTheSendRequestFlag(true); - ca_cond_signal(g_threadSendCBCond); - - if (!g_isReceivedWriteCB) - { - OIC_LOG(INFO, TAG, "wait..(unicast)"); - ca_cond_wait(g_threadSendCond, g_threadSendMutex); - } - else - { - CALEClientSetWriteCharacteristicCBFlag(false); - } - } OIC_LOG(INFO, TAG, "wake up"); break; @@ -602,16 +757,22 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat } } - 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 @@ -624,8 +785,8 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat } 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: @@ -636,6 +797,10 @@ error_exit: { OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); ca_mutex_unlock(g_threadSendMutex); + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } return res; } @@ -643,14 +808,19 @@ 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; } -CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const char* data, +CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data, const uint32_t dataLen) { - OIC_LOG_V(DEBUG, TAG, "CASendMulticastMessageImpl, send to, data: %s, %d", data, dataLen); + OIC_LOG_V(DEBUG, TAG, "CASendMulticastMessageImpl, send to, data: %p, %u", data, dataLen); VERIFY_NON_NULL(data, TAG, "data is null"); VERIFY_NON_NULL(env, TAG, "env is null"); @@ -668,95 +838,74 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const char* data, if (g_sendBuffer) { (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } + + CAResult_t res = CALEClientIsThereScannedDevices(env, NULL); + 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; - } - uint32_t index = 0; - while (index < length) + 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++) { jobject jarrayObj = (jobject) u_arraylist_get(g_deviceList, index); if (!jarrayObj) { - OIC_LOG(ERROR, TAG, "jarrayObj is null"); + OIC_LOG(ERROR, TAG, "jarrayObj is not available"); continue; } res = CALEClientSendData(env, jarrayObj); if (res != CA_STATUS_OK) { - OIC_LOG(ERROR, TAG, "BT device[%d] - send has failed"); - } - else - { - CALEClientSetTheSendRequestFlag(true); - ca_cond_signal(g_threadSendCBCond); - - if (!g_isReceivedWriteCB) - { - OIC_LOG(INFO, TAG, "wait..(multicast)"); - ca_cond_wait(g_threadSendCond, g_threadSendMutex); - } - else - { - CALEClientSetWriteCharacteristicCBFlag(false); - } + OIC_LOG(ERROR, TAG, "BT device - send has failed"); } jstring jni_address = CALEGetAddressFromBTDevice(env, jarrayObj); if (!jni_address) { OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); - goto error_exit; + continue; } const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); if (!address) { OIC_LOG(ERROR, TAG, "address is not available"); - goto error_exit; - } - - res = CALECheckSendState(address); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "send has failed"); - (*env)->ReleaseStringUTFChars(env, jni_address, address); - goto error_exit; + continue; } (*env)->ReleaseStringUTFChars(env, jni_address, address); - - index++; } - 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(); @@ -804,6 +953,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; } @@ -814,32 +965,59 @@ 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) - { - OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); - return CA_STATUS_FAILED; - } - - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (!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, "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, + JNI_FALSE); + if (NULL == newGatt) + { + OIC_LOG(ERROR, TAG, "CALEClientConnect has failed"); + return CA_STATUS_FAILED; } } else @@ -847,6 +1025,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) { @@ -855,28 +1046,53 @@ 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, + CALEClientGetAutoConnectFlag(env, jni_address)); + 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; } @@ -885,15 +1101,8 @@ jstring CALEClientGetAddressFromGattObj(JNIEnv *env, jobject gatt) VERIFY_NON_NULL_RET(gatt, TAG, "gatt is null", NULL); VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); - 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"); - return NULL; - } - - jmethodID jni_mid_getDevice = (*env)->GetMethodID(env, jni_cid_gattdevice_list, "getDevice", - "()Landroid/bluetooth/BluetoothDevice;"); + jmethodID jni_mid_getDevice = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, "getDevice", + "()Landroid/bluetooth/BluetoothDevice;"); if (!jni_mid_getDevice) { OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null"); @@ -927,16 +1136,9 @@ CAResult_t CALEClientGattClose(JNIEnv *env, jobject bluetoothGatt) VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null"); VERIFY_NON_NULL(env, TAG, "env is null"); - // get BluetoothGatt class - OIC_LOG(DEBUG, TAG, "get BluetoothGatt class"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); - return CA_STATUS_FAILED; - } - - jmethodID jni_mid_closeGatt = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, "close", "()V"); + // get BluetoothGatt method + OIC_LOG(DEBUG, TAG, "get BluetoothGatt method"); + jmethodID jni_mid_closeGatt = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, "close", "()V"); if (!jni_mid_closeGatt) { OIC_LOG(ERROR, TAG, "jni_mid_closeGatt is null"); @@ -960,12 +1162,6 @@ CAResult_t CALEClientGattClose(JNIEnv *env, jobject bluetoothGatt) CAResult_t CALEClientStartScan() { - if (!g_isStartedMulticastServer) - { - OIC_LOG(ERROR, TAG, "server is not started yet..scan will be passed"); - return CA_STATUS_FAILED; - } - if (!g_isStartedLEClient) { OIC_LOG(ERROR, TAG, "LE client is not started"); @@ -1006,19 +1202,22 @@ CAResult_t CALEClientStartScan() // scan gatt server with UUID if (g_leScanCallback && g_uuidList) { -#ifndef FULL_SCAN +#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) @@ -1036,7 +1235,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; } @@ -1082,13 +1281,12 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback) jni_mid_startLeScan, callback); if (!jni_obj_startLeScan) { - OIC_LOG(ERROR, TAG, "startLeScan is failed"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "startLeScan is failed"); } else { OIC_LOG(DEBUG, TAG, "startLeScan is started"); - g_isStartedScan = true; + CALEClientSetScanFlag(true); } return CA_STATUS_OK; @@ -1102,7 +1300,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; } @@ -1147,13 +1345,12 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj jni_mid_startLeScan, uuids, callback); if (!jni_obj_startLeScan) { - OIC_LOG(ERROR, TAG, "startLeScan With UUID is failed"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "startLeScan With UUID is failed"); } else { OIC_LOG(DEBUG, TAG, "startLeScan With UUID is started"); - g_isStartedScan = true; + CALEClientSetScanFlag(true); } return CA_STATUS_OK; @@ -1225,11 +1422,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) @@ -1240,6 +1444,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"); @@ -1248,7 +1459,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; } @@ -1303,89 +1514,276 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback) return CA_STATUS_OK; } -CAResult_t CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect, - jobject callback) +CAResult_t CALEClientSetAutoConnectFlag(JNIEnv *env, jstring jni_address, jboolean flag) +{ + OIC_LOG(DEBUG, TAG, "IN - CALEClientSetAutoConnectFlag"); + VERIFY_NON_NULL(env, TAG, "env"); + VERIFY_NON_NULL(jni_address, TAG, "jni_address"); + + ca_mutex_lock(g_deviceStateListMutex); + + char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + return CA_STATUS_FAILED; + } + + if (CALEClientIsDeviceInList(address)) + { + CALEState_t* curState = CALEClientGetStateInfo(address); + if(!curState) + { + OIC_LOG(ERROR, TAG, "curState is null"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + ca_mutex_unlock(g_deviceStateListMutex); + return CA_STATUS_FAILED; + } + OIC_LOG_V(INFO, TAG, "auto connect flag is set %d", flag); + + curState->autoConnectFlag = flag; + } + + (*env)->ReleaseStringUTFChars(env, jni_address, address); + ca_mutex_unlock(g_deviceStateListMutex); + OIC_LOG(DEBUG, TAG, "OUT - CALEClientSetAutoConnectFlag"); + return CA_STATUS_OK; +} + +jboolean CALEClientGetAutoConnectFlag(JNIEnv *env, jstring jni_address) +{ + OIC_LOG(DEBUG, TAG, "IN - CALEClientGetAutoConnectFlag"); + VERIFY_NON_NULL_RET(env, TAG, "env", false); + VERIFY_NON_NULL_RET(jni_address, TAG, "jni_address", false); + + ca_mutex_lock(g_deviceStateListMutex); + + char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + return JNI_FALSE; + } + + CALEState_t* curState = CALEClientGetStateInfo(address); + if(!curState) + { + OIC_LOG(INFO, TAG, "there is no information. auto connect flag is false"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + ca_mutex_unlock(g_deviceStateListMutex); + return JNI_FALSE; + } + OIC_LOG_V(INFO, TAG, "auto connect flag is %d", curState->autoConnectFlag); + + (*env)->ReleaseStringUTFChars(env, jni_address, address); + ca_mutex_unlock(g_deviceStateListMutex); + + OIC_LOG(DEBUG, TAG, "OUT - CALEClientGetAutoConnectFlag"); + return curState->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 (!g_leGattCallback) + { + OIC_LOG(INFO, TAG, "g_leGattCallback is null"); + return 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; - } - - // get BluetoothDevice class - OIC_LOG(DEBUG, TAG, "get BluetoothDevice class"); - jclass jni_cid_BluetoothDevice = (*env)->FindClass(env, "android/bluetooth/BluetoothDevice"); - if (!jni_cid_BluetoothDevice) - { - OIC_LOG(ERROR, TAG, "bleConnect: jni_cid_BluetoothDevice is null"); - return CA_STATUS_FAILED; + return NULL; } - // get connectGatt method - OIC_LOG(DEBUG, TAG, "get connectGatt method"); - jmethodID jni_mid_connectGatt = (*env)->GetMethodID(env, jni_cid_BluetoothDevice, "connectGatt", - "(Landroid/content/Context;ZLandroid/" - "bluetooth/BluetoothGattCallback;)" - "Landroid/bluetooth/BluetoothGatt;"); + // get BluetoothDevice method + OIC_LOG(DEBUG, TAG, "get BluetoothDevice method"); + jmethodID jni_mid_connectGatt = CALEGetJNIMethodID(env, "android/bluetooth/BluetoothDevice", + "connectGatt", + "(Landroid/content/Context;ZLandroid/" + "bluetooth/BluetoothGattCallback;)" + "Landroid/bluetooth/BluetoothGatt;"); 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 CA_STATUS_OK; + return jni_obj_connectGatt; } -CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt) +CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt) { - OIC_LOG(DEBUG, TAG, "GATT DISCONNECT"); + OIC_LOG(DEBUG, TAG, "IN - CALEClientCloseProfileProxy"); + VERIFY_NON_NULL(env, TAG, "env is null"); - VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null"); + VERIFY_NON_NULL(gatt, TAG, "gatt is null"); - if (!CALEIsEnableBTAdapter(env)) + jclass jni_cid_BTAdapter = (*env)->FindClass(env, CLASSPATH_BT_ADAPTER); + if (!jni_cid_BTAdapter) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_ADAPTER_NOT_ENABLED; + OIC_LOG(ERROR, TAG, "jni_cid_BTAdapter is null"); + return CA_STATUS_FAILED; } - // get BluetoothGatt class - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) + // 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, "jni_cid_BluetoothGatt is null"); + 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"); + + // get BluetoothGatt method OIC_LOG(DEBUG, TAG, "get gatt disconnect method"); - jmethodID jni_mid_disconnectGatt = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, + jmethodID jni_mid_disconnectGatt = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, "disconnect", "()V"); if (!jni_mid_disconnectGatt) { @@ -1394,6 +1792,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)) { @@ -1403,19 +1802,59 @@ CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt) return CA_STATUS_FAILED; } - OIC_LOG(DEBUG, TAG, "disconnecting Gatt..."); - + OIC_LOG(DEBUG, TAG, "disconnecting Gatt..."); + + return CA_STATUS_OK; +} + +CAResult_t CALEClientDisconnectAll(JNIEnv *env) +{ + OIC_LOG(DEBUG, TAG, "CALEClientDisconnectAll"); + VERIFY_NON_NULL(env, TAG, "env is null"); + + if (!g_gattObjectList) + { + 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) + { + OIC_LOG(ERROR, TAG, "jarrayObj is null"); + continue; + } + CAResult_t res = CALEClientDisconnect(env, jarrayObj); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); + continue; + } + } + return CA_STATUS_OK; } -CAResult_t CALEClientDisconnectAll(JNIEnv *env) +CAResult_t CALEClientDisconnectforAddress(JNIEnv *env, jstring remote_address) { - OIC_LOG(DEBUG, TAG, "CALEClientDisconnectAll"); + OIC_LOG(DEBUG, TAG, "IN-CALEClientDisconnectforAddress"); VERIFY_NON_NULL(env, TAG, "env is null"); if (!g_gattObjectList) { - OIC_LOG(ERROR, TAG, "g_gattObjectList is null"); + 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; } @@ -1428,17 +1867,43 @@ CAResult_t CALEClientDisconnectAll(JNIEnv *env) OIC_LOG(ERROR, TAG, "jarrayObj is null"); continue; } - CAResult_t res = CALEClientDisconnect(env, jarrayObj); - if (CA_STATUS_OK != res) + + jstring jni_setAddress = CALEClientGetAddressFromGattObj(env, jarrayObj); + if (!jni_setAddress) { - OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); - continue; + OIC_LOG(ERROR, TAG, "jni_setAddress is null"); + (*env)->ReleaseStringUTFChars(env, remote_address, address); + return CA_STATUS_FAILED; } - } - OICFree(g_gattObjectList); - g_gattObjectList = NULL; + 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; } @@ -1449,27 +1914,20 @@ 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; } - // get BluetoothGatt class - OIC_LOG(DEBUG, TAG, "get BluetoothGatt class"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); - return CA_STATUS_FAILED; - } - - OIC_LOG(DEBUG, TAG, "discovery gatt services method"); - jmethodID jni_mid_discoverServices = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "discoverServices", "()Z"); + // get BluetoothGatt.discoverServices method + OIC_LOG(DEBUG, TAG, "get BluetoothGatt.discoverServices method"); + jmethodID jni_mid_discoverServices = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, + "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); @@ -1482,17 +1940,49 @@ 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_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, "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); if (!jni_obj_character) { CALEClientSendFinish(env, gatt); - ca_cond_signal(g_threadSendCond); return CA_STATUS_FAILED; } @@ -1500,15 +1990,53 @@ CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt) if (CA_STATUS_OK != ret) { CALEClientSendFinish(env, gatt); - ca_cond_signal(g_threadSendCond); - 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"); @@ -1517,24 +2045,16 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt, if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_STATUS_FAILED; - } - - // get BluetoothGatt class - OIC_LOG(DEBUG, TAG, "get BluetoothGatt class"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_STATUS_FAILED; } + // get BluetoothGatt.write characteristic method OIC_LOG(DEBUG, TAG, "write characteristic method"); - jmethodID jni_mid_writeCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "writeCharacteristic", - "(Landroid/bluetooth/" - "BluetoothGattCharacteristic;)Z"); + jmethodID jni_mid_writeCharacteristic = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, + "writeCharacteristic", + "(Landroid/bluetooth/" + "BluetoothGattCharacteristic;)Z"); if (!jni_mid_writeCharacteristic) { OIC_LOG(ERROR, TAG, "jni_mid_writeCharacteristic is null"); @@ -1548,7 +2068,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 { @@ -1566,14 +2086,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt) if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_STATUS_FAILED; - } - - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_STATUS_FAILED; } @@ -1592,10 +2105,10 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt) } OIC_LOG(DEBUG, TAG, "read characteristic method"); - jmethodID jni_mid_readCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "readCharacteristic", - "(Landroid/bluetooth/" - "BluetoothGattCharacteristic;)Z"); + jmethodID jni_mid_readCharacteristic = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, + "readCharacteristic", + "(Landroid/bluetooth/" + "BluetoothGattCharacteristic;)Z"); if (!jni_mid_readCharacteristic) { OIC_LOG(ERROR, TAG, "jni_mid_readCharacteristic is null"); @@ -1628,24 +2141,16 @@ 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; } - // get BluetoothGatt class + // get BluetoothGatt.setCharacteristicNotification method OIC_LOG(DEBUG, TAG, "CALEClientSetCharacteristicNotification"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); - return CA_STATUS_FAILED; - } - - // set Characteristic Notification - jmethodID jni_mid_setNotification = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "setCharacteristicNotification", - "(Landroid/bluetooth/" - "BluetoothGattCharacteristic;Z)Z"); + jmethodID jni_mid_setNotification = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, + "setCharacteristicNotification", + "(Landroid/bluetooth/" + "BluetoothGattCharacteristic;Z)Z"); if (!jni_mid_setNotification) { OIC_LOG(ERROR, TAG, "jni_mid_getService is null"); @@ -1675,22 +2180,16 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return NULL; - } - - // get BluetoothGatt class - OIC_LOG(DEBUG, TAG, "CALEClientGetGattService"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return NULL; } - jmethodID jni_mid_getService = (*env)->GetMethodID( - env, jni_cid_BluetoothGatt, "getService", - "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothGattService;"); + // get BluetoothGatt.getService method + OIC_LOG(DEBUG, TAG, "BluetoothGatt.getService"); + jmethodID jni_mid_getService = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, + "getService", + "(Ljava/util/UUID;)Landroid/bluetooth/" + "BluetoothGattService;"); if (!jni_mid_getService) { OIC_LOG(ERROR, TAG, "jni_mid_getService is null"); @@ -1714,21 +2213,13 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha return NULL; } - // get bluetooth gatt service class - jclass jni_cid_BluetoothGattService = (*env)->FindClass( - env, "android/bluetooth/BluetoothGattService"); - if (!jni_cid_BluetoothGattService) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGattService is null"); - return NULL; - } - - OIC_LOG(DEBUG, TAG, "get gatt getCharacteristic method"); - jmethodID jni_mid_getCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGattService, - "getCharacteristic", - "(Ljava/util/UUID;)" - "Landroid/bluetooth/" - "BluetoothGattCharacteristic;"); + // get bluetooth gatt service method + jmethodID jni_mid_getCharacteristic = CALEGetJNIMethodID(env, "android/bluetooth/" + "BluetoothGattService", + "getCharacteristic", + "(Ljava/util/UUID;)" + "Landroid/bluetooth/" + "BluetoothGattCharacteristic;"); if (!jni_mid_getCharacteristic) { OIC_LOG(ERROR, TAG, "jni_mid_getCharacteristic is null"); @@ -1768,7 +2259,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; } @@ -1847,21 +2338,13 @@ jbyteArray CALEClientGetValueFromCharacteristic(JNIEnv *env, jobject characteris if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return NULL; - } - - jclass jni_cid_BTGattCharacteristic = (*env)->FindClass(env, "android/bluetooth/" - "BluetoothGattCharacteristic"); - if (!jni_cid_BTGattCharacteristic) - { - OIC_LOG(ERROR, TAG, "jni_cid_BTGattCharacteristic is null"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return NULL; } - OIC_LOG(DEBUG, TAG, "get value in Characteristic"); - jmethodID jni_mid_getValue = (*env)->GetMethodID(env, jni_cid_BTGattCharacteristic, "getValue", - "()[B"); + jmethodID jni_mid_getValue = CALEGetJNIMethodID(env, "android/bluetooth/" + "BluetoothGattCharacteristic", + "getValue", "()[B"); if (!jni_mid_getValue) { OIC_LOG(ERROR, TAG, "jni_mid_getValue is null"); @@ -1950,21 +2433,13 @@ 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; } OIC_LOG(DEBUG, TAG, "CALEClientSetUUIDToDescriptor"); - jclass jni_cid_BTGattCharacteristic = (*env)->FindClass(env, "android/bluetooth/" - "BluetoothGattCharacteristic"); - if (!jni_cid_BTGattCharacteristic) - { - OIC_LOG(ERROR, TAG, "jni_cid_BTGattCharacteristic is null"); - return CA_STATUS_FAILED; - } - - OIC_LOG(DEBUG, TAG, "set value in Characteristic"); - jmethodID jni_mid_getDescriptor = (*env)->GetMethodID(env, jni_cid_BTGattCharacteristic, + jmethodID jni_mid_getDescriptor = CALEGetJNIMethodID(env, "android/bluetooth/" + "BluetoothGattCharacteristic", "getDescriptor", "(Ljava/util/UUID;)Landroid/bluetooth/" "BluetoothGattDescriptor;"); @@ -1986,8 +2461,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"); @@ -2029,15 +2504,8 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt, return CA_STATUS_FAILED; } - jclass jni_cid_gatt = (*env)->FindClass(env, "android/bluetooth/BluetoothGatt"); - if (!jni_cid_gatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_gatt is null"); - return CA_STATUS_FAILED; - } - - OIC_LOG(DEBUG, TAG, "write Descriptor in gatt object"); - jmethodID jni_mid_writeDescriptor = (*env)->GetMethodID(env, jni_cid_gatt, "writeDescriptor", + jmethodID jni_mid_writeDescriptor = CALEGetJNIMethodID(env, "android/bluetooth/BluetoothGatt", + "writeDescriptor", "(Landroid/bluetooth/" "BluetoothGattDescriptor;)Z"); if (!jni_mid_writeDescriptor) @@ -2080,7 +2548,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"); @@ -2089,6 +2556,13 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device) if (!g_deviceList) { OIC_LOG(ERROR, TAG, "gdevice_list is null"); + + CALEClientSetScanFlag(false); + if(CA_STATUS_OK != CALEClientStopScan()) + { + OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed"); + } + ca_mutex_unlock(g_deviceListMutex); return CA_STATUS_FAILED; } @@ -2113,20 +2587,19 @@ 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(env, TAG, "env is null", true); VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", true); if (!g_deviceList) @@ -2161,7 +2634,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; } @@ -2169,7 +2641,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; @@ -2199,6 +2670,7 @@ CAResult_t CALEClientRemoveAllScanDevices(JNIEnv *env) continue; } (*env)->DeleteGlobalRef(env, jarrayObj); + jarrayObj = NULL; } OICFree(g_deviceList); @@ -2263,10 +2735,16 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address) { OIC_LOG_V(DEBUG, TAG, "remove object : %s", remoteAddress); (*env)->DeleteGlobalRef(env, jarrayObj); + jarrayObj = NULL; (*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; } @@ -2286,12 +2764,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) { @@ -2308,11 +2793,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); @@ -2425,9 +2911,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); @@ -2440,10 +2926,12 @@ CAResult_t CALEClientRemoveAllGattObjs(JNIEnv *env) continue; } (*env)->DeleteGlobalRef(env, jarrayObj); + jarrayObj = NULL; } OICFree(g_gattObjectList); g_gattObjectList = NULL; + OIC_LOG(INFO, TAG, "g_gattObjectList is removed"); ca_mutex_unlock(g_gattObjectMutex); return CA_STATUS_OK; } @@ -2457,9 +2945,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); @@ -2511,10 +2999,18 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt) { OIC_LOG_V(DEBUG, TAG, "remove object : %s", remoteAddress); (*env)->DeleteGlobalRef(env, jarrayObj); + jarrayObj = NULL; (*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); @@ -2534,9 +3030,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); @@ -2579,11 +3075,17 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr) { OIC_LOG_V(DEBUG, TAG, "remove object : %s", remoteAddress); (*env)->DeleteGlobalRef(env, jarrayObj); - + jarrayObj = NULL; (*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); @@ -2594,6 +3096,101 @@ 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() + jmethodID jni_mid_getDevice = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, + "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 */ @@ -2603,7 +3200,7 @@ CAResult_t CALEClientUpdateDeviceState(const char* address, uint32_t connectedSt { VERIFY_NON_NULL(address, TAG, "address is null"); - CALEState_t *newstate = (CALEState_t*) OICMalloc(sizeof(CALEState_t)); + CALEState_t *newstate = (CALEState_t*) OICCalloc(1, sizeof(*newstate)); if (!newstate) { OIC_LOG(ERROR, TAG, "out of memory"); @@ -2617,7 +3214,7 @@ CAResult_t CALEClientUpdateDeviceState(const char* address, uint32_t connectedSt return CA_STATUS_FAILED; } - strcpy(newstate->address, address); + OICStrcpy(newstate->address, sizeof(newstate->address), address); newstate->connectedState = connectedState; newstate->notificationState = notificationState; newstate->sendState = sendState; @@ -2651,6 +3248,7 @@ CAResult_t CALEClientAddDeviceStateToList(CALEState_t* state) { state->notificationState = curState->notificationState; } + state->autoConnectFlag = curState->autoConnectFlag; // delete previous state for update new state CAResult_t res = CALEClientRemoveDeviceState(state->address); @@ -2662,8 +3260,9 @@ 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, %d", + state->connectedState, state->notificationState, + state->address, state->autoConnectFlag); ca_mutex_unlock(g_deviceStateListMutex); return CA_STATUS_OK; @@ -2706,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) @@ -2735,6 +3334,39 @@ CAResult_t CALEClientRemoveAllDeviceState() return CA_STATUS_OK; } +CAResult_t CALEClientResetDeviceStateForAll() +{ + OIC_LOG(DEBUG, TAG, "CALEClientResetDeviceStateForAll"); + + ca_mutex_lock(g_deviceStateListMutex); + if (!g_deviceStateList) + { + OIC_LOG(ERROR, TAG, "g_deviceStateList is null"); + ca_mutex_unlock(g_deviceStateListMutex); + return CA_STATUS_FAILED; + } + + size_t length = u_arraylist_length(g_deviceStateList); + for (size_t index = 0; index < length; index++) + { + CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index); + if (!state) + { + OIC_LOG(ERROR, TAG, "jarrayObj is null"); + continue; + } + + // autoConnectFlag value will be not changed, + // since it has reset only termination case. + state->connectedState = STATE_DISCONNECTED; + state->notificationState = STATE_CHARACTER_UNSET; + state->sendState = STATE_SEND_NONE; + } + ca_mutex_unlock(g_deviceStateListMutex); + + return CA_STATUS_OK; +} + CAResult_t CALEClientRemoveDeviceState(const char* remoteAddress) { OIC_LOG(DEBUG, TAG, "CALEClientRemoveDeviceState"); @@ -2758,20 +3390,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) @@ -2786,6 +3420,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); @@ -2795,6 +3431,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); @@ -2918,37 +3557,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); @@ -2967,6 +3582,7 @@ void CALEClientUpdateSendCnt(JNIEnv *env) } // notity the thread ca_cond_signal(g_threadCond); + CALEClientSetSendFinishFlag(true); OIC_LOG(DEBUG, TAG, "set signal for send data"); } @@ -2976,8 +3592,6 @@ void CALEClientUpdateSendCnt(JNIEnv *env) CAResult_t CALEClientInitGattMutexVaraibles() { - OIC_LOG(DEBUG, TAG, "IN"); - if (NULL == g_bleReqRespClientCbMutex) { g_bleReqRespClientCbMutex = ca_mutex_new(); @@ -3018,16 +3632,6 @@ CAResult_t CALEClientInitGattMutexVaraibles() } } - if (NULL == g_threadSendCBMutex) - { - g_threadSendCBMutex = ca_mutex_new(); - if (NULL == g_threadSendCBMutex) - { - OIC_LOG(ERROR, TAG, "ca_mutex_new has failed"); - return CA_STATUS_FAILED; - } - } - if (NULL == g_deviceListMutex) { g_deviceListMutex = ca_mutex_new(); @@ -3068,34 +3672,41 @@ CAResult_t CALEClientInitGattMutexVaraibles() } } - if (NULL == g_writeCharacteristicCBMutex) + 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_writeCharacteristicCBMutex = ca_mutex_new(); - if (NULL == g_writeCharacteristicCBMutex) + g_threadWriteCharacteristicMutex = ca_mutex_new(); + if (NULL == g_threadWriteCharacteristicMutex) { OIC_LOG(ERROR, TAG, "ca_mutex_new has failed"); return CA_STATUS_FAILED; } } - if (NULL == g_theSendRequestMutex) + if (NULL == g_deviceScanRetryDelayMutex) { - g_theSendRequestMutex = ca_mutex_new(); - if (NULL == g_theSendRequestMutex) + g_deviceScanRetryDelayMutex = ca_mutex_new(); + if (NULL == g_deviceScanRetryDelayMutex) { OIC_LOG(ERROR, TAG, "ca_mutex_new has failed"); return CA_STATUS_FAILED; } } - OIC_LOG(DEBUG, TAG, "OUT"); return CA_STATUS_OK; } void CALEClientTerminateGattMutexVariables() { - OIC_LOG(DEBUG, TAG, "IN"); - ca_mutex_free(g_bleReqRespClientCbMutex); g_bleReqRespClientCbMutex = NULL; @@ -3108,22 +3719,20 @@ void CALEClientTerminateGattMutexVariables() ca_mutex_free(g_threadSendMutex); g_threadSendMutex = NULL; - ca_mutex_free(g_threadSendCBMutex); - g_threadSendCBMutex = NULL; - ca_mutex_free(g_deviceListMutex); g_deviceListMutex = NULL; ca_mutex_free(g_SendFinishMutex); g_SendFinishMutex = NULL; - ca_mutex_free(g_writeCharacteristicCBMutex); - g_writeCharacteristicCBMutex = NULL; + ca_mutex_free(g_scanMutex); + g_scanMutex = NULL; - ca_mutex_free(g_theSendRequestMutex); - g_theSendRequestMutex = NULL; + ca_mutex_free(g_threadWriteCharacteristicMutex); + g_threadWriteCharacteristicMutex = NULL; - OIC_LOG(DEBUG, TAG, "OUT"); + ca_mutex_free(g_deviceScanRetryDelayMutex); + g_deviceScanRetryDelayMutex = NULL; } void CALEClientSetSendFinishFlag(bool flag) @@ -3135,44 +3744,40 @@ void CALEClientSetSendFinishFlag(bool flag) ca_mutex_unlock(g_SendFinishMutex); } -void CALEClientSetWriteCharacteristicCBFlag(bool flag) -{ - OIC_LOG_V(DEBUG, TAG, "g_isReceivedWriteCB is %d", flag); - - ca_mutex_lock(g_writeCharacteristicCBMutex); - g_isReceivedWriteCB = flag; - ca_mutex_unlock(g_writeCharacteristicCBMutex); -} - -void CALEClientSetTheSendRequestFlag(bool flag) -{ - OIC_LOG_V(DEBUG, TAG, "g_isRequestedSend is %d", flag); - - ca_mutex_lock(g_theSendRequestMutex); - g_isRequestedSend = flag; - ca_mutex_unlock(g_theSendRequestMutex); -} - /** * adapter common */ -CAResult_t CAStartBLEGattClient() +CAResult_t CAStartLEGattClient() { - CAResult_t res = CALEClientStartMulticastServer(); - if (CA_STATUS_OK != res) + // init mutex for send logic + if (!g_deviceDescCond) { - OIC_LOG(ERROR, TAG, "CALEClientStartMulticastServer has failed"); + g_deviceDescCond = ca_cond_new(); } - else + + if (!g_threadCond) + { + g_threadCond = ca_cond_new(); + } + + if (!g_threadWriteCharacteristicCond) + { + g_threadWriteCharacteristicCond = ca_cond_new(); + } + + CAResult_t ret = CALEClientStartScan(); + if (CA_STATUS_OK != ret) { - g_isStartedLEClient = true; + OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); + return ret; } - return res; + g_isStartedLEClient = true; + return CA_STATUS_OK; } -void CAStopBLEGattClient() +void CAStopLEGattClient() { OIC_LOG(DEBUG, TAG, "CAStopBLEGattClient"); @@ -3210,9 +3815,31 @@ void CAStopBLEGattClient() OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed"); } + ca_mutex_lock(g_threadMutex); + OIC_LOG(DEBUG, TAG, "signal - connection cond"); ca_cond_signal(g_threadCond); - ca_cond_signal(g_threadSendCond); - g_isStartedLEClient = false; + CALEClientSetSendFinishFlag(true); + ca_mutex_unlock(g_threadMutex); + + ca_mutex_lock(g_threadWriteCharacteristicMutex); + OIC_LOG(DEBUG, TAG, "signal - WriteCharacteristic cond"); + ca_cond_signal(g_threadWriteCharacteristicCond); + ca_mutex_unlock(g_threadWriteCharacteristicMutex); + + ca_mutex_lock(g_deviceScanRetryDelayMutex); + OIC_LOG(DEBUG, TAG, "signal - delay cond"); + ca_cond_signal(g_deviceScanRetryDelayCond); + ca_mutex_unlock(g_deviceScanRetryDelayMutex); + + ca_cond_free(g_deviceDescCond); + ca_cond_free(g_threadCond); + ca_cond_free(g_threadWriteCharacteristicCond); + ca_cond_free(g_deviceScanRetryDelayCond); + + g_deviceDescCond = NULL; + g_threadCond = NULL; + g_threadWriteCharacteristicCond = NULL; + g_deviceScanRetryDelayCond = NULL; if (isAttached) { @@ -3221,24 +3848,38 @@ void CAStopBLEGattClient() } -void CATerminateBLEGattClient() +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(); } -CAResult_t CAUpdateCharacteristicsToGattServer(const char *remoteAddress, const char *data, - const uint32_t dataLen, CALETransferType_t type, - const int32_t position) +CAResult_t CAUpdateCharacteristicsToGattServer(const char *remoteAddress, const uint8_t *data, + uint32_t dataLen, CALETransferType_t type, + int32_t position) { OIC_LOG(DEBUG, TAG, "call CALEClientSendUnicastMessage"); VERIFY_NON_NULL(data, TAG, "data is null"); VERIFY_NON_NULL(remoteAddress, TAG, "remoteAddress is null"); + if (LE_UNICAST != type || position < 0) + { + OIC_LOG(ERROR, TAG, "this request is not unicast"); + return CA_STATUS_INVALID_PARAM; + } + return CALEClientSendUnicastMessage(remoteAddress, data, dataLen); } -CAResult_t CAUpdateCharacteristicsToAllGattServers(const char *data, uint32_t dataLen) +CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t dataLen) { OIC_LOG(DEBUG, TAG, "call CALEClientSendMulticastMessage"); VERIFY_NON_NULL(data, TAG, "data is null"); @@ -3246,69 +3887,55 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const char *data, uint32_t da return CALEClientSendMulticastMessage(data, dataLen); } -void CASetBLEReqRespClientCallback(CABLEClientDataReceivedCallback callback) +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 CASetBleClientThreadPoolHandle(ca_thread_pool_t handle) +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) { - OIC_LOG(DEBUG, TAG, "IN"); - - VERIFY_NON_NULL(local_address, TAG, "local_address is null"); - CAResult_t res = CALEClientGetInterfaceInfo(local_address); - if (CA_STATUS_OK != res) - { - OIC_LOG(INFO, TAG, "it didn't get local address"); - } - - OIC_LOG(DEBUG, TAG, "OUT"); - return CA_STATUS_OK; + VERIFY_NON_NULL(local_address, TAG, "local_address"); + OIC_LOG(INFO, TAG, "CAGetLEAddress is not support"); + return CA_NOT_SUPPORTED; } JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CARegisterLeScanCallback(JNIEnv *env, jobject obj, - jobject callback) +Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterLeScanCallback(JNIEnv *env, jobject obj, + jobject callback) { - OIC_LOG(DEBUG, TAG, "CARegisterLeScanCallback"); + OIC_LOG(DEBUG, TAG, "CaLeRegisterLeScanCallback"); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(callback, TAG, "callback is null"); g_leScanCallback = (*env)->NewGlobalRef(env, callback); } JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CARegisterLeGattCallback(JNIEnv *env, jobject obj, - jobject callback) +Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterGattCallback(JNIEnv *env, jobject obj, + jobject callback) { - OIC_LOG(DEBUG, TAG, "CARegisterLeGattCallback"); + OIC_LOG(DEBUG, TAG, "CaLeRegisterGattCallback"); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(callback, TAG, "callback is null"); g_leGattCallback = (*env)->NewGlobalRef(env, callback); } JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeScanCallback(JNIEnv *env, jobject obj, - jobject device, jint rssi, - jbyteArray scanRecord) +Java_org_iotivity_ca_CaLeClientInterface_caLeScanCallback(JNIEnv *env, jobject obj, + jobject device) { VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(device, TAG, "device is null"); CAResult_t res = CALEClientAddScanDeviceToList(env, device); @@ -3318,13 +3945,46 @@ Java_org_iotivity_jar_caleclientinterface_CALeScanCallback(JNIEnv *env, jobject } } +static jstring CALEClientGetAddressFromGatt(JNIEnv *env, jobject gatt) +{ + OIC_LOG(DEBUG, TAG, "IN - CAManagerGetAddressFromGatt"); + + VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); + VERIFY_NON_NULL_RET(gatt, TAG, "gatt is null", NULL); + + jmethodID jni_mid_getDevice = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, + "getDevice", METHODID_BT_DEVICE); + if (!jni_mid_getDevice) + { + OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null"); + return NULL; + } + + jobject jni_obj_device = (*env)->CallObjectMethod(env, gatt, jni_mid_getDevice); + if (!jni_obj_device) + { + OIC_LOG(ERROR, TAG, "jni_obj_device is null"); + return NULL; + } + + jstring jni_address = CALEGetAddressFromBTDevice(env, jni_obj_device); + if (!jni_address) + { + OIC_LOG(ERROR, TAG, "jni_address is null"); + return NULL; + } + + OIC_LOG(DEBUG, TAG, "OUT - CAManagerGetAddressFromGatt"); + return jni_address; +} + /* - * Class: org_iotivity_jar_caleinterface + * Class: org_iotivity_ca_jar_caleinterface * Method: CALeGattConnectionStateChangeCallback * Signature: (Landroid/bluetooth/BluetoothGatt;II)V */ JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback(JNIEnv *env, +Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(JNIEnv *env, jobject obj, jobject gatt, jint status, @@ -3333,9 +3993,14 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback( OIC_LOG_V(DEBUG, TAG, "CALeGattConnectionStateChangeCallback - status %d, newstate %d", status, newstate); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + 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) @@ -3355,6 +4020,8 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback( (*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); } @@ -3372,66 +4039,90 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback( goto error_exit; } } - else if (GATT_SUCCESS == status && STATE_DISCONNECTED == newstate) // le disconnected + else if (state_disconnected == newstate) // le disconnected { - CAResult_t res = CALEClientStartScan(); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - } - 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); } - res = CALEClientGattClose(env, gatt); + CAResult_t res = CALEClientGattClose(env, gatt); if (CA_STATUS_OK != res) { OIC_LOG(ERROR, TAG, "CALEClientGattClose has failed"); } - ca_cond_signal(g_threadSendCond); - } - else // error - { - // update state - jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); - if (!jni_address) + if (GATT_ERROR == status) { - OIC_LOG(ERROR, TAG, "jni_address is null"); - goto error_exit; + // when we get GATT ERROR(0x85), gatt connection can be called again. + OIC_LOG(INFO, TAG, "retry gatt connect"); - } + jstring leAddress = CALEClientGetAddressFromGatt(env, gatt); + if (!leAddress) + { + OIC_LOG(ERROR, TAG, "CALEClientGetAddressFromGatt has failed"); + goto error_exit; + } - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (address) + jobject btObject = CALEGetRemoteDevice(env, leAddress); + if (!btObject) + { + OIC_LOG(ERROR, TAG, "CALEGetRemoteDevice has failed"); + goto error_exit; + } + + jobject newGatt = CALEClientConnect(env, btObject, JNI_TRUE); + if (!newGatt) + { + OIC_LOG(ERROR, TAG, "CALEClientConnect has failed"); + goto error_exit; + } + + return; + } + else { - CAResult_t res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED, - STATE_CHARACTER_NO_CHANGE, - STATE_SEND_FAILED); - if (CA_STATUS_OK != res) + if (CALECheckConnectionStateValue(status)) { - OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); + // this state is unexpected reason to disconnect + // if the reason is suitable, connection logic of the device will be destroyed. + OIC_LOG(INFO, TAG, "connection logic destroy"); + goto error_exit; + } + else + { + // other reason except for gatt_success is expected to running + // background connection in BT platform. + OIC_LOG(INFO, TAG, "unknown state or manual disconnected state"); + CALEClientUpdateSendCnt(env); + return; } } - (*env)->ReleaseStringUTFChars(env, jni_address, address); - goto error_exit; + if (g_sendBuffer) + { + (*env)->DeleteGlobalRef(env, g_sendBuffer); + g_sendBuffer = NULL; + } } return; @@ -3439,29 +4130,28 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback( error_exit: CALEClientSendFinish(env, gatt); - ca_cond_signal(g_threadSendCond); return; } /* - * Class: org_iotivity_jar_caleinterface + * Class: org_iotivity_ca_jar_caleinterface * Method: CALeGattServicesDiscoveredCallback * Signature: (Landroid/bluetooth/BluetoothGatt;I)V */ JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNIEnv *env, +Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIEnv *env, jobject obj, jobject gatt, jint status) { OIC_LOG_V(DEBUG, TAG, "CALeGattServicesDiscoveredCallback - status %d: ", status); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); if (0 != status) // discovery error { CALEClientSendFinish(env, gatt); - ca_cond_signal(g_threadSendCond); return; } @@ -3469,7 +4159,6 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNI if (!jni_address) { CALEClientSendFinish(env, gatt); - ca_cond_signal(g_threadSendCond); return; } @@ -3477,7 +4166,6 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNI if (!address) { CALEClientSendFinish(env, gatt); - ca_cond_signal(g_threadSendCond); return; } @@ -3508,8 +4196,16 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNI res = CALEClientSetUUIDToDescriptor(env, gatt, jni_obj_GattCharacteristic); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientSetUUIDToDescriptor has failed"); - goto error_exit; + OIC_LOG_V(INFO, TAG, "Descriptor is not found : %d", res); + if (g_sendBuffer) + { + CAResult_t res = CALEClientWriteCharacteristic(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed"); + goto error_exit; + } + } } res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET, @@ -3522,67 +4218,43 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNI } else { - 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; + } } } + 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); - ca_cond_signal(g_threadSendCond); return; } /* - * Class: org_iotivity_jar_caleinterface - * Method: CALeGattCharacteristicReadCallback - * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;I)V - */ -JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicReadCallback(JNIEnv *env, - jobject obj, - jobject gatt, - jobject characteristic, - jbyteArray data, - jint status) -{ - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicReadCallback - status : %d", status); -} - -/* - * Class: org_iotivity_jar_caleinterface + * Class: org_iotivity_ca_jar_caleinterface * Method: CALeGattCharacteristicWritjclasseCallback * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;I)V */ JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicWriteCallback( - JNIEnv *env, jobject obj, jobject gatt, jobject characteristic, jbyteArray data, +Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback( + JNIEnv *env, jobject obj, jobject gatt, jbyteArray data, jint status) { OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - status : %d", status); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); - ca_mutex_lock(g_threadSendCBMutex); - if (!g_isRequestedSend) - { - OIC_LOG(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - waiting"); - ca_cond_wait(g_threadSendCBCond, g_threadSendCBMutex); - } - ca_mutex_unlock(g_threadSendCBMutex); - - jboolean isCopy; - char* wroteData = (char*) (*env)->GetByteArrayElements(env, data, &isCopy); - - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - write data : %s", wroteData); - // send success & signal jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); if (!jni_address) @@ -3596,16 +4268,38 @@ Java_org_iotivity_jar_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 { @@ -3616,57 +4310,58 @@ Java_org_iotivity_jar_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); } - CALEClientSetWriteCharacteristicCBFlag(true); - CALEClientSetTheSendRequestFlag(false); - ca_cond_signal(g_threadSendCond); (*env)->ReleaseStringUTFChars(env, jni_address, address); return; // error label. error_exit: - CALEClientSetWriteCharacteristicCBFlag(true); - CALEClientSetTheSendRequestFlag(false); CALEClientSendFinish(env, gatt); - ca_cond_signal(g_threadSendCond); return; } /* - * Class: org_iotivity_jar_caleinterface + * Class: org_iotivity_ca_jar_caleinterface * Method: CALeGattCharacteristicChangedCallback * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;)V */ JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicChangedCallback( - JNIEnv *env, jobject obj, jobject gatt, jobject characteristic, jbyteArray data) +Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback( + JNIEnv *env, jobject obj, jobject gatt, jbyteArray data) { OIC_LOG(DEBUG, TAG, "CALeGattCharacteristicChangedCallback"); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); VERIFY_NON_NULL_VOID(data, TAG, "data is null"); - // get Byte Array and covert to char* + // get Byte Array and convert to uint8_t* jint length = (*env)->GetArrayLength(env, data); jboolean isCopy; jbyte *jni_byte_responseData = (jbyte*) (*env)->GetByteArrayElements(env, data, &isCopy); - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - raw data received : %s", + OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - raw data received : %p", jni_byte_responseData); - char* receivedData = (char*) OICMalloc(sizeof(char) * length + 1); + uint8_t* receivedData = OICMalloc(length); if (!receivedData) { - OIC_LOG(ERROR, TAG, "recevicedData is null"); + OIC_LOG(ERROR, TAG, "receivedData is null"); return; } - memcpy(receivedData, (const char*) jni_byte_responseData, length); - receivedData[length] = '\0'; + memcpy(receivedData, jni_byte_responseData, length); (*env)->ReleaseByteArrayElements(env, data, jni_byte_responseData, JNI_ABORT); jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); @@ -3685,12 +4380,12 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicChangedCallback( return; } - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - data. : %s, %d", + OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - data. : %p, %d", receivedData, length); ca_mutex_lock(g_bleServerBDAddressMutex); uint32_t sentLength = 0; - g_CABLEClientDataReceivedCallback(address, OIC_GATT_SERVICE_UUID, receivedData, length, + g_CABLEClientDataReceivedCallback(address, receivedData, length, &sentLength); ca_mutex_unlock(g_bleServerBDAddressMutex); @@ -3698,73 +4393,40 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicChangedCallback( } /* - * Class: org_iotivity_jar_caleinterface - * Method: CALeGattDescriptorReadCallback + * Class: org_iotivity_ca_jar_caleinterface + * Method: CALeGattDescriptorWriteCallback * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattDescriptor;I)V */ JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattDescriptorReadCallback(JNIEnv *env, jobject obj, +Java_org_iotivity_ca_CaLeClientInterface_caLeGattDescriptorWriteCallback(JNIEnv *env, jobject obj, jobject gatt, - jobject descriptor, jint status) { - OIC_LOG_V(DEBUG, TAG, "CALeGattDescriptorReadCallback - status %d: ", status); -} - -/* - * Class: org_iotivity_jar_caleinterface - * Method: CALeGattDescriptorWriteCallback - * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattDescriptor;I)V - */ -JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattDescriptorWriteCallback(JNIEnv *env, jobject obj, - jobject gatt, - jobject descriptor, - jint status) -{ OIC_LOG_V(DEBUG, TAG, "CALeGattDescriptorWriteCallback - status %d: ", status); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + 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. error_exit: CALEClientSendFinish(env, gatt); - ca_cond_signal(g_threadSendCond); return; } - -/* - * Class: org_iotivity_jar_caleinterface - * Method: CALeGattReliableWriteCompletedCallback - * Signature: (Landroid/bluetooth/BluetoothGatt;I)V - */ -JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattReliableWriteCompletedCallback(JNIEnv *env, - jobject obj, - jobject gatt, - jint status) -{ - OIC_LOG_V(DEBUG, TAG, "CALeGattReliableWriteCompletedCallback - status %d: ", status); -} - -/* - * Class: org_iotivity_jar_caleinterface - * Method: CALeGattReadRemoteRssiCallback - * Signature: (Landroid/bluetooth/BluetoothGatt;II)V - */ -JNIEXPORT void JNICALL -Java_org_iotivity_jar_caleclientinterface_CALeGattReadRemoteRssiCallback(JNIEnv *env, jobject obj, - jobject gatt, jint rssi, - jint status) -{ - OIC_LOG_V(DEBUG, TAG, "CALeGattReadRemoteRssiCallback - rssi %d, status %d: ", rssi, status); -}