Мигаем светодиодом по расписанию | cron

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

Любой пользователь Linux когда-нибудь слышал о cron – сервисе (демоне), который можно использовать для запуска повторяющихся заданий по расписанию, задаваемого по календарному времени. Предусмотрен также неоднократный запуск заданий, т.е. задание можно запускать периодически в определенное время или через определенный промежуток времени. Демон имеет простой, понятный и удивительно гибкий для своей компактности синтаксис, который де-факто является своего рода стандартом в мире Unix и как следствие большое количество обучающих материалов с примерами. Было бы здорово использовать такой же синтаксис при планировании задач в микроконтроллере, чтобы не заниматься изобретением своего велосипеда.

MSP430.js | исходники

screenshot

В Linux каждый пользователь системы имеет свой файл заданий crontab, в котором описано, в какое время и какие программы запускать от имени этого пользователя, а также переменные, настраивающие среду окружения, в котором будут работать задачи cron. В микроконтроллере часть этих настроек выглядит явно избыточной – скорее всего там нет такого понятия, как пользователи и переменные среды окружения да и программы запускать тоже навряд ли получится. Можно упростить себе жизнь и просто ограничится каким-нибудь контейнером вроде связного списка, чтобы иметь возможность пройтись по контейнеру и динамически добавлять / удалять задачи cron в него например из командной строки. Ну а для демонстрации возможностей cron сойдёт даже обычный статический массив (нельзя изменять размер во время выполнения программы), заданный на этапе компиляции. Элемент контейнера состоит из события – выражения cron, и действия. Действие описывает устройство периферии (например светодиод) и в какое состояние его необходимо перевести.

crond.c

static struct crond_job jobs[] = {
  { .expr = "*/6 */2 * * * *", .led = {0b0000011111, 1, 0, 0} },
  { .expr = "2/6 */2 * * * *", .led = {0b1111100000, 0, 1, 0} },
  { .expr = "4/6 */2 * * * *", .led = {0b1111111111, 0, 0, 1} },

  { .expr = "*/6 1/2 * * * *", .led = {0b1010101010, 1, 1, 0} },
  { .expr = "2/6 1/2 * * * *", .led = {0b0101010101, 0, 1, 1} },
  { .expr = "4/6 1/2 * * * *", .led = {0b1111111111, 1, 0, 1} },
};

Как несложно убедиться каждое выражение cron состоит из шести полей, разделяемых пробелами или табуляторами. В этих полях задают время выполнения (Секунда, Минута, Час, День, Месяц, День недели), в них может находиться число, список чисел, разделённых запятыми, символы * или / и диапазон чисел, разделённых дефисом. Месяцы и дни недели можно также задавать в 3-х буквенном варианте:

* * * * * *     Действие (установить цвет RGB светодиодов с 1 по 10)
| | | | | |
| | | | | ----- День недели (0 - 6) (0 это воскресенье)
| | | | ------- Месяц (1 - 12)
| | | --------- День (1 - 31)
| | ----------- Час (0 - 23)
| ------------- Минута (0 - 59)
--------------- Секунда (0 - 59)

Символ * подразумевает любое значение. Каждую секунду:

* * * * * *

Каждый день в 03:15:00:

0 15 3 * * *

Каждый понедельник:

0 0 0 * * 1

Каждый четный час:

0 0 */2 * * *

Тоже что и выше, но расписанное полностью:

0 0 0,2,4,6,8,10,12,14,16,18,20,22 * * *

Каждый будний день в 22:00:

0 0 22 * * 1-5

Новый год:

59 59 23 31 dec *

Все условия (времени запуска) проверяются по «логическому И», кроме условий «день недели» и «день месяца» – указанные совместно, они обрабатываются по «логическому ИЛИ», то есть «по любому из дней», что отражено в документации (Ubuntu, Debian, FreeBSD). Однако такая логика неочевидна и не позволяет создать условие типа «первый понедельник каждого месяца» или «каждую пятницу в 13 число». Разработчики не изменяют данное поведение, считая его стандартом.

Также стоит помнить о переходе на летнее / зимнее время. Тут нет единого мнения и различные реализации cron могут вести себя по разному. В Unix системах есть альтернатива Anacron, который в отличие от cron не поддерживает запуск заданий по расписанию, вместо этого задания запускаются с заданным интервалом времени. Это очень удобно для систем которые работают не регулярно, например домашние рабочие станции или ноутбуки.

links

social