2

平台 (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
};
4

1 回答 1

0

我第一次尝试同样的事情没有运气,然后我找到了“pmset noidle”。( pmset.c ) 这引发了一个断言,只是不是正确的。查看函数 prevent_idle_sleep。

改变这个:

IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep,
                    kIOPMAssertionLevelOn,
                    CFSTR("pmset prevent sleep"),
                    &neverSleep))

至:

IOPMAssertionCreateWithName(kIOPMAssertionTypeInhibitCharging,
                    kIOPMAssertionLevelOn,
                    CFSTR("prevent charging..."),
                    &neverSleep))

并添加这些定义:

// Disables battery charging (requires root to initiate)
#define kIOPMAssertionTypeInhibitCharging       CFSTR("ChargeInhibit")
#define kIOPMChargeInhibitAssertion             kIOPMAssertionTypeInhibitCharging
于 2012-12-23T16:30:07.310 回答