работа с динамическими структурами/правилами

sergejey
Offline
Зарегистрирован: 29.11.2013

Здравствуйте,

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

Я хочу сделать возможность загружать в Arduino некий набор правил, по которым контроллер будет работать. Например "Если Pin 2 установлен в 1, то установить Pin 7 в 0". Этот набор правил будет загружаться из-вне, но сейчас речь не об этом. Я так представляю, что мне надо эти правила хранить в каком-то массиве, где каждая запись будет представлять собой определённую структуру. К сожалению, обычным многомерным массивом обойтись не смогу, т.к. правила будут достаточно гибкие и могут включать в себя какие-то множества сами по себе (например вместо одного условия несколько связанных через "И").

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

Спасибо!

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Подобного не видел, возможно просто не сталкивался с такими задачами на МК.

Один из вариантов:
1. Базовый класс, который дает возможность проверки любого входного условия (например чтение состояния пина), а также все возможные действия (например, установка состояния пина, прогаммирование таймера и т.п.). В дальнейшем можно расширять базовый класс в порожденных классах более сложной логикой.
2. Динамический односвязный список, который может содержать указатели на объекты базового класса

Последовательно загружаем кубики (входные условия). По каждому создаем объект базового класса (например парсим входные данные) и добавляем его в список. После окончания входных данных, передаем работу интерпретатору, который этот список обрабатывает.

Вот такая фантазия, полет мысли, думаю далеко не всё понятно, но и задача не достаточно конкретна.

Но памяти (ОЗУ) может понадобиться немало.

 

Сяу Ляу Вей
Offline
Зарегистрирован: 25.10.2013

sergejey пишет:

 Я так представляю, что мне надо эти правила хранить в каком-то массиве, где каждая запись будет представлять собой определённую структуру. К сожалению, обычным многомерным массивом обойтись не смогу, т.к. правила будут достаточно гибкие и могут включать в себя какие-то множества сами по себе (например вместо одного условия несколько связанных через "И").

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

Спасибо!

  http://ru.wikipedia.org/wiki/%CF%CB%C8%D1

 

Programmable Logic Array(PLA) — программируемая логическая матрица.

sergejey
Offline
Зарегистрирован: 29.11.2013

Сяу Ляу Вей, спасибо, но, пожалуй, это не много не то. Хотя почти то -- мне не нужно менять назначения выводов, мне нужно менять логику реакций. Я могу сделать интерпретатор, который будет из какого-то визарда генерить мне новый скетч, но залить его я всё равно не смогу...

kisoft, приблизительно так, может где-то есть примеры подобного? как организовать класс, как работать со списком в памяти и т.п. с Си у меня большие провалы, особенно при работе с памятью, указателями и т.п.

Попробую уточнить задачу на конкретном примере. Имеется контроллер, у которого есть трансивер на 433Mhz и он принимает пакеты определённой структуры, а так же может эти пакеты отправлять. Так вот, моя задача сделать из него некий модуль логики, который сможет реагировать на определённые пакеты с какими-то значениями (например, от датчика температуры пришло новое значение) и, в случае попадания в заданные условия (температура вне 20-25 гадусов) отправлять пакет на другое устройство (назовём его актуатор). Я могу написать это в скетче. Могу сделать обработку на компьютере. Но хотелось бы иметь возможность загружать с компьютера лишь правила и без обновления скетча перестраивать логику обработчика. Ну и что б совсем было сложно, я хочу иметь возможность задавать сложные условия, а так же возможность указывать несколько действий в качестве реакции.

Конечно, как вариант, пойти на более сложную платформу типа Raspberry, но сначало хочу до конца убедиться в невозможности затеи с Arduino :)

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Задача вполне решаема, я уже говорил, нужно определить список всех входных условий, список всех реакций. Далее определиться, нужны ли условные переходы между кубиками, если нет, то всё реализуется в виде односвязного списка, например. Если нужны переходы, то придется добавлять метки и это уже более сложный вариант.

Распишите несколько кубиков (все условия для каждого кубика, все реакции для каждого кубика) и сразу всё станет намного понятней. А то мы тут гадаем на кофейной гуще. Распишите хотя бы для себя всё конкретней и придет просветление.

 

sergejey
Offline
Зарегистрирован: 29.11.2013

Ок, попробую максимально конкретно :)

Я могу принимать пакеты от устройств, которые содержат: device_id (источник), destination_id (адресат), packet_id (id-пакета), command (числовой код команды), data (сопутствующие данные). Подробнее про формат обмена можно почитать по ссылке. Но это не принципиально -- протокол и сеть могут быть разными, неизменным остаётся суть -- мне приходят события от устройств.

А вот пример двух кубиков-правил:

Событие
от устройства id=100, command=24 (показание температуры), data=18 (градусов)
Основное условие:
device_id=100, command=24 и data>=15
Дополнительные условия:
нет
Действия:
1. пакет на устройство id=200, command=50 (включить реле), data=1
2. пакет на устройство id=201, command=50 (включить реле), data=1
 

Событие
от устройства id=101, command=10 (датчик движения), data=1
Основное условие:
device_id=101, command=10, data=1 (т.е. срабатывает по полному совпадению)
Дополнительные условия:
1. device_id=100, command=24, data<15 (здесь я предполагаю, что мы храним все последние полученные значения по ключам device_id+command и можем их использовать)
Действия:
1. пакет на устройство id=200, command=51 (выключить реле), data=1

Если бы мне надо было реализовать список условий на php, то заполненная структура имела бы следующий вид (возьму для краткости только одно правило):

$rules=array();

