@@ -218,6 +218,7 @@ - (instancetype)initWithPeripheral:(id<MBLBluetoothPeripheral>)peripheral
218218 self.identifier = peripheral.identifier ;
219219 self.nameImpl = peripheral.name ;
220220 self.discoveryTimeRSSI = RSSI;
221+ self.model = MBLModelUnknown;
221222
222223 self.state = MBLConnectionStateDisconnected;
223224
@@ -528,6 +529,7 @@ - (BFTask *)resetModulesAsync
528529 self .photometer ? self .photometer : [NSNull null ],
529530 self .proximity ? self .proximity : [NSNull null ],
530531 self .sensorFusion ? self .sensorFusion : [NSNull null ]];
532+ self.model = [self calculateModelType ];
531533
532534 // Save this as the reset state of the device
533535 // Do this on the bleQueue so that we don't process events while the save state is happening
@@ -616,7 +618,7 @@ - (BFTask *)setConfigurationAsync:(id<MBLRestorable>)configuration
616618 [self removeResetFile ];
617619
618620 // When the disconnect occurs we know the device has been cleared and is ready for a fresh programming
619- [[self waitForDisconnection ] continueOnMetaWearWithBlock: ^id _Nullable (BFTask * _Nonnull t) {
621+ [[self waitForDisconnect ] continueOnMetaWearWithBlock: ^id _Nullable (BFTask * _Nonnull t) {
620622 // Reconnect if we need to program the beast
621623 if (configuration) {
622624 [[[self connectAsync ] success: ^(id _Nonnull result) {
@@ -768,7 +770,7 @@ - (BFTask *)disconnectAsync
768770 switch (self.state ) {
769771 case MBLConnectionStateConnected:
770772 {
771- BFTask *task = [self waitForDisconnection ];
773+ BFTask *task = [self waitForDisconnect ];
772774 [[self waitForCommandCompletion ] continueOnMetaWearWithBlock: ^id _Nullable (BFTask * _Nonnull t) {
773775 self.state = MBLConnectionStateDisconnecting;
774776 [[MBLMetaWearManager sharedManager ] disconnectMetaWear: self fromPeripheralSide: YES ];
@@ -780,22 +782,63 @@ - (BFTask *)disconnectAsync
780782 case MBLConnectionStateDiscovery:
781783 {
782784 self.state = MBLConnectionStateDisconnecting;
783- BFTask *task = [self waitForDisconnection ];
785+ BFTask *task = [self waitForDisconnect ];
784786 [[self waitForCommandCompletion ] continueOnMetaWearWithBlock: ^id _Nullable (BFTask * _Nonnull t) {
785787 [[MBLMetaWearManager sharedManager ] disconnectMetaWear: self fromPeripheralSide: NO ];
786788 return nil ;
787789 }];
788790 return task;
789791 }
790792 case MBLConnectionStateDisconnecting:
791- return [self waitForDisconnection ];
793+ return [self waitForDisconnect ];
792794 case MBLConnectionStateDisconnected:
793795 return nil ;
794796 }
795797 }];
796798}
797799
798- - (BFTask *)waitForDisconnection
800+ - (MBLModel)calculateModelType
801+ {
802+ if ([self .deviceInfo.modelNumber isEqualToString: @" 0" ]) {
803+ return MBLModelMetaWearR;
804+ } else if ([self .deviceInfo.modelNumber isEqualToString: @" 1" ]) {
805+ if (self.modules ) {
806+ if (self.barometer ) {
807+ return MBLModelMetaWearRPro;
808+ } else {
809+ return MBLModelMetaWearRG;
810+ }
811+ } else {
812+ return MBLModelUnknown;
813+ }
814+ } else if ([self .deviceInfo.modelNumber isEqualToString: @" 2" ]) {
815+ if (self.modules ) {
816+ if (self.proximity ) {
817+ return MBLModelMetaDetector;
818+ } else if (self.hygrometer ) {
819+ return MBLModelMetaEnvironment;
820+ } else if (self.magnetometer ) {
821+ return MBLModelMetaWearCPro;
822+ } else {
823+ return MBLModelMetaWearC;
824+ }
825+ } else {
826+ return MBLModelUnknown;
827+ }
828+ } else if ([self .deviceInfo.modelNumber isEqualToString: @" 3" ]) {
829+ return MBLModelMetaHealth;
830+ } else if ([self .deviceInfo.modelNumber isEqualToString: @" 4" ]) {
831+ return MBLModelMetaTracker;
832+ } else if ([self .deviceInfo.modelNumber isEqualToString: @" 5" ]) {
833+ return MBLModelMetaMotionR;
834+ } else if ([self .deviceInfo.modelNumber isEqualToString: @" 6" ]) {
835+ return MBLModelMetaMotionC;
836+ } else {
837+ return MBLModelUnknown;
838+ }
839+ }
840+
841+ - (BFTask<MBLMetaWear *> *)waitForDisconnect ;
799842{
800843 BFTaskCompletionSource *taskSource = [BFTaskCompletionSource taskCompletionSource ];
801844 @synchronized (disconnectionSources) {
@@ -1113,6 +1156,13 @@ - (void)peripheral:(id<MBLBluetoothPeripheral>)peripheral didReadRSSI:(NSNumber
11131156
11141157- (BFTask<NSNumber *> *)readBatteryLifeAsync
11151158{
1159+ // Use the new age thing if we have it.
1160+ if (self.settings .batteryRemaining ) {
1161+ return [[self .settings.batteryRemaining readAsync ] continueWithSuccessBlock: ^id _Nullable (BFTask<MBLNumericData *> * _Nonnull t) {
1162+ return t.result .value ;
1163+ }];
1164+ }
1165+ // Fall back on the battery characteristic
11161166 if (!batteryLifeCharacteristic) {
11171167 return [BFTask taskWithError: [NSError errorWithDomain: kMBLErrorDomain
11181168 code: kMBLErrorNotConnected
@@ -1246,7 +1296,7 @@ - (BFTask *)prepareForFirmwareUpdateToVersionAsync:(MBLFirmwareBuild *)firmware
12461296 }
12471297 // Getting into DFU causes the device to disconnect, so we execute this
12481298 // async to make sure our disconnection handler gets registered first.
1249- BFTask *disconnectTask = [self waitForDisconnection ];
1299+ BFTask *disconnectTask = [self waitForDisconnect ];
12501300 if (alreadyInDFU) {
12511301 // See to simulate the disconnect that occurs when we jump to bootloader
12521302 [[MBLMetaWearManager sharedManager ] disconnectMetaWear: self fromPeripheralSide: NO ];
@@ -1492,12 +1542,24 @@ -(void)peripheral:(id<MBLBluetoothPeripheral>)peripheral didUpdateValueForCharac
14921542 if (!characteristic.value .length ) {
14931543 return ;
14941544 }
1495- uint8_t moduleId = *(uint8_t *)characteristic.value .bytes ;
1496- @synchronized (moduleInfoTaskSources) {
1497- BFTaskCompletionSource *source = moduleInfoTaskSources[[NSNumber numberWithInt: moduleId]];
1498- if (source) {
1545+ uint8_t *bytes = (uint8_t *)characteristic.value .bytes ;
1546+ uint8_t moduleId = *bytes; bytes++;
1547+ uint8_t registerId = *bytes;
1548+ // The first register is special and should only be read during initialization
1549+ if (registerId == 0x80 ) {
1550+ @synchronized (moduleInfoTaskSources) {
1551+ BFTaskCompletionSource *source = moduleInfoTaskSources[[NSNumber numberWithInt: moduleId]];
1552+ if (!source) {
1553+ // If another app tries to connect to this MetaWear it could issue these discovery
1554+ // commands again, so lets track any unexpected reads of the these registers and use that
1555+ // as an indicator someone is trying to use 2 apps simultaneously which is very
1556+ // dangerous and unsupported. Our only option is to disconnect this app.
1557+ MBLLog (MBLLogLevelWarning, @" Simultaneous Connection - Disconnecting %@ because another App has initiated a connection" , self);
1558+ [[MBLMetaWearManager sharedManager ] disconnectMetaWear: self fromPeripheralSide: NO ];
1559+ }
14991560 [moduleInfoTaskSources removeObjectForKey: [NSNumber numberWithInt: moduleId]];
15001561 if (error) {
1562+ // TODO: This can probably never be hit
15011563 [source trySetError: error];
15021564 } else if (characteristic.value .length >= 4 ) {
15031565 // 4 or more bytes indicates the module is present and active
@@ -1507,22 +1569,27 @@ -(void)peripheral:(id<MBLBluetoothPeripheral>)peripheral didUpdateValueForCharac
15071569 [source trySetResult: nil ];
15081570 }
15091571 [self decrementCount ];
1510- } else if (moduleId < self. modules . count ) {
1511- id module = self.modules [moduleId];
1512- if ([module respondsToSelector: @selector ( recievedData:error: )]) {
1513- [module recievedData: characteristic.value error: error];
1514- } else {
1515- assert ( NO && " No module found " );
1516- }
1517- } else if (moduleId == self. testDebug . moduleInfo . moduleId ) {
1518- if ([ self .testDebug respondsToSelector: @selector ( recievedData:error: )] ) {
1519- [self .testDebug recievedData: characteristic.value error: error];
1520- } else {
1521- assert ( NO && " No testDebug module found " );
1522- }
1572+ }
1573+ } else if (moduleId < self.modules . count ) {
1574+ id module = self. modules [moduleId];
1575+ if ( [module respondsToSelector: @selector ( recievedData:error: )]) {
1576+ [module recievedData: characteristic.value error: error];
1577+ } else {
1578+ assert ( NO && " No module found " );
1579+ }
1580+ } else if (moduleId == self.testDebug . moduleInfo . moduleId ) {
1581+ if ( [self .testDebug respondsToSelector: @selector ( recievedData:error: )]) {
1582+ [ self .testDebug recievedData: characteristic.value error: error];
1583+ } else {
1584+ assert ( NO && " No testDebug module found " );
15231585 }
15241586 }
15251587 } else if (characteristic == batteryLifeCharacteristic) {
1588+ if (!characteristic.value .length ) {
1589+ // Retry if no data received
1590+ [peripheral readValueForCharacteristic: characteristic];
1591+ return ;
1592+ }
15261593 @synchronized (batteryLifeSources) {
15271594 for (BFTaskCompletionSource *source in batteryLifeSources) {
15281595 if (error) {
0 commit comments