Skip to content

Commit

Permalink
Squashed merge: add connection timeout test
Browse files Browse the repository at this point in the history
  • Loading branch information
intent-kacper-cyranowski authored and aliberski committed Dec 20, 2024
1 parent 1473324 commit 36f0b56
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 17 deletions.
33 changes: 33 additions & 0 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ PODS:
- hermes-engine (0.74.1):
- hermes-engine/Pre-built (= 0.74.1)
- hermes-engine/Pre-built (0.74.1)
- MMKV (1.3.7):
- MMKVCore (~> 1.3.7)
- MMKVCore (1.3.7)
- MultiplatformBleAdapter (0.2.0)
- RCT-Folly (2024.01.01.00):
- boost
Expand Down Expand Up @@ -958,6 +961,28 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-mmkv (2.12.2):
- DoubleConversion
- glog
- hermes-engine
- MMKV (>= 1.3.3)
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React-Codegen
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-safe-area-context (4.10.1):
- React-Core
- React-nativeconfig (0.74.1)
Expand Down Expand Up @@ -1248,6 +1273,7 @@ DEPENDENCIES:
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- react-native-ble-plx (from `../..`)
- react-native-mmkv (from `../node_modules/react-native-mmkv`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- React-nativeconfig (from `../node_modules/react-native/ReactCommon`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
Expand Down Expand Up @@ -1277,6 +1303,8 @@ DEPENDENCIES:

SPEC REPOS:
trunk:
- MMKV
- MMKVCore
- MultiplatformBleAdapter
- SocketRocket

Expand Down Expand Up @@ -1344,6 +1372,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
react-native-ble-plx:
:path: "../.."
react-native-mmkv:
:path: "../node_modules/react-native-mmkv"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
React-nativeconfig:
Expand Down Expand Up @@ -1404,6 +1434,8 @@ SPEC CHECKSUMS:
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
hermes-engine: 16b8530de1b383cdada1476cf52d1b52f0692cbc
MMKV: 36a22a9ec84c9bb960613a089ddf6f48be9312b0
MMKVCore: 158e61c8516401a9fac730288acb29e6fc19bbf9
MultiplatformBleAdapter: ea8bac405ec200d0ca9de0f89afef6f06fb2abbc
RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47
RCTDeprecation: efb313d8126259e9294dc4ee0002f44a6f676aba
Expand All @@ -1430,6 +1462,7 @@ SPEC CHECKSUMS:
React-logger: 7e7403a2b14c97f847d90763af76b84b152b6fce
React-Mapbuffer: 11029dcd47c5c9e057a4092ab9c2a8d10a496a33
react-native-ble-plx: 08539040709361221aa9f8cada60dc730b9168c5
react-native-mmkv: 8c9a677e64a1ac89b0c6cf240feea528318b3074
react-native-safe-area-context: dcab599c527c2d7de2d76507a523d20a0b83823d
React-nativeconfig: b0073a590774e8b35192fead188a36d1dca23dec
React-NativeModulesApple: df46ff3e3de5b842b30b4ca8a6caae6d7c8ab09f
Expand Down
9 changes: 5 additions & 4 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"react": "18.2.0",
"react-native": "0.74.1",
"react-native-base64": "^0.2.1",
"react-native-mmkv": "^2.12.2",
"react-native-safe-area-context": "^4.10.1",
"react-native-screens": "^3.31.1",
"react-native-toast-message": "^2.1.6",
Expand All @@ -23,13 +24,13 @@
"@babel/core": "^7.20.0",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
"@react-native/babel-preset": "0.74.83",
"@react-native/eslint-config": "^0.72.2",
"@types/react-native-base64": "^0.2.0",
"@react-native/metro-config": "0.74.83",
"@react-native/typescript-config": "0.74.83",
"@types/react-native-base64": "^0.2.0",
"babel-plugin-module-resolver": "^5.0.0",
"metro-react-native-babel-preset": "0.76.8",
"@react-native/babel-preset": "0.74.83",
"@react-native/typescript-config": "0.74.83"
"metro-react-native-babel-preset": "0.76.8"
},
"engines": {
"node": ">=18"
Expand Down
1 change: 1 addition & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ThemeProvider } from 'styled-components'
import Toast from 'react-native-toast-message'
import { commonTheme } from './theme/theme'
import { Navigation } from './navigation'
import './services/storage/storage'

export function App() {
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { useRef, useState } from 'react'
import type { NativeStackScreenProps } from '@react-navigation/native-stack'
import { BleError, Characteristic, Device, type Subscription, type DeviceId, BleErrorCode } from 'react-native-ble-plx'
import { ScrollView } from 'react-native'
import { Alert, ScrollView } from 'react-native'
import base64 from 'react-native-base64'
import Toast from 'react-native-toast-message'
import type { TestStateType } from '../../../types'
import { BLEService } from '../../../services'
import { BLEService, usePersistentDeviceName } from '../../../services'
import type { MainStackParamList } from '../../../navigation/navigators'
import { AppButton, AppTextInput, ScreenDefaultContainer, TestStateDisplay } from '../../../components/atoms'
import { currentTimeCharacteristic, deviceTimeService } from '../../../consts/nRFDeviceConsts'
Expand All @@ -16,9 +16,10 @@ type DeviceConnectDisconnectTestScreenProps = NativeStackScreenProps<
'DEVICE_CONNECT_DISCONNECT_TEST_SCREEN'
>
const NUMBER_OF_CALLS_IN_THE_TEST_SCENARIO = 10
const CONNECTION_TIMEOUT = 5000

export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnectTestScreenProps) {
const [expectedDeviceName, setExpectedDeviceName] = useState('')
const [expectedDeviceName, setExpectedDeviceName] = usePersistentDeviceName()
const [testScanDevicesState, setTestScanDevicesState] = useState<TestStateType>('WAITING')
const [deviceId, setDeviceId] = useState('')
const [connectCounter, setConnectCounter] = useState(0)
Expand All @@ -27,11 +28,59 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec
const [disconnectCounter, setDisconnectCounter] = useState(0)
const [monitorMessages, setMonitorMessages] = useState<string[]>([])
const monitorSubscriptionRef = useRef<Subscription | null>(null)
const [timeoutTestState, setTimeoutTestState] = useState<TestStateType>('WAITING')
const [timeoutTestLabel, setTimeoutTestLabel] = useState('Timeout Test')

const startTimeoutTest = async () => {
await BLEService.initializeBLE()
setTimeoutTestLabel('Running')
await BLEService.scanDevices(
async (device: Device) => {
if (checkDeviceName(device)) {
BLEService.stopDeviceScan()
Alert.alert(
'Prepare for Timeout Test',
'Please turn off Bluetooth on the device you want to connect to. Press OK when ready.',
[
{
text: 'OK',
onPress: () => runTimeoutTest(device)
}
]
)
}
},
[deviceTimeService]
)
}

const runTimeoutTest = async (device: Device) => {
setTimeoutTestState('IN_PROGRESS')

try {
await BLEService.connectToDevice(device.id, CONNECTION_TIMEOUT)
setTimeoutTestState('ERROR')
setTimeoutTestLabel('Device was able to connect')
} catch (error) {
if (
error instanceof Error &&
(error.message === 'Operation was cancelled' || error.message === 'Operation timed out')
) {
console.info('Timeout test successful: Connection timed out as expected')
setTimeoutTestState('DONE')
setTimeoutTestLabel('Success')
} else {
console.error('Unexpected error during timeout test:', error)
setTimeoutTestState('ERROR')
setTimeoutTestLabel('Error occurred')
}
}
}

const addMonitorMessage = (message: string) => setMonitorMessages(prevMessages => [...prevMessages, message])

const checkDeviceName = (device: Device) =>
device.name?.toLocaleLowerCase() === expectedDeviceName.toLocaleLowerCase()
device.name?.toLocaleLowerCase() === expectedDeviceName?.toLocaleLowerCase()

const startConnectAndDiscover = async () => {
setTestScanDevicesState('IN_PROGRESS')
Expand Down Expand Up @@ -224,6 +273,8 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec
value={connectInDisconnectTestCounter.toString()}
/>
<TestStateDisplay label="Disconnect counter" value={disconnectCounter.toString()} />
<AppButton label="Start Timeout Test" onPress={startTimeoutTest} />
<TestStateDisplay label={timeoutTestLabel} state={timeoutTestState} />
<AppButton label="Setup monitor" onPress={() => startCharacteristicMonitor()} />
<AppButton label="Remove monitor" onPress={monitorSubscriptionRef.current?.remove} />
<TestStateDisplay label="Connect in disconnect test counter" value={JSON.stringify(monitorMessages, null, 4)} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ import { ScrollView } from 'react-native'
import Toast from 'react-native-toast-message'
import { wait } from '../../../utils/wait'
import type { TestStateType } from '../../../types'
import { BLEService } from '../../../services'
import { BLEService, usePersistentDeviceName } from '../../../services'
import type { MainStackParamList } from '../../../navigation/navigators'
import { AppButton, AppTextInput, ScreenDefaultContainer, TestStateDisplay } from '../../../components/atoms'
import { deviceTimeService } from '../../../consts/nRFDeviceConsts'

type DeviceOnDisconnectTestScreenProps = NativeStackScreenProps<MainStackParamList, 'DEVICE_ON_DISCONNECT_TEST_SCREEN'>

export function DeviceOnDisconnectTestScreen(_props: DeviceOnDisconnectTestScreenProps) {
const [expectedDeviceName, setExpectedDeviceName] = useState('')
const [expectedDeviceName, setExpectedDeviceName] = usePersistentDeviceName()
const [testScanDevicesState, setTestScanDevicesState] = useState<TestStateType>('WAITING')
const [deviceId, setDeviceId] = useState('')
const [currentTest, setCurrentTest] = useState<null | 'disconnectByDevice' | 'disconnectByPLX'>(null)
const onDisconnectRef = useRef<Subscription | null>(null)

const checkDeviceName = (device: Device) =>
device.name?.toLocaleLowerCase() === expectedDeviceName.toLocaleLowerCase()
device.name?.toLocaleLowerCase() === expectedDeviceName?.toLocaleLowerCase()

const connectAndDiscover = async () => {
setTestScanDevicesState('IN_PROGRESS')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Device, type Base64 } from 'react-native-ble-plx'
import { Platform, ScrollView } from 'react-native'
import base64 from 'react-native-base64'
import type { TestStateType } from '../../../types'
import { BLEService } from '../../../services'
import { BLEService, usePersistentDeviceName } from '../../../services'
import type { MainStackParamList } from '../../../navigation/navigators'
import { AppButton, AppTextInput, ScreenDefaultContainer, TestStateDisplay } from '../../../components/atoms'
import { wait } from '../../../utils/wait'
Expand All @@ -22,7 +22,7 @@ import {
type DevicenRFTestScreenProps = NativeStackScreenProps<MainStackParamList, 'DEVICE_NRF_TEST_SCREEN'>

export function DevicenRFTestScreen(_props: DevicenRFTestScreenProps) {
const [expectedDeviceName, setExpectedDeviceName] = useState('')
const [expectedDeviceName, setExpectedDeviceName] = usePersistentDeviceName()
const [testScanDevicesState, setTestScanDevicesState] = useState<TestStateType>('WAITING')
const [testDeviceConnectedState, setTestDeviceConnectedState] = useState<TestStateType>('WAITING')
const [testDiscoverServicesAndCharacteristicsFoundState, setTestDiscoverServicesAndCharacteristicsFoundState] =
Expand Down Expand Up @@ -115,7 +115,7 @@ export function DevicenRFTestScreen(_props: DevicenRFTestScreenProps) {
}

const onDeviceFound = (device: Device) => {
if (device.name?.toLocaleLowerCase() === expectedDeviceName.toLocaleLowerCase()) {
if (device.name?.toLocaleLowerCase() === expectedDeviceName?.toLocaleLowerCase()) {
setTestScanDevicesState('DONE')
startConnectToDevice(device)
.then(onDeviceDisconnected)
Expand Down Expand Up @@ -593,7 +593,7 @@ export function DevicenRFTestScreen(_props: DevicenRFTestScreenProps) {
new Promise<void>((resolve, reject) => {
BLEService.scanDevices(
(device: Device) => {
if (device.name?.toLocaleLowerCase() === expectedDeviceName.toLocaleLowerCase()) {
if (device.name?.toLocaleLowerCase() === expectedDeviceName?.toLocaleLowerCase()) {
BLEService.connectToDevice(device.id)
.then(() => BLEService.cancelDeviceConnection())
.then(() => resolve())
Expand Down
8 changes: 6 additions & 2 deletions example/src/services/BLEService/BLEService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,15 @@ class BLEServiceInstance {
.catch(console.error)
}

connectToDevice = (deviceId: DeviceId) =>
stopDeviceScan = () => {
this.manager.stopDeviceScan()
}

connectToDevice = (deviceId: DeviceId, timeout?: number) =>
new Promise<Device>((resolve, reject) => {
this.manager.stopDeviceScan()
this.manager
.connectToDevice(deviceId)
.connectToDevice(deviceId, { timeout })
.then(device => {
this.device = device
resolve(device)
Expand Down
2 changes: 2 additions & 0 deletions example/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './BLEService/BLEService'
export * from './storage/persistentDeviceName'
export * from './storage/storage'
5 changes: 5 additions & 0 deletions example/src/services/storage/persistentDeviceName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { useMMKVString } from 'react-native-mmkv'

export const PERSISTENT_DEVICE_NAME_KEY = 'PERSISTENT_DEVICE_NAME'

export const usePersistentDeviceName = () => useMMKVString(PERSISTENT_DEVICE_NAME_KEY)
3 changes: 3 additions & 0 deletions example/src/services/storage/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { MMKV } from 'react-native-mmkv'

export const storage = new MMKV()
5 changes: 5 additions & 0 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4764,6 +4764,11 @@ react-native-base64@^0.2.1:
resolved "https://registry.yarnpkg.com/react-native-base64/-/react-native-base64-0.2.1.tgz#3d0e73a649c4c0129f7b7695d3912456aebae847"
integrity sha512-eHgt/MA8y5ZF0aHfZ1aTPcIkDWxza9AaEk4GcpIX+ZYfZ04RcaNahO+527KR7J44/mD3efYfM23O2C1N44ByWA==

react-native-mmkv@^2.12.2:
version "2.12.2"
resolved "https://registry.yarnpkg.com/react-native-mmkv/-/react-native-mmkv-2.12.2.tgz#4bba0f5f04e2cf222494cce3a9794ba6a4894dee"
integrity sha512-6058Aq0p57chPrUutLGe9fYoiDVDNMU2PKV+lLFUJ3GhoHvUrLdsS1PDSCLr00yqzL4WJQ7TTzH+V8cpyrNcfg==

react-native-safe-area-context@^4.10.1:
version "4.10.1"
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.10.1.tgz#29fb27395ff7dfa2fa38788a27226330d73a81cc"
Expand Down

0 comments on commit 36f0b56

Please sign in to comment.