diff --git a/app/(tabs)/explore.tsx b/app/(tabs)/explore.tsx index 4eb8430..1ee2bc0 100644 --- a/app/(tabs)/explore.tsx +++ b/app/(tabs)/explore.tsx @@ -16,7 +16,6 @@ export default function TabTwoScreen() { version, isActivated, transferProgress, - isTransferring, discoveredDevices, loading, error, @@ -118,7 +117,8 @@ export default function TabTwoScreen() { {/* Transfer Status */} File Transfer - Transferring: {isTransferring ? 'Yes' : 'No'} + Converting: {loading.converting ? 'Yes' : 'No'} + Transferring: {loading.transferring ? 'Yes' : 'No'} Progress: {transferProgress}% diff --git a/ble/core/BleClient.ts b/ble/core/BleClient.ts index 4d76ea7..fed144e 100644 --- a/ble/core/BleClient.ts +++ b/ble/core/BleClient.ts @@ -96,7 +96,7 @@ export class BleClient { requestMTU: BLE_UUIDS.REQUEST_MTU }); if (device.mtu < BLE_UUIDS.REQUEST_MTU) { - console.log("MTU not supported, requesting default to ", BLE_UUIDS.REQUEST_MTU); + console.log(`MTU ${device.mtu} not supported, requesting default to ${BLE_UUIDS.REQUEST_MTU}`); device = await device.requestMTU(BLE_UUIDS.REQUEST_MTU); // Give some time for the stack to stabilize after MTU change await new Promise(resolve => setTimeout(resolve, 500)); diff --git a/ble/hooks/useBleExplorer.ts b/ble/hooks/useBleExplorer.ts index df9e2fb..4869027 100644 --- a/ble/hooks/useBleExplorer.ts +++ b/ble/hooks/useBleExplorer.ts @@ -6,9 +6,9 @@ import { BleClient, BleDevice, BleError, - BleProtocolService, COMMAND_TYPES, + BleProtocolService, APP_COMMAND_TYPES, ConnectionState, - DeviceInfo, + DeviceInfo, COMMAND_TYPES, } from '../index'; import {DeviceInfoService} from '../services/DeviceInfoService' import {FileTransferService} from "../services/FileTransferService"; @@ -25,11 +25,11 @@ interface BleState { version: string; isActivated: boolean; transferProgress: number; - isTransferring: boolean; discoveredDevices: BleDevice[]; loading: { connecting: boolean; querying: boolean; + converting: boolean; transferring: boolean; }; error: string | null; @@ -50,11 +50,11 @@ export const useBleExplorer = () => { version: '', isActivated: false, transferProgress: 0, - isTransferring: false, discoveredDevices: [], loading: { connecting: false, querying: false, + converting: false, transferring: false, }, error: null, @@ -334,7 +334,7 @@ export const useBleExplorer = () => { }; const convertToANI = useCallback(async (tempDir: Directory, media: ImagePicker.ImagePickerAsset): Promise => { - const tempFile = new File(tempDir, `${media.fileName}.ani`) + const tempFile = new File(tempDir, `${media.fileName?.split('.')[0]}.ani`) const formData = new FormData(); formData.append('file', { uri: media.uri, @@ -370,7 +370,9 @@ export const useBleExplorer = () => { if (media.type === 'video') { let tempFile: File; console.debug(`Converting video: ${media.fileName || 'video'}...`); + setState(prev => ({...prev, loading: {...prev.loading, converting: true}})); tempFile = await convertToANI(tempDir, media) + setState(prev => ({...prev, loading: {...prev.loading, converting: false}})); console.log(`Transferring converted file to device...`); await fileTransferService.transferFile( state.connectedDevice.id, diff --git a/ble/protocol/Constants.ts b/ble/protocol/Constants.ts index 6abe9b5..d6b75ad 100644 --- a/ble/protocol/Constants.ts +++ b/ble/protocol/Constants.ts @@ -2,7 +2,6 @@ export const PROTOCOL_VERSION = "1.0.0"; export const BLE_UUIDS = { SERVICE: '000002c4-0000-1000-8000-00805f9b34fb', - SERVICE_SHORT: 'ae00', BROADCAST_CHARACTERISTIC: "000002c1-0000-1000-8000-00805f9b34fb", WRITE_CHARACTERISTIC: '000002c5-0000-1000-8000-00805f9b34fb', READ_CHARACTERISTIC: '000002c6-0000-1000-8000-00805f9b34fb', @@ -11,13 +10,13 @@ export const BLE_UUIDS = { export const FRAME_CONSTANTS = { HEAD_DEVICE_TO_APP: 0xb0, - // HEAD_APP_TO_DEVICE: 0xc7, HEAD_APP_TO_DEVICE: 0xb1, MAX_DATA_SIZE: 496, HEADER_SIZE: 8, FOOTER_SIZE: 1, - FRAME_INTERVAL: 35, + FRAME_INTERVAL: 35, // package transfer idle interval in ms, set 35 ms for ble device have enough time to process data } as const; + export type FRAME_HEAD = typeof FRAME_CONSTANTS.HEAD_DEVICE_TO_APP | typeof FRAME_CONSTANTS.HEAD_APP_TO_DEVICE; export const COMMAND_TYPES = { @@ -32,7 +31,8 @@ export const COMMAND_TYPES = { DEVICE_INFO_SETTINGS: 0x0d, DEVICE_IDENTITY_CHECK: 0x0e, } as const; -export type COMMAND_TYPES = typeof COMMAND_TYPES[keyof typeof COMMAND_TYPES]; + +export type APP_COMMAND_TYPES = typeof COMMAND_TYPES[keyof typeof COMMAND_TYPES]; export const RESPONSE_TYPES = { ACTIVATION_STATUS: 0x01, diff --git a/ble/protocol/ProtocolManager.ts b/ble/protocol/ProtocolManager.ts index 16451a1..11caa1e 100644 --- a/ble/protocol/ProtocolManager.ts +++ b/ble/protocol/ProtocolManager.ts @@ -1,5 +1,5 @@ import {ProtocolFrame} from './types'; -import {FRAME_CONSTANTS, COMMAND_TYPES, FRAME_HEAD} from './Constants'; +import {FRAME_CONSTANTS, APP_COMMAND_TYPES, FRAME_HEAD} from './Constants'; export class ProtocolManager { @@ -13,9 +13,7 @@ export class ProtocolManager { for (let i = 0; i < frameData.length; i++) { sum += frameData[i]; } - const checksumV1 = (0 - sum) & 0xff const checksum = (~sum + 1) & 0xff - console.debug(`[ProtocolManager] Checksum V1 calculated: 0 - ${sum} = ${checksumV1.toString(16).padStart(2, '0')}`); console.debug(`[ProtocolManager] Checksum calculated: 0 - ${sum} = ${checksum.toString(16).padStart(2, '0')}`); return checksum; } @@ -25,10 +23,9 @@ export class ProtocolManager { } static createFrame( - type: COMMAND_TYPES, + type: APP_COMMAND_TYPES, data: Uint8Array, head: FRAME_HEAD = FRAME_CONSTANTS.HEAD_APP_TO_DEVICE, - requireFragmentation: boolean = true, maxDataSize: number = FRAME_CONSTANTS.MAX_DATA_SIZE ): Uint8Array[] { // Max pages index is 4 bytes, so we can fit up to 65535 pages of data @@ -36,7 +33,7 @@ export class ProtocolManager { if (data.length > maxTotalSize) { throw new Error(`Data size ${data.length} exceeds max size ${maxTotalSize}`); } - if (data.length <= maxDataSize || !requireFragmentation) { + if (data.length <= maxDataSize) { console.debug(`[ProtocolManager] Frame size ${data.length} is less than max size ${maxDataSize}, not fragmented`); return [this.createSingleFrame(type, data, head)]; } else { @@ -45,7 +42,7 @@ export class ProtocolManager { } } - private static createSingleFrame(type: COMMAND_TYPES, data: Uint8Array, head: FRAME_HEAD): Uint8Array { + private static createSingleFrame(type: APP_COMMAND_TYPES, data: Uint8Array, head: FRAME_HEAD): Uint8Array { const buffer = new Uint8Array(FRAME_CONSTANTS.HEADER_SIZE + data.length + FRAME_CONSTANTS.FOOTER_SIZE); let offset = 0; @@ -78,7 +75,7 @@ export class ProtocolManager { return buffer; } - private static createFragmentedFrames(type: COMMAND_TYPES, data: Uint8Array, head: FRAME_HEAD, maxDataSize: number): Uint8Array[] { + private static createFragmentedFrames(type: APP_COMMAND_TYPES, data: Uint8Array, head: FRAME_HEAD, maxDataSize: number): Uint8Array[] { const frames: Uint8Array[] = []; const totalSize = data.length; const totalPages = Math.ceil(totalSize / maxDataSize); diff --git a/ble/services/BleProtocolService.ts b/ble/services/BleProtocolService.ts index 1fb2014..2051353 100644 --- a/ble/services/BleProtocolService.ts +++ b/ble/services/BleProtocolService.ts @@ -1,6 +1,6 @@ import {BleClient} from '../core/BleClient'; import {ProtocolManager} from '../protocol/ProtocolManager'; -import {BLE_UUIDS, COMMAND_TYPES, FRAME_CONSTANTS} from '../protocol/Constants'; +import {BLE_UUIDS, APP_COMMAND_TYPES, FRAME_CONSTANTS} from '../protocol/Constants'; import {ProtocolFrame} from '../protocol/types'; import {Buffer} from 'buffer'; import {Subscription} from 'react-native-ble-plx'; @@ -139,13 +139,16 @@ export class BleProtocolService { } } - public async send(deviceId: string, type: COMMAND_TYPES, data: object | ArrayBuffer | Uint8Array, onProgress?: (progress: number) => void): Promise { + public async send(deviceId: string, type: APP_COMMAND_TYPES, data: object | ArrayBuffer | Uint8Array, onProgress?: (progress: number) => void): Promise { let payload: Uint8Array; if (data instanceof ArrayBuffer) { + console.debug("[BleProtocolService] Sending ArrayBuffer"); payload = new Uint8Array(data); } else if (data instanceof Uint8Array) { + console.debug("[BleProtocolService] Sending Uint8Array"); payload = data; } else { + console.debug("[BleProtocolService] Sending JSON payload"); const jsonStr = JSON.stringify(data); payload = new Uint8Array(Buffer.from(jsonStr)); } @@ -158,8 +161,10 @@ export class BleProtocolService { const safeMaxDataSize = Math.max(1, Math.min(maxPayloadSize, FRAME_CONSTANTS.MAX_DATA_SIZE)); console.debug(`[BleProtocolService] Sending with MTU=${mtu}, maxDataSize=${safeMaxDataSize}`); - - const frames = ProtocolManager.createFrame(type, payload, FRAME_CONSTANTS.HEAD_APP_TO_DEVICE, true, safeMaxDataSize); + const rawPayloadHex = payload.reduce((acc, val) => acc + val.toString(16).padStart(2, '0') + ' ', ''); + const formattedRawPayloadHex = rawPayloadHex.substring(0, 512) + "\n......\n" + rawPayloadHex.substring(rawPayloadHex.length - 512); + console.debug(`[BleProtocolService] Sending payload size=${payload.byteLength}, raw payload hex=\n${formattedRawPayloadHex}`); + const frames = ProtocolManager.createFrame(type, payload, FRAME_CONSTANTS.HEAD_APP_TO_DEVICE, safeMaxDataSize); const total = frames.length; console.debug(`Sending ${total} frames`); for (let i = 0; i < total; i++) { @@ -171,8 +176,7 @@ export class BleProtocolService { if (onProgress) { onProgress((i + 1) / total); } - - console.debug("Wrote frame", result); + // console.debug("Wrote frame", result); } } } diff --git a/ble/services/DeviceInfoService.ts b/ble/services/DeviceInfoService.ts index 3423059..9c29654 100644 --- a/ble/services/DeviceInfoService.ts +++ b/ble/services/DeviceInfoService.ts @@ -1,5 +1,5 @@ import {BleProtocolService} from './BleProtocolService'; -import {COMMAND_TYPES, RESPONSE_TYPES} from '../protocol/Constants'; +import {APP_COMMAND_TYPES, COMMAND_TYPES, RESPONSE_TYPES} from '../protocol/Constants'; import {DeviceInfo, ActivationStatus} from '../protocol/types'; import {Buffer} from 'buffer'; diff --git a/ble/services/FileTransferService.ts b/ble/services/FileTransferService.ts index c0568c0..783b629 100644 --- a/ble/services/FileTransferService.ts +++ b/ble/services/FileTransferService.ts @@ -1,5 +1,5 @@ import {BleProtocolService} from './BleProtocolService'; -import {COMMAND_TYPES} from '../protocol/Constants'; +import {APP_COMMAND_TYPES, COMMAND_TYPES} from '../protocol/Constants'; export class FileTransferService { @@ -16,7 +16,7 @@ export class FileTransferService { return FileTransferService.instance; } - public async transferFile(deviceId: string, filePath: string, type: COMMAND_TYPES, onProgress?: (progress: number) => void): Promise { + public async transferFile(deviceId: string, filePath: string, type: APP_COMMAND_TYPES, onProgress?: (progress: number) => void): Promise { try { const response = await fetch(filePath); if (!response.ok) {