$rule=array(
 'trigger'=>array('device_id'=>101, 'command'=>10, 'data_condition'=>'equal', 'data'=>1),
 'additional_conditions'=>array(
  array('device_id'=>100, 'command'=>24, 'data_condition'=>'less', 'data'=>15)
 ),
 'actions'=>array(
  array('device_id'=>200, 'command'=>51, 'data'=>1),
 ));

$rules[]=$rule; //добавляем триггер в общий список

ну и обработчик всех входящих событий проходился бы по этому массиву и соответственно его интерпретировал. но вот как это реализовать на Си я ума не приложу. Понятно, что все символьные значения полей можно закодировать цифрами для экономии памяти, но в целом принцип не изменится. PHP/Python/Java гораздо проще в этом плане, чем Си :)

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Это уже более конкретно, потому чуть проще.

PS Рекомендую читать сидя на стуле ;) Хотя, вцелом ничего особенного тут нет.

Считаем, что массив правил (кубики) мы заполнили. Если я правильно понимаю, то на начальном этапе массив условий будет статичным и не будет меняться каждую секунду.

Алгоритм должен быть примерно такой:

1. Ожидание пакета, пока он не пришел, делаем что то другое (не важно что)

2. Пакет пришел, нам необходимо найти первый или следующий кубик.

3. Если не нашли, игнорируем пакет и идем на п.1.

4. Если нашли - выполнить действия из кубика.

5. Если ищем только одно условие, то переходим на п.1. Если все условия, то переходим на п.2., т.е. ищем следующий кубик.

Структура кубика:

1. int device_id
2. int command_id
3. unsigned int data
4. EnumAction action

enum EnumAction
{
  eaEQ = 0, // равно
  eaLT, // меньше
  eaBG // больше
}

В дальнейшем можно наполнить другими действиями, например, не равно, меньше или равно, больше или равно, пока не суть важно, это всего лишь расширение функционала.

Пока оставим дополнительные условия, чтобы не спутать карты. Более того тут еще есть вопросы, не технические, а скорее принципиальные, типа как долго хранить сработавшие условия, откуда брать сработавшие условия, как узнать , сработало условие или нет и т.п.

С действиями, я смотрю, всё намного тупее, это всего лишь метод в кубике, который отправит пакет с нужными данными, т.е. в кубике можно просто хранить этот пакет (или список/массив пакетов).

1. byte packetNum - количество пакетов
2. Packets array[packetNum] - массив пакетов

Можно приблизительно прикинуть структуру кубика:

class Rule
{
  // Условие
  int device_id;
  int command_id;
  unsigned int data;
  EnumAction action;

  // Действия, точнее пакеты
  byte packetKol;
  Packet *packets;

  // *** Методы

  // Проверка совпадения условия, возвращает true, если совпадает
  bool checkRule( int device_id, int command_id, unsigned int data );
  // Другой вариант того же метода, но не паримся и передаем ему входной пакет
  // Но вариант этот хуже, потому что мы привязаны к структуре пакета - плохо
  bool checkRule( Packet *p_packet );

  // Отправка пакетов
  bool sendPackets();
};

// Количество кубиков
int rulesNum = 0;
// Массив кубиков
Rule *array = NULL;

// Когда получены данные, device_id, command_id, data
for( int i = 0; i < rulesNum; ++i )
{
  Rule *lp_rule = array[ i ];
  if( lp_rule->checkRule( device_id, command_id, data ) )
  {
    lp_rule->sendPackets();
  }
}

Если еще не скушно и не уснул, могу сказать, что здесь есть почти всё, с чем можно поиграться, даже для начала статически забить массив правил/кубиков и пробовать. Я бы такие задачи пробовал на большом компе (разумеется подсовывая данные и не отправляя их в сеть), потом перенес на МК.

 

sva1509
Offline
Зарегистрирован: 07.12.2012

Доброго времени суток !

Я так понял Вам необходим элементарный коммандный интерпретатор. В атмеге32 32 кб памяти, то есть при желании туда можно бейсик впихнуть. Ну а если озу мало - можно статическое озу по SPI добавить.

Так что на arduino сделать это более чем возможно.

Обратите внимание на:

http://ru.wikipedia.org/wiki/GNU_bison

 

sergejey
Offline
Зарегистрирован: 29.11.2013

kisoft, спасибо ОГРОМНОЕ! Как раз то, что нужно, чтобы дальше копать.

sva1509, спасибо за вариант! Действительно, интересный. Немного покопался в сети и нашёл Bitslash, хотя для моей задачи и избыточное решение, но может быть вернусь и к нему.

ещё один вариант пришёл в голову -- тоже несколько избыточный, но всё же: использовать роутер с OpenWRT (например, DLink Dir-320) и уже в нём реализовать работу с правилами на каком-нибудь знакомом мне скриптовом языке. По стоимости сопоставимо с Ethernet-shield-ом, но плюс в том, что там всё же с ресурсами по-проще.

В общем, всем спасибо, есть над чем подумать :)

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Про Bitslash недавно на форуме кто-то выкладывал информацию

sergejey
Offline
Зарегистрирован: 29.11.2013

В качестве пост скриптума -- всё-таки реализовал задуманное, но через вариант с подключением контроллера к роутеру на базе OpenWRT. Оформил в общедоступный проект с описанием вот тут . Очень кстати решение задачи совпало по времени с исправлением бага прошивки роутера TPLink W703N и теперь ардуинку можно использовать с ним без шаманства (раньше она отваливалась через минуту работы), так что хоть и пришлось отказаться от реализации всего на контроллере, но зато получилась очень универсальная и недорогая штуковина под различные нужды -- с WiFi, веб-интерфейсом, настройкой правил и даже HTTP API.

Спасибо ещё раз всем за предложенные варианты!

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Отлично, возможно кто-то воспользуется Вашим решением.