arduino1

Для небольшого проекта я обзавёлся Arduino Ethernet и начал писать для него программки. Проект подразумевает подключение десятков или даже несколько сотен идентичных устройств к IP сети и периодического сброса информации на Web сервер.

Проект рассчитан на долговременное использования. Устройства могут устанавливаться в труднодоступных местах или в вандалозащищённых корпусах. За время работы системы я хочу иметь возможность заменять или добавлять новые устройства в систему не используя программатор.

Учитывая всё это я решил озадачиться вопросом передачи конфигурации из центрального источника (сервера) во время начала работы платы, а не на записывая конфигурацию в EEPROM или Flash.

Протокол BOOTP/DHCP, который определён в RFC 951, 1531 и 2131 и рассчитан как раз на то, что бы производить первоначальную конфигурацию сетевых устройств. Одной из возможностей протокола является определение собственных типов переменных и их обработку на стороне клиента. Этой возможностью я как раз и хочу воспользоваться.

Реализация в библиотеке Arduino Ethernet протокола DHCP весьма ограничена и не подразумевает расширения. С помощью DHCP возможно (в версии 1.0.3) установить только IP адрес, маску сети, DNS сервер и маршрут по-умолчанию.

Я модифицировал соответствующий код в библиотеке и теперь стало возможно реализовывать вот такой способ настройки:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Определяем функцию-обработчик для неизвестных опций
void dhcpOptionParser(const uint8_t optionType, EthernetUDP *dhcpUdpSocket) {
    uint8_t opt_len = dhcpUdpSocket->read();
 
    if (optionType == 15) { // domain name
        // читаем нужную нам опцию при помощи dhcpUdpSocket->read()
    } else {
        while (opt_len--) {
            dhcpUdpSocket->read();
        }        
    }
}
 
// Определяем функцию-генератор дополнительных опций запроса
void dhcpOptionProvider(const uint8_t messageType, EthernetUDP *dhcpUdpSocket) {
    uint8_t buffer[] = {
        dhcpClassIdentifier,
        0x08,
        'M','S','F','T',' ','5','.','0'
    };
    dhcpUdpSocket->write(buffer, 10);
}
 
//...
 
// Инициализируем библиотеку Ethernet с нужными ссылками
void setup() {
    // ...
    Ethernet.begin(mac, (DhcpOptionParser *) &dhcpOptionParser, (DhcpOptionProvider *) &dhcpOptionProvider);
    // ...
}

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

Этот метод можно реализовать на любом DHCP сервере, в котором можно определять дополнительные опции. Например, для ISC-DHCP это будет выглядеть следующим образом (определяем новую опцию xTargetWebServerAddress с номером 128):

1
2
option xTargetWebServerAddress code 128 = ip-address;
option xTargetWebServerAddress www.habrahabr.ru;

Эти параметры нужно добавить в dhcpd.conf.

Как бонус я сделал возможность отправлять дополнительные опции как часть запроса. В примере Arduino пошлёт опцию Vendor Class Identifier (номер 60) со значением «MSFT 5.0»