expo-ble模块测试demo 联调BLE模块 take 10 新增log 打印ani文件前后512字节
This commit is contained in:
parent
f816165779
commit
83cdf722ac
|
|
@ -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 */}
|
||||
<ThemedView style={styles.section}>
|
||||
<ThemedText type="subtitle">File Transfer</ThemedText>
|
||||
<ThemedText>Transferring: {isTransferring ? 'Yes' : 'No'}</ThemedText>
|
||||
<ThemedText>Converting: {loading.converting ? 'Yes' : 'No'}</ThemedText>
|
||||
<ThemedText>Transferring: {loading.transferring ? 'Yes' : 'No'}</ThemedText>
|
||||
<ThemedText>Progress: {transferProgress}%</ThemedText>
|
||||
</ThemedView>
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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<File> => {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
public async send(deviceId: string, type: APP_COMMAND_TYPES, data: object | ArrayBuffer | Uint8Array, onProgress?: (progress: number) => void): Promise<void> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
public async transferFile(deviceId: string, filePath: string, type: APP_COMMAND_TYPES, onProgress?: (progress: number) => void): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(filePath);
|
||||
if (!response.ok) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue