Vibration motor control
Some of my devices have an actuator that can cause vibration to the phone for semi-silent notifications.
In Linux the vibration motor is usually exposed over
/dev/input/event#
input device as a device that can do force
feedback (EV_FF
). It's not as bad as it sounds. Input subsystem
makes it possible to upload a vibration pattern to the kernel, and let the
kernel handle the timing.
So if your program crashes, the vibration motor will not end up being permanenty enabled until you reboot or stop it manually.
Example program to control the vibration motor
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <stdbool.h> #include <errno.h> #include <fcntl.h> #include <poll.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/input.h> void syscall_error(int is_err, const char* fmt, ...) { va_list ap; if (!is_err) return; printf("ERROR: "); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(": %s\n", strerror(errno)); exit(1); } int open_event_dev(const char* name_needle, int flags) { char path[256]; char name[256]; int fd, ret; // find the right device and open it for (int i = 0; i < 10; i++) { snprintf(path, sizeof path, "/dev/input/event%d", i); fd = open(path, flags); if (fd < 0) continue; ret = ioctl(fd, EVIOCGNAME(256), name); if (ret < 0) continue; if (strstr(name, name_needle)) return fd; close(fd); } errno = ENOENT; return -1; } int main(int ac, char* av[]) { int fd, ret; struct pollfd pfds[1]; int effects; fd = open_event_dev("vibrator", O_RDWR | O_CLOEXEC); syscall_error(fd < 0, "Can't open vibrator event device"); ret = ioctl(fd, EVIOCGEFFECTS, &effects); syscall_error(ret < 0, "EVIOCGEFFECTS failed"); struct ff_effect e = { .type = FF_RUMBLE, .id = -1, .replay = { .length = 500, .delay = 500, }, .u.rumble = { .strong_magnitude = 1, }, }; ret = ioctl(fd, EVIOCSFF, &e); syscall_error(ret < 0, "EVIOCSFF failed"); struct input_event play = { .type = EV_FF, .code = e.id, .value = 3 }; ret = write(fd, &play, sizeof play); syscall_error(ret < 0, "write failed"); sleep(4); ret = ioctl(fd, EVIOCRMFF, e.id); syscall_error(ret < 0, "EVIOCRMFF failed"); close(fd); return 0; }