创建 ChargeInhibit 断言 (OS X 10.6.8)
平台 (OS X 10.6.8) - [Macbook Pro - 这很重要,因为我想处理电池处理 - 不适用于台式机]
如果我犯了一个我没有看到的基本错误,请原谅我,因为我没有编写任何 C/C++在五年或更长时间内,我没有完全遵循苹果 API 希望你处理它们的方式,所以这就是我的问题。基本上,我希望能够根据我的命令禁止交流适配器充电,以便我可以选择是否在笔记本电脑使用和插入时为其充电。我找不到任何实用程序可以做到这一点因此,我一开始将其视为硬件级别的东西,无法通过软件更改,但后来我遇到了一些令人鼓舞的事情:
如果您打开终端窗口并运行,
pmset -g assertionslog
您会得到一个断言列表,每个 0 或 1 表示是否有进程已断言该断言。第一个标题为 ChargeInhibit,经过一番挖掘后我发现这在软件级别上完全符合我的要求。我只需要弄清楚如何断言它。
我从苹果源存档中名为 的文件中复制了一些代码SetActive.c(链接) 我将函数 sendSmartBatteryCommand 复制到我的 XCode 项目中,并花时间链接其他标头并复制定义,直到我可以正确编译它。这是复制的函数:
// The copied function,
// modified very slightly:
// to return a success/fail value instead of void
kern_return_t sendSmartBatteryCommand(uint32_t which, uint32_t level)
{
io_service_t sbmanager = MACH_PORT_NULL;
io_connect_t sbconnection = MACH_PORT_NULL;
kern_return_t kret = 99;
uint32_t output_count = 1;
uint64_t uc_return = kIOReturnError;
uint64_t level_64 = level;
// Find SmartBattery manager
sbmanager = IOServiceGetMatchingService(MACH_PORT_NULL,
IOServiceMatching("AppleSmartBatteryManager"));
if(MACH_PORT_NULL == sbmanager) {
goto bail;
}
kret = IOServiceOpen( sbmanager, mach_task_self(), 0, &sbconnection);
if(kIOReturnSuccess != kret) {
goto bail;
}
kret = IOConnectCallMethod(
sbconnection, // connection
which, // selector
&level_64, // uint64_t *input
1, // input Count
NULL, // input struct count
0, // input struct count
&uc_return, // output
&output_count, // output count
NULL, // output struct
0); // output struct count
bail:
if (MACH_PORT_NULL != sbconnection) {
IOServiceClose(sbconnection);
}
if (MACH_PORT_NULL != sbmanager) {
IOObjectRelease(sbmanager);
}
return kret;
}
当我尝试使用它发送充电抑制和流入禁用的断言时,我得到了成功值,但是 pmset 的日志没有显示任何更改,电池充电的实际状态也没有显示不充电。
我还尝试将要查找的服务名称从“AppleSmartBatteryManager”修改为无意义的单词,只是为了查看该函数是否返回失败,结果确实如此,这表明我正在连接到真正的服务。
关于如何尽可能简单地实现这一目标有什么建议吗?
顺便说一句,我尝试从苹果源站点上的源包重新编译 PowerManagement 项目中的 AppleSmartBatteryManager,但 XCode 中的错误超出了我的处理能力。我希望尝试以某种方式与现有服务进行交互,而不会让我与我自己的项目一起重新编译 AppleSmartBatteryManager 源代码。
编辑: 顺便说一句,这是我调用该函数的一个示例:
int CInh()
{
kern_return_t kret = sendSmartBatteryCommand( kSBUCChargeInhibit, 255); // zero:uninhibit, non-zero:inhibit
if(kret == KERN_SUCCESS)
return 1;
else
return 0;
}
其中“which”参数的选项在我的头文件中的枚举中定义(也从 SetActive.c 复制):
enum {
kSBUCInflowDisable = 0,
kSBUCChargeInhibit = 1
};
Platform (OS X 10.6.8) -
[Macbook Pro - this is important as I want to deal with the battery handling - not applicable for a desktop]
Forgive me if I've made a basic mistake that I don't see, as I haven't written any C/C++ in five years or more, and I'm not fully following the way apple APIs want you to deal with them, so this is what my question regards. Basically, I want to be able to inhibit charging from the AC adaptor at my command, so that I can choose whether to charge my laptop or not while it's in use and plugged in. I hadn't been able to find any utilities that do this, so I had at first written it off as something that was on the hardware level and couldn't be changed from software, but then I ran across something encouraging:
If you open a Terminal window and run
pmset -g assertionslog
you get a list of assertions, and a 0 or 1 for each, indicating if some process has asserted that assertion. The first of them is titled ChargeInhibit, and I discovered after some digging that this does exactly what I want, at the software level. I just have to figure out how to assert it.
I copied some code from a file in the apple source archive called SetActive.c (link) I copied the function sendSmartBatteryCommand into my XCode project, and spent time linking other headers and copying over definitions until I could get it to compile correctly. Here is the copied function:
// The copied function,
// modified very slightly:
// to return a success/fail value instead of void
kern_return_t sendSmartBatteryCommand(uint32_t which, uint32_t level)
{
io_service_t sbmanager = MACH_PORT_NULL;
io_connect_t sbconnection = MACH_PORT_NULL;
kern_return_t kret = 99;
uint32_t output_count = 1;
uint64_t uc_return = kIOReturnError;
uint64_t level_64 = level;
// Find SmartBattery manager
sbmanager = IOServiceGetMatchingService(MACH_PORT_NULL,
IOServiceMatching("AppleSmartBatteryManager"));
if(MACH_PORT_NULL == sbmanager) {
goto bail;
}
kret = IOServiceOpen( sbmanager, mach_task_self(), 0, &sbconnection);
if(kIOReturnSuccess != kret) {
goto bail;
}
kret = IOConnectCallMethod(
sbconnection, // connection
which, // selector
&level_64, // uint64_t *input
1, // input Count
NULL, // input struct count
0, // input struct count
&uc_return, // output
&output_count, // output count
NULL, // output struct
0); // output struct count
bail:
if (MACH_PORT_NULL != sbconnection) {
IOServiceClose(sbconnection);
}
if (MACH_PORT_NULL != sbmanager) {
IOObjectRelease(sbmanager);
}
return kret;
}
I get success values back when I try to use it to send assertions for charge inhibiting and inflow disabling, but the log from pmset doesn't show any changes, and neither does the actual state of my battery charging / not-charging.
I've also tried modifying the name of the service to look for from "AppleSmartBatteryManager" to a nonsense word just to see if the function returns failure, and it does, so that indicates I'm connecting to a real service.
Any tips on how I can achieve this as simply as possible?
By the way, I've tried to recompile the AppleSmartBatteryManager in the PowerManagement project from the source package on the apple source site, but I way more errors in XCode than I can deal with. I'm looking to try to interact with the existing service in some way that does not make me recompile the AppleSmartBatteryManager source alongside my own project.
EDIT:
By the way, this is an example of me calling the function:
int CInh()
{
kern_return_t kret = sendSmartBatteryCommand( kSBUCChargeInhibit, 255); // zero:uninhibit, non-zero:inhibit
if(kret == KERN_SUCCESS)
return 1;
else
return 0;
}
Where options for the "which" parameter are defined in an enum in my header file (also copied from SetActive.c):
enum {
kSBUCInflowDisable = 0,
kSBUCChargeInhibit = 1
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我首先尝试了同样的事情,但没有成功,然后我发现了“pmset noidle”。 (pmset.c) 这提出了一个断言,但不是正确的断言。看一下函数prevent_idle_sleep。
将其更改
为:
并添加这些定义:
I first tried the same thing with no luck, then i found "pmset noidle." (pmset.c) This raises an assertion, just not the right one. Look at the function prevent_idle_sleep.
Change this:
to:
and add these defines: