iOS Question [SOLVED] Read BLE RSSI while connected

techknight

Well-Known Member
Licensed User
Longtime User
I noticed Android has a ReadRemoteRSSI function, but I cannot find it in the iOS version.

iOS does have a ReadRSSI() feature that works once per second interval for retrieving a connected RSSI value.

For example,

B4X:
-(void)update


{


[_peripheral readRSSI];// _peripheral is the connected device


deviceRSSI.text = [NSString stringWithFormat:@"%d",[[_peripheral RSSI] intValue]];


}

How do I make this work in B4I?
 

techknight

Well-Known Member
Licensed User
Longtime User
I found this online:

B4X:
- (void)updateConnectedRSSITimerFunc {
   for(TheCustomPeripheral *arrayItem in self.peripherals) {
     if(arrayItem.connected) {
         //This is called every 4 seconds from an NSTimer succesfully
         [arrayItem.peripheral readRSSI];
         NSLog(@"RSSI request");
     }
   }
}

-(void) peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error {
   NSLog(@"RSSI returned %@", [RSSI stringValue]);
}

from here: https://stackoverflow.com/questions/27394949/readrssi-not-calling-didreadrssi

But I feel like I am pissing in the wind here because I dont know what to do with that, or how to plug this in. the source code for iBLE isnt available I presume.
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Everything that I am finding online is written in swift. B4I doesnt support inline swift so that sorta "walled gardens" the situation. Anyways.

Help?
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
So, I tried this:

B4X:
#IF OBJC
#import <CoreBluetooth/CoreBluetooth.h>
#import <CoreBluetooth/CBPeripheral.h>

CBPeripheral*           peripheral;

- (void)GetRSSIVal {
//    var peripheral = CBPeripheral;
    peripheral.delegate = self;
    [peripheral readRSSI];  
//    [self.bi raiseEvent:nil event:@"some_sub:" params:@[@10]];
}

- (void)peripheral:(CBPeripheral *)peripheral
       didReadRSSI:(NSNumber *)RSSI
             error:(NSError *)error {
            NSLog(@"RSSI returned %@", [RSSI stringValue]);
            [self.bi raiseEvent:nil event:@"some_sub:" params:@[RSSI]];
}
#End If

This isnt giving me any compile errors, but the peripheral: event never fires. Ugh. So now I am lost. the only shred of thought I have, is somehow getting the CBPeripheral/peripheral from the connected instance through BleManager. But how?
 
Last edited:
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Well, getRSSI is designed to fire a CBperipheral event did readrssi which contains the value. So I dont know if this will work?

Since I have the event in the OBJC clause, I Will try it and see.
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Got it working!

B4X:
    Dim per As NativeObject = manager.GetPeripheralObject
    Dim central As NativeObject = Me
    central.RunMethod("GetRSSIVal:", Array(per))

#IF OBJC
#import <CoreBluetooth/CoreBluetooth.h>
#import <CoreBluetooth/CBPeripheral.h>
#import <CoreBluetooth/CBCentralManager.h>

- (void)GetRSSIVal:(CBPeripheral*)peripheral {
//    CBPeripheral *peripheral = [CBPeripheral manager:retrieveConnectedPeripherals];
    peripheral.delegate = self;
    [peripheral readRSSI];   
    NSLog(@"Peripheral %@", peripheral.name);
}

- (void)peripheral:(CBPeripheral *)peripheral
       didReadRSSI:(NSNumber *)RSSI
             error:(NSError *)error {
            NSLog(@"RSSI returned %@", [RSSI stringValue]);
           //  [self.bi raiseEvent:nil event:@"some_sub:" params:@[RSSI]];
}
#End If

I am sure I need to clean up some of this.

in my log, I have RSSI returned -39

So its working!
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
I tried to simplify it a little more by simply just doing this:

B4X:
per.RunMethod("readRSSI", Null)

But it doesnt work as the event does not fire.

So the delegate self is important.
 
Upvote 0

techknight

Well-Known Member
Licensed User
Longtime User
Here is my final code, it is working:

B4X:
Sub GetRSSI
    If connected = False Then Return 'No RSSI Available.
    Dim per As NativeObject = manager.GetPeripheralObject
    Dim NativeMe As NativeObject = Me
    NativeMe.RunMethod("GetRSSIVal:", Array(per))
End Sub

Sub Peripheral_RssiAvailable(RSSI As Double)
    Log("RSSI: " & RSSI)
    Dim RSSILevel As Int = CalculateSignalLevel(RSSI, 5)
    Log ("RSSI Level: " & RSSILevel)
End Sub

Sub CalculateSignalLevel(RSSI As Double, maxbars As Int) As Int
    Dim MIN_RSSI As Int = -90
    Dim MAX_RSSI As Int = -55
    Dim inputRange As Float = MAX_RSSI - MIN_RSSI
    Dim outputRange As Float = maxbars - 1
    If RSSI <= MIN_RSSI Then
        Return 0
    Else if RSSI >= MAX_RSSI Then
        Return maxbars - 1
    Else
        Return (RSSI - MIN_RSSI) * outputRange / inputRange
    End If
End Sub

#IF OBJC
#import <CoreBluetooth/CoreBluetooth.h>
#import <CoreBluetooth/CBPeripheral.h>

- (void)GetRSSIVal:(CBPeripheral*)peripheral {
    peripheral.delegate = self; //IMPORTANT or the event wont fire!
    [peripheral readRSSI];
}

- (void)peripheral:(CBPeripheral *)peripheral
       didReadRSSI:(NSNumber *)RSSI
             error:(NSError *)error {
            [self.bi raiseEvent:nil event:@"peripheral_rssiavailable:" params:@[RSSI]];
}
#End If

This could probably simply just be put into the iBLE library.

Edit: For the sake of goofing off, and my own learning curiosity, I tried this:

B4X:
    per.SetField("delegate", Me)
    per.RunMethod("readRSSI", Null)

That works too!
 
Upvote 0
Top