#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;
// 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 ca_mutex g_gattObjectMutex = NULL;
static ca_mutex g_deviceStateListMutex = NULL;
+static ca_mutex g_deviceScanRetryDelayMutex = NULL;
+static ca_cond g_deviceScanRetryDelayCond = NULL;
+
static ca_mutex g_scanMutex = NULL;
static CABLEDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL;
-static jboolean g_autoConnectFlag = JNI_FALSE;
+/**
+ * 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()
isAttached = true;
}
+ jmethodID mid_getApplicationContext = CAGetJNIMethodID(env, "android/content/Context",
+ "getApplicationContext",
+ "()Landroid/content/Context;");
+
+ if (!mid_getApplicationContext)
+ {
+ OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
+ return CA_STATUS_FAILED;
+ }
+
+ jobject jApplicationContext = (*env)->CallObjectMethod(env, g_context,
+ mid_getApplicationContext);
+ if (!jApplicationContext)
+ {
+ OIC_LOG(ERROR, TAG, "Could not get application context");
+ return CA_STATUS_FAILED;
+ }
+
jclass jni_LEInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface");
if (!jni_LEInterface)
{
goto error_exit;
}
- (*env)->NewObject(env, jni_LEInterface, LeInterfaceConstructorMethod, g_context);
+ (*env)->NewObject(env, jni_LEInterface, LeInterfaceConstructorMethod, jApplicationContext);
OIC_LOG(DEBUG, TAG, "Create instance for CaLeClientInterface");
if (isAttached)
// init mutex for send logic
g_threadCond = ca_cond_new();
g_threadWriteCharacteristicCond = ca_cond_new();
+ g_deviceScanRetryDelayCond = ca_cond_new();
CALEClientCreateDeviceList();
CALEClientJNISetContext();
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();
OIC_LOG(ERROR, TAG, "CALEClientRemoveAllGattObjs has failed");
}
- g_isStartedMulticastServer = false;
CALEClientSetScanFlag(false);
- CALEClientSetSendFinishFlag(false);
+ CALEClientSetSendFinishFlag(true);
CALEClientTerminateGattMutexVariables();
CALEClientDestroyJniInterface();
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;
+
g_isSignalSetFlag = false;
- CALEClientSetAutoConnectFlag(JNI_FALSE);
if (isAttached)
{
CAResult_t CALEClientStartMulticastServer()
{
- OIC_LOG(DEBUG, TAG, "CALEClientStartMulticastServer");
-
- if (g_isStartedMulticastServer)
- {
- OIC_LOG(ERROR, TAG, "server is already started..it will be skipped");
- return CA_STATUS_FAILED;
- }
-
- if (!g_jvm)
- {
- OIC_LOG(ERROR, TAG, "g_jvm is null");
- return CA_STATUS_FAILED;
- }
-
- bool isAttached = false;
- JNIEnv* env;
- jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
- if (JNI_OK != res)
- {
- OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
- res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
+ OIC_LOG(DEBUG, TAG, "it is not needed in this platform");
- if (JNI_OK != res)
- {
- OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
- return CA_STATUS_FAILED;
- }
- isAttached = true;
- }
-
- g_isStartedMulticastServer = true;
- CAResult_t ret = CALEClientStartScan();
- if (CA_STATUS_OK != ret)
- {
- OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
- }
-
- if (isAttached)
- {
- (*g_jvm)->DetachCurrentThread(g_jvm);
- }
-
- return ret;
+ return CA_NOT_SUPPORTED;
}
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)
g_clientErrorCallback = callback;
}
-CAResult_t CALEClientIsThereScannedDevices()
+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))
+ if (0 == u_arraylist_length(g_deviceList) // multicast
+ || (address && !CALEClientIsDeviceInScanDeviceList(env, address))) // unicast
{
// Wait for LE peripherals to be discovered.
2 * MICROSECS_PER_SEC; // Microseconds
bool devicesDiscovered = false;
- for (size_t i = 0;
- 0 == u_arraylist_length(g_deviceList) && i < RETRIES;
- ++i)
+ 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)
{
- devicesDiscovered = true;
- break;
+ 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;
+ }
+ }
+ }
+ }
}
}
return CA_STATUS_OK;
}
+
CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* data,
const uint32_t dataLen)
{
CALEClientSetSendFinishFlag(false);
- CAResult_t ret = CALEClientIsThereScannedDevices();
+ CAResult_t ret = CALEClientIsThereScannedDevices(env, address);
if (CA_STATUS_OK != ret)
{
OIC_LOG(INFO, TAG, "there is no scanned device");
}
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:
g_sendBuffer = NULL;
}
- CAResult_t res = CALEClientIsThereScannedDevices();
+ CAResult_t res = CALEClientIsThereScannedDevices(env, NULL);
if (CA_STATUS_OK != res)
{
OIC_LOG(INFO, TAG, "there is no scanned device");
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;
}
}
// connection request
- jobject newGatt = CALEClientConnect(env, device, CALEClientGetAutoConnectFlag());
+ jobject newGatt = CALEClientConnect(env, device,
+ JNI_FALSE);
if (NULL == newGatt)
{
OIC_LOG(ERROR, TAG, "CALEClientConnect has failed");
}
OIC_LOG(DEBUG, TAG, "start to connect LE");
- jobject gatt = CALEClientConnect(env, device, JNI_TRUE);
+ jobject gatt = CALEClientConnect(env, device,
+ CALEClientGetAutoConnectFlag(env, jni_address));
if (NULL == gatt)
{
OIC_LOG(ERROR, TAG, "CALEClientConnect has failed");
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 = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, "getDevice",
+ "()Landroid/bluetooth/BluetoothDevice;");
if (!jni_mid_getDevice)
{
OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null");
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 = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, "close", "()V");
if (!jni_mid_closeGatt)
{
OIC_LOG(ERROR, TAG, "jni_mid_closeGatt is null");
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");
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
{
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
{
return CA_STATUS_OK;
}
-void CALEClientSetAutoConnectFlag(jboolean flag)
+CAResult_t CALEClientSetAutoConnectFlag(JNIEnv *env, jstring jni_address, jboolean flag)
{
- OIC_LOG_V(INFO, TAG, "auto connect flag is set %d", flag);
- g_autoConnectFlag = 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()
+jboolean CALEClientGetAutoConnectFlag(JNIEnv *env, jstring jni_address)
{
- OIC_LOG_V(INFO, TAG, "auto connect flag is %d", g_autoConnectFlag);
- return g_autoConnectFlag;
+ 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)
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(INFO, TAG, "BT adapter is not enabled");
return NULL;
}
- // 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 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 = CAGetJNIMethodID(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");
VERIFY_NON_NULL(env, TAG, "env is null");
VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null");
- // 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;
- }
-
+ // get BluetoothGatt method
OIC_LOG(DEBUG, TAG, "get gatt disconnect method");
- jmethodID jni_mid_disconnectGatt = (*env)->GetMethodID(env, jni_cid_BluetoothGatt,
- "disconnect", "()V");
+ jmethodID jni_mid_disconnectGatt = CAGetJNIMethodID(env, CLASSPATH_BT_GATT,
+ "disconnect", "()V");
if (!jni_mid_disconnectGatt)
{
OIC_LOG(ERROR, TAG, "jni_mid_disconnectGatt is null");
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 = CAGetJNIMethodID(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);
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");
- 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 = CAGetJNIMethodID(env, CLASSPATH_BT_GATT,
+ "writeCharacteristic",
+ "(Landroid/bluetooth/"
+ "BluetoothGattCharacteristic;)Z");
if (!jni_mid_writeCharacteristic)
{
OIC_LOG(ERROR, TAG, "jni_mid_writeCharacteristic is null");
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");
- return CA_STATUS_FAILED;
- }
-
jstring jni_uuid = (*env)->NewStringUTF(env, OIC_GATT_CHARACTERISTIC_RESPONSE_UUID);
if (!jni_uuid)
{
}
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 = CAGetJNIMethodID(env, CLASSPATH_BT_GATT,
+ "readCharacteristic",
+ "(Landroid/bluetooth/"
+ "BluetoothGattCharacteristic;)Z");
if (!jni_mid_readCharacteristic)
{
OIC_LOG(ERROR, TAG, "jni_mid_readCharacteristic is null");
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 = CAGetJNIMethodID(env, CLASSPATH_BT_GATT,
+ "setCharacteristicNotification",
+ "(Landroid/bluetooth/"
+ "BluetoothGattCharacteristic;Z)Z");
if (!jni_mid_setNotification)
{
OIC_LOG(ERROR, TAG, "jni_mid_getService is null");
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");
- 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 = CAGetJNIMethodID(env, CLASSPATH_BT_GATT,
+ "getService",
+ "(Ljava/util/UUID;)Landroid/bluetooth/"
+ "BluetoothGattService;");
if (!jni_mid_getService)
{
OIC_LOG(ERROR, TAG, "jni_mid_getService is null");
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 = CAGetJNIMethodID(env, "android/bluetooth/"
+ "BluetoothGattService",
+ "getCharacteristic",
+ "(Ljava/util/UUID;)"
+ "Landroid/bluetooth/"
+ "BluetoothGattCharacteristic;");
if (!jni_mid_getCharacteristic)
{
OIC_LOG(ERROR, TAG, "jni_mid_getCharacteristic is null");
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");
- 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 = CAGetJNIMethodID(env, "android/bluetooth/"
+ "BluetoothGattCharacteristic",
+ "getValue", "()[B");
if (!jni_mid_getValue)
{
OIC_LOG(ERROR, TAG, "jni_mid_getValue is null");
}
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,
- "getDescriptor",
- "(Ljava/util/UUID;)Landroid/bluetooth/"
- "BluetoothGattDescriptor;");
+ jmethodID jni_mid_getDescriptor = CAGetJNIMethodID(env, "android/bluetooth/"
+ "BluetoothGattCharacteristic",
+ "getDescriptor",
+ "(Ljava/util/UUID;)Landroid/bluetooth/"
+ "BluetoothGattDescriptor;");
if (!jni_mid_getDescriptor)
{
OIC_LOG(ERROR, TAG, "jni_mid_getDescriptor is null");
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",
- "(Landroid/bluetooth/"
- "BluetoothGattDescriptor;)Z");
+ jmethodID jni_mid_writeDescriptor = CAGetJNIMethodID(env, "android/bluetooth/BluetoothGatt",
+ "writeDescriptor",
+ "(Landroid/bluetooth/"
+ "BluetoothGattDescriptor;)Z");
if (!jni_mid_writeDescriptor)
{
OIC_LOG(ERROR, TAG, "jni_mid_writeDescriptor is null");
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;
}
bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress)
{
- 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)
continue;
}
(*env)->DeleteGlobalRef(env, jarrayObj);
+ jarrayObj = NULL;
}
OICFree(g_deviceList);
{
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);
continue;
}
(*env)->DeleteGlobalRef(env, jarrayObj);
+ jarrayObj = NULL;
}
OICFree(g_gattObjectList);
{
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);
{
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))
}
// get method ID of getDevice()
- jclass jni_cid_gattdevice_list = (*env)->FindClass(env, CLASSPATH_BT_GATT);
- if (!jni_cid_gattdevice_list)
- {
- OIC_LOG(ERROR, TAG, "jni_cid_gattdevice_list is null");
- (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
- return NULL;
- }
-
- jmethodID jni_mid_getDevice = (*env)->GetMethodID(env, jni_cid_gattdevice_list, "getDevice",
- METHODID_BT_DEVICE);
+ jmethodID jni_mid_getDevice = CAGetJNIMethodID(env, CLASSPATH_BT_GATT,
+ "getDevice", METHODID_BT_DEVICE);
if (!jni_mid_getDevice)
{
OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null");
{
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");
{
state->notificationState = curState->notificationState;
}
+ state->autoConnectFlag = curState->autoConnectFlag;
// delete previous state for update new state
CAResult_t res = CALEClientRemoveDeviceState(state->address);
}
}
u_arraylist_add(g_deviceStateList, state); // update new state
- OIC_LOG_V(INFO, TAG, "Set State Info to List : %d, %d, %s",
- state->connectedState, state->notificationState, state->address);
+ 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;
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");
}
}
+ if (NULL == g_deviceScanRetryDelayMutex)
+ {
+ g_deviceScanRetryDelayMutex = ca_mutex_new();
+ if (NULL == g_deviceScanRetryDelayMutex)
+ {
+ OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+ return CA_STATUS_FAILED;
+ }
+ }
+
return CA_STATUS_OK;
}
ca_mutex_free(g_threadWriteCharacteristicMutex);
g_threadWriteCharacteristicMutex = NULL;
+
+ ca_mutex_free(g_deviceScanRetryDelayMutex);
+ g_deviceScanRetryDelayMutex = NULL;
}
void CALEClientSetSendFinishFlag(bool flag)
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_isStartedLEClient = true;
+ g_threadWriteCharacteristicCond = ca_cond_new();
}
- return res;
+ CAResult_t ret = CALEClientStartScan();
+ if (CA_STATUS_OK != ret)
+ {
+ OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
+ return ret;
+ }
+
+ g_isStartedLEClient = true;
+ return CA_STATUS_OK;
}
void CAStopLEGattClient()
}
ca_mutex_lock(g_threadMutex);
+ OIC_LOG(DEBUG, TAG, "signal - connection cond");
ca_cond_signal(g_threadCond);
+ 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)
{
(*g_jvm)->DetachCurrentThread(g_jvm);
}
}
+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 = CAGetJNIMethodID(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_ca_jar_caleinterface
* Method: CALeGattConnectionStateChangeCallback
goto error_exit;
}
}
- else if (GATT_ERROR == status && state_disconnected == newstate)
+ else if (state_disconnected == newstate) // le disconnected
{
- OIC_LOG(INFO, TAG, "Background connection running.. please wait");
- }
- else // le disconnected
- {
- CAResult_t res = CALEClientStartScan();
- if (CA_STATUS_OK != res)
- {
- if (CA_ADAPTER_NOT_ENABLED == res)
- {
- // scan will be started with start server when adapter is enabled
- OIC_LOG(INFO, TAG, "Adapter was disabled");
- }
- else
- {
- OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
- goto error_exit;
- }
- }
-
jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
if (!jni_address)
{
(*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");
}
+ if (gatt_success == status)
+ {
+ // that state is a general reason to disconnect BLE.
+ // its means manual disconnected message from BT platform.
+ // in this case Scanning has to start again and clean previous data.
+ CAResult_t res = CALEClientStartScan();
+ if (CA_STATUS_OK != res)
+ {
+ if (CA_ADAPTER_NOT_ENABLED == res)
+ {
+ // scan will be started with start server when adapter is enabled
+ OIC_LOG(INFO, TAG, "Adapter was disabled");
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
+ goto error_exit;
+ }
+ }
+ }
+ else if (GATT_ERROR == status)
+ {
+ // 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;
+ }
+
+ 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
+ {
+ if (CALECheckConnectionStateValue(status))
+ {
+ // 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;
+ }
+ }
+
if (g_sendBuffer)
{
(*env)->DeleteGlobalRef(env, g_sendBuffer);
}
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");
VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null");
- 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)