diff options
author | Kiran Kelageri <kirankelageri@codeaurora.org> | 2015-07-30 16:16:14 -0700 |
---|---|---|
committer | Kiran Kelageri <kirankelageri@codeaurora.org> | 2015-08-04 14:42:58 -0700 |
commit | fbec7160bd960dc9a98c2b924554710d3f77a411 (patch) | |
tree | 00e1efe941a0dbddb9206a60b39830f636e2873a /wipower-host | |
parent | 675d87c33ad8008f93b2f83b2db13a981a1321e7 (diff) | |
download | android_packages_apps_BluetoothExt-fbec7160bd960dc9a98c2b924554710d3f77a411.tar.gz android_packages_apps_BluetoothExt-fbec7160bd960dc9a98c2b924554710d3f77a411.tar.bz2 android_packages_apps_BluetoothExt-fbec7160bd960dc9a98c2b924554710d3f77a411.zip |
Bluetooth-Wipower: Wipower refactoring.
Wipower code move from aosp (packages and frameworks)
to vendor on M.
Change-Id: I632d456acc99f53c482c828a9b44b2bea8a7d7fb
Diffstat (limited to 'wipower-host')
18 files changed, 3293 insertions, 0 deletions
diff --git a/wipower-host/Android.mk b/wipower-host/Android.mk new file mode 100644 index 0000000..20d13f5 --- /dev/null +++ b/wipower-host/Android.mk @@ -0,0 +1,5 @@ +ifeq ($(BOARD_USES_WIPOWER),true) +LOCAL_PATH := $(call my-dir) +include $(call all-subdir-makefiles) +endif + diff --git a/wipower-host/a4wp/Android.mk b/wipower-host/a4wp/Android.mk new file mode 100644 index 0000000..996d243 --- /dev/null +++ b/wipower-host/a4wp/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional +src_dirs:= src/org/codeaurora/bluetooth/a4wp_app \ + src/org/codeaurora/bluetooth/wipower + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, $(src_dirs)) + +LOCAL_PACKAGE_NAME := a4wpservice +LOCAL_CERTIFICATE := platform +LOCAL_JAVA_LIBRARIES += com.quicinc.wbc +LOCAL_JAVA_LIBRARIES += android.wipower + +LOCAL_REQUIRED_MODULES := bluetooth.default + +LOCAL_PROGUARD_ENABLED := disabled + +LOCAL_MULTILIB := 32 +LOCAL_JNI_SHARED_LIBRARIES := libwipower_jni + +include $(BUILD_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/wipower-host/a4wp/AndroidManifest.xml b/wipower-host/a4wp/AndroidManifest.xml new file mode 100644 index 0000000..ef75a6f --- /dev/null +++ b/wipower-host/a4wp/AndroidManifest.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.codeaurora.bt_wipower" + android:sharedUserId="android.uid.bluetooth"> + + <original-package android:name="org.codeaurora.bt_wipower" /> + + <uses-permission android:name="android.permission.ACCESS_BLUETOOTH_SHARE" /> + <uses-permission android:name="android.permission.BLUETOOTH" /> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.BLUETOOTH_STACK" /> + <application android:process="com.android.bluetooth" + android:name=".wipower.WipowerApp" + android:persistent="false" + android:supportsRtl="true"> + <uses-library android:name="com.quicinc.wbc" + android:required="false" /> + <uses-library android:name="android.wipower" + android:required="false" /> + <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" /> + <receiver + android:name=".wipower.BTEventHandler" + android:exported="true" + android:enabled="true" + android:process="com.android.bluetooth"> + <intent-filter> + <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" /> + </intent-filter> + </receiver> + <service + android:name = ".wipower.WipowerService" + android:exported="true" + android:enabled="true" + android:process="com.android.bluetooth"> + <intent-filter> + <action android:name="android.wipower.IWipower" /> + </intent-filter> + </service> + + <service + android:process="com.android.bluetooth" + android:exported="true" + android:name = ".a4wp.A4wpService"> + </service> + <receiver + android:process="com.android.bluetooth" + android:exported="true" + android:name=".a4wp.BTEventHandler"> + <intent-filter> + <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" /> + </intent-filter> + </receiver> + + </application> +</manifest> diff --git a/wipower-host/a4wp/src/org/codeaurora/bluetooth/a4wp_app/A4wpService.java b/wipower-host/a4wp/src/org/codeaurora/bluetooth/a4wp_app/A4wpService.java new file mode 100644 index 0000000..c5024a6 --- /dev/null +++ b/wipower-host/a4wp/src/org/codeaurora/bluetooth/a4wp_app/A4wpService.java @@ -0,0 +1,1131 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.codeaurora.bt_wipower.a4wp; + +import java.util.UUID; + +import android.bluetooth.BluetoothManager; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothGattServer; +import android.bluetooth.BluetoothGattServerCallback; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.app.Service; +import android.net.Credentials; +import java.io.OutputStream; +import android.util.Log; +import android.os.IBinder; +import android.content.Intent; +import android.os.Process; +import java.nio.ByteBuffer; +import android.wipower.WipowerManager; +import android.wipower.WipowerManagerCallback; +import android.wipower.WipowerManager.WipowerState; +import android.wipower.WipowerManager.PowerApplyEvent; +import android.wipower.WipowerManager.PowerLevel; +import android.wipower.WipowerDynamicParam; +import com.quicinc.wbc.WbcManager; +import com.quicinc.wbc.WbcTypes; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; + +import android.bluetooth.le.AdvertiseCallback; +import android.bluetooth.le.AdvertiseSettings; +import android.bluetooth.le.AdvertiseData; +import android.bluetooth.le.BluetoothLeAdvertiser; +import android.os.ParcelUuid; +import android.os.PowerManager; +import android.os.SystemProperties; + +/** + * Class which executes A4WP service + */ +public class A4wpService extends Service +{ + private static final String LOGTAG = "A4wpService"; + private static OutputStream mOutputStream = null; + private BluetoothAdapter mBluetoothAdapter = null; + private BluetoothGattServer mBluetoothGattServer = null; + private BluetoothGattCharacteristic mPruAlertChar = null; + private BluetoothDevice mDevice = null; + private PowerManager.WakeLock mWakeLock = null; + + // Advertising variables + private final static int START_ADVERTISING = 1; + private final static int STOP_ADVERTISING = 0; + + private static final UUID A4WP_SERVICE_UUID = UUID.fromString("6455fffe-a146-11e2-9e96-0800200c9a67"); + //PRU writes + private static final UUID A4WP_PRU_CTRL_UUID = UUID.fromString("6455e670-a146-11e2-9e96-0800200c9a67"); + private static final UUID A4WP_PTU_STATIC_UUID = UUID.fromString("6455e671-a146-11e2-9e96-0800200c9a67"); + //PRU reads + private static final UUID A4WP_PRU_ALERT_UUID = UUID.fromString("6455e672-a146-11e2-9e96-0800200c9a67"); + private static final UUID A4WP_PRU_STATIC_UUID = UUID.fromString("6455e673-a146-11e2-9e96-0800200c9a67"); + private static final UUID A4WP_PRU_DYNAMIC_UUID = UUID.fromString("6455e674-a146-11e2-9e96-0800200c9a67"); + + private static final UUID A4WP_PRU_ALERT_DESC_UUID = UUID.fromString("64552902-a146-11e2-9e96-0800200c9a67"); + + private static final Object mLock = new Object(); + private int mState = BluetoothProfile.STATE_DISCONNECTED; + + private final static short DEFAULT_FIELDS = 0x0000; + private final static short DEFAULT_PROTOCOL_REV = 0x0000; + private final static short DEFAULT_RFU = 0x0000; + //03 if MTP, Has to be 04 for fluid. + private final static byte DEFAULT_CATEGORY = 0x0003; + private final static byte DEFAULT_CAPABILITIES = 0x0010; + private final static byte DEFAULT_HW_VERSION = 0x0007; + private final static byte DEFAULT_FW_VERSION = 0x0006; + private final static byte DEFAULT_MAX_POWER_DESIRED = 0x0032; // 5Watts + private final static short DEFAULT_VRECT_MIN = 7100; // 7.1 Volts + private final static short DEFAULT_VRECT_MAX = 19300; // 19.3 Volts + private final static short DEFAULT_VRECT_SET = 7100; // 7.1 Volts + private final static short DEFAULT_DELTA_R1 = 0x0001; + private final static int DEFAULT_RFU_VAL = 0x0000; + private static final int MSB_MASK = 0xFF00; + private static final int LSB_MASK= 0x00FF; + // On charge port disbaled need to be set to 10.2 Volts + private final static short VRECT_MIN_CHG_DISABLED = 10200; + // Populate Vrectmin, Vrectmax, Vrectset and temperature in the optional fields + private final static byte OPTIONAL_FIELD_MASK = 0x3C; + + //Timeout value set to 5Sec which enures we advertise in limited mode + private static final int WIPOWER_ADV_TIMEOUT = 5000; + + //PRU Write param length for validation + private static final byte A4WP_PTU_STATIC_LENGTH = 0x11; + private static final byte A4WP_PRU_CTRL_LENGTH = 0x05; + private static final byte CCCD_LENGTH = 0x02; // Client Characteristic Configuration Declaration length + + //Advertisement interval values. + private static final byte A4WP_ADV_MIN_INTERVAL = 0x20; + private static final byte A4WP_ADV_MAX_INTERVAL = 0x20; + + //mask bits for charge port and irect validations + private static final int CHARGE_PORT_MASK = 0x02; + private static final int IRECT_MASK_MSB = 0x00; + private static final int IRECT_MASK_LSB = 0x15; + private static final int VRECT_MASK = 0x00; + private static short VRECT_DYN; + + //Indices definitions + private static final int OPTIONAL_FIELDS = 0; + private static final int VRECT_LSB = 1; + private static final int VRECT_MSB = 2; + private static final int IRECT_LSB = 3; + private static final int IRECT_MSB = 4; + private static final int VRECT_MIN_LSB = 10; + private static final int VRECT_MIN_MSB = 11; + private static final int VRECT_SET_LSB = 12; + private static final int VRECT_SET_MSB = 13; + private static final int VRECT_MAX_LSB = 14; + private static final int VRECT_MAX_MSB = 15; + private static final int PRU_ALERT = 16; + + private static boolean mWipowerBoot = false; + private static boolean isChargePortSet = false; + static boolean mChargeComplete = true; + static boolean mOutputControl = false; + private static boolean mDiscInitiated = false; // If TRUE, means A4WP app has initiated the disconnection with PTU + private static boolean mEnablePruAlerts = false; // Are PRU Alerts enabled + + private AdvertiseSettings mAdvertiseSettings; + private AdvertiseData mAdvertisementData; + private BluetoothLeAdvertiser mAdvertiser; + private AdvertiseCallback mAdvertiseCallback = new myAdvertiseCallback(1); + ParcelUuid uuid1 = ParcelUuid.fromString("6455fffe-a146-11e2-9e96-0800200c9a67"); + + /*a> Due to bad coupling irect value drops to zero and vrect remains + constant would render stark to reset the CHG_OK pin, So as to + set this pin on coupling being recovered host delivers the charge + enable command to set the CHG_OK pin. + b> Charge port needs to be enabled only if the vrect value is greater + than the Vmin values */ + private void chkDynParamsAndStartCharging(byte[] value) + { + VRECT_DYN = 0x00; + if (!isChargePortSet) { + VRECT_DYN = (short)toUnsigned(value[VRECT_LSB]); + VRECT_DYN |= (short)(toUnsigned(value[VRECT_MSB]) << 8); + if (DEFAULT_VRECT_MIN <= VRECT_DYN && mOutputControl) { + mWipowerManager.startCharging(); + isChargePortSet = true; + } + } + if (isChargePortSet) { + if ((byte)(value[PRU_ALERT] & CHARGE_PORT_MASK) == CHARGE_PORT_MASK) { + if ((value[IRECT_LSB] <= IRECT_MASK_LSB && value[IRECT_MSB] == IRECT_MASK_MSB) + && (value[VRECT_LSB] > VRECT_MASK || value[VRECT_MSB] > VRECT_MASK)) { + mWipowerManager.startCharging(); + } + } + } + } + + private synchronized void initiateDisconnection() { + Log.v(LOGTAG, "initiateDisconnection:" + " mDiscInitiated:" + mDiscInitiated + " mState:" + mState); + if ((mDiscInitiated == false) && (mState == BluetoothProfile.STATE_CONNECTED)) + { + if (mBluetoothGattServer != null && mDevice != null) { + Log.v(LOGTAG, "initiateDisconnection:" + " dropping Connection"); + mDiscInitiated = true; + mBluetoothGattServer.cancelConnection(mDevice); + if (mChargeComplete == true) { + mWipowerManager.enablePowerApply(true, true, true); + } else { + mWipowerManager.enablePowerApply(true, true, false); + } + } + } + return; + } + + private WbcManager.WbcEventListener mWbcCallback = new WbcManager.WbcEventListener() { + + @Override + public void onWbcEventUpdate(int what, int arg1, int arg2) { + Log.v(LOGTAG, "onWbcEventUpdate rcvd: " + what + ", " + arg1 + ", " + arg2); + if ((what == WbcTypes.WBC_EVENT_TYPE_CHARGING_REQUIRED_STATUS)){ + if ((arg1 == WbcTypes.WBC_BATTERY_STATUS_CHARGING_NOT_REQUIRED)){ + // this will set charge complete bit in pru alert + // eventally leading to a possible disconnect from ptu + mChargeComplete = true; + if (mPruAlert != null) + { + byte alert = 0; + alert = (byte) (alert | CHARGE_COMPLETE_BIT); + mPruAlert.sendPruAlert(alert); + } + } else { + // We could be in 600mS scan state here and since charging needs to be resumed + // send enable power apply command to scan for short beacons */ + mChargeComplete = false; + if ((mState == BluetoothProfile.STATE_DISCONNECTED) && (mWipowerManager != null)) + mWipowerManager.enablePowerApply(true, true, false); + } + } else if (what == WbcTypes.WBC_EVENT_TYPE_PTU_PRESENCE_STATUS) { + if (arg1 == WbcTypes.WBC_PTU_STATUS_NOT_PRESENT) { + initiateDisconnection(); + } + } + Log.v(LOGTAG, "onWbcEventUpdate: charge complete " + mChargeComplete); + } + }; + + private void acquire_wake_lock(boolean wake) { + if (wake == true) { + if (mWakeLock == null) { + PowerManager pm = (PowerManager)getSystemService( + Context.POWER_SERVICE); + if (pm == null) { + Log.e(LOGTAG, "failed to get PM"); + return; + } + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + "StartingWipowerConnection"); + mWakeLock.setReferenceCounted(false); + mWakeLock.acquire(); + Log.w(LOGTAG, "Acquire Wake Lock"); + } else { + Log.w(LOGTAG, "Wake Lock already held"); + } + } else { + if (mWakeLock != null) { + mWakeLock.release(); + mWakeLock = null; + Log.w(LOGTAG, "Release Wake Lock"); + } + } + } + + private class PruStaticParam { + private byte mOptvalidity; + private byte mProtoRevision; + private byte mRfu; + private byte mCategory; + private byte mCapabilities; + private byte mHwRev; + private byte mFwRev; + private byte mMaxPowerDesired; + private short mVrectMinStatic; + private short mVrectMaxStatic; + private short mVrectSet; + private short mDeltaR1; + private int mRfuVal; + + public PruStaticParam() { + mOptvalidity = (byte)DEFAULT_FIELDS; + mProtoRevision = (byte)DEFAULT_PROTOCOL_REV; + mRfu = (byte)DEFAULT_RFU; + mCategory = (byte)DEFAULT_CATEGORY; + mCapabilities = (byte)DEFAULT_CAPABILITIES; + mHwRev = (byte)DEFAULT_HW_VERSION; + mFwRev = (byte)DEFAULT_FW_VERSION; + mMaxPowerDesired = (byte)DEFAULT_MAX_POWER_DESIRED; + mVrectMinStatic = (short)DEFAULT_VRECT_MIN; + mVrectMaxStatic = (short)DEFAULT_VRECT_MAX; + mVrectSet = (short)DEFAULT_VRECT_SET; + mDeltaR1 = (short)DEFAULT_DELTA_R1; + mRfuVal = (int)DEFAULT_RFU_VAL; + Log.v(LOGTAG, "PruStaticParam initialized"); + } + + public byte[] getValue() { + byte[] res = new byte[20]; + res[0] = mOptvalidity; + res[1] = mProtoRevision; + res[2] = mRfu; + res[3] = mCategory; + res[4] = mCapabilities; + res[5] = mHwRev; + res[6] = mFwRev; + res[7] = mMaxPowerDesired; + res[8] = (byte)(LSB_MASK & mVrectMinStatic); + res[9] = (byte)((MSB_MASK & mVrectMinStatic) >> 8); + res[10] = (byte)(LSB_MASK & mVrectMaxStatic); + res[11] = (byte)((MSB_MASK & mVrectMaxStatic) >> 8); + res[12] = (byte)(LSB_MASK & mVrectSet); + res[13] = (byte)((MSB_MASK & mVrectSet) >> 8); + res[14] = (byte)(LSB_MASK & mDeltaR1); + res[15] = (byte)((MSB_MASK & mDeltaR1) >> 8); + res[16] = (byte)(LSB_MASK & mRfuVal); + res[17] = (byte)((MSB_MASK & mRfuVal) >> 8); + res[18] = (byte)((0xFF0000 & mRfuVal) >> 16); + res[19] = (byte)((0xFF000000 & mRfuVal) >> 24); + + return res; + } + + /*This is used to set the charging values*/ + public void setValue(byte[] value) { + mOptvalidity = value[0]; + mProtoRevision = value[1]; + mRfu = value[2]; + mCategory = value[3] ; + mCapabilities = value[4]; + mHwRev = value[5]; + mFwRev = value[6]; + mMaxPowerDesired = value[7]; + mVrectMinStatic = value[8]; + mVrectMinStatic |= (short)(value[9] << 8); + mVrectMinStatic = value[10]; + mVrectMinStatic |= (short)(value[11] << 8); + mVrectSet = value[12]; + mVrectSet |= (short)(value[13] << 8); + mDeltaR1 = value[14]; + mDeltaR1 |= (short)(value[15] << 8); + mRfuVal = value[16]; + mRfuVal |= (int)(value[17] << 8); + mRfuVal |= (int)(value[18] << 16); + mRfuVal |= (int)(value[19] << 24); + + return; + } + + } + + private class PruAlert { + private final int PRU_ALERT_NOTIFY_BIT = 0x0100; // Notify bit in CCCD + private byte mAlert; + + public PruAlert(byte value) { + mAlert = value; + mEnablePruAlerts = false; + } + + public void setValue(byte value) { + mAlert = value; + } + + public byte[] getValue() { + byte[] res = new byte[1]; + res[0] = mAlert; + return res; + } + + // Handle the CCCD Write for Notifications/Indications from PTU + private int processPruAlertRequest(byte[] value) { + int status = 0; + int intValue= 0; + intValue = ((value[0]<< 8) & 0x0000ff00) | ((value[1] << 0) & 0x000000ff); + + Log.v(LOGTAG, "processPruAlertRequest. Value: " + intValue); + + if ((intValue & PRU_ALERT_NOTIFY_BIT) == PRU_ALERT_NOTIFY_BIT) { + Log.v(LOGTAG, "processPruAlertRequest. PRU Alerts Enabled"); + mEnablePruAlerts = true; + mWipowerManager.enableAlertNotification(true); + } else { + mWipowerManager.enableAlertNotification(false); + mEnablePruAlerts = false; + } + + return status; + } // end of processPruAlertRequest + + // Send Notification/Indications to PTU + private int sendPruAlert(byte alertValue) { + int status = 0; + byte[] alertVal = {0}; + + Log.v(LOGTAG, "sendPruAlert. Value: " + alertValue); + + if (mEnablePruAlerts == false) + { + Log.v(LOGTAG, "sendPruAlert. PRU Alerts are Disabled"); + return status; + } + + if (mPruAlertChar == null) + { + Log.v(LOGTAG, "sendPruAlert. Alert characteristic is NULL"); + return status; + } + + if (alertValue == 0) + { + Log.v(LOGTAG, "sendPruAlert. No alerts to send"); + return status; + } + + if (mDevice == null) + { + Log.v(LOGTAG, "sendPruAlert. mDevice is NULL"); + return status; + } + + if (mState != BluetoothProfile.STATE_CONNECTED) + { + Log.v(LOGTAG, "sendPruAlert. Not CONNECTED"); + return status; + } + + + alertVal[0] = alertValue; + mPruAlertChar.setValue(alertVal); + mBluetoothGattServer.notifyCharacteristicChanged(mDevice, + mPruAlertChar, false); + + return status; + } // end of sendPruAlert + + } + + private class PtuStaticParam { + private byte mOptValidity; + private byte mPower; + private byte mMaxSrcImpedence; + private byte mMaxLoadResistance; + private short mId; + private byte mClass; + private byte mHwRev; + private byte mFwRev; + private byte mProtocolRev; + private byte mMaxDevicesSupported; + private int mReserved1; + private short mReserved2; + + public PtuStaticParam(byte[] value) { + mOptValidity = value[0]; + mPower = value[1]; + mMaxSrcImpedence = value[2]; + mMaxLoadResistance = value[3]; + mId = (short)(value[4] & 0xff); + mId |= (short)((value[5] & 0xff) << 8); + mClass = value[6]; + mHwRev = value[7]; + mFwRev = value[8]; + mProtocolRev = value[9]; + mMaxDevicesSupported = value[10]; + mReserved1 = (int)(value[11] & 0xff); + mReserved1 |= (int)((value[12] & 0xff) << 8); + mReserved1 |= (int)((value[13] & 0xff) << 16); + mReserved1 |= (int)((value[14] & 0xff) << 16); + mReserved2 = (short)(value[15] & 0xff); + mReserved2 |= (short)((value[16] & 0xff) << 8); + } + + public void print() { + Log.v(LOGTAG, "mOptValidity" + toHex(mOptValidity) + "mPower" + toHex(mPower) + "mMaxSrcImpedence" + toHex(mMaxSrcImpedence) + "mMaxLoadResistance" + toHex(mMaxLoadResistance)); + Log.v(LOGTAG, "mId" + toHex(mId) + "mClass" + toHex(mClass) + "mHwRev" + toHex(mHwRev) + "mFwRev" + toHex(mFwRev)); + Log.v(LOGTAG, "mProtocolRev" + toHex(mProtocolRev) + "mMaxDevicesSupported" + toHex(mMaxDevicesSupported) + "mReserved1" + toHex(mReserved1) + "mReserved2" + toHex(mReserved2)); + } + + public double getPower() { + double val = ((mPower&0xfc)>>2); + val = 0.5*(val+1); + Log.v(LOGTAG, "getPower<=" + val); + if (val > 22) val = 22.0; + return val; + } + + public double getMaxSrcImpedence() { + double val = ((mMaxSrcImpedence&0xf8)>>3); + val = 50 + (val*10); + Log.v(LOGTAG, "getSrcImpedence<=" + val); + if (val > 375) val = 375.0; + return val; + } + + public double getMaxLoadResistance() { + double val = ((mMaxLoadResistance&0xf8)>>3); + val = 5 * (val+1); + Log.v(LOGTAG, "getMaxLoadResistance<=" + val); + if (val > 55) val = 55.0; + return val; + } + + public float getMaxDevicesSupported() { + int val = mMaxDevicesSupported +1; + Log.v(LOGTAG, "getMaxDevicesSupported<=" + val); + if (val > 8) val = 8; + return val; + } + + public short getId() { + return mId; + } + + public int getPtuClass() { + return (mClass > 4) ? 5 : (mClass+1); + } + + public byte getHwRev () { + return mHwRev; + } + + public byte getFwRev () { + return mFwRev; + } + + public byte getProtocolRev () { + return mProtocolRev; + } + } + + public static String toHex(int num) { + return String.format("0x%8s", Integer.toHexString(num)).replace(' ', '0'); + } + + private class PruControl { + public byte mEnable; + public byte mPermission; + public byte mTimeSet; + public short mReserved; + public PruControl () { + mEnable = 0x0; + mPermission = 0x0; + mTimeSet = 0x0; + mReserved = 0x0; + mReserved = 0x0; + } + + public void print() { + Log.v(LOGTAG, "mEnable: " + toHex(mEnable)); + Log.v(LOGTAG, "mPermission: " + toHex(mPermission)); + Log.v(LOGTAG, "mTimeSet: " + toHex(mTimeSet)); + Log.v(LOGTAG, "mReserved: " + toHex(mReserved)); + } + + public void setValue(byte[] value) { + mEnable = (byte)value[0]; + mPermission = (byte)value[1]; + mTimeSet = (byte)value[2]; + mReserved = (short)(value[3] & 0xFF); + mReserved = (short)((value[4] & 0xFF) << 8); + return; + } + + public byte[] getValue() { + byte[] res = new byte[5]; + res[0] = mEnable; + res[1] = mPermission; + res[2] = mTimeSet; + res[3] = (byte)(LSB_MASK & mReserved); + res[4] = (byte)(MSB_MASK & mReserved);; + return res; + } + + public boolean getEnablePruOutput() { + if ((mEnable&0x80) == 0x80) return true; + else return false; + } + + public boolean getEnableCharger() { + if ((mEnable&0x40) == 0x40) return true; + else return false; + } + + /* returns 0 Maximum power + 1 66% + 2 33% + */ + public PowerLevel getReducePower() { + PowerLevel res = PowerLevel.POWER_LEVEL_MINIMUM; + int val = ((mEnable & 0x30) >> 4 ); + if (val == 0) { + res = PowerLevel.POWER_LEVEL_MAXIMUM; + } else if (val == 1 && val == 3) { + res = PowerLevel.POWER_LEVEL_MEDIUM; + } else if (val == 2) { + res = PowerLevel.POWER_LEVEL_MINIMUM; + } + return res; + } + + /* returns 0x00 permitted without reason + 0x01 Permitted with waiting time due to limited affordable power + 0x80 Denied with system error 3 + 0x81 Denied due to limited affordable power + 0x82 Denied due to limited PTU Number of Devices + 0x83 Denied due to limited PTU Class support + */ + public boolean getPermission() { + + Log.v(LOGTAG, "getPermission" + mPermission); + if ((mPermission&0x80) == 0x80) return false; + else return true; + } + + /* returns time in ms */ + public int getSetTime() { + return (mTimeSet*10); + } + }; + + private PruAlert mPruAlert; + private PruControl mPruControl; + private PruStaticParam mPruStaticParam; //20 bytes + private PtuStaticParam mPtuStaticParam; //20 bytes + private static WipowerDynamicParam mPruDynamicParam; //20 bytes + private WipowerManager mWipowerManager; + private WbcManager mWbcManager; + + public A4wpService() { + Log.v(LOGTAG, "A4wpService"); + } + + static private void cleanupService() { + Log.v(LOGTAG, "cleanupService"); + } + + private int processPruControl(byte[] value) { + int status = 0; + + Log.v(LOGTAG, "processPruControl>"); + if (value != null) { + mPruControl.setValue(value); + } else { + Log.e(LOGTAG, "control value is null"); + return status; + } + mPruControl.print(); + + if (mWipowerManager == null) { + Log.e(LOGTAG, "mWipowerManager is null"); + return status; + } + + if (mPruControl.getEnablePruOutput()) { + Log.v(LOGTAG, "do Enable PruOutPut"); + /* Wake lock is enabled by default, to disbale need to set property */ + if(SystemProperties.getBoolean("persist.a4wp.skipwakelock", false) == false) { + /* Hold wake lock during connection */ + acquire_wake_lock(true); + } + mOutputControl = true; + } else { + Log.v(LOGTAG, "do Disable PruOutPut"); + if (mChargeComplete == true) { + mWipowerManager.enablePowerApply(true, true, true); + } + mWipowerManager.stopCharging(); + isChargePortSet = false; + mOutputControl = false; + return status; + } + + if (mPruControl.getEnableCharger()) { + Log.v(LOGTAG, "do Enable Charging"); + } else { + Log.v(LOGTAG, "do Disable Charging"); + } + + PowerLevel val = mPruControl.getReducePower(); + if (val == PowerLevel.POWER_LEVEL_MAXIMUM) { + Log.v(LOGTAG, "put to Max Power"); + } else if (val == PowerLevel.POWER_LEVEL_MEDIUM){ + Log.v(LOGTAG, "put to Medium Power"); + } else if (val == PowerLevel.POWER_LEVEL_MINIMUM){ + Log.v(LOGTAG, "put to Min Power"); + } + + mWipowerManager.setPowerLevel(val); + + return status; + } + + private int processPtuStaticParam(byte[] value) { + int status = 0; + Log.v(LOGTAG, "processPtuStaticParam>"); + mPtuStaticParam = new PtuStaticParam(value); + mPtuStaticParam.print(); + + return status; + } + + private static final byte CHARGE_COMPLETE_BIT = 0x08; + + /** + * Wipower callbacks + */ + private final WipowerManagerCallback mWipowerCallback = new WipowerManagerCallback() { + + @Override + public void onWipowerReady() { + Log.v(LOGTAG, "onWipowerReady"); + mWipowerManager.enablePowerApply(false, false, false); + if (mChargeComplete == true) { + mWipowerManager.enablePowerApply(true, true, true); + } else { + mWipowerManager.enablePowerApply(true, true, false); + } + mWipowerBoot = true; + } + + @Override + public void onWipowerStateChange(WipowerState state) { + Log.v(LOGTAG, "onWipowerStateChange" + state); + } + + @Override + public void onPowerApply(PowerApplyEvent state) { + Log.v(LOGTAG, "onPowerApply:" + state); + + if (state == PowerApplyEvent.OFF) { + initiateDisconnection(); + } + } + + @Override + public void onWipowerAlert(byte alert) { + Log.v(LOGTAG, "onWipowerAlert: " + alert + " alert recieved"); + mPruAlert.sendPruAlert(alert); + } + + + @Override + public void onWipowerData(WipowerDynamicParam data) { + Log.v(LOGTAG, "onWipowerData Alert"); + byte[] value = data.getValue(); + chkDynParamsAndStartCharging(value); + Log.v(LOGTAG, "calling SetValue"); + mPruDynamicParam.setValue(value); + } + + }; + + public static short toUnsigned(byte b) { + return (short)(b & 0xff); + } + + /** + * GATT callbacks + */ + private final BluetoothGattServerCallback mGattCallbacks = new BluetoothGattServerCallback() { + @Override + public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { + WipowerState state = WipowerState.OFF; + if (newState == BluetoothProfile.STATE_DISCONNECTED) { + if (mWipowerManager != null && device.equals(mDevice)) { + Log.v(LOGTAG, "onConnectionStateChange:DISCONNECTED PrevState:" + " Device:" + device + " ChargeComplete:" + mChargeComplete); + mState = newState; + mDiscInitiated = false; + mOutputControl = false; + mWipowerManager.enableDataNotification(false); + mWipowerManager.enableAlertNotification(false); + mEnablePruAlerts = false; + mWipowerManager.stopCharging(); + if (mChargeComplete != true) { + mWipowerManager.enablePowerApply(true, true, false); + } + if(SystemProperties.getBoolean("persist.a4wp.skipwakelock", false) == false) { + /* Drop wake lock once the connection is dropped gracefully */ + acquire_wake_lock(false); + } + mDevice = null; + } + isChargePortSet = false; + mPruDynamicParam.resetValues(); + } else if (newState == BluetoothProfile.STATE_CONNECTED) { + Log.v(LOGTAG, "onConnectionStateChange:CONNECTED"); + } + } + + @Override + public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, + BluetoothGattCharacteristic characteristic, + boolean preparedWrite, boolean responseNeeded, + int offset, byte[] value) { + + UUID id = characteristic.getUuid(); + int status =0; + + Log.v(LOGTAG, "onCharacteristicWriteRequest:" + id); + if (id == A4WP_PRU_CTRL_UUID && value.length == A4WP_PRU_CTRL_LENGTH) + { + status = processPruControl(value); + } + else if(id == A4WP_PTU_STATIC_UUID && value.length == A4WP_PTU_STATIC_LENGTH) + { + status = processPtuStaticParam(value); + } + + if (responseNeeded == true) { + mBluetoothGattServer.sendResponse(device, requestId, status, + offset, value); + } + } + + @Override + public void onDescriptorReadRequest(BluetoothDevice device, int requestId, + int offset, BluetoothGattDescriptor descriptor) { + + UUID id = descriptor.getUuid(); + byte[] value = {0}; + int status = 0; + + Log.v(LOGTAG, "onDescriptorReadRequest() - descriptor" + id); + if (id == A4WP_PRU_ALERT_DESC_UUID) + { + value = mPruAlert.getValue(); + } + + + if (value != null) + { + Log.v(LOGTAG, "device=" + id + "requestId=" + requestId + "status=" + status + "offset=" + offset + "value=" + value[0]); + mBluetoothGattServer.sendResponse(device, requestId, status, offset, value); + } + } + + @Override + public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, + BluetoothGattDescriptor descriptor, boolean preparedWrite, + boolean responseNeeded, int offset, byte[] value) { + + int status = 0; + UUID id = descriptor.getUuid(); + Log.v(LOGTAG, "onDescriptorWriteRequest() - descriptor" + id); + if ((id == A4WP_PRU_ALERT_DESC_UUID) && (value.length == CCCD_LENGTH)) + { + mDevice = device; // save the device as Notifications may need to be generated anytime now + status = mPruAlert.processPruAlertRequest(value); + } else + { + Log.v(LOGTAG, "onDescriptorWriteRequest() - Invalid descriptor: " + id + " OR length: " + value.length); + } + + if (responseNeeded == true) + mBluetoothGattServer.sendResponse(device, requestId, status, + offset, value); + } + + @Override + public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, + int offset, BluetoothGattCharacteristic characteristic) { + + UUID id = characteristic.getUuid(); + byte[] value = {0}; + int status = 0; + + Log.v(LOGTAG, "onCharacteristicReadRequest:" + id); + if(id == A4WP_PRU_STATIC_UUID && mState == BluetoothProfile.STATE_DISCONNECTED) + { + mWipowerManager.enablePowerApply(false, false, false); + value = mPruStaticParam.getValue(); + mDevice = device; + mState = BluetoothProfile.STATE_CONNECTED; + mWipowerManager.enableDataNotification(true); + } + else if (id == A4WP_PRU_DYNAMIC_UUID) { + if (mPruDynamicParam == null) { + Log.e(LOGTAG, "mPruDynamicParam is NULL"); + return; + } + value = mPruDynamicParam.getValue(); + if (mChargeComplete == true) { + value[PRU_ALERT] = (byte)(value[PRU_ALERT] | CHARGE_COMPLETE_BIT); + } else { + value[PRU_ALERT] = (byte)(value[PRU_ALERT] & (~CHARGE_COMPLETE_BIT)); + } + value[OPTIONAL_FIELDS] = (byte)OPTIONAL_FIELD_MASK; + value[VRECT_MAX_LSB] = (byte)(LSB_MASK & DEFAULT_VRECT_MAX); + value[VRECT_MAX_MSB] = (byte)((MSB_MASK & DEFAULT_VRECT_MAX) >> 8); + if ((byte)(value[PRU_ALERT] & CHARGE_PORT_MASK) == CHARGE_PORT_MASK) { + value[VRECT_MIN_LSB] = (byte)(LSB_MASK & DEFAULT_VRECT_SET); + value[VRECT_MIN_MSB] = (byte)((MSB_MASK & DEFAULT_VRECT_SET) >> 8); + value[VRECT_SET_LSB] = (byte)(LSB_MASK & DEFAULT_VRECT_SET); + value[VRECT_SET_MSB] = (byte)((MSB_MASK & DEFAULT_VRECT_SET) >> 8); + } else { + value[VRECT_MIN_LSB] = (byte)(LSB_MASK & VRECT_MIN_CHG_DISABLED); + value[VRECT_MIN_MSB] = (byte)((MSB_MASK & VRECT_MIN_CHG_DISABLED) >> 8); + value[VRECT_SET_LSB] = (byte)(LSB_MASK & VRECT_MIN_CHG_DISABLED); + value[VRECT_SET_MSB] = (byte)((MSB_MASK & VRECT_MIN_CHG_DISABLED) >> 8); + } + } + else if (id == A4WP_PRU_CTRL_UUID) { + if (mPruControl == null) { + Log.e(LOGTAG, "mPruControl is NULL"); + return; + } + value = mPruControl.getValue(); + } + if (mBluetoothGattServer != null) { + mBluetoothGattServer.sendResponse(device, requestId, status, offset, value); + } + } + + @Override + public void onServiceAdded(final int status, BluetoothGattService service) { + Log.i(LOGTAG, "Service added"); + } + }; + + private void closeServer() { + if (mBluetoothGattServer != null) { + if (mDevice != null) mBluetoothGattServer.cancelConnection(mDevice); + mBluetoothGattServer.close(); + } + } + + private final class myAdvertiseCallback extends AdvertiseCallback { + private int mIndex; + + myAdvertiseCallback(int index) { + mIndex = index; + } + + @Override + public void onStartSuccess(AdvertiseSettings settingsInEffect) { + Log.d(LOGTAG, "advertise success " + mIndex); + if (mWipowerManager != null) { + mWipowerManager.enablePowerApply(false, false, false); + if (mChargeComplete == true) { + mWipowerManager.enablePowerApply(true, true, true); + } else { + mWipowerManager.enablePowerApply(true, true, false); + } + } + } + + @Override + public void onStartFailure(int errorCode) { + Log.d(LOGTAG, "advetise failure " + mIndex); + } + } + + + private void StartAdvertising() + { + /* serviceData represnts service data for Wipower that needs + to be part of advertising, + 0x28 i& 0x00 represents the primary based handle + 0xFF and 0x60 represents: + ADV Flags are set to: CAT3 PRU 21, Reboot bit and OVP indicator + */ + byte[] serviceData = new byte[] { + 0x28, 0x00, (byte)0xff, 0x60 }; + + mAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser(); + mAdvertisementData = new AdvertiseData.Builder() + .addServiceData(uuid1, serviceData).build(); + + mAdvertiseSettings = new AdvertiseSettings.Builder() + .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) + .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) + .setConnectable(true).build(); + + Log.d(LOGTAG, " Calling mAdvertiser.startAdvertising"); + if(mAdvertiser != null) + mAdvertiser.startAdvertising(mAdvertiseSettings, mAdvertisementData, mAdvertiseCallback); + else + Log.d(LOGTAG, " mAdvertiser is null"); + } + + private void stopAdvertising() + { + /* to be completed */ + if (mAdvertiseCallback != null && mAdvertiser != null) { + mAdvertiser.stopAdvertising(mAdvertiseCallback); + } + } + + private boolean startServer() { + BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + if (bluetoothManager == null) return false; + + mBluetoothGattServer = bluetoothManager.openGattServer(this, mGattCallbacks); + Log.d(LOGTAG,"calling start server......"); + if (mBluetoothGattServer == null) { + Log.e(LOGTAG,"mBluetoothGattServer is NULL"); + return false; + } + + BluetoothGattCharacteristic pruControl = new BluetoothGattCharacteristic( + A4WP_PRU_CTRL_UUID, + BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ, + BluetoothGattCharacteristic.PERMISSION_WRITE | + BluetoothGattCharacteristic.PERMISSION_READ); + + BluetoothGattCharacteristic ptuStatic = new BluetoothGattCharacteristic( + A4WP_PTU_STATIC_UUID, + BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ, + BluetoothGattCharacteristic.PERMISSION_WRITE | + BluetoothGattCharacteristic.PERMISSION_READ); + + mPruAlertChar = new BluetoothGattCharacteristic( + A4WP_PRU_ALERT_UUID, + BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY, + BluetoothGattCharacteristic.PERMISSION_READ ); + + BluetoothGattCharacteristic pruStatic = new BluetoothGattCharacteristic( + A4WP_PRU_STATIC_UUID, + BluetoothGattCharacteristic.PROPERTY_READ, + BluetoothGattCharacteristic.PERMISSION_READ); + + BluetoothGattCharacteristic pruDynamic = new BluetoothGattCharacteristic( + A4WP_PRU_DYNAMIC_UUID, + BluetoothGattCharacteristic.PROPERTY_READ, + BluetoothGattCharacteristic.PERMISSION_READ); + + + BluetoothGattDescriptor pruAlertDesc = new BluetoothGattDescriptor( + A4WP_PRU_ALERT_DESC_UUID, + BluetoothGattCharacteristic.PERMISSION_READ | + BluetoothGattCharacteristic.PERMISSION_WRITE); + + mPruAlertChar.addDescriptor(pruAlertDesc); + + BluetoothGattService a4wpService = new BluetoothGattService( + A4WP_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY); + + a4wpService.addCharacteristic(pruControl); + a4wpService.addCharacteristic(ptuStatic); + a4wpService.addCharacteristic(mPruAlertChar); + a4wpService.addCharacteristic(pruStatic); + a4wpService.addCharacteristic(pruDynamic); + + + mBluetoothGattServer.addService(a4wpService); + Log.d(LOGTAG, "calling StartAdvertising"); + StartAdvertising(); + + return true; + } + + @Override + public void onCreate() { + Log.v(LOGTAG, "onCreate"); + super.onCreate(); + + // Ensure Bluetooth is enabled + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { + Log.d(LOGTAG, "Bluetooth is not available or enabled - exiting..."); + return; + } + + Log.v(LOGTAG, "calling startService"); + startServer(); + //Initialize PRU Static param + mPruStaticParam = new PruStaticParam(); + mPruDynamicParam = new WipowerDynamicParam(); + mPruAlert = new PruAlert((byte)0); + mPruControl = new PruControl(); + + mWipowerManager = WipowerManager.getWipowerManger(this, mWipowerCallback); + if (mWipowerManager != null) + mWipowerManager.registerCallback(mWipowerCallback); + mWbcManager = WbcManager.getInstance(); + if (mWbcManager != null) { + mChargeComplete = (mWbcManager.getChargingRequired() == 0); + Log.v(LOGTAG, "onCreate: charge complete " + mChargeComplete); + mWbcManager.register(mWbcCallback); + } + } + + @Override + public void onDestroy() { + Log.v(LOGTAG, "onDestroy"); + if (mWipowerManager != null) + mWipowerManager.unregisterCallback(mWipowerCallback); + if (mWbcManager != null) + mWbcManager.unregister(mWbcCallback); + if(SystemProperties.getBoolean("persist.a4wp.skipwakelock", false) == false) { + //release wake lock during BT-OFF. + acquire_wake_lock(false); + } + mOutputControl = false; + isChargePortSet = false; + } + + @Override + public IBinder onBind(Intent in) { + Log.v(LOGTAG, "onBind"); + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(LOGTAG, "onStart Command called!!"); + + //mWipowerBoot is used to hold power enable command till the service is been registered completely + if (mWipowerBoot == true && mWipowerManager != null) { + if (mChargeComplete == true) { + mWipowerManager.enablePowerApply(true, true, true); + } else { + mWipowerManager.enablePowerApply(true, true, false); + } + } + if(SystemProperties.getBoolean("persist.a4wp.skipwakelock", false) == false) { + //release wake lock in case if held during crashes or on BT restart. + acquire_wake_lock(false); + } + return START_STICKY; + } +} diff --git a/wipower-host/a4wp/src/org/codeaurora/bluetooth/a4wp_app/BTEventHandler.java b/wipower-host/a4wp/src/org/codeaurora/bluetooth/a4wp_app/BTEventHandler.java new file mode 100644 index 0000000..d59d5f6 --- /dev/null +++ b/wipower-host/a4wp/src/org/codeaurora/bluetooth/a4wp_app/BTEventHandler.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.codeaurora.bt_wipower.a4wp; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.SystemProperties; +import android.util.Log; + +import java.lang.Object; + +public class BTEventHandler extends BroadcastReceiver { + private static final String TAG = "BTEventHandler"; + private static final boolean V = true/*Constants.VERBOSE*/; + private int state; + + @Override + public void onReceive(Context context, Intent intent) { + if(SystemProperties.getBoolean("persist.bluetooth.a4wp", false) == false) { + Log.e(TAG, "A4WP is not supported"); + return; + } + + String action = intent.getAction(); + + + if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { + state = intent.getIntExtra + (BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); + if (BluetoothAdapter.STATE_ON == state) { + if (V) Log.v(TAG, "Received BLUETOOTH_STATE_ON"); + ComponentName service = context.startService + (new Intent(context, A4wpService.class)); + if (service != null) { + Log.e(TAG, "A4wp service started successfully"); + } else { + Log.e(TAG, "Could Not Start A4wp Service"); + return; + } + } else if (BluetoothAdapter.STATE_OFF == state) { + if (V) Log.v(TAG, "Received BLUETOOTH_STATE_OFF"); + context.stopService(new Intent(context, A4wpService.class)); + + } + } + } +} diff --git a/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/BTEventHandler.java b/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/BTEventHandler.java new file mode 100644 index 0000000..b191448 --- /dev/null +++ b/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/BTEventHandler.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.codeaurora.bt_wipower.wipower; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.SystemProperties; +import android.util.Log; + +import java.lang.Object; + +public class BTEventHandler extends BroadcastReceiver { + private static final String TAG = "BTEventHandler"; + private static final boolean V = false/*Constants.VERBOSE*/; + private int state; + + @Override + public void onReceive(Context context, Intent intent) { + if(SystemProperties.getBoolean("ro.bluetooth.wipower", false) == false) { + Log.e(TAG, "WipowerService is not supported"); + return; + } + + String action = intent.getAction(); + + if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { + state = intent.getIntExtra + (BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); + if (BluetoothAdapter.STATE_ON == state) { + if (V) Log.e(TAG, "Received BLUETOOTH_STATE_ON"); + + ComponentName service = context.startService + (new Intent(context, WipowerService.class)); + if (service != null) { + Log.e(TAG, "WipowerService started successfully"); + } else { + Log.e(TAG, "Could Not Start Wipower Service "); + return; + } + + + } else if (BluetoothAdapter.STATE_OFF == state) { + if (V) Log.v(TAG, "Received BLUETOOTH_STATE_OFF"); + context.stopService(new Intent(context, WipowerService.class)); + } + } + } +} diff --git a/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/WipowerApp.java b/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/WipowerApp.java new file mode 100644 index 0000000..d9127f3 --- /dev/null +++ b/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/WipowerApp.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @hide + */ + +package org.codeaurora.bt_wipower.wipower; + +import android.app.Application; +import android.util.Log; + +public class WipowerApp extends Application { + private static final String TAG = "BluetoothWipowerApp"; + private static final boolean DBG = true; + + static { + if (DBG) Log.d(TAG,"Loading JNI Library"); + System.loadLibrary("wipower_jni"); + } +} diff --git a/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/WipowerService.java b/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/WipowerService.java new file mode 100644 index 0000000..bda73be --- /dev/null +++ b/wipower-host/a4wp/src/org/codeaurora/bluetooth/wipower/WipowerService.java @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.codeaurora.bt_wipower.wipower; + +import java.util.UUID; +import android.bluetooth.BluetoothManager; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothGattServer; +import android.bluetooth.BluetoothGattServerCallback; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.app.Service; +import android.net.Credentials; +import java.io.OutputStream; +import android.util.Log; +import android.os.IBinder; +import android.content.Intent; +import android.os.Process; +import java.nio.ByteBuffer; +import android.wipower.IWipower; +import android.wipower.IWipowerManagerCallback; +import android.os.RemoteCallbackList; +import android.os.RemoteException; + +/** + * Class which executes A4WP service + */ +public class WipowerService extends Service +{ + private static final String LOGTAG = "WipowerService"; + private static OutputStream mOutputStream = null; + private BluetoothAdapter mBluetoothAdapter = null; + private BluetoothGattServer mBluetoothGattServer = null; + private BluetoothDevice mDevice = null; + + private static final Object mLock = new Object(); + private int mState = BluetoothProfile.STATE_DISCONNECTED; + + public boolean startCharging() { + int ret = enableNative(true); + return (ret==0) ? true : false; + } + + public boolean stopCharging() { + int ret = enableNative(false); + return (ret==0) ? true : false; + } + + public int getState() { + int ret = getStateNative(); + return ret; + } + + public boolean setCurrentLimit(byte value) { + int ret = setCurrentLimitNative(value); + return (ret==0) ? true : false; + } + + public byte getCurrentLimit() { + byte ret = getCurrentLimitNative(); + return ret; + } + + public boolean enableAlert(boolean enable) { + int ret = enableAlertNative(enable); + return (ret==0) ? true : false; + } + + public boolean enableData(boolean enable) { + int ret = enableDataNative(enable); + return (ret==0) ? true : false; + } + + public boolean enablePowerApply(boolean enable, boolean on, boolean time_flag) { + Log.v(LOGTAG, "enablePowerApply: Calling Native enablei: " + enable + " on: " + on); + int ret = enablePowerApplyNative(enable, on, time_flag); + return (ret==0) ? true : false; + } + + public void registerCallback(IWipowerManagerCallback callback) { + mCallbacks.register(callback); + } + + public void unregisterCallback(IWipowerManagerCallback callback) { + mCallbacks.unregister(callback); + } + + private static class WipowerBinder extends IWipower.Stub { + private WipowerService mService; + + public WipowerBinder(WipowerService svc) { + Log.e(LOGTAG, ">In Constructor"); + mService = svc; + } + + public WipowerService getService() { + if (mService != null && mService.isAvailable()) { + return mService; + } + return null; + } + + public boolean startCharging() { + boolean ret = false; + if (mService == null) { + Log.e(LOGTAG, "startCharging:Service not found"); + } else { + ret = mService.startCharging(); + } + return ret; + } + + public boolean stopCharging() { + boolean ret = false; + if (mService == null) { + Log.e(LOGTAG, "stopCharging:Service not found"); + } else { + ret = mService.stopCharging(); + } + return ret; + } + + public int getState() { + int ret = -1; + if (mService == null) { + Log.e(LOGTAG, "getState:Service not found"); + } else { + ret = mService.getState(); + } + + return ret; + } + + public boolean setCurrentLimit(byte value) { + boolean ret = false; + if (mService == null) { + Log.e(LOGTAG, "setCurrentLimit:Service not found"); + } else { + ret = mService.setCurrentLimit(value); + } + + return ret; + } + + public byte getCurrentLimit() { + byte value = (byte)0xff; + if (mService == null) { + Log.e(LOGTAG, "getCurrentLimit:Service not found"); + } else { + value = mService.getCurrentLimit(); + } + return value; + } + + public boolean enableAlert(boolean enable) { + boolean ret = false; + if (mService == null) { + Log.e(LOGTAG, "enableAlert:Service not found"); + } else { + ret = mService.enableAlert(enable); + } + return ret; + } + + public boolean enableData(boolean enable) { + boolean ret = false; + if (mService == null) { + Log.e(LOGTAG, "enableData:Service not found"); + } else { + ret = mService.enableData(enable); + } + return ret; + } + + public boolean enablePowerApply(boolean enable, boolean on, boolean time_flag) { + boolean ret = false; + Log.v(LOGTAG, "enablePowerApply: binder"); + if (mService == null) { + Log.e(LOGTAG, "enableData:Service not found"); + } else { + ret = mService.enablePowerApply(enable, on, time_flag); + } + return ret; + } + + + public void registerCallback(IWipowerManagerCallback callback) { + if (mService == null) { + Log.e(LOGTAG, "registerCallback:Service not found"); + } else { + mService.registerCallback(callback); + } + + } + + public void unregisterCallback(IWipowerManagerCallback callback) { + if (mService == null) { + Log.e(LOGTAG, "unregisterCallback:Service not found"); + } else { + mService.unregisterCallback(callback); + } + } + + }; + + private WipowerBinder mBinder; + private RemoteCallbackList<IWipowerManagerCallback> mCallbacks; + + public WipowerService() { + Log.v(LOGTAG, "WipowerService"); + + } + + private boolean isAvailable() { + return false; + } + + static private void cleanupService() { + Log.v(LOGTAG, "cleanupService"); + } + + @Override + public void onCreate() { + Log.v(LOGTAG, "onCreate"); + super.onCreate(); + + mCallbacks = new RemoteCallbackList<IWipowerManagerCallback>(); + mBinder = new WipowerBinder(this); + Log.v(LOGTAG, "onCreate>>"); + + } + + @Override + public void onDestroy() { + Log.v(LOGTAG, "onDestroy"); + } + + @Override + public IBinder onBind(Intent in) { + Log.v(LOGTAG, "onBind"); + return mBinder; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(LOGTAG, "onStart Command called!!"); + + Log.v(LOGTAG, "Calling classInitNative"); + classInitNative(); + + Log.v(LOGTAG, "Calling InitNative"); + initNative(); + //Make this restarable service by + //Android app manager + return START_NOT_STICKY; + } + + + void stateChangeCallback (int state) { + Log.e(LOGTAG, "stateChangeCallback: " + state); + if (mCallbacks !=null) { + int n = mCallbacks.beginBroadcast(); + Log.v(LOGTAG,"Broadcasting updateAdapterState() to " + n + " receivers."); + for (int i=0; i <n;i++) { + try { + mCallbacks.getBroadcastItem(i).onWipowerStateChange(state); + } catch (RemoteException e) { + Log.e(LOGTAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); + } + } + mCallbacks.finishBroadcast(); + } + } + + void wipowerAlertNotify (int alert) { + Log.e(LOGTAG, "wipowerAlertNotify: " + alert); + + if (mCallbacks !=null) { + int n=mCallbacks.beginBroadcast(); + Log.d(LOGTAG,"Broadcasting wipower alert() to " + n + " receivers."); + for (int i=0; i <n;i++) { + try { + mCallbacks.getBroadcastItem(i).onWipowerAlert((byte)alert); + } catch (RemoteException e) { + Log.e(LOGTAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); + } + } + mCallbacks.finishBroadcast(); + } + } + + void wipowerPowerNotify (byte alert) { + Log.e(LOGTAG, "wipowerPowerNotify: " + alert); + + if (mCallbacks !=null) { + int n=mCallbacks.beginBroadcast(); + Log.d(LOGTAG,"Broadcasting wipower power alert() to " + n + " receivers."); + for (int i=0; i <n;i++) { + try { + mCallbacks.getBroadcastItem(i).onPowerApply((byte)alert); + } catch (RemoteException e) { + Log.e(LOGTAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); + } + } + mCallbacks.finishBroadcast(); + } + } + + + void wipowerDataNotify (byte[] data) { + Log.e(LOGTAG, "wipowerDataNotify: " + data); + + if (mCallbacks !=null) { + int n = mCallbacks.beginBroadcast(); + Log.d(LOGTAG,"Broadcasting wipowerdata() to " + n + " receivers."); + for (int i=0; i <n;i++) { + try { + mCallbacks.getBroadcastItem(i).onWipowerData(data); + } catch (RemoteException e) { + Log.e(LOGTAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); + } + + } + mCallbacks.finishBroadcast(); + } + } + + private native static void classInitNative(); + private native void initNative(); + private native int enableNative(boolean enable); + private native int setCurrentLimitNative(byte value); + private native byte getCurrentLimitNative(); + private native int getStateNative(); + private native int enableAlertNative(boolean enable); + private native int enableDataNative(boolean enable); + private native int enablePowerApplyNative(boolean enable, boolean on, boolean time_flag); + +} diff --git a/wipower-host/jni/Android.mk b/wipower-host/jni/Android.mk new file mode 100644 index 0000000..e44ce54 --- /dev/null +++ b/wipower-host/jni/Android.mk @@ -0,0 +1,30 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES:= \ + android_hardware_wipower.cpp \ + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + packages/apps/Bluetooth/jni + + +LOCAL_REQUIRED_MODULES := bluetooth.default + +LOCAL_PROGUARD_ENABLED := disabled + + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + libandroid_runtime \ + libcutils \ + liblog \ + libhardware + +LOCAL_MULTILIB := 32 +LOCAL_JNI_SHARED_LIBRARIES := libbluetooth_jni + +LOCAL_MODULE := libwipower_jni +include $(BUILD_SHARED_LIBRARY) diff --git a/wipower-host/jni/android_hardware_wipower.cpp b/wipower-host/jni/android_hardware_wipower.cpp new file mode 100644 index 0000000..01d5f08 --- /dev/null +++ b/wipower-host/jni/android_hardware_wipower.cpp @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "wipower" + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" +#include "utils/Log.h" +#include "utils/misc.h" +#include <cutils/properties.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include "android_hardware_wipower.h" +#include "com_android_bluetooth.h" + +#define CHECK_CALLBACK_ENV \ + if (!checkCallbackThread()) { \ + ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\ + return; \ + } + +#define DBG false + +namespace android { + + +static jmethodID method_wipowerstateChangeCallback; +static jmethodID method_wipowerAlertNotify; +static jmethodID method_wipowerDataNotify; +static jmethodID method_wipowerPowerNotify; + +static const wipower_interface_t *sWipowerInterface = NULL; +static jobject sCallbacksObj; +static JNIEnv *sCallbackEnv = NULL; + +static const bt_interface_t *sBluetoothInterface = NULL; + + +JNIEnv* getCallbackEnv() { + return sCallbackEnv; +} + +const bt_interface_t* getBluetoothInterface() { + return sBluetoothInterface; +} + +static bool checkCallbackThread() { + sCallbackEnv = getCallbackEnv(); + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (sCallbackEnv != env || sCallbackEnv == NULL) { + ALOGE("Callback env check fail: env: %p, callback: %p", env, sCallbackEnv); + return false; + } + return true; +} + + +static void wipower_state_changed_cb(wipower_state_t state) { + if (DBG) + ALOGV("%s: State is: %d", __FUNCTION__, state); + CHECK_CALLBACK_ENV + sCallbackEnv->CallVoidMethod(sCallbacksObj, method_wipowerstateChangeCallback, (jint) state); +} + +static void wipower_alerts_cb(unsigned char alert_data) { + if (DBG) + ALOGV("%s: alert_data is: %d", __FUNCTION__, alert_data); + CHECK_CALLBACK_ENV + sCallbackEnv->CallVoidMethod(sCallbacksObj, method_wipowerAlertNotify, (jint) alert_data); +} + +static void wipower_data_cb(wipower_dyn_data_t *alert_data) { + if (DBG) + ALOGV("%s: wp data is: %x", __FUNCTION__, (unsigned int)alert_data); + jbyteArray wp_data = NULL; + + CHECK_CALLBACK_ENV + wp_data = sCallbackEnv->NewByteArray(sizeof(wipower_dyn_data_t)); + if (wp_data == NULL) { + ALOGE("%s: alloc failure", __FUNCTION__); + return; + } + + sCallbackEnv->SetByteArrayRegion(wp_data, 0, sizeof(wipower_dyn_data_t), + (jbyte*)alert_data); + + + sCallbackEnv->CallVoidMethod(sCallbacksObj, method_wipowerDataNotify, wp_data); + + sCallbackEnv->DeleteLocalRef(wp_data); +} + +static void wipower_power_cb(unsigned char alert_data) { + if (DBG) + ALOGV("%s: alert_data is: %d", __FUNCTION__, alert_data); + CHECK_CALLBACK_ENV + sCallbackEnv->CallVoidMethod(sCallbacksObj, method_wipowerPowerNotify, (jint) alert_data); +} + +static void callback_thread_event(bt_cb_thread_evt event) { + JavaVM* vm = AndroidRuntime::getJavaVM(); + ALOGE("Kiran: Callback thread attached: %d", event); + if (event == ASSOCIATE_JVM) { + JavaVMAttachArgs args; + char name[] = "wipower Service Callback Thread"; + args.version = JNI_VERSION_1_6; + args.name = name; + args.group = NULL; + vm->AttachCurrentThread(&sCallbackEnv, &args); + ALOGE("Kiran: Callback thread attached: %p", sCallbackEnv); + } else if (event == DISASSOCIATE_JVM) { + if (!checkCallbackThread()) { + ALOGE("Kiran: Callback: '%s' is not called on the correct thread", __FUNCTION__); + return; + } + vm->DetachCurrentThread(); + } +} + +wipower_callbacks_t sWipowerCallbacks = { + sizeof(sWipowerCallbacks), + wipower_state_changed_cb, + wipower_alerts_cb, + wipower_data_cb, + wipower_power_cb, + callback_thread_event +}; + + +static void android_wipower_wipowerJNI_classInitNative(JNIEnv* env, jclass clazz) { + int err; + hw_module_t* module; + + ALOGE("%s:",__FUNCTION__); + + method_wipowerstateChangeCallback = env->GetMethodID(clazz, "stateChangeCallback", "(I)V"); + + method_wipowerAlertNotify = env->GetMethodID(clazz, "wipowerAlertNotify", "(I)V"); + + method_wipowerDataNotify = env->GetMethodID(clazz, "wipowerDataNotify", + "([B)V"); + + method_wipowerPowerNotify = env->GetMethodID(clazz, "wipowerPowerNotify", + "(B)V"); + + ALOGE("%s: succesfully executed",__FUNCTION__); + + char value[PROPERTY_VALUE_MAX]; + property_get("bluetooth.mock_stack", value, ""); + + const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID); + + err = hw_get_module(id, (hw_module_t const**)&module); + + if (err == 0) { + hw_device_t* abstraction; + err = module->methods->open(module, id, &abstraction); + if (err == 0) { + bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction; + sBluetoothInterface = btStack->get_bluetooth_interface(); + } else { + ALOGE("Error while opening Bluetooth library"); + } + } else { + ALOGE("No Bluetooth Library found"); + } + +} + +static void android_wipower_wipowerJNI_initNative (JNIEnv* env, jobject obj) { + if (DBG) + ALOGV("%s:",__FUNCTION__); + + const bt_interface_t* btInf; + + if ( (btInf = getBluetoothInterface()) == NULL) { + ALOGE("Bluetooth module is not loaded"); + return; + } + + + //Get WiPower Interface + sWipowerInterface = (const wipower_interface_t*)btInf->get_profile_interface(WIPOWER_PROFILE_ID); + if (sWipowerInterface == NULL) { + ALOGE("%s: Get wipower interface: %x",__FUNCTION__, (unsigned int)sWipowerInterface); + return; + } + //Initialize wipower interface + int ret = sWipowerInterface->init(&sWipowerCallbacks); + + if (ret != 0) + ALOGE("wipower init failed"); + + sCallbacksObj = env->NewGlobalRef(obj); +} + +/* native interface */ +static jint android_wipower_wipowerJNI_enableNative + (JNIEnv* env, jobject thiz, jboolean enable) +{ + if (DBG) + ALOGD("%s->", __func__); + + if (sWipowerInterface == NULL) { + ALOGE("No Interface initialized"); + return JNI_FALSE; + } + + int ret = sWipowerInterface->enable(enable); + + if (ret != 0) { + ALOGE("wipower enable failed"); + return JNI_FALSE; + } else { + ALOGE("wipower enabled successfully"); + } + return 0; +} + +/* native interface */ +static jint android_wipower_wipowerJNI_setCurrentLimitNative + (JNIEnv* env, jobject thiz, jbyte value) +{ + if (sWipowerInterface == NULL) { + ALOGE("No Interface initialized"); + return JNI_FALSE; + } + + int ret = sWipowerInterface->set_current_limit(value); + + if (ret != 0) { + ALOGE("wipower set current limit failed"); + return JNI_FALSE; + } else { + ALOGD("%s:success", __func__); + } + + return 0; +} + +/* native interface */ +static jbyte android_wipower_wipowerJNI_getCurrentLimitNative + (JNIEnv* env, jobject thiz) +{ + + if (sWipowerInterface == NULL) { + ALOGE("No Interface initialized"); + return JNI_FALSE; + } + + unsigned char val = sWipowerInterface->get_current_limit(); + + ALOGV("%s: %d", __func__, val); + + return val; +} + +/* native interface */ +static jint android_wipower_wipowerJNI_getStateNative + (JNIEnv* env, jobject thiz) +{ + + if (sWipowerInterface == NULL) { + ALOGE("No Interface initialized"); + return JNI_FALSE; + } + + int val = sWipowerInterface->get_state(); + + ALOGV("%s: %d", __func__, val); + + return val; +} + +/* native interface */ +static jint android_wipower_wipowerJNI_enableAlertNative + (JNIEnv* env, jobject thiz, jboolean enable) +{ + + if (sWipowerInterface == NULL) { + ALOGE("No Interface initialized"); + return JNI_FALSE; + } + + int ret = sWipowerInterface->enable_alerts(enable); + + if (ret != 0) { + ALOGE("%s: Failure", __func__); + return JNI_FALSE; + } else { + ALOGV("%s: Success", __func__); + } + return 0; +} + +/* native interface */ +static jint android_wipower_wipowerJNI_enableDataNative + (JNIEnv* env, jobject thiz, jboolean enable) +{ + + if (sWipowerInterface == NULL) { + ALOGE("No Interface initialized"); + return JNI_FALSE; + } + + int ret = sWipowerInterface->enable_data_notify(enable); + + if (ret != 0) { + ALOGE("%s: Failure", __func__); + return JNI_FALSE; + } else { + ALOGV("%s: Success", __func__); + } + + return 0; +} + +/* native interface */ +static jint android_wipower_wipowerJNI_enablePowerApplyNative + (JNIEnv* env, jobject thiz, jboolean enable, jboolean on, + jboolean time_flag) +{ + + if (sWipowerInterface == NULL) { + ALOGE("No Interface initialized"); + return JNI_FALSE; + } + + int ret = sWipowerInterface->enable_power_apply(enable, on, time_flag); + + if (ret != 0) { + ALOGE("%s: Failure", __func__); + return JNI_FALSE; + } else { + ALOGV("%s: Success", __func__); + } + + return 0; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "classInitNative", "()V", + (void*)android_wipower_wipowerJNI_classInitNative}, + + { "initNative", "()V", + (void*)android_wipower_wipowerJNI_initNative}, + + { "enableNative", "(Z)I", + (void*)android_wipower_wipowerJNI_enableNative}, + + { "setCurrentLimitNative", "(B)I", + (void*)android_wipower_wipowerJNI_setCurrentLimitNative}, + + { "getCurrentLimitNative", "()B", + (void*)android_wipower_wipowerJNI_getCurrentLimitNative}, + + { "getStateNative", "()I", + (void*)android_wipower_wipowerJNI_getStateNative}, + + { "enableAlertNative", "(Z)I", + (void*)android_wipower_wipowerJNI_enableAlertNative}, + + { "enableDataNative", "(Z)I", + (void*)android_wipower_wipowerJNI_enableDataNative}, + + { "enablePowerApplyNative", "(ZZZ)I", + (void*)android_wipower_wipowerJNI_enablePowerApplyNative}, +}; +int register_android_hardware_wipower(JNIEnv* env) +{ + + ALOGV("%s: >\n", __func__); + return jniRegisterNativeMethods(env, "org/codeaurora/bt_wipower/wipower/WipowerService", gMethods, NELEM(gMethods)); +} +} + +jint JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + JNIEnv *e; + int status; + ALOGE("Wipower : loading WIPOWER-JNI\n"); + + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) { + ALOGE("JNI version mismatch error"); + return JNI_ERR; + } + + if ((status = android::register_android_hardware_wipower(e)) < 0) { + ALOGE("jni adapter service registration failure, status: %d", status); + return JNI_ERR; + } + return JNI_VERSION_1_6; +} diff --git a/wipower-host/jni/android_hardware_wipower.h b/wipower-host/jni/android_hardware_wipower.h new file mode 100644 index 0000000..eca9589 --- /dev/null +++ b/wipower-host/jni/android_hardware_wipower.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef COM_ANDROID_WIPOWER_H +#define COM_ANDROID_WIPOWER_H + +#include "JNIHelp.h" +#include "jni.h" +#include "hardware/hardware.h" +#include "hardware/bluetooth.h" +#include "hardware/wipower.h" + +namespace android { + + +int register_android_hardware_wipower (JNIEnv* env); + +} + +#endif /* COM_ANDROID_WIPOWER_H */ + diff --git a/wipower-host/wipower_lib/Android.mk b/wipower-host/wipower_lib/Android.mk new file mode 100644 index 0000000..8b94fbe --- /dev/null +++ b/wipower-host/wipower_lib/Android.mk @@ -0,0 +1,19 @@ + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := android.wipower +LOCAL_SRC_FILES := $(call all-java-files-under,.) +LOCAL_SRC_FILES += android/wipower/IWipowerManagerCallback.aidl +LOCAL_SRC_FILES += android/wipower/IWipower.aidl +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := android.wipower.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions +LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) + diff --git a/wipower-host/wipower_lib/android.wipower.xml b/wipower-host/wipower_lib/android.wipower.xml new file mode 100644 index 0000000..72413bc --- /dev/null +++ b/wipower-host/wipower_lib/android.wipower.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +--> + +<permissions> + <library name="android.wipower" file="/system/framework/android.wipower.jar"/> +</permissions> diff --git a/wipower-host/wipower_lib/android/wipower/IWipower.aidl b/wipower-host/wipower_lib/android/wipower/IWipower.aidl new file mode 100644 index 0000000..b326628 --- /dev/null +++ b/wipower-host/wipower_lib/android/wipower/IWipower.aidl @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package android.wipower; + + +import android.wipower.IWipowerManagerCallback; +import android.os.ParcelUuid; +import android.os.ParcelFileDescriptor; + +/** + * System private API for talking with the WiPower Manger. + * + * {@hide} + */ +interface IWipower +{ + int getState(); + boolean startCharging(); + boolean stopCharging(); + + boolean setCurrentLimit(in byte value); + byte getCurrentLimit(); + + boolean enableAlert(boolean enable); + boolean enableData(boolean enable); + boolean enablePowerApply(boolean enable, boolean on, boolean time_flag); + + void registerCallback(in IWipowerManagerCallback callback); + void unregisterCallback(in IWipowerManagerCallback callback); + +} diff --git a/wipower-host/wipower_lib/android/wipower/IWipowerManagerCallback.aidl b/wipower-host/wipower_lib/android/wipower/IWipowerManagerCallback.aidl new file mode 100644 index 0000000..a2c1306 --- /dev/null +++ b/wipower-host/wipower_lib/android/wipower/IWipowerManagerCallback.aidl @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package android.wipower; + +/** + * Application level callback for Wipower manager APIs. + * + * {@hide} + */ +interface IWipowerManagerCallback +{ + void onWipowerStateChange(int state); + + void onWipowerAlert(byte alert); + + void onWipowerData(in byte[] value); + + void onPowerApply(byte value); +} diff --git a/wipower-host/wipower_lib/android/wipower/WipowerDynamicParam.java b/wipower-host/wipower_lib/android/wipower/WipowerDynamicParam.java new file mode 100644 index 0000000..949c33a --- /dev/null +++ b/wipower-host/wipower_lib/android/wipower/WipowerDynamicParam.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +package android.wipower; + +import android.util.Log; + +import android.os.SystemProperties; + + +/** + * Class holds the PRU Dynamic parameter and related attributes + * + * {@hide} + */ + +public class WipowerDynamicParam { + private byte mOptValidity; + private short mRectVoltage; + private short mRectCurrent; + private short mOutputVoltage; + private short mOutputCurrent; + private byte mTemperature; + private short mMinRectVoltageDyn; + private short mMaxRectVoltageDyn; + private short mSetRectVoltageDyn; + private byte mAlert; + private short mReserved1; + private byte mReserved2; + + private static final String LOGTAG = "WipowerDynamicParam"; + private static boolean sDebug = false; + + private static final int MSB_MASK = 0xFF00; + private static final int LSB_MASK = 0x00FF; + + /* ADC conversions for voaltag and current */ + private static final float VREG_ADC_TO_mV_RATIO = ((float)(2.44/256)*10000); + private static final float IREG_ADC_TO_mA_RATIO = ((float)(2.44/256)*500); + + /* Over volatage protection parameters */ + private static final byte OVP_BIT = (byte)0x80; + private static final short OVP_THRESHHOLD_VAL = 21500; + + + /** + * Default Constructor + * {@hide} + */ + public WipowerDynamicParam() { + mOptValidity = 0x00; + mRectVoltage = 0x00; + mRectCurrent = 0x00; + mOutputVoltage = 0x00; + mOutputCurrent = 0x00; + mTemperature = 0x00; + mMinRectVoltageDyn = 0x00; + mMaxRectVoltageDyn = 0x00; + mSetRectVoltageDyn = 0x00; + mAlert = 0x00; + mReserved1 = 0; + mReserved2 = 0; + } + + /** + * helper to convert num to hex + * {@hide} + */ + private static String toHex(int num) { + return String.format("0x%8s", Integer.toHexString(num)).replace(' ', '0'); + } + + /** + * helper print function + * {@hide} + */ + void print() { + sDebug = SystemProperties.getBoolean("persist.a4wp.logging", false); + if (sDebug) Log.v(LOGTAG, "mOptValidity " + toHex(mOptValidity) + + "mRectVoltage " + toHex(mRectVoltage) + "mRectCurrent " + + toHex(mRectCurrent) + "mOutputVoltage " + toHex(mOutputVoltage)); + if (sDebug) Log.v(LOGTAG, "mOutputCurrent " + toHex(mOutputCurrent) + + "mTemperature " + toHex(mTemperature) + "mMinRectVoltageDyn " + + toHex(mMinRectVoltageDyn) + "mMaxRectVoltageDyn " + toHex(mMaxRectVoltageDyn)); + if (sDebug) Log.v(LOGTAG, "mSetRectVoltageDyn " + + toHex(mSetRectVoltageDyn) + "mAlert " + toHex(mAlert) + + "mReserved1 " + toHex(mReserved1) + "mReserved2 " + toHex(mReserved2)); + } + + /** + * {@hide} + * Gets the PRU dynamic parameter values in bytes + * + * @return byte array of PRU Dynamic parameter + * + */ + public byte[] getValue() { + byte[] res = new byte[20]; + print(); + res[0] = mOptValidity; + res[1] = (byte)(LSB_MASK & mRectVoltage); + res[2] = (byte)((MSB_MASK & mRectVoltage) >> 8); + res[3] = (byte)(LSB_MASK & mRectCurrent); + res[4] = (byte)((MSB_MASK & mRectCurrent) >> 8); + res[5] = (byte)(LSB_MASK & mOutputVoltage); + res[6] = (byte)((MSB_MASK & mOutputVoltage) >> 8); + res[7] = (byte)(LSB_MASK & mOutputCurrent); + res[8] = (byte)((MSB_MASK & mOutputCurrent) >> 8); + res[9] = mTemperature; + res[10] = (byte)(LSB_MASK & mMinRectVoltageDyn); + res[11] = (byte)((MSB_MASK & mMinRectVoltageDyn) >> 8); + res[12] = (byte)(LSB_MASK & mSetRectVoltageDyn); + res[13] = (byte)((MSB_MASK & mSetRectVoltageDyn) >> 8); + res[14] = (byte)(LSB_MASK & mMaxRectVoltageDyn); + res[15] = (byte)((MSB_MASK & mMaxRectVoltageDyn) >> 8); + res[16] = mAlert; + if (((res[16] & OVP_BIT) == OVP_BIT) && (mRectVoltage < OVP_THRESHHOLD_VAL)) + res[16] = (byte)(res[16] & ~OVP_BIT); + + Log.i(LOGTAG, "mPruDynamicParam.getValue"); + return res; + } + + public void resetValues() { + mOptValidity = 0x00; + mRectVoltage = 0x00; + mRectCurrent = 0x00; + mOutputVoltage = 0x00; + mOutputCurrent = 0x00; + mTemperature = 0x00; + mMinRectVoltageDyn = 0x00; + mMaxRectVoltageDyn = 0x00; + mSetRectVoltageDyn = 0x00; + mAlert = 0x00; + mReserved1 = 0x00; + mReserved2 = 0x00; + } + + public static short toUnsigned(byte b) { + return (short)(b & 0xff); + } + + public static short VREG_ADC_TO_mV(short adc){ + return (short)((adc)*(VREG_ADC_TO_mV_RATIO)); + } + + public static short IREG_ADC_TO_mA(short adc) { + return (short)((adc)*(IREG_ADC_TO_mA_RATIO)); + } + + /** + * {@hide} + * Sets the PRU dynamic parameter values for A4WP App in bytes + * + * @return none + */ + public void setValue(byte[] value) { + + resetValues(); + mOptValidity = value[0]; + mRectVoltage = (short)toUnsigned(value[1]); + mRectVoltage |= (short)(toUnsigned(value[2]) << 8); + mRectCurrent = (short)toUnsigned(value[3]); + mRectCurrent |= (short)(toUnsigned(value[4]) << 8); + mOutputVoltage = (short)toUnsigned(value[5]); + mOutputVoltage |= (short)(toUnsigned(value[6]) << 8); + mOutputCurrent = (short)toUnsigned(value[7]); + mOutputCurrent |= (short)(toUnsigned(value[8]) << 8); + mTemperature = value[9]; + mMinRectVoltageDyn = (short)toUnsigned(value[10]); + mMinRectVoltageDyn |= (short)(toUnsigned(value[11]) << 8); + mSetRectVoltageDyn = (short)toUnsigned(value[12]); + mSetRectVoltageDyn |= (short)(toUnsigned(value[13]) << 8); + mMaxRectVoltageDyn = (short)toUnsigned(value[14]); + mMaxRectVoltageDyn |= (short)(toUnsigned(value[15]) << 8); + + mAlert = value[16]; + mReserved1 = (short)(toUnsigned(value[17])); + mReserved1 = (short)(toUnsigned(value[18]) << 8); + mReserved2 = value[19]; + Log.i(LOGTAG, "mPruDynamicParam.setAppValue"); + print(); + return; + } + } + diff --git a/wipower-host/wipower_lib/android/wipower/WipowerManager.java b/wipower-host/wipower_lib/android/wipower/WipowerManager.java new file mode 100644 index 0000000..edbb7df --- /dev/null +++ b/wipower-host/wipower_lib/android/wipower/WipowerManager.java @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package android.wipower; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.IPackageManager; +import android.os.IBinder; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; +import android.os.SystemProperties; + +/** + * Public APIs for wipower control + * This class exposes APIs to control wipower module on the phone + * These APIs would be used by wireless charging application in context + * of Bluetooth A4WP profile + * + * {@hide} + */ + +public final class WipowerManager { + private static final String TAG = "WipowerManager"; + private static final boolean DBG = true; + private static final boolean VDBG = false; + + private static IWipower mService; + private static ArrayList<WipowerManagerCallback> mCallbacks; + private static WipowerDynamicParam mPruData; + private static WipowerState mState; + private static WipowerManager mWipowerManager; + + /** + * Power levels used to indicate the charging levels + * + * {@hide} + */ + public enum PowerLevel { + POWER_LEVEL_MAXIMUM, + POWER_LEVEL_MEDIUM, + POWER_LEVEL_MINIMUM, + POWER_LEVEL_UNKNOWN + }; + + /** + * Wipower States + * {@hide} + */ + public enum WipowerState { + OFF, + ON + }; + + /** + * Wipower power applied event + * {@hide} + */ + public enum PowerApplyEvent { + OFF, + ON + }; + + /* helper function to invoke callbacks to application layer*/ + void updateWipowerState(WipowerState state){ + if (mCallbacks != null) { + int n = mCallbacks.size(); + Log.v(TAG,"Broadcasting updateAdapterState() to " + n + " receivers."); + for (int i = 0; i < n; i++) { + mCallbacks.get(i).onWipowerStateChange(state); + } + } + } + + /* helper function to invoke callbacks to application layer*/ + void updateWipowerData(WipowerDynamicParam pruData){ + if (mCallbacks != null) { + int n = mCallbacks.size(); + Log.v(TAG,"Broadcasting updateWipowerData() to " + n + " receivers."); + for (int i = 0; i < n; i++) { + mCallbacks.get(i).onWipowerData(pruData); + } + } + } + + /* helper function to invoke callbacks to application layer*/ + void updateWipowerAlert(byte alert){ + if (mCallbacks != null) { + int n = mCallbacks.size(); + Log.v(TAG,"Broadcasting updateWipowerAlert() to " + n + " receivers."); + for (int i = 0; i < n; i++) { + mCallbacks.get(i).onWipowerAlert(alert); + } + } + } + + void updatePowerApplyAlert(PowerApplyEvent alert){ + if (mCallbacks != null) { + int n = mCallbacks.size(); + if (VDBG) Log.v(TAG,"Broadcasting updatePowerApplyAlert() to " + n + " receivers."); + for (int i = 0; i < n; i++) { + mCallbacks.get(i).onPowerApply(alert); + } + } + } + + + /* helper function to invoke callbacks to application layer*/ + void updateWipowerReady(){ + if (mCallbacks != null) { + int n = mCallbacks.size(); + if (VDBG) Log.v(TAG,"Broadcasting updateWipowerReady " + n + " receivers."); + for (int i = 0; i < n; i++) { + mCallbacks.get(i).onWipowerReady(); + } + } + } + + final private IWipowerManagerCallback mWiPowerMangerCallback = + new IWipowerManagerCallback.Stub() { + + public void onWipowerStateChange(int state) { + WipowerState s; + + if (state == 1) { + s = WipowerState.ON; + } else { + s = WipowerState.OFF; + } + + Log.v(TAG, "onWipowerStateChange: state" + state); + updateWipowerState(s); + } + + public void onWipowerAlert(byte alert) { + Log.v(TAG, "onWipowerAlert: alert" + alert); + updateWipowerAlert(alert); + + } + + public void onPowerApply(byte alert) { + PowerApplyEvent s; + + if (alert == 0x1) { + s = PowerApplyEvent.ON; + } else { + s = PowerApplyEvent.OFF; + } + + if (VDBG) Log.v(TAG, "onPowerApply: alert" + alert); + updatePowerApplyAlert(s); + + } + + public void onWipowerData(byte[] value) { + Log.v(TAG, "onWipowerData: " + value); + if (mPruData != null) { + mPruData.setValue(value); + updateWipowerData(mPruData); + } else { + Log.e(TAG, "mPruData is null"); + } + + } + }; + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + mService = IWipower.Stub.asInterface(service); + + if (DBG) Log.v(TAG, "Proxy object connected: " + mService); + try { + mService.registerCallback(mWiPowerMangerCallback); + } catch (android.os.RemoteException e) { + Log.e(TAG, "not able to register as client"); + } + + Log.v(TAG, "Calling onWipowerReady"); + updateWipowerReady(); + + } + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.v(TAG, "Proxy object disconnected"); + try { + mService.unregisterCallback(mWiPowerMangerCallback); + } catch (android.os.RemoteException e) { + Log.e(TAG, "not able to unregister as client"); + } + mService = null; + } + }; + + public static synchronized WipowerManager getWipowerManger(Context context, WipowerManagerCallback callback) { + if (!isWipowerSupported()) { + Log.e(TAG, "Wipower not supported"); + return null; + } + + if (mWipowerManager == null) { + if (DBG) Log.v(TAG, "Instantiate Singleton"); + mWipowerManager = new WipowerManager(context.getApplicationContext(), callback); + } + return mWipowerManager; + } + + /** + * WipowerManager is the main class which exposes Application interfaces + * Wireless Charging control + * + * {@hide} + */ + private WipowerManager(Context context, WipowerManagerCallback callback) { + if (mService == null) { + try { + + Intent bindIntent = new Intent(IWipower.class.getName()); + ComponentName comp = bindIntent.resolveSystemService(context.getPackageManager(), 0); + bindIntent.setComponent(comp); + if (comp == null || !context.bindService(bindIntent, mConnection, Context.BIND_AUTO_CREATE)) { + Log.e(TAG, "Could not bind to Wipower Service"); + } + } catch (SecurityException e) { + Log.e(TAG, "Security Exception"); + } + } + + Log.v(TAG, "Bound to Wipower Service"); + mPruData = new WipowerDynamicParam(); + mCallbacks = new ArrayList<WipowerManagerCallback>(); + } + + static boolean isWipowerSupported() { + + if (SystemProperties.getBoolean("ro.bluetooth.wipower", false) == true) { + Log.v(TAG, "System.getProperty is true"); + return true; + } else { + Log.v(TAG, "System.getProperty is false"); + return false; + } + } + + + /** + * startCharing initiate the wireless charging process by internally + * setting output voltage for the wireless charging module + * <p>This is an asynchronous call: Status of this indicated by + * {@link WipowerManagerCallback::onWipowerStateChange} + * + * @return true on sucess, + * false if start charging fails or if the hardware doesn't support this feature + * {@hide} + */ + public boolean startCharging() { + boolean ret = false; + + if (!isWipowerSupported()) { + Log.e(TAG, "Wipower not supported"); + return false; + } + + if (mService == null) { + Log.e(TAG, "startCharging: Service not available"); + } else { + try { + ret = mService.startCharging(); + } catch (android.os.RemoteException e) { + Log.e(TAG, "Service Exceptione"); + } + } + + return ret; + } + + /** + * stopCharing stop the wireless charging process by internally + * setting output voltage for the wireless charging module + * <p>This is an asynchronous call: Status of this indicated by + * {@link WipowerManagerCallback::onWipowerStateChange} + * + * @return true on sucess + * false if start charging fails or if the hardware doesn't support this feature + * {@hide} + */ + public boolean stopCharging() { + boolean ret = false; + + if (!isWipowerSupported()) { + Log.e(TAG, "Wipower not supported"); + return false; + } + + if (mService == null) { + Log.e(TAG, " Wipower Service not available"); + } else { + try { + ret = mService.stopCharging(); + } catch (android.os.RemoteException e) { + Log.e(TAG, "Service Exceptione"); + } + } + + return ret; + } + + /** + * Sets the current level for Wireless charging module + * + * @param {@link Powerlevel} indicating the desired power level + * + * @return true on success + * false if start charging fails or if the hardware doesn't support this feature + * + * {@hide} + */ + public boolean setPowerLevel(PowerLevel powerlevel) { + boolean ret = false; + + if (!isWipowerSupported()) { + Log.e(TAG, "Wipower not supported"); + return false; + } + + if (mService == null) { + Log.e(TAG, " Wipower Service not available"); + } else { + byte level = 0; + if( powerlevel == PowerLevel.POWER_LEVEL_MINIMUM) level = 2; + else if( powerlevel == PowerLevel.POWER_LEVEL_MEDIUM) level = 1; + else if( powerlevel == PowerLevel.POWER_LEVEL_MAXIMUM) level = 0; + try { + ret = mService.setCurrentLimit(level); + } catch (android.os.RemoteException e) { + Log.e(TAG, "Service Exceptione"); + } + } + return ret; + } + + /** + * Gets the current level for Wireless charging module + * + * @return {@link Powerlevel} current power level + * + * {@hide} + */ + public PowerLevel getPowerLevel() { + PowerLevel ret = PowerLevel.POWER_LEVEL_UNKNOWN; + + if (mService == null) { + Log.e(TAG, " Wipower Service not available"); + } else { + byte res = 0; + try { + res = mService.getCurrentLimit(); + } catch (android.os.RemoteException e) { + Log.e(TAG, "Service Exceptione"); + } + if(res == 0) ret = PowerLevel.POWER_LEVEL_MINIMUM; + else if(res == 1) ret = PowerLevel.POWER_LEVEL_MEDIUM; + else if(res == 2) ret = PowerLevel.POWER_LEVEL_MAXIMUM; + } + return ret; + } + + /** + * Gets the current state of Wireless charging + * + * @return {@link WipowerState } wireless charging state + * {@hide} + */ + public WipowerState getState() { + WipowerState ret = WipowerState.OFF; + if (mService == null) { + Log.e(TAG, " Wipower Service not available"); + } else { + int res = 0; + try { + res = mService.getState(); + } catch (android.os.RemoteException e) { + Log.e(TAG, "Service Exceptione"); + } + if (res == 0) { + ret = WipowerState.OFF; + } + else { + ret = WipowerState.ON; + } + } + return ret; + } + + /** + * Enables Alert notifications. + * + * @return true on success or flase otherwise + * {@hide} + */ + public boolean enableAlertNotification(boolean enable) { + boolean ret = false; + if (mService == null) { + Log.e(TAG, "Service not available"); + } else { + try { + ret = mService.enableAlert(enable); + } catch (android.os.RemoteException e) { + Log.e(TAG, "Service Exception"); + } + } + + return ret; + } + + /** + * Enables data notifications. + * + * @return true on success or flase otherwise + * {@hide} + */ + public boolean enableDataNotification(boolean enable) { + boolean ret = false; + if (mService == null) { + Log.e(TAG, "Service not available"); + } else { + try { + ret = mService.enableData(enable); + } catch (android.os.RemoteException e) { + Log.e(TAG, "Service Exceptione"); + } + } + + return ret; + } + + /** + * Enables power detection command. + * + * @return true on success or flase otherwise + * {@hide} + */ + public boolean enablePowerApply(boolean enable, boolean on, boolean time_flag) { + boolean ret = false; + Log.v(TAG,"enablePowerApply: enable: " + enable + " on: " + on + " time_flag:" + time_flag); + if (mService == null) { + Log.e(TAG, "Service not available"); + } else { + try { + ret = mService.enablePowerApply(enable, on, time_flag); + } catch (android.os.RemoteException e) { + Log.e(TAG, "Service Exceptione"); + } + } + + return ret; + } + + + /** API used to reigester the wipower callbacks. + * {@hide} + */ + public void registerCallback(WipowerManagerCallback callback) { + if (VDBG) Log.v(TAG, "registerCallback:Service called"); + if (mService == null) { + Log.e(TAG, "registerCallback:Service not available"); + } + + mCallbacks.add(callback); + } + + /** API used to unreigester the wipower callbacks. + * {@hide} + */ + public void unregisterCallback(WipowerManagerCallback callback) { + if (mService == null) { + Log.e(TAG, "Service not available"); + } + mCallbacks.remove(callback); + } +} diff --git a/wipower-host/wipower_lib/android/wipower/WipowerManagerCallback.java b/wipower-host/wipower_lib/android/wipower/WipowerManagerCallback.java new file mode 100644 index 0000000..fe871ed --- /dev/null +++ b/wipower-host/wipower_lib/android/wipower/WipowerManagerCallback.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package android.wipower; + +import android.wipower.WipowerManager.WipowerState; +import android.wipower.WipowerManager.PowerApplyEvent; + +/** + * Application level callback for Wipower manager APIs. + * + * {@hide} + */ +public interface WipowerManagerCallback +{ + + /** + * Clients should wait till onWipowerReady notification + * before initiating Wipower charging or using any other + * WipowerManager related APIs + * Clients should create the instance of WipowerManger and starts + * Wipower charging on onWipowerReady callback + * {@hide} + */ + void onWipowerReady(); + + /** + * Indicates the Wipower state + * + * @param {@link WipowerState} + * + * {@hide} + */ + void onWipowerStateChange(WipowerState state); + + /** + * Indicates the Wipower Alert + * + * @param {@link alert} + * + * {@hide} + */ + void onWipowerAlert(byte alert); + + /** + * Indicates the Wipower PRU Data notifications + * + * @param {@link WipowerDynamicParam} + * + * {@hide} + */ + void onWipowerData(WipowerDynamicParam value); + + /** + * Indicates the power apply event + * + * @param {@link PowerApplyEvent} + * + * {@hide} + */ + void onPowerApply(PowerApplyEvent event); + +} |