Для системного администратора, работающего у интернет провайдера, очень часто возникает задача мониторинга большого числа активного оборудования. Конечно для этих целей можно использовать nagios, cacti, zabbix и подобные им средства мониторинга. Но у всех у них есть один существенный недостаток — необходимо использовать браузер как средство отображения состояния контролируемых узлов сети.
Ознакомивших с «админским светофором» возникла идея создания интерактивной карты города, с расположенными на ней светодиодами: красный — узел недоступен, зеленый — доступен. Но если использовать описанный метод зажигания светодиодов, то понадобится 2 x n, где n — количество контролируемых узлов. Таким образом для контролирования 10 узлов понадобится 20 выводов. Понятно что указанный способ для решения задачи, в случае контролирования более чем 5 узлов, не подходит.

Итак, каким же способом можно уменьшить количество используемых выходов? С ходу в голову приходит использование дешифратора. Способ хороший, но необходимо придумать свой шифр, в котором необходимо учесть все возможные комбинации работы контролируемых узлов. Способ хороший, но не очень хорошо поддающейся масштабированию.
Более удачным видится способ преобр��зования последовательного сигнала в параллельный. То есть от платы с arduino уходит последовательный сигнал, а в дополнительной схеме уже реализуется управление светодиодами. По этому пути и пойдем.
И так нам понадобится:
  • разработать схему преобразования последовательного сигнала в параллельный;
  • создать выходной каскад со светодиодами для отображения состояния;
  • разработать алгоритм записи нужной информации в схему;
  • реализовать алгоритм опроса узлов сети.


Разработка схемы

Для преобразования последовательного сигнала будем использовать сдвиговый регистр. Под рукой была парочка 74ALS164, вот их и задействуем. Первым делом топаем на сайт производителя и качаем datasheet. У данного регистра имеются:
  • вход сброса CLR;
  • вход тактирования CLK;
  • 2 сигнальных входа A и B;
  • 8 выходов.

По таблице истинности видно что сброс происходит при нулем значении на входе CLR. Запись данных в регистр осуществляется по фронту сигнала CLK. Входной сигнал формируется из сигналов A и B через логическое умножение (И). Таким образом один из сигнальных входов, например B, можно смело подвести к уровню логической 1. Во время работы необходимо присутствие на входе CLR уровня логической единицы. Управляя входом A можно заносить необходимую информацию в регистр. Стробирование на входе CLK позволит добиться однозначности входных и выходных данных.
Но если использовать всего 1 микросхему, то у нас имеется всего 8 выходов. Да не густо. Но тут на помощь приходит каскадирование. То есть если соединить восьмой выход первого регистра с входом A второго, то данные будут заносится во второй регистр с задержкой в 8 тактов.

Выходной каскад

Для управления светодиодами можно использовать 2 вывода на узел, то есть зажигать красный светодиод или зеленый. Но в таком случае произойдет удвоение числа необходимых регистров. Что бы этого избежать будем использовать включение светодиодов по схеме:
image
В этом случае необходимо будет подобрать значения сопротивления резисторов для подходящего свечения светодиодов в случаях горения красного и зеленого светодиодов.
После разводки и пайки получилось следующее:
image
На отладочной плате присутствует 2 сдвиговых регистра и 10 пар светодиодов. К сожалению 4 желтых светодиода в центре платы не горят, очень похоже на битые выводы регистров, но для отладки хватит.

Разработка алгоритма записи

Итак у нас есть схема управления горения светодиодов. Необходимо организовать переключение горения с красного на зеленый и обратно, в любом разряде регистров. Для этого будет использоваться массив битов, каждый бит соответствует одному узлу и двум светодиодам: 1 горит зеленый, 0 – красный. Подавая эту последовательность битов на выход arduino и тактируя каждый разряд выводом CLK мы произведем запись в регистры. Для обеспечения однозначности перед каждой записью новой информации будем производить сброс регистров подавая на вход CLR логиче��кий ноль.

Разработка алгоритма опроса узлов

За основу взять код из «админского светофора», но не производится замер времени соединения, а только сам факт его установки или не установки. Используется двумерный массив адресов узлов и массив выходных данных, которые будут заноситься в регистры. Для простоты отладки будем проверять всего 5 узлов.

Код достаточно простой и с комментариями:
//Определим выходные пины
#define SIG 7 // сигнал
#define CLK 6 // тактирование
#define RST 5 // сброс

// подключаем необходимые библиотеки
#include <SPI.h>
#include <Ethernet.h>

//производим инициализацию ethernet shield
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // мак адрес
byte ip[] = {192,168,2,177}; // ip адрес
// массив с контролируемыми узлами
byte pingAddr[][4] = { {172,2,0,5},
                       {172,2,0,6},
                       {172,2,0,7},
                       {172,2,0,8},
                       {172,2,0,9} };
// массив выходных данных
bool out[] = {0,0,0,0,0};
// шлюз и маска
byte gateway[] = {192,168,2,1};
byte subnet[] = {255,255,255,0};

// буфер для отладки
char buffer[256];

// функция проверки доступности хоста
void checkHost(int i)
{
  Client client(pingAddr[i], 80);
  // если соедениться не удается
  if(!client.connect()) {
    // выводим вообщение об этом
    sprintf(buffer, "Connection failed for %d.%d.%d.%d",
    pingAddr[i][0],pingAddr[i][1],pingAddr[i][2],pingAddr[i][3]);
    Serial.println(buffer);
    // и если горит зеленый диод, переключим на на красный
    if(out[i] == 1) {
      out[i] = 0;
      // выведем новые значения в регистры
      setMap();
    }
  // если удалось соединиться
  } else {
    // и горит красный, то включим зеленый
    if(out[i] == 0) {
      out[i] = 1;
      setMap();
    }
  }
  client.stop();
}

// функция вывода массива данных
void setMap()
{
  // сбросим все регистры
  digitalWrite(RST, LOW);
  delay(5);
  digitalWrite(RST, HIGH);
  int i;
  // организуем последовательный вывод
  for(i=0;i<5;i++)
  {
    // если 0 то низкий уровень
    if(out[i]==0)
      digitalWrite(SIG, LOW);
      // если 1 то высокий
    else
      digitalWrite(SIG, HIGH);
    // сделаем паузу во избежание гонок
    delay(1);
    // дадим фронт записи
    digitalWrite(CLK, HIGH);
    delay(1);
    digitalWrite(CLK, LOW);
    // снимаем высокий уровень с сигнальной линии
    digitalWrite(SIG, LOW);
  }
}

void setup()
{
  // инициализируем ethernet shield
  Ethernet.begin(mac, ip, gateway, subnet);
  // последовательный порт
  Serial.begin(9600);
  // настраеваем порты ввода/вывода
  pinMode(SIG, OUTPUT); // signal
  pinMode(CLK, OUTPUT); // CLK
  pinMode(RST, OUTPUT); // reset
  // выставляем начальное состояние
  digitalWrite(CLK, LOW);
  digitalWrite(SIG, LOW);
  digitalWrite(RST, HIGH);
}

// основной цикл
void loop()
{
  int i;
  // для каждого хоста из массива
  for(i=0;i<5;i++){
    // произвести проверку
    checkHost(i);
    delay(1000);
  }
  // отдохнуть 5 секунд, и по новой
  delay(5000);
}


Вот и все.
Теперь осталось найти нужного размера карту города, прикрепить в нужных местах светодиоды и наблюдать за доступностью узлов в реальном времени и не вставая с места.