Commit 211744a9b91fa58963fc94d39326ab902d28c10c
1 parent
b867ff0e
feat:ota import
Showing
10 changed files
with
1187 additions
and
0 deletions
HDFwear.xcodeproj/project.pbxproj
... | ... | @@ -280,6 +280,7 @@ |
280 | 280 | 6CFEEBC02773353700621863 /* BOReferenceVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFEEBBF2773353700621863 /* BOReferenceVC.swift */; }; |
281 | 281 | 6CFEEBC22773354500621863 /* HRReferenceVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFEEBC12773354500621863 /* HRReferenceVC.swift */; }; |
282 | 282 | 6CFEEBC42773355700621863 /* SleepReferenceVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFEEBC32773355700621863 /* SleepReferenceVC.swift */; }; |
283 | + 84067DB52B5E67DC0030E30E /* OTA in Resources */ = {isa = PBXBuildFile; fileRef = 84067DB42B5E67DC0030E30E /* OTA */; }; | |
283 | 284 | 844959782B48EF900029E2E0 /* BluetoothManager+Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844959772B48EF900029E2E0 /* BluetoothManager+Deprecated.swift */; }; |
284 | 285 | 845ADEA12B551C8E00C3AD73 /* NewStepModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845ADEA02B551C8E00C3AD73 /* NewStepModel.swift */; }; |
285 | 286 | 8473FB622B4BF1A200409148 /* TaskManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8473FB612B4BF1A200409148 /* TaskManager.swift */; }; |
... | ... | @@ -662,6 +663,7 @@ |
662 | 663 | 6CFEEBBF2773353700621863 /* BOReferenceVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BOReferenceVC.swift; sourceTree = "<group>"; }; |
663 | 664 | 6CFEEBC12773354500621863 /* HRReferenceVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HRReferenceVC.swift; sourceTree = "<group>"; }; |
664 | 665 | 6CFEEBC32773355700621863 /* SleepReferenceVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SleepReferenceVC.swift; sourceTree = "<group>"; }; |
666 | + 84067DB42B5E67DC0030E30E /* OTA */ = {isa = PBXFileReference; lastKnownFileType = folder; path = OTA; sourceTree = "<group>"; }; | |
665 | 667 | 844959772B48EF900029E2E0 /* BluetoothManager+Deprecated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BluetoothManager+Deprecated.swift"; sourceTree = "<group>"; }; |
666 | 668 | 845ADE9F2B5507FA00C3AD73 /* 20240126ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = 20240126ReadMe.md; sourceTree = "<group>"; }; |
667 | 669 | 845ADEA02B551C8E00C3AD73 /* NewStepModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewStepModel.swift; sourceTree = "<group>"; }; |
... | ... | @@ -1125,6 +1127,7 @@ |
1125 | 1127 | 6C6F405E27434B8D00F9473C /* Tools */ = { |
1126 | 1128 | isa = PBXGroup; |
1127 | 1129 | children = ( |
1130 | + 84067DB42B5E67DC0030E30E /* OTA */, | |
1128 | 1131 | 6C411EDE275DE737009B2E02 /* BluetoothManager.swift */, |
1129 | 1132 | 844959772B48EF900029E2E0 /* BluetoothManager+Deprecated.swift */, |
1130 | 1133 | 6C1F987E279BF0AA00C0C3BA /* BluetoothManager+Set.swift */, |
... | ... | @@ -1464,6 +1467,7 @@ |
1464 | 1467 | 6C34958827A12DB000F792AA /* DailCell.xib in Resources */, |
1465 | 1468 | 6CE7E3E62782AA8300D6B374 /* Localizable.strings in Resources */, |
1466 | 1469 | 6C228BB3279261340078B22E /* ContactCell.xib in Resources */, |
1470 | + 84067DB52B5E67DC0030E30E /* OTA in Resources */, | |
1467 | 1471 | 6C9CAC3A278C2A4D00787CA6 /* Motion.storyboard in Resources */, |
1468 | 1472 | 6CC6E57727716BA9006C01A7 /* CustomProgress.xib in Resources */, |
1469 | 1473 | 6C1B7E9927B794B300DB9D1C /* NFCCell.xib in Resources */, | ... | ... |
HDFwear/HDFwear-Bridging-Header.h
HDFwear/Tools/OTA/LETransceiver.h
0 → 100644
1 | +// | |
2 | +// LETransceiver.h | |
3 | +// ActsBluetoothSpeed | |
4 | +// | |
5 | +// Created by inidhu on 2019/3/15. | |
6 | +// Copyright © 2019 Actions. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import <Foundation/Foundation.h> | |
10 | +#import <CoreBluetooth/CoreBluetooth.h> | |
11 | + | |
12 | +NS_ASSUME_NONNULL_BEGIN | |
13 | + | |
14 | +#define KeyWriteServiceUUID @"kWriteServiceUUID" | |
15 | +#define KeyIndicateServiceUUID @"kIndicateServiceUUID" | |
16 | +#define KeyWriteCharacteristicUUID @"kWriteCharacteristicUUID" | |
17 | +#define KeyIndicateCharacteristicUUID @"kIndicateCharacteristicUUID" | |
18 | + | |
19 | +@protocol LEConnctionDelegate <NSObject> | |
20 | + | |
21 | +@required | |
22 | +- (void)onFoundPeripheral:(CBPeripheral *) peripheral advertisementData:(NSDictionary *) advertisementData; | |
23 | + | |
24 | +@optional | |
25 | +- (void)onConnectedPeripheral:(CBPeripheral *) peripheral; | |
26 | +- (void)onDisconnectedPeripheral:(CBPeripheral *) peripheral; | |
27 | + | |
28 | +@end | |
29 | + | |
30 | +@protocol LEDataDelegate <NSObject> | |
31 | + | |
32 | +@optional | |
33 | + | |
34 | +- (void)onDataReceive:(NSData *) data; | |
35 | + | |
36 | +@end | |
37 | + | |
38 | +@interface LETransceiver : NSObject<CBPeripheralDelegate, CBCentralManagerDelegate> | |
39 | + | |
40 | +@property (weak, nonatomic) id<LEConnctionDelegate> connectionDelegate; | |
41 | +@property (weak, nonatomic) id<LEDataDelegate> dataDelegate; | |
42 | + | |
43 | +- (void)setUUIDs:(NSDictionary *) uuids; | |
44 | + | |
45 | +- (void)scanStart; | |
46 | +- (void)scanStop; | |
47 | + | |
48 | +- (void)connect:(CBPeripheral *)peripheral; | |
49 | +- (void)disconnect:(CBPeripheral *)peripheral; | |
50 | + | |
51 | +- (void)write:(NSData *) data; | |
52 | +- (void)write:(NSData *) data index:(int) i; | |
53 | + | |
54 | +@end | |
55 | + | |
56 | +NS_ASSUME_NONNULL_END | ... | ... |
HDFwear/Tools/OTA/LETransceiver.m
0 → 100644
1 | +// | |
2 | +// LETransceiver.m | |
3 | +// ActsBluetoothSpeed | |
4 | +// | |
5 | +// Created by inidhu on 2019/3/15. | |
6 | +// Copyright © 2019 Actions. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import "LETransceiver.h" | |
10 | +#import <UIKit/UIKit.h> | |
11 | + | |
12 | + | |
13 | +@implementation LETransceiver { | |
14 | + NSString *writeServiceUUID; | |
15 | + NSString *writeCharacteristicUUID; | |
16 | + NSString *indicateServiceUUID; | |
17 | + NSString *indicateCharacteristicUUID; | |
18 | + | |
19 | + CBCharacteristicWriteType writeType; | |
20 | + CBCentralManager *centralManager; | |
21 | + | |
22 | + CBPeripheral *connectedPeripheral; | |
23 | + CBCharacteristic *characteristicWrite; | |
24 | + CBCharacteristic *characteristicIndicate; | |
25 | + | |
26 | + NSTimer *connectTimer; | |
27 | + BOOL isReadyToSendWrite; | |
28 | + | |
29 | + | |
30 | +} | |
31 | + | |
32 | +- (id) init { | |
33 | + self = [super init]; | |
34 | + | |
35 | + writeType = CBCharacteristicWriteWithoutResponse; | |
36 | + | |
37 | + centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; | |
38 | + | |
39 | + return self; | |
40 | +} | |
41 | + | |
42 | +- (void)setUUIDs:(NSDictionary *) uuids { | |
43 | + NSArray *keys = [uuids allKeys]; | |
44 | + for (NSString *key in keys) { | |
45 | + if ([key isEqualToString:KeyWriteServiceUUID]) { | |
46 | + writeServiceUUID = [[uuids objectForKey:KeyWriteServiceUUID] uppercaseString]; | |
47 | + } else if ([key isEqualToString:KeyIndicateServiceUUID]) { | |
48 | + indicateServiceUUID = [[uuids objectForKey:KeyIndicateServiceUUID] uppercaseString]; | |
49 | + } else if ([key isEqualToString:KeyWriteCharacteristicUUID]) { | |
50 | + writeCharacteristicUUID = [[uuids objectForKey:KeyWriteCharacteristicUUID] uppercaseString]; | |
51 | + } else if ([key isEqualToString:KeyIndicateCharacteristicUUID]) { | |
52 | + indicateCharacteristicUUID = [[uuids objectForKey:KeyIndicateCharacteristicUUID] uppercaseString]; | |
53 | + } | |
54 | + } | |
55 | +} | |
56 | + | |
57 | +- (void)scanStart { | |
58 | + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], CBCentralManagerScanOptionAllowDuplicatesKey, nil]; | |
59 | + /* | |
60 | + NSMutableArray *servicesUUID = [[NSMutableArray alloc] init]; | |
61 | + if (writeServiceUUID) | |
62 | + [servicesUUID addObject:writeServiceUUID]; | |
63 | + if (indicateServiceUUID) | |
64 | + [servicesUUID addObject:indicateServiceUUID]; | |
65 | + */ | |
66 | + [centralManager scanForPeripheralsWithServices:nil options:options]; | |
67 | +} | |
68 | + | |
69 | +- (void)scanStop { | |
70 | + [centralManager stopScan]; | |
71 | +} | |
72 | + | |
73 | +- (void)connect:(CBPeripheral *)peripheral { | |
74 | + [self scanStop]; | |
75 | + | |
76 | + [centralManager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES}]; | |
77 | + | |
78 | + if (connectTimer) { | |
79 | + [connectTimer invalidate]; | |
80 | + } | |
81 | + connectTimer = [NSTimer scheduledTimerWithTimeInterval:20.0 target:self selector:@selector(connectTimeout:) userInfo:peripheral repeats:NO]; | |
82 | +} | |
83 | + | |
84 | +- (void)disconnect:(CBPeripheral *)peripheral { | |
85 | + if (![self isPeripheralConnected:peripheral]) { | |
86 | + return; | |
87 | + } | |
88 | + | |
89 | + NSLog(@"disconnect %@", peripheral.name); | |
90 | + [centralManager cancelPeripheralConnection:peripheral]; | |
91 | +} | |
92 | + | |
93 | +- (BOOL) isPeripheralConnected:(CBPeripheral *) peripheral { | |
94 | + if (IOS_VERSION >= 7.0) { | |
95 | + if (peripheral.state == CBPeripheralStateConnected) { | |
96 | + return YES; | |
97 | + } | |
98 | + } else { | |
99 | +#ifndef __IPHONE_7_0 | |
100 | + if (peripheral.isConnected) { | |
101 | + return YES; | |
102 | + } | |
103 | +#endif | |
104 | + } | |
105 | + return NO; | |
106 | +} | |
107 | + | |
108 | +- (NSUInteger) getMtuForType:(CBCharacteristicWriteType) type { | |
109 | + return [connectedPeripheral maximumWriteValueLengthForType:type]; | |
110 | +} | |
111 | + | |
112 | +- (void)write:(NSData *) data { | |
113 | + if (characteristicWrite) { | |
114 | + NSUInteger mtu = [self getMtuForType:CBCharacteristicWriteWithoutResponse]; | |
115 | + NSLog(@"writeData mtu: %ld, %@", mtu, data); | |
116 | + for (NSUInteger index = 0; index < data.length; index += mtu) { | |
117 | + NSUInteger len = (data.length - index) > mtu ? mtu : (data.length - index); | |
118 | + NSData *value = [data subdataWithRange:NSMakeRange(index, len)]; | |
119 | + [connectedPeripheral writeValue:value forCharacteristic:characteristicWrite type:CBCharacteristicWriteWithoutResponse]; | |
120 | + NSLog(@"writeValue: %@", value); | |
121 | + } | |
122 | + } | |
123 | +} | |
124 | + | |
125 | +- (void)write:(NSData *) data index:(int) i { | |
126 | + if (characteristicWrite) { | |
127 | + NSUInteger mtu = [self getMtuForType:CBCharacteristicWriteWithoutResponse]; | |
128 | + NSLog(@"i writeData mtu: %ld, %@", mtu, data); | |
129 | + | |
130 | + for (NSUInteger index = 0; index < data.length; index += mtu) { | |
131 | + NSUInteger len = (data.length - index) > mtu ? mtu : (data.length - index); | |
132 | + NSData *value = [data subdataWithRange:NSMakeRange(index, len)]; | |
133 | + if(i != 0 && i % 62 == 0) { | |
134 | + NSData *value2 = [value subdataWithRange:NSMakeRange(0, 1)]; | |
135 | + NSData *value3 = [value subdataWithRange:NSMakeRange(1, value.length - 1)]; | |
136 | + [connectedPeripheral writeValue:value2 forCharacteristic:characteristicWrite type:CBCharacteristicWriteWithResponse]; | |
137 | + [connectedPeripheral writeValue:value3 forCharacteristic:characteristicWrite type:CBCharacteristicWriteWithoutResponse]; | |
138 | + } else { | |
139 | + [connectedPeripheral writeValue:value forCharacteristic:characteristicWrite type:CBCharacteristicWriteWithoutResponse]; | |
140 | + } | |
141 | + NSLog(@"writeValue: %@", value); | |
142 | + } | |
143 | + } | |
144 | +} | |
145 | + | |
146 | +- (void)connectTimeout:(NSTimer *)timer { | |
147 | + CBPeripheral *peripheral = (CBPeripheral *)[timer userInfo]; | |
148 | + [self disconnect:peripheral]; | |
149 | +} | |
150 | + | |
151 | +#pragma mark -- CBCentralManagerDelegate | |
152 | +- (void)centralManagerDidUpdateState:(CBCentralManager *)central { | |
153 | + NSString *messtoshow; | |
154 | + switch (central.state) { | |
155 | + case CBManagerStatePoweredOn:{ | |
156 | + messtoshow=[NSString stringWithFormat:@"CBCentralManagerStatePoweredOn"]; | |
157 | + [self scanStart]; | |
158 | + break; | |
159 | + } | |
160 | + case CBManagerStateUnknown: | |
161 | + { | |
162 | + messtoshow=[NSString stringWithFormat:@"State unknown, update imminent"]; | |
163 | + break; | |
164 | + } | |
165 | + case CBManagerStateResetting: | |
166 | + { | |
167 | + messtoshow=[NSString stringWithFormat:@"The connection with the system service was momentarily lost, update imminent."]; | |
168 | + break; | |
169 | + } | |
170 | + case CBManagerStateUnsupported: | |
171 | + { | |
172 | + messtoshow=[NSString stringWithFormat:@"The platform doesn't support Bluetooth Low Energy"]; | |
173 | + break; | |
174 | + } | |
175 | + case CBManagerStateUnauthorized: | |
176 | + { | |
177 | + messtoshow=[NSString stringWithFormat:@"The app is not authorized to use Bluetooth Low Energy"]; | |
178 | + break; | |
179 | + } | |
180 | + case CBManagerStatePoweredOff: | |
181 | + { | |
182 | + [self disconnect:connectedPeripheral]; | |
183 | + | |
184 | + messtoshow=[NSString stringWithFormat:@"Bluetooth is currently powered off"]; | |
185 | + break; | |
186 | + } | |
187 | + default: | |
188 | + break; | |
189 | + } | |
190 | + NSLog(@"%@",messtoshow); | |
191 | +} | |
192 | + | |
193 | +- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ | |
194 | +// NSLog(@"didDiscoverPeripheral: %@", peripheral); | |
195 | + | |
196 | + if(_connectionDelegate && [_connectionDelegate respondsToSelector:@selector(onFoundPeripheral:advertisementData:)]) { | |
197 | + [_connectionDelegate onFoundPeripheral:peripheral advertisementData:advertisementData]; | |
198 | + } | |
199 | +} | |
200 | + | |
201 | +- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{ | |
202 | + NSLog(@"didConnectPeripheral: %@", peripheral.name); | |
203 | + | |
204 | + peripheral.delegate = self; | |
205 | + [peripheral discoverServices:nil]; | |
206 | +} | |
207 | + | |
208 | +- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{ | |
209 | + NSLog(@"Fail to connect: %@", peripheral.name); | |
210 | +} | |
211 | + | |
212 | +- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{ | |
213 | + NSLog(@"didDisconnectPeripheral %@, error: %@",peripheral, error); | |
214 | + | |
215 | + connectedPeripheral = nil; | |
216 | + characteristicWrite = nil; | |
217 | + characteristicIndicate = nil; | |
218 | + if(_connectionDelegate && [_connectionDelegate respondsToSelector:@selector(onDisconnectedPeripheral:)]) { | |
219 | + [_connectionDelegate onDisconnectedPeripheral:peripheral]; | |
220 | + } | |
221 | +} | |
222 | + | |
223 | +#pragma mark -- CBPeripheralDelegate | |
224 | +- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{ | |
225 | + NSLog(@"didDiscoverServices: %@", peripheral.name); | |
226 | + if (error) { | |
227 | + NSLog(@"Error discovering service:%@", [error localizedDescription]); | |
228 | + return; | |
229 | + } | |
230 | + | |
231 | + for (CBService *service in peripheral.services) { | |
232 | + | |
233 | + NSLog(@"service: %@", service); | |
234 | + [peripheral discoverCharacteristics:nil forService:service]; | |
235 | + } | |
236 | + | |
237 | +} | |
238 | + | |
239 | +- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{ | |
240 | + NSLog(@"didDiscoverCharacteristicsForService: %@, %@", peripheral.name, service.UUID.UUIDString); | |
241 | + if (error) { | |
242 | + NSLog(@"Error didDiscoverCharacteristicsForService:%@",[error localizedDescription]); | |
243 | + return; | |
244 | + } | |
245 | + | |
246 | + NSLog(@"UUID: %@, %@, %@", service.UUID.UUIDString, writeServiceUUID, indicateServiceUUID); | |
247 | + if ([service.UUID.UUIDString isEqualToString:writeServiceUUID]) { | |
248 | + for (CBCharacteristic *characteristic in service.characteristics) { | |
249 | + NSLog(@"DiscoverCharacteristics: %@", characteristic.UUID); | |
250 | + | |
251 | + if ([characteristic.UUID.UUIDString isEqualToString:writeCharacteristicUUID]) | |
252 | + characteristicWrite = characteristic; | |
253 | + } | |
254 | + } | |
255 | + | |
256 | + if ([service.UUID.UUIDString isEqualToString:indicateServiceUUID]) { | |
257 | + for (CBCharacteristic *characteristic in service.characteristics) { | |
258 | + NSLog(@"DiscoverCharacteristics: %@", characteristic.UUID); | |
259 | + | |
260 | + if ([characteristic.UUID.UUIDString isEqualToString:indicateCharacteristicUUID]) { | |
261 | + [peripheral setNotifyValue:YES forCharacteristic:characteristic]; | |
262 | + characteristicIndicate = characteristic; | |
263 | + } | |
264 | + } | |
265 | + } | |
266 | + | |
267 | + | |
268 | + if (characteristicWrite && characteristicIndicate) { | |
269 | + connectedPeripheral = peripheral; | |
270 | + [connectTimer invalidate]; | |
271 | + | |
272 | + if(_connectionDelegate && [_connectionDelegate respondsToSelector:@selector(onConnectedPeripheral:)]) { | |
273 | + [_connectionDelegate onConnectedPeripheral:peripheral]; | |
274 | + } | |
275 | + } | |
276 | +} | |
277 | + | |
278 | +- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(nullable NSError *)error { | |
279 | + | |
280 | +} | |
281 | + | |
282 | +- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { | |
283 | + | |
284 | + if (error) { | |
285 | + NSLog(@"%@,%@,Error didWriteValueForCharacteristic:%@",characteristic.UUID,[characteristic value], [error localizedDescription]); | |
286 | + return; | |
287 | + } | |
288 | + | |
289 | +} | |
290 | + | |
291 | +- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { | |
292 | + if (error) { | |
293 | + NSLog(@"Error didUpdateValueForCharacteristic:%@", [error localizedDescription]); | |
294 | + return; | |
295 | + } | |
296 | + NSLog(@"didUpdateValueForCharacteristic: %@ %@", characteristic.UUID, characteristic.value); | |
297 | + | |
298 | + if (_dataDelegate && [_dataDelegate respondsToSelector:@selector(onDataReceive:)]) { | |
299 | + [_dataDelegate onDataReceive:[characteristic value]]; | |
300 | + } | |
301 | +} | |
302 | + | |
303 | +@end | ... | ... |
HDFwear/Tools/OTA/OTAManager.h
0 → 100644
1 | +// | |
2 | +// OTAManager.h | |
3 | +// ActsBluetoothOTA | |
4 | +// | |
5 | +// Created by inidhu on 2019/5/20. | |
6 | +// Copyright © 2019 Actions. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import <Foundation/Foundation.h> | |
10 | +#import "RemoteStatus.h" | |
11 | + | |
12 | +NS_ASSUME_NONNULL_BEGIN | |
13 | + | |
14 | +typedef enum{ | |
15 | + STATE_UNKNOWN = 0, | |
16 | + STATE_IDLE = 1, | |
17 | + STATE_PREPARING = 2, | |
18 | + STATE_PREPARED = 3, | |
19 | + STATE_TRANSFERRING = 4, | |
20 | + STATE_TRANSFERRED = 5, | |
21 | +} OTAStatus; | |
22 | + | |
23 | + | |
24 | +@protocol OTAManagerDelegate <NSObject> | |
25 | + | |
26 | +@optional | |
27 | + | |
28 | +- (void)sendData:(NSData *) data; | |
29 | +- (void)sendData:(NSData *)data index:(int) i; | |
30 | +- (void)audioDataReceive:(NSData *) data; | |
31 | +- (void)receiveAudioPSN:(NSInteger) psn data:(NSData *) data; | |
32 | +- (void)receiveSpeed:(NSInteger) speed; | |
33 | +- (void)receiveRemoteStatus:(RemoteStatus *) status; | |
34 | +- (void)onStatus:(OTAStatus) state; | |
35 | +- (void)onError:(NSInteger) errCode; | |
36 | + | |
37 | +@end | |
38 | + | |
39 | +@interface OTAManager : NSObject | |
40 | + | |
41 | +@property (weak, nonatomic) id<OTAManagerDelegate> delegate; | |
42 | + | |
43 | +- (BOOL)setOTAFile:(NSString *) path; | |
44 | +- (NSString *)getOTAVersion; | |
45 | +- (void)prepare; | |
46 | +- (void)upgrade; | |
47 | +- (void)confirmUpdateAndReboot; | |
48 | +- (void)setMaxMtu:(NSInteger)maxMtu; | |
49 | + | |
50 | +- (BOOL)receiveData:(NSData *) data; | |
51 | + | |
52 | + | |
53 | +@end | |
54 | + | |
55 | +NS_ASSUME_NONNULL_END | ... | ... |
HDFwear/Tools/OTA/OTAManager.m
0 → 100644
1 | +// | |
2 | +// OTAManager.m | |
3 | +// ActsBluetoothOTA | |
4 | +// | |
5 | +// Created by inidhu on 2019/5/20. | |
6 | +// Copyright © 2019 Actions. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import "OTAManager.h" | |
10 | +#import "Utils.h" | |
11 | + | |
12 | +@implementation OTAManager { | |
13 | + NSMutableData *receiveBuffer; | |
14 | + | |
15 | + NSInteger waitTimeout; | |
16 | + NSInteger restartTimeout; | |
17 | + NSInteger otaUnit; | |
18 | + NSInteger interval; | |
19 | + NSInteger ackEnable; | |
20 | + | |
21 | + NSString *fwVersion; | |
22 | + NSData *vRAM; | |
23 | + NSInteger otaMode; | |
24 | + NSInteger batteryThreshold; | |
25 | + | |
26 | + OTAStatus curState; | |
27 | + | |
28 | + NSData *otaFileData; | |
29 | + | |
30 | + NSTimer *timeoutTimer; | |
31 | + | |
32 | + BOOL remoteCrcSupport; | |
33 | + | |
34 | + NSInteger mWriteBytes; | |
35 | + | |
36 | + NSInteger maxMtu; | |
37 | +} | |
38 | + | |
39 | +- (id)init { | |
40 | + self = [super init]; | |
41 | + | |
42 | + fwVersion = @"1.01"; | |
43 | + otaMode = 0; | |
44 | + batteryThreshold = 30; | |
45 | + remoteCrcSupport = NO; | |
46 | + | |
47 | + return self; | |
48 | +} | |
49 | + | |
50 | +- (BOOL)setOTAFile:(NSString *) path { | |
51 | + if (path.length <= 0) | |
52 | + return NO; | |
53 | + | |
54 | + NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path]; | |
55 | + otaFileData = [handle readDataToEndOfFile]; | |
56 | + | |
57 | + return YES; | |
58 | +} | |
59 | + | |
60 | +- (NSString *)getOTAVersion { | |
61 | + NSData *data = [otaFileData subdataWithRange:NSMakeRange(0, 4)]; | |
62 | + NSString *magic = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
63 | + if ([magic isEqualToString:@"AOTA"]) { | |
64 | + data = [otaFileData subdataWithRange:NSMakeRange(64, 32)]; | |
65 | + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
66 | + } else { | |
67 | + data = [otaFileData subdataWithRange:NSMakeRange(12, 4)]; | |
68 | + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
69 | + } | |
70 | +} | |
71 | + | |
72 | +- (void)scheduleTimeoutTimer { | |
73 | + [self removeTimeoutTimer]; | |
74 | + | |
75 | + timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(timeoutReport) userInfo:nil repeats:NO]; | |
76 | +} | |
77 | + | |
78 | +- (void)removeTimeoutTimer { | |
79 | + if (timeoutTimer) { | |
80 | + [timeoutTimer invalidate]; | |
81 | + } | |
82 | +} | |
83 | + | |
84 | +- (void)timeoutReport { | |
85 | + [self notifyStatus:STATE_UNKNOWN]; | |
86 | +} | |
87 | + | |
88 | +- (void)readOTAHeader { | |
89 | + NSData *data = [otaFileData subdataWithRange:NSMakeRange(0, 4)]; | |
90 | + NSString *magic = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
91 | + if ([magic isEqualToString:@"AOTA"]) { | |
92 | + data = [otaFileData subdataWithRange:NSMakeRange(64, 32)]; | |
93 | + fwVersion = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
94 | + Byte placeholder[16] = {0x00}; | |
95 | + vRAM = [NSData dataWithBytes:placeholder length:16]; | |
96 | + } else { | |
97 | + data = [otaFileData subdataWithRange:NSMakeRange(12, 4)]; | |
98 | + fwVersion = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
99 | + vRAM = [otaFileData subdataWithRange:NSMakeRange(56, 16)]; | |
100 | + } | |
101 | +} | |
102 | + | |
103 | +- (void)checkRemoteStatus { | |
104 | + NSMutableArray *tlvs = [[NSMutableArray alloc] init]; | |
105 | + | |
106 | + // package version | |
107 | + NSData *tlv = [self assembleType:0x01 length:fwVersion.length value:[fwVersion dataUsingEncoding:NSUTF8StringEncoding]]; | |
108 | + [tlvs addObject:tlv]; | |
109 | + | |
110 | + // component size | |
111 | + Byte valueSize[2] = {0x00, 0x00}; | |
112 | + tlv = [self assembleType:0x02 length:2 value:[NSData dataWithBytes:valueSize length:2]]; | |
113 | + [tlvs addObject:tlv]; | |
114 | + | |
115 | + // VRAM | |
116 | + tlv = [self assembleType:0x03 length:vRAM.length value:vRAM]; | |
117 | + [tlvs addObject:tlv]; | |
118 | + | |
119 | + // ota work mode | |
120 | + Byte valueMode[1] = {(Byte)otaMode}; | |
121 | + tlv = [self assembleType:0x04 length:1 value:[NSData dataWithBytes:valueMode length:1]]; | |
122 | + [tlvs addObject:tlv]; | |
123 | + | |
124 | + // feature support: Support CRC32 Checksum | |
125 | + Byte valueFeature[1] = {(Byte)0x1}; | |
126 | + tlv = [self assembleType:0x09 length:1 value:[NSData dataWithBytes:valueFeature length:1]]; | |
127 | + [tlvs addObject:tlv]; | |
128 | + | |
129 | + NSData *command = [self assembleCommand:0x01 withTLVs:tlvs]; | |
130 | + [self sendData:command]; | |
131 | +} | |
132 | + | |
133 | +- (void)prepare{ | |
134 | + [self notifyStatus:STATE_PREPARING]; | |
135 | + [self readOTAHeader]; | |
136 | + [self checkRemoteStatus]; | |
137 | + [self scheduleTimeoutTimer]; | |
138 | +} | |
139 | + | |
140 | +- (void)setMaxMtu:(NSInteger)maxMtu; { | |
141 | + self -> maxMtu = maxMtu; | |
142 | +} | |
143 | + | |
144 | +- (void)upgrade { | |
145 | +/* [self notifyStatus:STATE_PREPARING]; | |
146 | + | |
147 | + [self readOTAHeader]; | |
148 | + [self checkRemoteStatus]; | |
149 | + [self scheduleTimeoutTimer]; | |
150 | + */ | |
151 | + | |
152 | + [self requestRemoteParameters]; | |
153 | + [self scheduleTimeoutTimer]; | |
154 | + mWriteBytes = 0; | |
155 | +} | |
156 | + | |
157 | +- (void)confirmUpdateAndReboot { | |
158 | + NSLog(@"confirmUpdateAndReboot"); | |
159 | + NSData *buffer = [self assembleCommand:0x06 withTLVs:nil]; | |
160 | + [self sendData:buffer]; | |
161 | +} | |
162 | + | |
163 | +/* TLV结构组装 */ | |
164 | +- (NSData *)assembleType:(NSInteger) type length:(NSInteger) length value:(NSData *) value { | |
165 | + NSInteger len = 3; | |
166 | + Byte *buffer = (Byte *)malloc(len); | |
167 | + | |
168 | + NSInteger index = 0; | |
169 | + | |
170 | + // Type | |
171 | + buffer[index++] = (Byte) (type & 0xFF); | |
172 | + | |
173 | + // Length | |
174 | + buffer[index++] = (Byte) (length & 0xFF); | |
175 | + buffer[index++] = (Byte) ((length >> 8) & 0xFF); | |
176 | + | |
177 | + // Value | |
178 | + NSMutableData *data = [NSMutableData dataWithBytes:buffer length:len]; | |
179 | + [data appendData:value]; | |
180 | + | |
181 | + free(buffer); | |
182 | + | |
183 | + return data; | |
184 | +} | |
185 | + | |
186 | +/* 命令组装 */ | |
187 | +- (NSData *)assembleCommand:(NSInteger) cmdId withTLVs:(NSArray *) subTLVs { | |
188 | + NSInteger subTLVsLen = 0; | |
189 | + if (subTLVs && subTLVs.count > 0) { | |
190 | + for (NSData *tlv in subTLVs) | |
191 | + subTLVsLen += tlv.length; | |
192 | + } | |
193 | + | |
194 | + // Header | |
195 | + Byte *buffer = (Byte *)malloc(2); | |
196 | + // Server ID | |
197 | + buffer[0] = (Byte) 0x09; | |
198 | + // Command ID | |
199 | + buffer[1] = (Byte) (cmdId & 0xFF); | |
200 | + NSData *header = [NSData dataWithBytes:buffer length:2]; | |
201 | + free(buffer); | |
202 | + | |
203 | + // Super TLV | |
204 | + NSData *superTLV = [self assembleType:0x80 length:subTLVsLen value:nil]; | |
205 | + | |
206 | + NSMutableData *cmdData = [NSMutableData dataWithData:header]; | |
207 | + [cmdData appendData:superTLV]; | |
208 | + for (NSData *tlv in subTLVs) { | |
209 | + [cmdData appendData:tlv]; | |
210 | + } | |
211 | + | |
212 | + return cmdData; | |
213 | +} | |
214 | + | |
215 | +- (void)notifyStatus:(OTAStatus) state { | |
216 | + if (curState == state) | |
217 | + return; | |
218 | + | |
219 | + curState = state; | |
220 | + if(_delegate && [_delegate respondsToSelector:@selector(onStatus:)]) { | |
221 | + [_delegate onStatus:curState]; | |
222 | + } | |
223 | +} | |
224 | + | |
225 | +- (NSArray *)readOTADataFrom:(NSInteger) offset withLength:(NSInteger) length byBitmap:(NSData *) bitmap groupNum:(int) groupNum { | |
226 | + NSLog(@"groupNum:%d", groupNum); | |
227 | + NSArray *pkgIdx = [Utils getZeroBitIndexMap:bitmap groupNum:groupNum]; | |
228 | + NSInteger pkgNum = pkgIdx.count; | |
229 | + NSLog(@"pkgNum:%d", pkgNum); | |
230 | + | |
231 | + NSMutableArray *packages = [[NSMutableArray alloc] init]; | |
232 | + for (NSInteger i = 0; i < pkgNum; i++) { | |
233 | + NSInteger index = [pkgIdx[i] integerValue]; | |
234 | + NSInteger odd = length - index * otaUnit; | |
235 | + if (odd <= 0) | |
236 | + break; | |
237 | + | |
238 | + NSInteger o = offset + index * otaUnit; | |
239 | + NSInteger len = odd > otaUnit ? otaUnit : odd; | |
240 | + | |
241 | + NSData *pkg = [otaFileData subdataWithRange:NSMakeRange(o, len)]; | |
242 | + NSLog(@"i: %ld o: %ld pkgIdx: %ld pkgNum: %ld count: %ld", i, o, index, pkgNum, pkg.length); | |
243 | + if (pkg.length <= 0) | |
244 | + break; | |
245 | + | |
246 | + [packages addObject:pkg]; | |
247 | + } | |
248 | + | |
249 | + return packages; | |
250 | +} | |
251 | + | |
252 | +- (void)sendData:(NSData *) data { | |
253 | + if(_delegate && [_delegate respondsToSelector:@selector(sendData:)]) { | |
254 | + [_delegate sendData:data]; | |
255 | + } | |
256 | +} | |
257 | + | |
258 | +- (void)sendData:(NSData *) data index:(int) i{ | |
259 | + if(_delegate && [_delegate respondsToSelector:@selector(sendData:index:)]) { | |
260 | + [_delegate sendData:data index:i]; | |
261 | + } | |
262 | +} | |
263 | + | |
264 | +- (void)requestRemoteParameters { | |
265 | + NSData *data = [self assembleCommand:0x02 withTLVs:nil]; | |
266 | + [self sendData:data]; | |
267 | +} | |
268 | + | |
269 | +- (void)notifyRemoteAppReady:(NSInteger) state { | |
270 | + // ota status | |
271 | + Byte bytes[1] = {(Byte)(state & 0xFF)}; | |
272 | + NSData *value = [NSData dataWithBytes:bytes length:1]; | |
273 | + NSData *tlv = [self assembleType:0x01 length:0x01 value:value]; | |
274 | + | |
275 | + NSArray *tlvs = [NSArray arrayWithObject:tlv]; | |
276 | + | |
277 | + NSData *data = [self assembleCommand:0x09 withTLVs:tlvs]; | |
278 | + [self sendData:data]; | |
279 | +} | |
280 | + | |
281 | +/* 去除开始位置无效数据 */ | |
282 | +- (NSData *)abandonInvalidHeaderData:(NSData *) data { | |
283 | + Byte *bytes = (Byte *)[data bytes]; | |
284 | + NSInteger length = data.length; | |
285 | + | |
286 | + NSInteger index = 0; | |
287 | + for (index = 0; index < length; index++) { | |
288 | + if (bytes[index] == 0x09) | |
289 | + break; | |
290 | + } | |
291 | + | |
292 | + return [data subdataWithRange:NSMakeRange(index, length - index)]; | |
293 | +} | |
294 | + | |
295 | +- (BOOL)receiveData:(NSData *) data { | |
296 | + if (!receiveBuffer) { | |
297 | + receiveBuffer = [[NSMutableData alloc] init]; | |
298 | + } | |
299 | + | |
300 | + [receiveBuffer appendData:data]; | |
301 | + | |
302 | + data = [self abandonInvalidHeaderData:receiveBuffer]; | |
303 | + receiveBuffer = [NSMutableData dataWithData:data]; | |
304 | + | |
305 | + /* 数据长度不足,等待下一次数据包 */ | |
306 | + if (data.length <= 5) { | |
307 | + return NO; | |
308 | + } | |
309 | + | |
310 | + Byte *bytes = (Byte *)[data bytes]; | |
311 | + NSInteger length = data.length; | |
312 | + NSInteger index = 0; | |
313 | + | |
314 | + Byte serviceId = bytes[index++]; | |
315 | + Byte commandId = bytes[index++]; | |
316 | + | |
317 | + Byte superTLV[3] = {0}; | |
318 | + superTLV[0] = bytes[index++]; | |
319 | + superTLV[1] = bytes[index++]; | |
320 | + superTLV[2] = bytes[index++]; | |
321 | + NSInteger subTLVsLen = superTLV[1] + (superTLV[2] << 8); | |
322 | + | |
323 | + /* 数据长度不足,等待下一次数据包 */ | |
324 | + if (length - index < subTLVsLen) { | |
325 | + return NO; | |
326 | + } | |
327 | + | |
328 | + NSData *tmp = [data subdataWithRange:NSMakeRange(index + subTLVsLen, length - index - subTLVsLen)]; | |
329 | + receiveBuffer = [NSMutableData dataWithData:tmp]; | |
330 | + | |
331 | + NSData *tlvs = [data subdataWithRange:NSMakeRange(index, subTLVsLen)]; | |
332 | + bytes = (Byte *)[tlvs bytes]; | |
333 | + length = tlvs.length; | |
334 | + index = 0; | |
335 | + | |
336 | + switch (commandId) { | |
337 | + case 0x01: { | |
338 | + if (bytes[index] != 0x7F) { | |
339 | + return NO; | |
340 | + } | |
341 | + | |
342 | + index += 3; | |
343 | + // index++; | |
344 | + // int length = bytes[index]; | |
345 | + // index++; | |
346 | + // length += (((int)bytes[index]) << 8); | |
347 | + // index++; | |
348 | + NSLog(@"length: %ld", length); | |
349 | + NSInteger errCode = [Utils bytes2UInt32:bytes index:index]; | |
350 | + index += 4; | |
351 | + | |
352 | + NSLog(@"error code: %ld", errCode); | |
353 | + [self removeTimeoutTimer]; | |
354 | + | |
355 | + NSData *data; | |
356 | + RemoteStatus *status = [[RemoteStatus alloc] init]; | |
357 | + | |
358 | + for ( ; index < length; ) { | |
359 | + int type = bytes[index++]; | |
360 | + int len = bytes[index++]; | |
361 | + len += (((int)bytes[index]) << 8); | |
362 | + index++; | |
363 | + NSLog(@"index: %ld, type: %d, len: %d", index, type, len); | |
364 | + switch (type) { | |
365 | + case 0x04: // battery threshold | |
366 | + status.batteryThreshold = bytes[index++]; | |
367 | + break; | |
368 | + case 0x05: // version name | |
369 | + data = [NSData dataWithBytes:&bytes[index] length:len]; | |
370 | + index += len; | |
371 | + status.versionName = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
372 | + break; | |
373 | + case 0x06: // board name | |
374 | + data = [NSData dataWithBytes:&bytes[index] length:len]; | |
375 | + index += len; | |
376 | + status.boardName = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
377 | + break; | |
378 | + case 0x07: // hardware rev | |
379 | + data = [NSData dataWithBytes:&bytes[index] length:len]; | |
380 | + index += len; | |
381 | + status.hardwareRev = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
382 | + break; | |
383 | + case 0x08: // version code | |
384 | + status.versionCode = [Utils bytes2UInt32:bytes index:index]; | |
385 | + index += 4; | |
386 | + break; | |
387 | + case 0x09: // feature support | |
388 | + status.featureSupport = bytes[index++]; | |
389 | + remoteCrcSupport = status.featureSupport & 0x01; | |
390 | + break; | |
391 | + default: | |
392 | + index += len; | |
393 | + break; | |
394 | + } | |
395 | + } | |
396 | + | |
397 | + if (errCode == 100000) { | |
398 | + // [self requestRemoteParameters]; | |
399 | + // [self scheduleTimeoutTimer]; | |
400 | + if(_delegate && [_delegate respondsToSelector:@selector(receiveRemoteStatus:)]) { | |
401 | + [_delegate receiveRemoteStatus:status]; | |
402 | + } | |
403 | + | |
404 | + [self notifyStatus:STATE_PREPARED]; | |
405 | + } else { | |
406 | + curState = STATE_UNKNOWN; | |
407 | + if(_delegate && [_delegate respondsToSelector:@selector(onError:)]) { | |
408 | + [_delegate onError:errCode]; | |
409 | + } | |
410 | + } | |
411 | + break; | |
412 | + } | |
413 | + case 0x02:{ | |
414 | + // app wait timeout | |
415 | + index += 3; | |
416 | + waitTimeout = [Utils bytes2Short:bytes index:index]; | |
417 | + index += 2; | |
418 | + | |
419 | + // device restart timeout | |
420 | + index += 3; | |
421 | + restartTimeout = [Utils bytes2Short:bytes index:index]; | |
422 | + index += 2; | |
423 | + | |
424 | + // ota unit size | |
425 | + index += 3; | |
426 | + otaUnit = [Utils bytes2Short:bytes index:index]; | |
427 | + NSLog(@"otaUnit:%ld", otaUnit); | |
428 | + if (maxMtu != 0) { | |
429 | + if ((maxMtu - 10) >= otaUnit) { | |
430 | + | |
431 | + } else { | |
432 | + otaUnit = maxMtu - 10; //根据最大mtu定制化设置单包最大数据量 | |
433 | + } | |
434 | + } else { | |
435 | + otaUnit = 172; | |
436 | + } | |
437 | + | |
438 | + index += 2; | |
439 | + | |
440 | + // interval | |
441 | + index += 3; | |
442 | + interval = [Utils bytes2Short:bytes index:index]; | |
443 | + index += 2; | |
444 | + | |
445 | + // ack enable | |
446 | + index += 3; | |
447 | + ackEnable = bytes[index] & 0xFF; | |
448 | + index++; | |
449 | + | |
450 | + [self removeTimeoutTimer]; | |
451 | + [self notifyRemoteAppReady:1]; | |
452 | + | |
453 | + // [self notifyStatus:STATE_PREPARED]; | |
454 | + break; | |
455 | + } | |
456 | + case 0x03:{ | |
457 | + [self notifyStatus:STATE_TRANSFERRING]; | |
458 | + | |
459 | + if (ackEnable == 1) { | |
460 | + NSArray *array = [NSArray arrayWithObject:tlvs]; | |
461 | + NSData *buf = [self assembleCommand:0x03 withTLVs:array]; | |
462 | + [self sendData:buf]; | |
463 | + } | |
464 | + | |
465 | + // file offset | |
466 | + int index = 3; | |
467 | + int offset = [Utils bytes2UInt32:bytes index:index]; | |
468 | + index += 4; | |
469 | + | |
470 | + // file length | |
471 | + index += 3; | |
472 | + int length = [Utils bytes2UInt32:bytes index:index]; | |
473 | + index += 4; | |
474 | + | |
475 | + // file apply bitmap | |
476 | + if (tlvs.length > 17) { | |
477 | + index ++; | |
478 | + int len = [Utils bytes2Short:bytes index:index]; | |
479 | + index += 2; | |
480 | + if (tlvs.length >= 17 + len) { | |
481 | + Byte *bitmap = (Byte *)malloc(len); | |
482 | + for (int i = 0; i < len; i++) { | |
483 | + bitmap[i] = bytes[index++]; | |
484 | + NSLog(@"bitmap[%d]: %x", i, bitmap[i]); | |
485 | + } | |
486 | + | |
487 | + NSData *bitmapData = [NSData dataWithBytes:bitmap length:len]; | |
488 | + free(bitmap); | |
489 | + | |
490 | + // 计算组数 | |
491 | + int groupNum = length / otaUnit + 1; | |
492 | + | |
493 | + NSArray *frames = [self readOTADataFrom:offset withLength:length byBitmap:bitmapData groupNum:groupNum]; | |
494 | +// for (NSInteger i = 0; i < frames.count; i++) { | |
495 | + for (int i = 0; i < frames.count; i++) { | |
496 | + Byte b[1] = {(Byte)(i % 256)}; | |
497 | + NSMutableData *pkg = [NSMutableData dataWithBytes:b length:1]; | |
498 | + | |
499 | + NSInteger command = 0x04; | |
500 | + if (remoteCrcSupport) { | |
501 | + command = 0x0B; | |
502 | + int32_t checksum = [Utils crc32:frames[i]]; | |
503 | + [pkg appendData: [NSData dataWithBytes: &checksum length: 4]]; | |
504 | + } | |
505 | + | |
506 | + [pkg appendData:frames[i]]; | |
507 | + NSArray *array = [NSArray arrayWithObject:pkg]; | |
508 | + NSData *data = [self assembleCommand:command withTLVs:array]; | |
509 | + | |
510 | + [self sendData:data index:i]; | |
511 | +// NSLog(@"nick_data:%@", data); | |
512 | + mWriteBytes += data.length; | |
513 | + [_delegate receiveSpeed:mWriteBytes]; | |
514 | + } | |
515 | + } | |
516 | + } | |
517 | + break; | |
518 | + } | |
519 | + case 0x05:{ | |
520 | + // package valid size | |
521 | + index += 3; | |
522 | + int pkgValidSize = [Utils bytes2UInt32:bytes index:index]; | |
523 | + index += 4; | |
524 | + | |
525 | + // received file size | |
526 | + index += 3; | |
527 | + int receivedSize = [Utils bytes2UInt32:bytes index:index]; | |
528 | + index += 4; | |
529 | + | |
530 | + NSLog(@"receive 0x0905 pkgValidSize: %d, receivedSize: %d", pkgValidSize, receivedSize); | |
531 | + break; | |
532 | + } | |
533 | + case 0x06:{ | |
534 | + index += 3; | |
535 | + int valid = bytes[index] & 0xFF; | |
536 | + index++; | |
537 | + | |
538 | + // NSData *buffer = [self assembleCommand:0x06 withTLVs:nil]; | |
539 | + // [self sendData:buffer]; | |
540 | + NSLog(@"receive 0x0906 valid: %d", valid); | |
541 | + | |
542 | + if (_delegate && [_delegate respondsToSelector:@selector(onStatus:)]) { | |
543 | + if (valid == 1) { | |
544 | + [_delegate onStatus:STATE_TRANSFERRED]; | |
545 | + } else { | |
546 | + [_delegate onStatus:STATE_UNKNOWN]; | |
547 | + } | |
548 | + } | |
549 | + | |
550 | + break; | |
551 | + } | |
552 | + case 0x07:{ | |
553 | + if (bytes[index++] == 0x7F) { | |
554 | + index += 2; | |
555 | + int errCode = [Utils bytes2UInt32:bytes index:index]; | |
556 | + index += 4; | |
557 | + if (errCode != 100000 | |
558 | + && _delegate | |
559 | + && [_delegate respondsToSelector:@selector(onError:)]) { | |
560 | + NSLog(@"0x0907 Error: %d", errCode); | |
561 | + | |
562 | + [_delegate onError:errCode]; | |
563 | + } | |
564 | + } | |
565 | + | |
566 | + break; | |
567 | + } | |
568 | + case 0x7D:{ | |
569 | + int type = bytes[index] & 0xFF; | |
570 | + index++; | |
571 | + int len = [Utils bytes2Short:bytes index:index]; | |
572 | + index += 2; | |
573 | + int psn = bytes[index] & 0xFF; | |
574 | + index++; | |
575 | + NSLog(@"0x097D, : %d, len: %d", psn, len); | |
576 | + | |
577 | + type = bytes[index] & 0xFF; | |
578 | + index++; | |
579 | + len = [Utils bytes2Short:bytes index:index]; | |
580 | + index += 2; | |
581 | + | |
582 | + NSData *buffer = [tlvs subdataWithRange:NSMakeRange(index, len)]; | |
583 | + NSLog(@"Receive 0x097D, data size: %d, %@", len, buffer); | |
584 | + | |
585 | + if (_delegate && [_delegate respondsToSelector:@selector(receiveAudioPSN:data:)]) { | |
586 | + [_delegate receiveAudioPSN:psn data:buffer]; | |
587 | + } | |
588 | + | |
589 | + break; | |
590 | + } | |
591 | + default: | |
592 | + break; | |
593 | + } | |
594 | + | |
595 | + // 如果还有剩余数据,则继续处理 | |
596 | + if (receiveBuffer.length > 0) { | |
597 | + [self receiveData:nil]; | |
598 | + } | |
599 | + | |
600 | + return YES; | |
601 | +} | |
602 | + | |
603 | +@end | ... | ... |
HDFwear/Tools/OTA/RemoteStatus.h
0 → 100644
1 | +// | |
2 | +// RemoteStatus.h | |
3 | +// ActsBluetoothOTA | |
4 | +// | |
5 | +// Created by inidhu on 2019/9/12. | |
6 | +// Copyright © 2019 Actions. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import <Foundation/Foundation.h> | |
10 | + | |
11 | +NS_ASSUME_NONNULL_BEGIN | |
12 | + | |
13 | +@interface RemoteStatus : NSObject | |
14 | + | |
15 | +@property (nonatomic, strong, nullable) NSString *versionName; | |
16 | +@property (nonatomic, strong, nullable) NSString *boardName; | |
17 | +@property (nonatomic, strong, nullable) NSString *hardwareRev; | |
18 | +@property (nonatomic, readwrite) NSInteger batteryThreshold; | |
19 | +@property (nonatomic, readwrite) NSInteger versionCode; | |
20 | +@property (nonatomic, readwrite) NSInteger featureSupport; | |
21 | + | |
22 | +@end | |
23 | + | |
24 | +NS_ASSUME_NONNULL_END | ... | ... |
HDFwear/Tools/OTA/RemoteStatus.m
0 → 100644
1 | +// | |
2 | +// RemoteStatus.m | |
3 | +// ActsBluetoothOTA | |
4 | +// | |
5 | +// Created by inidhu on 2019/9/12. | |
6 | +// Copyright © 2019 Actions. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import "RemoteStatus.h" | |
10 | + | |
11 | +@implementation RemoteStatus | |
12 | + | |
13 | +- (id)init | |
14 | +{ | |
15 | + if (self = [super init]) { | |
16 | + | |
17 | + self.batteryThreshold = 30; | |
18 | + self.versionName = nil; | |
19 | + self.boardName = nil; | |
20 | + self.hardwareRev = nil; | |
21 | + self.versionCode = 0; | |
22 | + self.featureSupport = 0x00; | |
23 | + } | |
24 | + | |
25 | + return self; | |
26 | +} | |
27 | + | |
28 | +@end | ... | ... |
HDFwear/Tools/OTA/Utils.h
0 → 100644
1 | +// | |
2 | +// Utils.h | |
3 | +// ActsBluetoothOTA | |
4 | +// | |
5 | +// Created by inidhu on 2019/5/22. | |
6 | +// Copyright © 2019 Actions. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import <Foundation/Foundation.h> | |
10 | + | |
11 | +NS_ASSUME_NONNULL_BEGIN | |
12 | + | |
13 | +@interface Utils : NSObject | |
14 | + | |
15 | ++ (UInt32)bytes2UInt32:(Byte*) bytes index:(NSInteger) index; | |
16 | ++ (UInt16)bytes2Short:(Byte*) bytes index:(NSInteger) index; | |
17 | + | |
18 | ++ (NSArray *)getZeroBitIndexMap:(NSData *) bitmap groupNum:(int) group; | |
19 | + | |
20 | ++ (int32_t)crc32:(NSData *)data; | |
21 | + | |
22 | +@end | |
23 | + | |
24 | +NS_ASSUME_NONNULL_END | ... | ... |
HDFwear/Tools/OTA/Utils.m
0 → 100644
1 | +// | |
2 | +// Utils.m | |
3 | +// ActsBluetoothOTA | |
4 | +// | |
5 | +// Created by inidhu on 2019/5/22. | |
6 | +// Copyright © 2019 Actions. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import "Utils.h" | |
10 | + | |
11 | +@implementation Utils | |
12 | + | |
13 | + | |
14 | ++ (UInt32)bytes2UInt32:(Byte*)bytes index:(NSInteger)index { | |
15 | + return (((bytes[index + 3] & 0xFF) << 24) + ((bytes[index + 2] & 0xFF) << 16)) + ((bytes[index + 1] & 0xFF) << 8) + (bytes[index] & 0xFF); | |
16 | +} | |
17 | + | |
18 | ++ (UInt16)bytes2Short:(Byte*)bytes index:(NSInteger)index { | |
19 | + return ((bytes[index + 1] & 0xFF) << 8) + (bytes[index] & 0xFF); | |
20 | +} | |
21 | + | |
22 | +/* 计算0比特位的个数 */ | |
23 | ++ (NSInteger)countZeroBit:(NSData *) bitmap { | |
24 | + NSInteger count = 0; | |
25 | + | |
26 | + Byte *bytes = (Byte *)[bitmap bytes]; | |
27 | + NSInteger length = bitmap.length; | |
28 | + | |
29 | + for (int i = 0; i < length; i++ ) { | |
30 | + Byte x = bytes[i]; | |
31 | + while ((x + 1) != 0) { | |
32 | + x |= (x + 1); | |
33 | + count++; | |
34 | + } | |
35 | + } | |
36 | + | |
37 | + return count; | |
38 | +} | |
39 | + | |
40 | +/* 从bitmap获取相应0bit位的索引 */ | |
41 | ++ (NSArray *)getZeroBitIndexMap:(NSData *) bitmap groupNum:(int) groupNum{ | |
42 | + NSMutableArray *indexMap = [[NSMutableArray alloc] init]; | |
43 | + | |
44 | + NSInteger count = 0; | |
45 | + NSInteger index = 0; | |
46 | + Byte *bytes = (Byte *)[bitmap bytes]; | |
47 | + for (NSInteger i = 0; i < bitmap.length; i++) { | |
48 | + Byte b = bytes[i]; | |
49 | + for (NSInteger j = 0; j < groupNum; j++) { | |
50 | + int offset = (index % groupNum); | |
51 | + | |
52 | + if ((b & (0x1 << offset)) == 0x0) { | |
53 | + [indexMap addObject:[NSNumber numberWithInteger:index]]; | |
54 | + count++; | |
55 | + } | |
56 | + | |
57 | + index++; | |
58 | + } | |
59 | + } | |
60 | + | |
61 | + return indexMap; | |
62 | +} | |
63 | + | |
64 | ++ (int32_t)crc32:(NSData *)data { | |
65 | + uint32_t *table = malloc(sizeof(uint32_t) * 256); | |
66 | + uint32_t crc = 0xffffffff; | |
67 | + uint8_t *bytes = (uint8_t *)[data bytes]; | |
68 | + | |
69 | + for (uint32_t i=0; i<256; i++) { | |
70 | + table[i] = i; | |
71 | + for (int j=0; j<8; j++) { | |
72 | + if (table[i] & 1) { | |
73 | + table[i] = (table[i] >>= 1) ^ 0xedb88320; | |
74 | + } else { | |
75 | + table[i] >>= 1; | |
76 | + } | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + for (int i=0; i<data.length; i++) { | |
81 | + crc = (crc >> 8) ^ table[crc & 0xff ^ bytes[i]]; | |
82 | + } | |
83 | + crc ^= 0xffffffff; | |
84 | + | |
85 | + free(table); | |
86 | + return crc; | |
87 | +} | |
88 | + | |
89 | +@end | ... | ... |