Для небольшого проекта я обзавёлся 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»