最終更新日:2014/02/18
MacBook Pro 15 early 2011のバッテリーを据え置き状態で付けっぱなしにしておいたら1年半でバッテリーがダメになって交換しました(月一回の充放電はしてましたが)。今度はちゃんと対策しようとした記録です。
前回書いたChargeInhibitは自分の勘違いでDisableInflowが実行されています。これはAC電源を切る命令です。とりあえず目的が達成できていたのであまり詳しく調べませんでしたが、昨日やたら人が来たので久しぶりに調べてみたら根本的な勘違いをしていました!
MacBook Pro 15 early 2011 @ 10.6.8
DisableInflowはIOPMAssertionCreateWithNameで実行できます。
// Disables AC Power Inflow (requires root to initiate)
#define kIOPMAssertionTypeDisableInflow CFSTR("DisableInflow")
#define kIOPMInflowDisableAssertion kIOPMAssertionTypeDisableInflow
IOPMAssertionID assertionID = 0;
IOReturn ret = IOPMAssertionCreateWithName(kIOPMInflowDisableAssertion,
kIOPMAssertionLevelOn,
CFSTR("kIOPMInflowDisableAssertion"),
&assertionID);
上のリンクのsendSmartBatteryCommand
は完璧なコードで間違いはありません。
動かない原因は引数が10.6.8では変わっているのと、実行プロセスにroot権限が無いとエラーになります。
ハードやOS依存の部分があると思うので試す方は要注意ですがMacBook Pro 15 early 2011 @ 10.6.8では次の命令でオン・オフできます。
kSBUCInflowDisable = 0,
なので下記コードでACをソフトウェアで接続、切断できます。
sendSmartBatteryCommand(0, 1); //充電オフ
sendSmartBatteryCommand(0, 0); //充電オン
この命令を送るプロセスにはroot権限がないと命令が実行されません。
今はターミナルでsudoを付けて動かしています。
sendSmartBatteryCommandは下のAppleSmartBatteryManagerUserClient::secureChargeInhibit
関数を実行する関数です。AppleSmartBatteryManagerUserClient::externalMethod
経由で実行されます。
参考リンク先では
(kSBUCChargeInhibit, 255)
で実行しています。
enum {
kSBUCInflowDisable = 0,
kSBUCChargeInhibit = 1
};
なので、(1,255)
です。
しかし、2006のAppleSmartBatteryManagerUserClientのソースは次のようになっています。
IOReturn AppleSmartBatteryManagerUserClient::secureInflowDisable(
int level,
int *return_code)
{
int admin_priv = 0;
IOReturn ret = kIOReturnNotPrivileged;
if( !(level == 0 || level == 1))
{
*return_code = kIOReturnBadArgument;
return kIOReturnSuccess;
}
ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
admin_priv = (kIOReturnSuccess == ret);
if(admin_priv && fOwner) {
*return_code = fOwner->disableInflow( level );
return kIOReturnSuccess;
} else {
*return_code = kIOReturnNotPrivileged;
return kIOReturnSuccess;
}
}
enum {
kSBInflowDisable = 0,
kSBChargeInhibit = 1,
kSBSetPollingInterval = 2,
kSBSMBusReadWriteWord = 3
};
これでわかったのは、sendSmartBatteryCommand
の返り値kret
は常にkIOReturnSuccessでuc_return
に実際のエラーが格納されているということです。
そこでどのエラーが返ってきているか確認したら次の2つが返ってきていました
#define kIOReturnNotPrivileged iokit_common_err(0x2c1) // privilege violation
#define kIOReturnBadArgument iokit_common_err(0x2c2) // invalid argument
(0,255)
で実行した時は0x2c2
のkIOReturnBadArgument
が返ってきています。上のAppleSmartBatteryManagerUserClient::secureChargeInhibit
のソースに書いてある通り、0、1で指定すると動きました。
kSBInflowDisableは0なので0ですが、kSBChargeInhibitらしき1はやっぱり指定しても駄目なのでChargeInhibitは今のところやっぱり駄目です…。
rootが必要なのはIOPMLibPrivate.hのヘッダにより予想していたので常時sudoで実行していましたが、sudo無しで実行するとkIOReturnNotPrivilegedのエラーが返ってきました。
// Disables AC Power Inflow (requires root to initiate)
#define kIOPMAssertionTypeDisableInflow CFSTR("DisableInflow")
#define kIOPMInflowDisableAssertion kIOPMAssertionTypeDisableInflow
// Disables battery charging (requires root to initiate)
#define kIOPMAssertionTypeInhibitCharging CFSTR("ChargeInhibit")
#define kIOPMChargeInhibitAssertion kIOPMAssertionTypeInhibitCharging
sendSmartBatteryCommand
の引数がAppleが公開している2006年ぐらいのソースと違っているので10.7以降、そしてMacBook Airなどの新ハードウェアでは引数が違う場合があると思われますが未確認です。自分で試して見る場合には十分に注意して行って下さい。過充電状態にならないように自動で制御するアプリケーションです。
startCharging
の«event ASBMExec» {0, 0}
とstopCharging
の«event ASBMExec» {0, 1}
の値をいろいろ弄るといけるかもしれません。ただし、何が起こるかは分からないので自己責任でやってください。この値がsendSmartBatteryCommand
にそのまま渡されます。エラーメッセージは文字列か16進数の文字列で返されますので参考にして下さい。AutoChargeInhibitがダウンロードできます。