@bota-dev/react-native-sdk 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +279 -0
- package/lib/commonjs/BotaClient.js +223 -0
- package/lib/commonjs/BotaClient.js.map +1 -0
- package/lib/commonjs/ble/BleManager.js +494 -0
- package/lib/commonjs/ble/BleManager.js.map +1 -0
- package/lib/commonjs/ble/constants.js +166 -0
- package/lib/commonjs/ble/constants.js.map +1 -0
- package/lib/commonjs/ble/index.js +54 -0
- package/lib/commonjs/ble/index.js.map +1 -0
- package/lib/commonjs/ble/parsers.js +345 -0
- package/lib/commonjs/ble/parsers.js.map +1 -0
- package/lib/commonjs/index.js +81 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/managers/DeviceManager.js +437 -0
- package/lib/commonjs/managers/DeviceManager.js.map +1 -0
- package/lib/commonjs/managers/OTAManager.js +227 -0
- package/lib/commonjs/managers/OTAManager.js.map +1 -0
- package/lib/commonjs/managers/RecordingManager.js +384 -0
- package/lib/commonjs/managers/RecordingManager.js.map +1 -0
- package/lib/commonjs/managers/index.js +27 -0
- package/lib/commonjs/managers/index.js.map +1 -0
- package/lib/commonjs/models/Device.js +2 -0
- package/lib/commonjs/models/Device.js.map +1 -0
- package/lib/commonjs/models/Recording.js +2 -0
- package/lib/commonjs/models/Recording.js.map +1 -0
- package/lib/commonjs/models/Status.js +6 -0
- package/lib/commonjs/models/Status.js.map +1 -0
- package/lib/commonjs/models/index.js +39 -0
- package/lib/commonjs/models/index.js.map +1 -0
- package/lib/commonjs/protocol/ProtocolHandler.js +343 -0
- package/lib/commonjs/protocol/ProtocolHandler.js.map +1 -0
- package/lib/commonjs/protocol/index.js +13 -0
- package/lib/commonjs/protocol/index.js.map +1 -0
- package/lib/commonjs/storage/StorageManager.js +333 -0
- package/lib/commonjs/storage/StorageManager.js.map +1 -0
- package/lib/commonjs/storage/index.js +19 -0
- package/lib/commonjs/storage/index.js.map +1 -0
- package/lib/commonjs/upload/S3Uploader.js +133 -0
- package/lib/commonjs/upload/S3Uploader.js.map +1 -0
- package/lib/commonjs/upload/UploadQueue.js +280 -0
- package/lib/commonjs/upload/UploadQueue.js.map +1 -0
- package/lib/commonjs/upload/index.js +20 -0
- package/lib/commonjs/upload/index.js.map +1 -0
- package/lib/commonjs/utils/errors.js +187 -0
- package/lib/commonjs/utils/errors.js.map +1 -0
- package/lib/commonjs/utils/index.js +40 -0
- package/lib/commonjs/utils/index.js.map +1 -0
- package/lib/commonjs/utils/logger.js +135 -0
- package/lib/commonjs/utils/logger.js.map +1 -0
- package/lib/commonjs/utils/retry.js +160 -0
- package/lib/commonjs/utils/retry.js.map +1 -0
- package/lib/module/BotaClient.js +216 -0
- package/lib/module/BotaClient.js.map +1 -0
- package/lib/module/ble/BleManager.js +484 -0
- package/lib/module/ble/BleManager.js.map +1 -0
- package/lib/module/ble/constants.js +159 -0
- package/lib/module/ble/constants.js.map +1 -0
- package/lib/module/ble/index.js +8 -0
- package/lib/module/ble/index.js.map +1 -0
- package/lib/module/ble/parsers.js +328 -0
- package/lib/module/ble/parsers.js.map +1 -0
- package/lib/module/index.js +22 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/managers/DeviceManager.js +429 -0
- package/lib/module/managers/DeviceManager.js.map +1 -0
- package/lib/module/managers/OTAManager.js +219 -0
- package/lib/module/managers/OTAManager.js.map +1 -0
- package/lib/module/managers/RecordingManager.js +376 -0
- package/lib/module/managers/RecordingManager.js.map +1 -0
- package/lib/module/managers/index.js +8 -0
- package/lib/module/managers/index.js.map +1 -0
- package/lib/module/models/Device.js +2 -0
- package/lib/module/models/Device.js.map +1 -0
- package/lib/module/models/Recording.js +2 -0
- package/lib/module/models/Recording.js.map +1 -0
- package/lib/module/models/Status.js +2 -0
- package/lib/module/models/Status.js.map +1 -0
- package/lib/module/models/index.js +8 -0
- package/lib/module/models/index.js.map +1 -0
- package/lib/module/protocol/ProtocolHandler.js +336 -0
- package/lib/module/protocol/ProtocolHandler.js.map +1 -0
- package/lib/module/protocol/index.js +6 -0
- package/lib/module/protocol/index.js.map +1 -0
- package/lib/module/storage/StorageManager.js +324 -0
- package/lib/module/storage/StorageManager.js.map +1 -0
- package/lib/module/storage/index.js +6 -0
- package/lib/module/storage/index.js.map +1 -0
- package/lib/module/upload/S3Uploader.js +126 -0
- package/lib/module/upload/S3Uploader.js.map +1 -0
- package/lib/module/upload/UploadQueue.js +272 -0
- package/lib/module/upload/UploadQueue.js.map +1 -0
- package/lib/module/upload/index.js +7 -0
- package/lib/module/upload/index.js.map +1 -0
- package/lib/module/utils/errors.js +173 -0
- package/lib/module/utils/errors.js.map +1 -0
- package/lib/module/utils/index.js +8 -0
- package/lib/module/utils/index.js.map +1 -0
- package/lib/module/utils/logger.js +129 -0
- package/lib/module/utils/logger.js.map +1 -0
- package/lib/module/utils/retry.js +149 -0
- package/lib/module/utils/retry.js.map +1 -0
- package/lib/typescript/src/BotaClient.d.ts +77 -0
- package/lib/typescript/src/BotaClient.d.ts.map +1 -0
- package/lib/typescript/src/ble/BleManager.d.ts +111 -0
- package/lib/typescript/src/ble/BleManager.d.ts.map +1 -0
- package/lib/typescript/src/ble/constants.d.ts +111 -0
- package/lib/typescript/src/ble/constants.d.ts.map +1 -0
- package/lib/typescript/src/ble/index.d.ts +7 -0
- package/lib/typescript/src/ble/index.d.ts.map +1 -0
- package/lib/typescript/src/ble/parsers.d.ts +100 -0
- package/lib/typescript/src/ble/parsers.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +16 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/managers/DeviceManager.d.ts +84 -0
- package/lib/typescript/src/managers/DeviceManager.d.ts.map +1 -0
- package/lib/typescript/src/managers/OTAManager.d.ts +78 -0
- package/lib/typescript/src/managers/OTAManager.d.ts.map +1 -0
- package/lib/typescript/src/managers/RecordingManager.d.ts +90 -0
- package/lib/typescript/src/managers/RecordingManager.d.ts.map +1 -0
- package/lib/typescript/src/managers/index.d.ts +7 -0
- package/lib/typescript/src/managers/index.d.ts.map +1 -0
- package/lib/typescript/src/models/Device.d.ts +139 -0
- package/lib/typescript/src/models/Device.d.ts.map +1 -0
- package/lib/typescript/src/models/Recording.d.ts +110 -0
- package/lib/typescript/src/models/Recording.d.ts.map +1 -0
- package/lib/typescript/src/models/Status.d.ts +104 -0
- package/lib/typescript/src/models/Status.d.ts.map +1 -0
- package/lib/typescript/src/models/index.d.ts +7 -0
- package/lib/typescript/src/models/index.d.ts.map +1 -0
- package/lib/typescript/src/protocol/ProtocolHandler.d.ts +69 -0
- package/lib/typescript/src/protocol/ProtocolHandler.d.ts.map +1 -0
- package/lib/typescript/src/protocol/index.d.ts +5 -0
- package/lib/typescript/src/protocol/index.d.ts.map +1 -0
- package/lib/typescript/src/storage/StorageManager.d.ts +116 -0
- package/lib/typescript/src/storage/StorageManager.d.ts.map +1 -0
- package/lib/typescript/src/storage/index.d.ts +5 -0
- package/lib/typescript/src/storage/index.d.ts.map +1 -0
- package/lib/typescript/src/upload/S3Uploader.d.ts +38 -0
- package/lib/typescript/src/upload/S3Uploader.d.ts.map +1 -0
- package/lib/typescript/src/upload/UploadQueue.d.ts +95 -0
- package/lib/typescript/src/upload/UploadQueue.d.ts.map +1 -0
- package/lib/typescript/src/upload/index.d.ts +6 -0
- package/lib/typescript/src/upload/index.d.ts.map +1 -0
- package/lib/typescript/src/utils/errors.d.ts +82 -0
- package/lib/typescript/src/utils/errors.d.ts.map +1 -0
- package/lib/typescript/src/utils/index.d.ts +7 -0
- package/lib/typescript/src/utils/index.d.ts.map +1 -0
- package/lib/typescript/src/utils/logger.d.ts +68 -0
- package/lib/typescript/src/utils/logger.d.ts.map +1 -0
- package/lib/typescript/src/utils/retry.d.ts +53 -0
- package/lib/typescript/src/utils/retry.d.ts.map +1 -0
- package/package.json +95 -0
- package/src/BotaClient.ts +238 -0
- package/src/ble/BleManager.ts +573 -0
- package/src/ble/constants.ts +158 -0
- package/src/ble/index.ts +7 -0
- package/src/ble/parsers.ts +395 -0
- package/src/index.ts +64 -0
- package/src/managers/DeviceManager.ts +545 -0
- package/src/managers/OTAManager.ts +263 -0
- package/src/managers/RecordingManager.ts +434 -0
- package/src/managers/index.ts +12 -0
- package/src/models/Device.ts +164 -0
- package/src/models/Recording.ts +123 -0
- package/src/models/Status.ts +126 -0
- package/src/models/index.ts +7 -0
- package/src/protocol/ProtocolHandler.ts +459 -0
- package/src/protocol/index.ts +5 -0
- package/src/storage/StorageManager.ts +343 -0
- package/src/storage/index.ts +5 -0
- package/src/upload/S3Uploader.ts +164 -0
- package/src/upload/UploadQueue.ts +310 -0
- package/src/upload/index.ts +6 -0
- package/src/utils/errors.ts +310 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/logger.ts +137 -0
- package/src/utils/retry.ts +177 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLE Service and Characteristic UUIDs for Bota devices
|
|
3
|
+
* Based on Device-App Protocol specification
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Standard Bluetooth SIG Services
|
|
7
|
+
export const SERVICE_DEVICE_INFO = '180A';
|
|
8
|
+
export const SERVICE_BATTERY = '180F';
|
|
9
|
+
export const SERVICE_NORDIC_DFU = 'FE59';
|
|
10
|
+
|
|
11
|
+
// Bota Custom Services
|
|
12
|
+
export const SERVICE_BOTA_AUDIO = 'B07A0001-0000-1000-8000-00805F9B34FB';
|
|
13
|
+
export const SERVICE_BOTA_CONTROL = 'B07A0002-0000-1000-8000-00805F9B34FB';
|
|
14
|
+
export const SERVICE_BOTA_PROVISIONING = 'B07A0003-0000-1000-8000-00805F9B34FB';
|
|
15
|
+
export const SERVICE_BOTA_STORAGE = 'B07A0004-0000-1000-8000-00805F9B34FB';
|
|
16
|
+
|
|
17
|
+
// Device Information Service Characteristics (0x180A)
|
|
18
|
+
export const CHAR_MANUFACTURER_NAME = '2A29';
|
|
19
|
+
export const CHAR_MODEL_NUMBER = '2A24';
|
|
20
|
+
export const CHAR_SERIAL_NUMBER = '2A25';
|
|
21
|
+
export const CHAR_HARDWARE_REVISION = '2A27';
|
|
22
|
+
export const CHAR_FIRMWARE_REVISION = '2A26';
|
|
23
|
+
|
|
24
|
+
// Battery Service Characteristics (0x180F)
|
|
25
|
+
export const CHAR_BATTERY_LEVEL = '2A19';
|
|
26
|
+
|
|
27
|
+
// Bota Audio Service Characteristics (B07A0001)
|
|
28
|
+
export const CHAR_AUDIO_DATA = 'B07A0001-0001-1000-8000-00805F9B34FB';
|
|
29
|
+
export const CHAR_AUDIO_CODEC = 'B07A0001-0002-1000-8000-00805F9B34FB';
|
|
30
|
+
export const CHAR_AUDIO_CONTROL = 'B07A0001-0003-1000-8000-00805F9B34FB';
|
|
31
|
+
|
|
32
|
+
// Bota Control Service Characteristics (B07A0002)
|
|
33
|
+
export const CHAR_DEVICE_STATUS = 'B07A0002-0001-1000-8000-00805F9B34FB';
|
|
34
|
+
export const CHAR_RECORDING_CONTROL = 'B07A0002-0002-1000-8000-00805F9B34FB';
|
|
35
|
+
export const CHAR_RECORDING_STATUS = 'B07A0002-0003-1000-8000-00805F9B34FB';
|
|
36
|
+
export const CHAR_TIME_SYNC = 'B07A0002-0004-1000-8000-00805F9B34FB';
|
|
37
|
+
export const CHAR_DEVICE_COMMAND = 'B07A0002-0005-1000-8000-00805F9B34FB';
|
|
38
|
+
|
|
39
|
+
// Bota Provisioning Service Characteristics (B07A0003)
|
|
40
|
+
export const CHAR_PAIRING_STATE = 'B07A0003-0001-1000-8000-00805F9B34FB';
|
|
41
|
+
export const CHAR_DEVICE_TOKEN = 'B07A0003-0002-1000-8000-00805F9B34FB';
|
|
42
|
+
export const CHAR_API_ENDPOINT = 'B07A0003-0003-1000-8000-00805F9B34FB';
|
|
43
|
+
export const CHAR_WIFI_CONFIG = 'B07A0003-0004-1000-8000-00805F9B34FB';
|
|
44
|
+
export const CHAR_PROVISIONING_RESULT = 'B07A0003-0005-1000-8000-00805F9B34FB';
|
|
45
|
+
|
|
46
|
+
// Bota Storage Service Characteristics (B07A0004)
|
|
47
|
+
export const CHAR_STORAGE_INFO = 'B07A0004-0001-1000-8000-00805F9B34FB';
|
|
48
|
+
export const CHAR_RECORDING_LIST = 'B07A0004-0002-1000-8000-00805F9B34FB';
|
|
49
|
+
export const CHAR_RECORDING_TRANSFER = 'B07A0004-0003-1000-8000-00805F9B34FB';
|
|
50
|
+
export const CHAR_TRANSFER_CONTROL = 'B07A0004-0004-1000-8000-00805F9B34FB';
|
|
51
|
+
export const CHAR_TRANSFER_STATUS = 'B07A0004-0005-1000-8000-00805F9B34FB';
|
|
52
|
+
|
|
53
|
+
// Device name prefixes for scanning
|
|
54
|
+
export const DEVICE_NAME_PREFIX = 'Bota-';
|
|
55
|
+
export const DEVICE_NAME_PREFIX_PIN = 'Bota-Pin-';
|
|
56
|
+
export const DEVICE_NAME_PREFIX_PIN_4G = 'Bota-Pin4G-';
|
|
57
|
+
export const DEVICE_NAME_PREFIX_NOTE = 'Bota-Note-';
|
|
58
|
+
|
|
59
|
+
// Manufacturer data byte positions
|
|
60
|
+
export const MFG_DATA_DEVICE_TYPE = 0;
|
|
61
|
+
export const MFG_DATA_FW_MAJOR = 1;
|
|
62
|
+
export const MFG_DATA_FW_MINOR = 2;
|
|
63
|
+
export const MFG_DATA_PAIRING_STATE = 3;
|
|
64
|
+
export const MFG_DATA_BATTERY = 4;
|
|
65
|
+
|
|
66
|
+
// Device type values in manufacturer data
|
|
67
|
+
export const DEVICE_TYPE_PIN = 0x01;
|
|
68
|
+
export const DEVICE_TYPE_PIN_4G = 0x02;
|
|
69
|
+
export const DEVICE_TYPE_NOTE = 0x03;
|
|
70
|
+
|
|
71
|
+
// Pairing state values
|
|
72
|
+
export const PAIRING_STATE_UNPAIRED = 0x00;
|
|
73
|
+
export const PAIRING_STATE_PAIRING = 0x01;
|
|
74
|
+
export const PAIRING_STATE_PAIRED = 0x02;
|
|
75
|
+
export const PAIRING_STATE_ERROR = 0x03;
|
|
76
|
+
|
|
77
|
+
// Provisioning result codes
|
|
78
|
+
export const PROVISIONING_SUCCESS = 0x00;
|
|
79
|
+
export const PROVISIONING_INVALID_TOKEN = 0x01;
|
|
80
|
+
export const PROVISIONING_STORAGE_ERROR = 0x02;
|
|
81
|
+
export const PROVISIONING_CHUNK_ERROR = 0x03;
|
|
82
|
+
|
|
83
|
+
// API endpoint values
|
|
84
|
+
export const API_ENDPOINT_PRODUCTION = 0x00;
|
|
85
|
+
export const API_ENDPOINT_SANDBOX = 0x01;
|
|
86
|
+
|
|
87
|
+
// Transfer control commands
|
|
88
|
+
export const TRANSFER_CMD_LIST = 0x01;
|
|
89
|
+
export const TRANSFER_CMD_START = 0x02;
|
|
90
|
+
export const TRANSFER_CMD_CONFIRM_SYNC = 0x07;
|
|
91
|
+
|
|
92
|
+
// Transfer packet types (Device → App)
|
|
93
|
+
export const PACKET_TYPE_DATA = 0x01;
|
|
94
|
+
export const PACKET_TYPE_EOF = 0x02;
|
|
95
|
+
export const PACKET_TYPE_ERROR = 0xff;
|
|
96
|
+
|
|
97
|
+
// ACK types (App → Device)
|
|
98
|
+
export const ACK_TYPE_ACK = 0x10;
|
|
99
|
+
export const ACK_TYPE_NACK = 0x11;
|
|
100
|
+
export const ACK_TYPE_ABORT = 0x12;
|
|
101
|
+
|
|
102
|
+
// Device command values
|
|
103
|
+
export const DEVICE_CMD_ENTER_DFU = 0x03;
|
|
104
|
+
|
|
105
|
+
// Device state values (from status)
|
|
106
|
+
export const DEVICE_STATE_IDLE = 0x00;
|
|
107
|
+
export const DEVICE_STATE_RECORDING = 0x01;
|
|
108
|
+
export const DEVICE_STATE_SYNCING = 0x02;
|
|
109
|
+
export const DEVICE_STATE_UPLOADING = 0x03;
|
|
110
|
+
export const DEVICE_STATE_CHARGING = 0x04;
|
|
111
|
+
export const DEVICE_STATE_LOW_BATTERY = 0x05;
|
|
112
|
+
export const DEVICE_STATE_STORAGE_FULL = 0x06;
|
|
113
|
+
export const DEVICE_STATE_ERROR = 0xff;
|
|
114
|
+
|
|
115
|
+
// Device status flags (bitmask)
|
|
116
|
+
export const FLAG_CHARGING = 1 << 0;
|
|
117
|
+
export const FLAG_USB_CONNECTED = 1 << 1;
|
|
118
|
+
export const FLAG_LOW_BATTERY = 1 << 2;
|
|
119
|
+
export const FLAG_CRITICAL_BATTERY = 1 << 3;
|
|
120
|
+
export const FLAG_STORAGE_WARNING = 1 << 4;
|
|
121
|
+
export const FLAG_STORAGE_FULL = 1 << 5;
|
|
122
|
+
export const FLAG_CELLULAR_AVAILABLE = 1 << 6;
|
|
123
|
+
export const FLAG_CELLULAR_ROAMING = 1 << 7;
|
|
124
|
+
export const FLAG_WIFI_CONNECTED = 1 << 8;
|
|
125
|
+
export const FLAG_RECORDING_ACTIVE = 1 << 9;
|
|
126
|
+
export const FLAG_SYNC_REQUIRED = 1 << 10;
|
|
127
|
+
export const FLAG_UPDATE_AVAILABLE = 1 << 11;
|
|
128
|
+
|
|
129
|
+
// Audio codec values
|
|
130
|
+
export const CODEC_PCM_16K = 0x00;
|
|
131
|
+
export const CODEC_PCM_8K = 0x01;
|
|
132
|
+
export const CODEC_OPUS_16K = 0x10;
|
|
133
|
+
export const CODEC_OPUS_8K = 0x11;
|
|
134
|
+
|
|
135
|
+
// BLE error codes
|
|
136
|
+
export const BLE_ERROR_SUCCESS = 0x00;
|
|
137
|
+
export const BLE_ERROR_INVALID_COMMAND = 0x01;
|
|
138
|
+
export const BLE_ERROR_INVALID_STATE = 0x02;
|
|
139
|
+
export const BLE_ERROR_INVALID_PARAMETER = 0x03;
|
|
140
|
+
export const BLE_ERROR_STORAGE_FULL = 0x10;
|
|
141
|
+
export const BLE_ERROR_RECORDING_NOT_FOUND = 0x11;
|
|
142
|
+
export const BLE_ERROR_TRANSFER_FAILED = 0x12;
|
|
143
|
+
export const BLE_ERROR_TOKEN_INVALID = 0x20;
|
|
144
|
+
export const BLE_ERROR_TOKEN_EXPIRED = 0x21;
|
|
145
|
+
export const BLE_ERROR_NETWORK_ERROR = 0x30;
|
|
146
|
+
export const BLE_ERROR_UPLOAD_FAILED = 0x31;
|
|
147
|
+
export const BLE_ERROR_UNKNOWN = 0xff;
|
|
148
|
+
|
|
149
|
+
// Timeouts (ms)
|
|
150
|
+
export const SCAN_TIMEOUT = 30000;
|
|
151
|
+
export const CONNECTION_TIMEOUT = 30000;
|
|
152
|
+
export const OPERATION_TIMEOUT = 10000;
|
|
153
|
+
export const TRANSFER_PACKET_TIMEOUT = 2000;
|
|
154
|
+
|
|
155
|
+
// Transfer settings
|
|
156
|
+
export const TRANSFER_WINDOW_SIZE = 4;
|
|
157
|
+
export const DEFAULT_MTU = 23;
|
|
158
|
+
export const MAX_MTU = 512;
|
package/src/ble/index.ts
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLE data parsers for Bota device protocol
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Buffer } from 'buffer';
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
DeviceType,
|
|
9
|
+
PairingState,
|
|
10
|
+
DeviceState,
|
|
11
|
+
DeviceStatus,
|
|
12
|
+
DeviceFlags,
|
|
13
|
+
StorageInfo,
|
|
14
|
+
} from '../models/Device';
|
|
15
|
+
import type { DeviceRecording, AudioCodec, TransferPacket } from '../models/Recording';
|
|
16
|
+
import {
|
|
17
|
+
DEVICE_TYPE_PIN,
|
|
18
|
+
DEVICE_TYPE_PIN_4G,
|
|
19
|
+
DEVICE_TYPE_NOTE,
|
|
20
|
+
PAIRING_STATE_UNPAIRED,
|
|
21
|
+
PAIRING_STATE_PAIRING,
|
|
22
|
+
PAIRING_STATE_PAIRED,
|
|
23
|
+
PAIRING_STATE_ERROR,
|
|
24
|
+
DEVICE_STATE_IDLE,
|
|
25
|
+
DEVICE_STATE_RECORDING,
|
|
26
|
+
DEVICE_STATE_SYNCING,
|
|
27
|
+
DEVICE_STATE_UPLOADING,
|
|
28
|
+
DEVICE_STATE_CHARGING,
|
|
29
|
+
DEVICE_STATE_LOW_BATTERY,
|
|
30
|
+
DEVICE_STATE_STORAGE_FULL,
|
|
31
|
+
DEVICE_STATE_ERROR,
|
|
32
|
+
FLAG_CHARGING,
|
|
33
|
+
FLAG_USB_CONNECTED,
|
|
34
|
+
FLAG_LOW_BATTERY,
|
|
35
|
+
FLAG_CRITICAL_BATTERY,
|
|
36
|
+
FLAG_STORAGE_WARNING,
|
|
37
|
+
FLAG_STORAGE_FULL,
|
|
38
|
+
FLAG_CELLULAR_AVAILABLE,
|
|
39
|
+
FLAG_CELLULAR_ROAMING,
|
|
40
|
+
FLAG_WIFI_CONNECTED,
|
|
41
|
+
FLAG_RECORDING_ACTIVE,
|
|
42
|
+
FLAG_SYNC_REQUIRED,
|
|
43
|
+
FLAG_UPDATE_AVAILABLE,
|
|
44
|
+
CODEC_PCM_16K,
|
|
45
|
+
CODEC_PCM_8K,
|
|
46
|
+
CODEC_OPUS_16K,
|
|
47
|
+
CODEC_OPUS_8K,
|
|
48
|
+
PACKET_TYPE_DATA,
|
|
49
|
+
PACKET_TYPE_EOF,
|
|
50
|
+
PACKET_TYPE_ERROR,
|
|
51
|
+
} from './constants';
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Parse device type from manufacturer data byte
|
|
55
|
+
*/
|
|
56
|
+
export function parseDeviceType(byte: number): DeviceType {
|
|
57
|
+
switch (byte) {
|
|
58
|
+
case DEVICE_TYPE_PIN:
|
|
59
|
+
return 'bota_pin';
|
|
60
|
+
case DEVICE_TYPE_PIN_4G:
|
|
61
|
+
return 'bota_pin_4g';
|
|
62
|
+
case DEVICE_TYPE_NOTE:
|
|
63
|
+
return 'bota_note';
|
|
64
|
+
default:
|
|
65
|
+
return 'bota_pin';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Parse pairing state from manufacturer data byte
|
|
71
|
+
*/
|
|
72
|
+
export function parsePairingState(byte: number): PairingState {
|
|
73
|
+
switch (byte) {
|
|
74
|
+
case PAIRING_STATE_UNPAIRED:
|
|
75
|
+
return 'unpaired';
|
|
76
|
+
case PAIRING_STATE_PAIRING:
|
|
77
|
+
return 'pairing';
|
|
78
|
+
case PAIRING_STATE_PAIRED:
|
|
79
|
+
return 'paired';
|
|
80
|
+
case PAIRING_STATE_ERROR:
|
|
81
|
+
return 'error';
|
|
82
|
+
default:
|
|
83
|
+
return 'unpaired';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Parse firmware version from major/minor bytes
|
|
89
|
+
*/
|
|
90
|
+
export function parseFirmwareVersion(major: number, minor: number): string {
|
|
91
|
+
return `${major}.${minor}.0`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Parse device state from status byte
|
|
96
|
+
*/
|
|
97
|
+
export function parseDeviceState(byte: number): DeviceState {
|
|
98
|
+
switch (byte) {
|
|
99
|
+
case DEVICE_STATE_IDLE:
|
|
100
|
+
return 'idle';
|
|
101
|
+
case DEVICE_STATE_RECORDING:
|
|
102
|
+
return 'recording';
|
|
103
|
+
case DEVICE_STATE_SYNCING:
|
|
104
|
+
return 'syncing';
|
|
105
|
+
case DEVICE_STATE_UPLOADING:
|
|
106
|
+
return 'uploading';
|
|
107
|
+
case DEVICE_STATE_CHARGING:
|
|
108
|
+
return 'charging';
|
|
109
|
+
case DEVICE_STATE_LOW_BATTERY:
|
|
110
|
+
return 'lowBattery';
|
|
111
|
+
case DEVICE_STATE_STORAGE_FULL:
|
|
112
|
+
return 'storageFull';
|
|
113
|
+
case DEVICE_STATE_ERROR:
|
|
114
|
+
return 'error';
|
|
115
|
+
default:
|
|
116
|
+
return 'idle';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Parse device flags from 16-bit value
|
|
122
|
+
*/
|
|
123
|
+
export function parseDeviceFlags(value: number): DeviceFlags {
|
|
124
|
+
return {
|
|
125
|
+
charging: (value & FLAG_CHARGING) !== 0,
|
|
126
|
+
usbConnected: (value & FLAG_USB_CONNECTED) !== 0,
|
|
127
|
+
lowBattery: (value & FLAG_LOW_BATTERY) !== 0,
|
|
128
|
+
criticalBattery: (value & FLAG_CRITICAL_BATTERY) !== 0,
|
|
129
|
+
storageWarning: (value & FLAG_STORAGE_WARNING) !== 0,
|
|
130
|
+
storageFull: (value & FLAG_STORAGE_FULL) !== 0,
|
|
131
|
+
cellularAvailable: (value & FLAG_CELLULAR_AVAILABLE) !== 0,
|
|
132
|
+
cellularRoaming: (value & FLAG_CELLULAR_ROAMING) !== 0,
|
|
133
|
+
wifiConnected: (value & FLAG_WIFI_CONNECTED) !== 0,
|
|
134
|
+
recordingActive: (value & FLAG_RECORDING_ACTIVE) !== 0,
|
|
135
|
+
syncRequired: (value & FLAG_SYNC_REQUIRED) !== 0,
|
|
136
|
+
updateAvailable: (value & FLAG_UPDATE_AVAILABLE) !== 0,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Parse device status from 16-byte characteristic value
|
|
142
|
+
*
|
|
143
|
+
* Format:
|
|
144
|
+
* Bytes 0-3: Timestamp (Unix seconds)
|
|
145
|
+
* Byte 4: Battery % (0-100)
|
|
146
|
+
* Byte 5: State
|
|
147
|
+
* Byte 6: Storage % (0-100)
|
|
148
|
+
* Byte 7: Signal (0-5)
|
|
149
|
+
* Bytes 8-9: Pending recordings count
|
|
150
|
+
* Bytes 10-13: Last sync time (Unix seconds)
|
|
151
|
+
* Bytes 14-15: Flags
|
|
152
|
+
*/
|
|
153
|
+
export function parseDeviceStatus(data: Buffer): DeviceStatus {
|
|
154
|
+
if (data.length < 16) {
|
|
155
|
+
throw new Error(`Invalid status data length: ${data.length}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const timestamp = data.readUInt32LE(0);
|
|
159
|
+
const batteryLevel = data.readUInt8(4);
|
|
160
|
+
const state = parseDeviceState(data.readUInt8(5));
|
|
161
|
+
const storageUsedPercent = data.readUInt8(6);
|
|
162
|
+
const signalStrength = data.readUInt8(7);
|
|
163
|
+
const pendingRecordings = data.readUInt16LE(8);
|
|
164
|
+
const lastSyncTimestamp = data.readUInt32LE(10);
|
|
165
|
+
const flagsValue = data.readUInt16LE(14);
|
|
166
|
+
const flags = parseDeviceFlags(flagsValue);
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
batteryLevel,
|
|
170
|
+
storageUsedPercent,
|
|
171
|
+
state,
|
|
172
|
+
pendingRecordings,
|
|
173
|
+
lastSyncAt: lastSyncTimestamp > 0 ? new Date(lastSyncTimestamp * 1000) : null,
|
|
174
|
+
signalStrength,
|
|
175
|
+
flags,
|
|
176
|
+
timestamp,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Parse storage info from 16-byte characteristic value
|
|
182
|
+
*
|
|
183
|
+
* Format:
|
|
184
|
+
* Bytes 0-3: Total storage (KB)
|
|
185
|
+
* Bytes 4-7: Used storage (KB)
|
|
186
|
+
* Bytes 8-9: Total recording count
|
|
187
|
+
* Bytes 10-11: Pending sync count
|
|
188
|
+
* Bytes 12-15: Reserved
|
|
189
|
+
*/
|
|
190
|
+
export function parseStorageInfo(data: Buffer): StorageInfo {
|
|
191
|
+
if (data.length < 12) {
|
|
192
|
+
throw new Error(`Invalid storage info length: ${data.length}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
totalKb: data.readUInt32LE(0),
|
|
197
|
+
usedKb: data.readUInt32LE(4),
|
|
198
|
+
totalRecordings: data.readUInt16LE(8),
|
|
199
|
+
pendingSyncCount: data.readUInt16LE(10),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Parse audio codec from byte value
|
|
205
|
+
*/
|
|
206
|
+
export function parseAudioCodec(byte: number): AudioCodec {
|
|
207
|
+
switch (byte) {
|
|
208
|
+
case CODEC_PCM_16K:
|
|
209
|
+
return 'pcm_16k';
|
|
210
|
+
case CODEC_PCM_8K:
|
|
211
|
+
return 'pcm_8k';
|
|
212
|
+
case CODEC_OPUS_16K:
|
|
213
|
+
return 'opus_16k';
|
|
214
|
+
case CODEC_OPUS_8K:
|
|
215
|
+
return 'opus_8k';
|
|
216
|
+
default:
|
|
217
|
+
return 'opus_16k';
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Parse recording list from notification data
|
|
223
|
+
* Each recording entry is typically 24 bytes:
|
|
224
|
+
* - UUID: 16 bytes
|
|
225
|
+
* - Timestamp: 4 bytes (Unix seconds)
|
|
226
|
+
* - Duration: 2 bytes (seconds)
|
|
227
|
+
* - Size: 2 bytes (KB, or needs scaling)
|
|
228
|
+
*/
|
|
229
|
+
export function parseRecordingList(data: Buffer): DeviceRecording[] {
|
|
230
|
+
const recordings: DeviceRecording[] = [];
|
|
231
|
+
const entrySize = 24;
|
|
232
|
+
|
|
233
|
+
// First byte might be count
|
|
234
|
+
let offset = 0;
|
|
235
|
+
if (data.length > 0 && data.length % entrySize !== 0) {
|
|
236
|
+
// Skip count byte
|
|
237
|
+
offset = 1;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
while (offset + entrySize <= data.length) {
|
|
241
|
+
const uuid = formatUuid(data.slice(offset, offset + 16));
|
|
242
|
+
const timestamp = data.readUInt32LE(offset + 16);
|
|
243
|
+
const durationSeconds = data.readUInt16LE(offset + 20);
|
|
244
|
+
const sizeKb = data.readUInt16LE(offset + 22);
|
|
245
|
+
|
|
246
|
+
recordings.push({
|
|
247
|
+
uuid,
|
|
248
|
+
startedAt: new Date(timestamp * 1000),
|
|
249
|
+
durationMs: durationSeconds * 1000,
|
|
250
|
+
fileSizeBytes: sizeKb * 1024,
|
|
251
|
+
codec: 'opus_16k', // Default, actual codec read separately
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
offset += entrySize;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return recordings;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Format 16-byte UUID buffer to string
|
|
262
|
+
*/
|
|
263
|
+
function formatUuid(data: Buffer): string {
|
|
264
|
+
const hex = data.toString('hex');
|
|
265
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Parse transfer packet from device
|
|
270
|
+
*
|
|
271
|
+
* Format:
|
|
272
|
+
* Byte 0: Packet type (0x01=data, 0x02=EOF, 0xFF=error)
|
|
273
|
+
* Bytes 1-2: Sequence number
|
|
274
|
+
* Bytes 3-4: Chunk size (data) or CRC32 start (EOF)
|
|
275
|
+
* Bytes 5+: Audio data (data) or CRC32 remainder (EOF)
|
|
276
|
+
*/
|
|
277
|
+
export function parseTransferPacket(data: Buffer): TransferPacket {
|
|
278
|
+
if (data.length < 3) {
|
|
279
|
+
throw new Error(`Invalid transfer packet length: ${data.length}`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const type = data.readUInt8(0);
|
|
283
|
+
const sequenceNumber = data.readUInt16LE(1);
|
|
284
|
+
|
|
285
|
+
switch (type) {
|
|
286
|
+
case PACKET_TYPE_DATA:
|
|
287
|
+
return {
|
|
288
|
+
type: 'data',
|
|
289
|
+
sequenceNumber,
|
|
290
|
+
data: data.slice(5), // Skip header
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
case PACKET_TYPE_EOF:
|
|
294
|
+
return {
|
|
295
|
+
type: 'eof',
|
|
296
|
+
sequenceNumber,
|
|
297
|
+
checksum: data.readUInt32LE(3),
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
case PACKET_TYPE_ERROR:
|
|
301
|
+
return {
|
|
302
|
+
type: 'error',
|
|
303
|
+
sequenceNumber,
|
|
304
|
+
errorCode: data.length > 3 ? data.readUInt8(3) : 0xff,
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
default:
|
|
308
|
+
throw new Error(`Unknown packet type: ${type}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Create time sync data buffer
|
|
314
|
+
*
|
|
315
|
+
* Format:
|
|
316
|
+
* Bytes 0-3: Unix timestamp (seconds)
|
|
317
|
+
* Bytes 4-5: Milliseconds (0-999)
|
|
318
|
+
* Bytes 6-7: Timezone offset (signed, minutes from UTC)
|
|
319
|
+
*/
|
|
320
|
+
export function createTimeSyncData(date: Date = new Date()): Buffer {
|
|
321
|
+
const buffer = Buffer.alloc(8);
|
|
322
|
+
const unixSeconds = Math.floor(date.getTime() / 1000);
|
|
323
|
+
const milliseconds = date.getMilliseconds();
|
|
324
|
+
const timezoneOffset = -date.getTimezoneOffset(); // getTimezoneOffset returns opposite sign
|
|
325
|
+
|
|
326
|
+
buffer.writeUInt32LE(unixSeconds, 0);
|
|
327
|
+
buffer.writeUInt16LE(milliseconds, 4);
|
|
328
|
+
buffer.writeInt16LE(timezoneOffset, 6);
|
|
329
|
+
|
|
330
|
+
return buffer;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Create ACK packet for transfer
|
|
335
|
+
*
|
|
336
|
+
* Format:
|
|
337
|
+
* Byte 0: ACK type (0x10=ACK, 0x11=NACK, 0x12=Abort)
|
|
338
|
+
* Bytes 1-2: Sequence number
|
|
339
|
+
*/
|
|
340
|
+
export function createAckPacket(
|
|
341
|
+
ackType: 'ack' | 'nack' | 'abort',
|
|
342
|
+
sequenceNumber: number
|
|
343
|
+
): Buffer {
|
|
344
|
+
const buffer = Buffer.alloc(3);
|
|
345
|
+
|
|
346
|
+
switch (ackType) {
|
|
347
|
+
case 'ack':
|
|
348
|
+
buffer.writeUInt8(0x10, 0);
|
|
349
|
+
break;
|
|
350
|
+
case 'nack':
|
|
351
|
+
buffer.writeUInt8(0x11, 0);
|
|
352
|
+
break;
|
|
353
|
+
case 'abort':
|
|
354
|
+
buffer.writeUInt8(0x12, 0);
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
buffer.writeUInt16LE(sequenceNumber, 1);
|
|
359
|
+
return buffer;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Create transfer control command
|
|
364
|
+
*
|
|
365
|
+
* Format:
|
|
366
|
+
* Byte 0: Command (0x01=list, 0x02=start, 0x07=confirm)
|
|
367
|
+
* Bytes 1+: Recording UUID (for start/confirm)
|
|
368
|
+
*/
|
|
369
|
+
export function createTransferCommand(
|
|
370
|
+
command: 'list' | 'start' | 'confirm',
|
|
371
|
+
recordingUuid?: string
|
|
372
|
+
): Buffer {
|
|
373
|
+
let cmdByte: number;
|
|
374
|
+
switch (command) {
|
|
375
|
+
case 'list':
|
|
376
|
+
cmdByte = 0x01;
|
|
377
|
+
break;
|
|
378
|
+
case 'start':
|
|
379
|
+
cmdByte = 0x02;
|
|
380
|
+
break;
|
|
381
|
+
case 'confirm':
|
|
382
|
+
cmdByte = 0x07;
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (recordingUuid) {
|
|
387
|
+
const uuidBuffer = Buffer.from(recordingUuid.replace(/-/g, ''), 'hex');
|
|
388
|
+
const buffer = Buffer.alloc(1 + uuidBuffer.length);
|
|
389
|
+
buffer.writeUInt8(cmdByte, 0);
|
|
390
|
+
uuidBuffer.copy(buffer, 1);
|
|
391
|
+
return buffer;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return Buffer.from([cmdByte]);
|
|
395
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bota React Native SDK
|
|
3
|
+
*
|
|
4
|
+
* SDK for communicating with Bota wearable devices via BLE.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Main client
|
|
10
|
+
export { BotaClient } from './BotaClient';
|
|
11
|
+
export type { BotaConfig, SdkState, BluetoothState } from './BotaClient';
|
|
12
|
+
|
|
13
|
+
// Managers
|
|
14
|
+
export { DeviceManager, RecordingManager, OTAManager } from './managers';
|
|
15
|
+
export type { UploadInfoProvider, FirmwareInfo, OtaStage, OtaProgress } from './managers';
|
|
16
|
+
|
|
17
|
+
// Models - Device
|
|
18
|
+
export type {
|
|
19
|
+
DeviceType,
|
|
20
|
+
PairingState,
|
|
21
|
+
ConnectionState,
|
|
22
|
+
DeviceState,
|
|
23
|
+
DeviceFlags,
|
|
24
|
+
DiscoveredDevice,
|
|
25
|
+
ConnectedDevice,
|
|
26
|
+
DeviceStatus,
|
|
27
|
+
StorageInfo,
|
|
28
|
+
ScanOptions,
|
|
29
|
+
Environment,
|
|
30
|
+
ProvisioningResult,
|
|
31
|
+
} from './models/Device';
|
|
32
|
+
|
|
33
|
+
// Models - Recording
|
|
34
|
+
export type {
|
|
35
|
+
AudioCodec,
|
|
36
|
+
DeviceRecording,
|
|
37
|
+
UploadInfo,
|
|
38
|
+
SyncStage,
|
|
39
|
+
SyncProgress,
|
|
40
|
+
UploadTaskStatus,
|
|
41
|
+
UploadTask,
|
|
42
|
+
TransferPacket,
|
|
43
|
+
} from './models/Recording';
|
|
44
|
+
|
|
45
|
+
// Models - Status & Events
|
|
46
|
+
export type {
|
|
47
|
+
LogLevel,
|
|
48
|
+
SdkStatus,
|
|
49
|
+
DeviceManagerEvents,
|
|
50
|
+
RecordingManagerEvents,
|
|
51
|
+
BotaClientEvents,
|
|
52
|
+
} from './models/Status';
|
|
53
|
+
|
|
54
|
+
// Errors
|
|
55
|
+
export {
|
|
56
|
+
BotaError,
|
|
57
|
+
BluetoothError,
|
|
58
|
+
DeviceError,
|
|
59
|
+
ProvisioningError,
|
|
60
|
+
TransferError,
|
|
61
|
+
UploadError,
|
|
62
|
+
SdkError,
|
|
63
|
+
isBotaError,
|
|
64
|
+
} from './utils/errors';
|