Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Сенсор внезапного движения

Очень давно, на всех носимых устройствах, оснащённых жёстким диском (ноута, смартфонах) появился сенсор внезапного движения. В жёстком диске считывающая головка находится, не касаясь, над поверхностью диска с данными. Если ноут резко поднять, головка может чиркнуть по поверхности диска и испортить его. Для этого нужен сенсор внезапного движения (акселерометр), он реагирует на ускорение в любую сторону и «паркует» головку — уводит её в зону, где она ничего не может повредить.

На ноутах с твёрдотельным накопителем (ССД), этого сенсора обычно не бывает — он там не нужен. Например, на моём Макбуке Эйр его не было, нет его и на 15″ Макбуке Про с Ретиной моего друга, я специально смотрел — в этих ноутах нет жёстких дисков. В Макбуках Про предыдущей модели, без Ретины и с жёстким диском, сенсор, естественно, был.

Каково же было моё удивление, когда я обнаружил, после покупки Макбука Про 13″, что в сведениях о системе есть упомянутый сенсор:

Сенсор внезапного движения (148.70КиБ)

Думаю, его просто забыли убрать, наверное это рудимент прежней модели Макбука. Но наличие сенсора не говорит о том, что он работает. Я сегодня потратил пару часов, чтобы разобраться как в Маке читают этот сенсор и написал вот такую программу на Си:

// MacbookPro (OS X 10.5+) SMS reading. Evgeny Stepanischev May 2013
// gcc  -framework IOKit  motion.c
#include <IOKit/IOKitLib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define RETURNONFAIL(code) do { if (errcode != KERN_SUCCESS) {\
    fprintf(stderr, "Error code: 0x%Xn", GETCODE(errcode));\
    return code;\
} } while (0)

#define GETCODE(err) ((err)&0x3fff)

typedef struct {
    int16_t x;
    int16_t y;
    int16_t z;
} ostruct;

int main() {
    mach_port_t masterPort;
    kern_return_t errcode;
    io_iterator_t iterator;
    io_object_t service;
    io_connect_t connect;

    void *in;
    ostruct *out;
    size_t osize = 40, isize = 40;

    errcode = IOMasterPort(MACH_PORT_NULL, &masterPort);
    RETURNONFAIL(-1);

    CFMutableDictionaryRef matchingDictionary = IOServiceMatching("SMCMotionSensor");

    errcode = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
    RETURNONFAIL(-2);

    service = IOIteratorNext(iterator);
    IOObjectRelease(iterator);

    if (service == kIOReturnNoDevice) {
        return -3;
    }

    errcode = IOServiceOpen(service, mach_task_self(), 0, &connect);
    IOObjectRelease(service);
    RETURNONFAIL(-4);

    in = malloc(isize);
    out = malloc(osize);

    if (in == NULL || out == NULL) {
        return -6;
    }

    memset(out, 0, osize);
    memset(in, 1, isize);

    errcode = IOConnectCallStructMethod(connect, 5, in, osize, out, &isize);
    RETURNONFAIL(-5);

    printf("%d, %d, %d\n", (*out).x, (*out).y, (*out).z);

    return 0;
}

Программа выводит три числа: показатели наклона влево/вправо, назад/вперёд и показатель ускорения, который меняется, если ноут резко поднять или опустить.

Размер структуры 40 и второй параметр функции IOConnectCallStructMethod («5») — «магические» значения, первое — фиксированный размер буфера, который требуется функции, второе — номер вызываемой функции в ядре (SMCMotionSensor).

2 комментария
Sanja 2013

у меня на ноуте Fujitsu производитель заботливо положил на desktop PDF-ку с описанием процедуры отключения акселерометра, если используется SSD.

Евгений Степанищев (bolknote.ru) 2013

Комментарий для Sanja:

Эпл тоже рассказывает как это сделать: http://support.apple.com/kb/HT1935