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

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

На ноутах с твёрдотельным накопителем (ССД), этого сенсора обычно не бывает — он там не нужен. Например, на моём Макбуке Эйр его не было, нет его и на 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 комментария

Берём «Макбук» со стола, экран гаснет или блокируется

В предыдущей заметке я писал, что обнаружил сенсор внезапного движения у своего «Макбука». Решил извлечь практическую пользу из этого — написал программу на Си, которая отправляет ноут в спячку, стоит поднять его со стола:

// gcc -framework CoreFoundation -framework IOKit  gethensleep.c -o getthensleep
// Evgeny Stepanischev May 2013
#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/param.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)

#define THRESHOLD 0.2

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

void macSleep() {
    io_registry_entry_t r = IORegistryEntryFromPath(
        kIOMasterPortDefault,
        "IOService:/IOResources/IODisplayWrangler"
    );

    if (r) {
        IORegistryEntrySetCFProperty(r, CFSTR("IORequestIdle"), kCFBooleanTrue);
        IOObjectRelease(r);
    }
}

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);

    int16_t prevz;
    bool inited = false;

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

        if (inited) {
            float min = MIN(prevz, (*out).z);
            float max = MAX(prevz, (*out).z);

            if (max) {
                float dev = 1 - min / max;

                if (dev > THRESHOLD) {
                    macSleep();
                }
            }
        } else {
            inited = true;
        }

        prevz = (*out).z;
        usleep(10000);
    }

    return 0;
}

Порог срабатывания (0.2) я подобрал экспериментальным путём. Скомпилировать можно компилятором gcc (входит в XCode), строка компиляции указана первой в приведёном коде. Можно засунуть в автозагрузку и наслаждаться эффектом.

Кстати, если хотите, то можно вместо спячки заставить ноут заблокировать экран (т. е. показать экран логина), для этого надо вместо функции macSleep вызвать другую:

// нужно добавить ещё один ключ компиляции: -framework ApplicationServices
#include <ApplicationServices/ApplicationServices.h>

void macLock () {
    CGSCreateLoginSession(NULL);
}

27 комментариев

Разрушенные церкви бугульминского района Татарстана

У меня есть хобби, о котором, возможно, многие успели забыть (на время холодов я сделал паузу) — люблю фотографировать полуразрушенные храмы и церкви. В них есть какое-то неуловимое очарование, которое я с трудом и лишь изредка улавливаю в цельных постройках. Кроме того, у меня есть немного более практическая цель — запечатлеть остатки оригинальных фресок, которые почти наверняка пропадут после реставрации здания. С реставрацией фресок у нас не заморачиваются — просто делают новые на этом месте.

Я в последние майские праздники ездил по некоторым кладбищам бавлинского и бугульминского районов Татарстана — искал могилы своих предков, заодно заехал в парочку разрушенных церквей.

Разрушенная кирпичная церковь с куполом и травой на крыше под голубым небом, с арочными окнами и дверями, окружённая зелёной лужайкой и памятником.
Каменная геральдическая доска с короной и пустым щитом, встроенная в старую красную кирпичную стену.

Первая — церковь Вознесения, построенная в 1764 году на деньги П.И. Рычкова в селе Спасское (Бугульминский район), объект культурного наследия республиканского значения. Внутрь уже не попасть, церковь начали восстанавливать, но в один из пристроев вход ещё открыт. На стенах и вокруг здания в кустах есть интерсные восьмиугольники, увенчанные короной, в которых что-то находилось — видны отверстия креплений. Интересно, что там было?

Разрушенная кирпичная церковь с обвалившейся штукатуркой и отсутствующей крышей, стоящая на зелёном холме под голубым небом с облаками.
Вид изнутри разрушенного здания: обвалившаяся кирпичная кладка купола, оголённые деревянные балки перекрытий и облупившаяся штукатурка стен под ясным небом.
Обветшавшая стена с облупившейся штукатуркой, трещиной и остатками росписи, обрамлённая красным кирпичом.
Почерневшая и облупившаяся фреска в прямоугольной нише с надписью кириллицей, частично сохранившая зелёные и коричневые тона на фоне осыпавшейся штукатурки.

На второй серии снимков — Храм Петра и Павла из села Ключёвка, я о нём уже писал когда-то. Судя по документам, в этом храме крестили мою прабабушку по маминой линии. Вероятный год постройки — 1809, на чьи средства построен храм мне неизвестно, но село основано купцом Рыковом, возможно он и стал спонсором. В храме много фресок, где ещё угадываются контуры сцен и надписей, кое-что даже ещё пока выглядит очень неплохо, но само здание открыто всем ветрам, крыша провалилась, значит всё это будет ветшать.

12 комментариев