3

Whatever I seem to try I cannot currently get back the Battery level from the iOS/SocketScan API. I am using version 10.3.36, here is my code so far:

func onDeviceArrival(result: SKTRESULT, device deviceInfo: DeviceInfo!) {
    print("onDeviceArrival:\(deviceInfo.getName())")
scanApiHelper.postGetBattery(deviceInfo, target: self, response: #selector(onGetBatteryInfo))

}

func onGetBatteryInfo(scanObj: ISktScanObject) {

    let result:SKTRESULT = scanObj.Msg().Result()
    print("GetBatteryInfo status:\(result)")

    if (result == ESKT_NOERROR) {
        let batterylevel = scanObj.Property().getUlong()
        print("Battery is:\(batterylevel)")
    } else {
        print("Error GetBatteryInfo status:\(result)")
    }

However, the values I get back are:

GetBatteryInfo status:0

Battery is:1677741312

If my code is correct then how do I make the Battery result I get back a meaningful result, like a percentage?
If I'm way off then how do I get back info like the battery level, firmware version etc?

Thanks

David

Destrif
  • 2,104
  • 1
  • 14
  • 22
Dave
  • 351
  • 4
  • 18

3 Answers3

2

EDIT: SKTBATTERY_GETCURLEVEL isn't supported in Swift. However, the docs explain that the battery level response includes the min, current and max levels encoded in the first, second and third bytes, respectively.

The following is equivalent to using SKTBATTERY_GETCURLEVEL

Swift

func onGetBatteryInfo(scanObj: ISktScanObject) {

    let result:SKTRESULT = scanObj.Msg().Result()

    if(SKTSUCCESS(result)){

        let batteryInfo = scanObj.Property().getUlong();

        let batteryMin = ((batteryInfo >> 4) & 0xff);
        let batteryCurrent = ((batteryInfo >> 8) & 0xff);
        let batteryMax = ((batteryInfo >> 12) & 0xff);

        let batteryPercentage = batteryCurrent / (batteryMax - batteryMin);
        print("Battery is:\(batteryPercentage)")

        self.setBatteryLevel = batteryPercentage
        self.tableView.reloadData

    } else {

        print("Error GetBatteryInfo status:\(result)")
    }
}

Objective-C

-(void) onGetBatteryInfo:(ISktScanObject*)scanObj {

SKTRESULT result=[[scanObj Msg]Result];
if(SKTSUCCESS(result)){

    long batteryLevel = SKTBATTERY_GETCURLEVEL([[scanObj Property] getUlong]);
    NSLog(@"BatteryInfo %ld", batteryLevel);

    [self setBatteryLevel:batteryLevel];
    [self.tableView reloadData];

} else {

    NSLog(@"Error GetBatteryInfo status: %ld",result);
}
}
Edison
  • 11,881
  • 5
  • 42
  • 50
  • Thanks for the answer, that's exactly what I thought, but in Swift as far as I can see it knows nothing about SKTBATTERY_GETCURLEVEL, you can't use SKTBATTERY_GETCURLEVEL as you get use of unresolved identifer. that's why I am stuck as according to the documentation it should be fine! – Dave Jul 07 '16 at 22:17
  • 1
    @Dave I edited tymac's answer to inline the code for `SKTBATTERY_GETCURLEVEL` because you are right, that is a `#define` macro which doesn't exist in the swift version – Enrico Jul 07 '16 at 22:42
  • 1
    Thanks @Enrico. As noted I translated it from Objective-C. Actually I have an open ticket with SocketScan myself as I need to ask them about something else. Dave if you want to use their native class method you can just write an Objective-C 'extension'. I added the Objective-C incase you want it. Enrico's use of bitwise masking to get the percentage equivalent is amazing :) – Edison Jul 08 '16 at 00:40
  • Hi Guys that is brilliant! Works a treat, thanks so much for your help, I would not have got that working in a million years otherwise!!!! Awesome stuff, thanks!!! – Dave Jul 08 '16 at 07:37
  • Glad we could help you out. Good luck in your project @Dave. – Edison Jul 08 '16 at 07:41
  • I just found out that Enrico is from the SocketScan Dev Team so this is totally official. lol Thanks guys. – Edison Jul 08 '16 at 19:02
0

Here's code I use. Theres a variable defined in appDelegate for the batteryPercentage, and that is read when the v value is needed. The value is updated each 120 seconds by a timer, this way actions can occur as the level drops etc.

 func onBatteryLevel (scanObj: ISktScanObject) {
    let result: SKTRESULT = scanObj.Msg().Result()
    if (SKTRESULT(result) > -1) {
        let property: ISktScanProperty = scanObj.Property()
        var batteryLevel = property.getUlong()

        #if arch(x86_64) || arch(arm64)
            batteryLevel = (batteryLevel<<(48))>>(56)
            #else
            batteryLevel = (batteryLevel<<(48-32))>>(56-32)
        #endif
        batteryPercentage = Int(batteryLevel)
    } else {
        debug ("data error \(result)")
    }
}
0

For Swift 4 I just came across this problem and came up with the following solution.

var lastDeviceConnected : CaptureHelperDevice? {

    didSet {

        guard let lastDevice = self.lastDeviceConnected else { return }
        lastDevice.getBatteryLevelWithCompletionHandler { result, batteryLevel in

            guard result == SKTResult.E_NOERROR, let batteryLevel = batteryLevel else { return }

            let minimum = SKTHelper.getMinimumLevel(fromBatteryLevel: Int(batteryLevel))
            let maximum = SKTHelper.getMaximumLevel(fromBatteryLevel: Int(batteryLevel))
            let current = SKTHelper.getCurrentLevel(fromBatteryLevel: Int(batteryLevel))

            print("minimum: \(minimum)")
            print("maximum: \(maximum)")
            print("current: \(current)")

            // current is out battery level in %
            // minimum and maximum could for example be used for 
            // for a slider or something that visually presents
            // the battery status
        }
    }
}

In my example I'm not handling the case that there could be no device or that the battery status might not have been retrieved as expected. I simply guard / return. In your example you might want to handle the issue.

David Seek
  • 16,783
  • 19
  • 105
  • 136