МАРСОХОД

Open Source Hardware Project

Проекты Altera Quartus II для платы Марсоход2

Web Server в плате Марсоход2 с Ethernet шилдом.

 New Year Tree in Marsohod2 board

Давно хотел сделать такой проект — WebServer в плате Марсоход2. Но хотел сделать не так, как это делают все, с помощью процессора Nios или любого другого. Нет, хотелось сделать именно аппаратный сервер в FPGA в виде стэйт-машины, которая принимает и отсылает пакеты Ethernet без участия традиционного процессора. Хотелось бы сделать очень быстрый сервер.

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

А пока, вы можете попробовать работоспособность моего веб сервера в живую. Попробуйте обратиться по адресу http://84.51.195.178 (не знаю как долго проработает сервер и плата на этом IP адресе). Это адрес ADSL модема, который переадресует запросы на подключение к плате Марсоход2 с шилдом Ethernet. По идее, если все сработает нормально, вы должны увидеть в своем браузере елочку, как на картинке выше.

modem

Сама плата Марсоход2 подключена к модему кабелем Ethernet. Модем отконфигурирован, чтобы отсылать запросы на TCP подключение к порту 80 на плату Марсоход2 на ее IP адрес. Адрес платы в локальной сети фиксированный - 10.8.3.9, ну а адрес модема в интернет, как вы поняли 84.51.195.178

Как это все работает.
Вот топ модуль проекта в среде Altera Quartus II. Выглядит все довольно мелко, так как проект большой. Можно кликнуть на картинке, чтоб увидеть чуть крупнее.

top module

Итак:

  • модуль eth_receive принимает Ethernet пакет и считает его контрольную сумму. Выдает принятые байты и их порядковый номер в пакете. Так же генерирует сигнал crc32_ok по окончании приема пакета.
  • модуль pkt_write пишет принятые пакеты в двухпортовое ОЗУ прямо по мере приема пакета. Модуль содержит указатель на принимаемый пакет head[2:0]. Если по окончании приема контрольная сума пакета была верной (сигнал crc32_ok), то указатель head будет увеличен. Следующий принимаемый пакет будет принят по другим адресам в двухпортовом ОЗУ. Указатель head имеет 3 разряда, всего может адресовать 8 принятых пакетов.
  • модуль pkt_ram – это двухпортовое ОЗУ для хранения принятых пакетов. Получается как бы ФИФО на 8 пакетов по 2048 байт. Обратите внимание, что запись пакета в память ведется байтами, а чтение пакета ведется словами по 256 бит, то есть 32-х байтными словами. Ну я же хочу сделать быстрый сервер, поэтому для анализа заголовков пакетов ethernet мне достаточно сделать всего 2 чтения из статической памяти.
  • самый главный модуль pkt_reader. Он читает из двухпортового ОЗУ принятые пакеты и анализирует их и формирует ответы. В этом модуле есть трехбитный указатель на последний обработанный пакет tail[2:0]. Как только новый пакет принят и указатель head из модуля pkt_write изменяется, то pkt_reader тут же видит, что голова ушла вперед, отличается от tail и модуль переходит к обработке пакета. Один такт на решение о начале обработки пакета:

always @(posedge clk)
begin
 case(state)
  STATE_WAIT_PKT: begin
   if( tail != head ) //just wait receiver head goes forward
    state <= STATE_CHK_MAC;
  end
….


Ну дальше там уже довольно сложная логика и state-machine. Как я уже сказал, чтение из памяти ведется 32-х байтными словами. Одно чтение сразу позволяет определить тип пакета ARP или IP, еще определить предназначен ли пакет для моего MAC адреса.

Следующее чтение позволяет проанализировать другие важные поля пакета. Об этом расскажу чуть позже. Тут важно, что когда модуль принял решение об отправке ответного пакета данных, то он начинает их считывать из памяти шаблонов пакетов и, модифицируя на лету шаблон пакета, передает байты в фифо на передачу в ethernet.

  • модуль rom хранит шаблоны пакетов для отправки клиентам. Всего заготовлено 3 пакета (вообще-то маловато, нужно бы больше), это минимальное число заготовок пакетов, необходимое для более или менее правильной работы системы. Вообще-то по честному нужно реализовать весь стек протоколов TCP/IP. Я же делаю какую-то самую минимальную функциональность. В памяти rom хранится заготовка для пакета ARP Replay, TCP SYN-ACK и TCP ACK-PUSH-FIN. Вся моя веб страничка помещается в один ethernet пакет.
  • модуль send_fifo – это просто фифо передаваемых данных. Оно нужно, чтобы отвязать частоту приемника от частоты передатчика, ведь чип Realtek Ethernet сам диктует нам приемную и передающую частоты и не гарантируется, что они одинаковые (в смысле не гарантируется, что они синфазные).
  • модуль sender читает из фифо и отправляет пакет в RTL чип, который находится на ethernet шилде платы Марсоход2.

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

Про сетевые протоколы.
Чтобы устройство работало в сети оно прежде всего должно отвечать на запросы ARP. Каждое сетевое устройство имеет шесть байт аппаратного адреса MAC и 4 байта адреса TCP/IP.

В моем проекте MAC адрес и IP адрес платы задается прямо в модуле pkt_reader на писанном на языке Verilog HDL:


localparam MY_MAC = 48'hd850e6ea5678;
localparam MY_IP = 32'h0903080A; // my fixed IP is 10.8.3.9


 В своей локальной сети я использую адреса типа 10.8.xx.xx и маска подсети 255.255.0.0

Так вот, когда кто-то хочет обратиться к заданному IP адресу прежде всего в сеть выдается широковещательный (broadcast) ARP запрос: "У кого IP=x.x.x.x?" 

Тот, кто имеет такой IP должен ответить пакетом ARP Reply: "У меня IP и мой MAC адрес xx.xx.xx.xx.xx.xx".

После этого уже пакеты для нужного IP адреса отправляются непосредственно на нужный MAC адрес и сетевой маршрутизатор прямо из заголовков пакетов знает на какой порт коммутировать пакет.

Вот такой обмен происходит от браузера к моему серверу:

TCP stack
Сам протокол TCP/IP так же очень сложный, нужно проанализировать довольно много полей входящего запроса, чтобы сформировать правильный ответ. Нужно проверить на мой ли IP адрес пришел пакет, нужно проверить пришел ли пакет на мой порт HTTP=80, проверить TCP флаги: SYN/ACK/PUSH и другие. Еще нужно учесть SEQ и ACK номера в пакете, они отвечают за очередность передаваемых данных. Очень много тут всего. Я упростил себе жизнь тем что условился, что вся моя веб страница должна умещаться в один ethernet пакет. То есть она должна быть где-то около 1 килобайта, не больше. Тогда мне не нужно хранить данные о TCP сессиях для каждого входящего соединения. Конечно, когда страницы будут большими так сделать не получится, придется делать полностью стек TCP/IP (кстати думаю я мог бы сделать).

В принципе, как я сказал, сейчас я делаю только три ответа:

  • ARP Reply на ARP Request
  • TCP SYN-ACK на TCP SYN
  • TCP ACK-PUSH-FIN на TCP ACK-PUSH-FIN

это все. Все остальные пакеты просто игнорируются.

Конечно, такой проект нельзя сделать без анализатора сетевых протоколов Wireshark. С его помощью можно смотреть приходящие и отправляемые пакеты. Вот как выглядит обмен пакетами с точки зрения программы WIreshark:

wireshark

Еще думаю нужно рассказать про шаблоны пакетов, которые я храню в модуле rom.
Дело в том, что нельзя просто так взять и хранить целиком готовый пакет и его просто отсылать. Например я не знаю MAC адреса клиентов, которые будут мне присылать запросы. Или я заранее не знаю TCP порт и IP клиента, который будет присылать пакеты..

Поэтому в памяти я придумал хранить шаблоны пакетов, а не готовые пакеты. Разрядность памяти 12 бит. Младшие 8 бит — это передаваемый байт, а старшие 4 бита — это возможная команда подстановки. В шаблоне оставлены поля, которые будут заполняться на лету.

Содержимое памяти rom я зараннее подготавливаю специальной утилиткой-программой mkrom, написанной на C в Visual Studio. Эта утилита генерирует для Quartus II Memory Initialization File  файл rom.mif

Вот так выглядит в программе шаблон ARP Reply:


#define CMD_REMOTE_MAC 0x100
#define CMD_REMOTE_IP 0x200
#define CMD_MY_MAC 0x300
#define CMD_MY_IP 0x400
#define CMD_TCP_PORT 0x500
#define CMD_TCP_ACK 0x600
#define CMD_TCP_CHS0 0x700
#define CMD_IP_CHS0 0x800
#define CMD_PRESUM 0xE00
#define CMD_CRC 0xF00

unsigned short arp_reply_pkt[] = {
CMD_REMOTE_MAC+0, //dest addr
CMD_REMOTE_MAC+1,
CMD_REMOTE_MAC+2,
CMD_REMOTE_MAC+3,
CMD_REMOTE_MAC+4,
CMD_REMOTE_MAC+5,
CMD_MY_MAC+0, //0x55, 0x44, 0x33, 0x55, 0x44, 0x33, //src addr (my MAC addr)
CMD_MY_MAC+1,
CMD_MY_MAC+2,
CMD_MY_MAC+3,
CMD_MY_MAC+4,
CMD_MY_MAC+5,
0x08, 0x06, //type = arp
0x00, 0x01, //hw type = ethernet
0x08, 0x00, //protocol type = IP
0x06,
0x04,
0x00, 0x02, //arp opcode - reply
CMD_MY_MAC+0, //0x55, 0x44, 0x33, 0x55, 0x44, 0x33, //sender MAC (my MAC addr)
CMD_MY_MAC+1,
CMD_MY_MAC+2,
CMD_MY_MAC+3,
CMD_MY_MAC+4,
CMD_MY_MAC+5,
CMD_MY_IP+0, //0x0a, 0x08, 0x03, 0x09, //sender IP (my fixed IP)
CMD_MY_IP+1,
CMD_MY_IP+2,
CMD_MY_IP+3,
CMD_REMOTE_MAC+0, //target MAC
CMD_REMOTE_MAC+1,
CMD_REMOTE_MAC+2,
CMD_REMOTE_MAC+3,
CMD_REMOTE_MAC+4,
CMD_REMOTE_MAC+5,
CMD_REMOTE_IP+0, //target IP
CMD_REMOTE_IP+1,
CMD_REMOTE_IP+2,
CMD_REMOTE_IP+3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
CMD_CRC+0,
CMD_CRC+1,
CMD_CRC+2,
CMD_CRC+3 //end packet
};


Там, где находятся слова CMD_xxx будет на лету вставлено соответствующее значение вычисленное или взятое из входного запроса.

Довольно сложно получилось, но кажется работает.
ARP – это еще не самое сложное. Вот TCP пакет отправить — вот это эпопея..
Нужно дополнительно вычислить IP checksum и TCP checksum и на лету вставлять их в отправляемый пакет...

Кое-что заранее подсчитывается в утилите mkrom, которая генерирует MIF файл, чтобы облегчить операции вычисления контрольных сумм IP и TCP...

Если вам нужно сгенерировать свою страницу, то придется исправлять текст в программе mkrom, перекомпилировать эту утилиту с Visual Studio и заново генерировать MIF файл для Quartus II проекта.

Ну и из плохих новостей: не все клиенты видят мою web страницу. Видимо не все правильно в моей реализации TCP/IP..

Я проверял на:

  • Windows 8 / Windows 7 – работает
  • Android Tablet: Samsung Galaxy Tab 10” и Asus Google Nexus 7” New – работает
  • Android Phone HTC One – работает
  • Apple iPad mini – не работает :-(

Вот такие пироги..
Надеюсь, Вы сможете увидеть отклик о моего web server а по адресу 81.54.195.178...

PS: ну и конечно, я не делал стресс тестов, когда много клиентов подключаются одновременно. Посмотрим, что получится..

PSS: Весь проект со всеми исходниками можно взять здесь: 

 

Комментарии  

0 #12 alman 08.01.2015 11:42
Цитирую Mastar24:

"Мухолёт" ...


Простите, но конечные устройства не подходят для стандартицазии. Стандартами имеет смысл описывать протоколы и интерфейсы, чтобы упростить использование модулей.
0 #11 alman 07.01.2015 16:46
Цитирую Mastar24:

меня интересует Управление Широтно-импульсной модуляций через выходы левого и правого моторов одного Марсохода1(а), другим Марсоходом1(б), не затрагивая алгоритм действий Марсоходом1(б).



Это к примеру. В процессе обсуждения вырабатывается общее видение и согласие интерфейса, затем он объявляется как стандарт и именуется. Разумеется, сама схема не может быть стандартом - стандартом описываются входы/выходы устройства и поведение устройства.
0 #10 Mastar24 07.01.2015 13:09
Цитирую alman:

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

Идея мне очень нравится. Например, меня интересует Управление Широтно-импульс ной модуляций через выходы левого и правого моторов одного Марсохода1(а), другим Марсоходом1(б), не затрагивая алгоритм действий Марсоходом1(б).
0 #9 alman 06.01.2015 21:15
Цитирую nckm:

Что подразумевается под сотрудничеством в области создания стандартов?

Некий комитет для обсуждения и принятия стандартов. По образу и подобию TheOpenGroup или IEEE.
Банальный пример стандарта - шина Wishbone. Т.е. я предлагаю создать некоторую некоммерческую организацию для разработки, внедрения и лицензионой защиты стандартов - сигналам и протоколам взаимодействия устройств.

Например, я бы хотел поучаствовать в разработке протокола сопряжения нескольких марсоходов. Т.е. по аппаратной реализации мог бы высказать замечания, пожелания и критику, например по сигналам и временным диаграммам.
0 #8 nckm 06.01.2015 19:59
Цитирую alman:

Интересно ли сотрудничество в области создания стандартов?

Что подразумевается под сотрудничеством в области создания стандартов?
0 #7 nckm 06.01.2015 19:58
Цитирую alman:
Цитирую Питоша:
http://s017.radikal.ru/i414/1501/84/0f6ed0f2f918.png: http://www.radikal.ru


Устройство за файрволлом, оно и не должно на ping отвечать. Если бы кто и ответил на ping, то это был бы ADSL модем.

Впрочем, наверняка сама плата на пинг не ответит, потому что это ICMP протокол, который вряд-ли реализован на устройстве.


PING не реализован, естественно..
+1 #6 nckm 06.01.2015 19:57
Цитирую alman:
Фарйфокс на Андроидо-телефоне открыл страницу.

А вот со сборкой проекта возникла проблема:

Error (265013): Can't open SignalTap II Logic Analyzer. Verify that the license file exists and is stored in the correct location. If you are using the Quartus II Web Edition software, you must turn on the TalkBack feature to use the SignalTap II Logic Analyzer.

Сильно интересуюсь этим устройством:
Цена платы расширения?
Какая лицензия этого устройства ?
Сколько логических элементов занимает устройство?
Интересно ли сотрудничество в области создания стандартов?


может забыл какой-то signal-tap файл приложить.. Самое простое - выключить использование SignalTap в настройках проекта, он только для отладки. Тогда и размер получается 1231LE, 511registers, 196K bits ram.

Лицензия - ну как все на сайте - берите и используйте на здоровье.
0 #5 alman 06.01.2015 18:56
Цитирую Питоша:
http://s017.radikal.ru/i414/1501/84/0f6ed0f2f918.png: http://www.radikal.ru


Устройство за файрволлом, оно и не должно на ping отвечать. Если бы кто и ответил на ping, то это был бы ADSL модем.

Впрочем, наверняка сама плата на пинг не ответит, потому что это ICMP протокол, который вряд-ли реализован на устройстве.
0 #4 Питоша 06.01.2015 18:42
http://s017.radikal.ru/i414/1501/84/0f6ed0f2f918.png: http://www.radikal.ru
0 #3 Rangicut 06.01.2015 17:07
Мило. И Вас с Новым Годом) Сам делал проект с аппаратным сервером, но для UDP передачи. На opencores, кстати, лежит что-то похожее для Virtex-6, но оно жутко не оптимизировано. ..
0 #2 alman 06.01.2015 16:47
Фарйфокс на Андроидо-телефо не открыл страницу.

А вот со сборкой проекта возникла проблема:

Error (265013): Can't open SignalTap II Logic Analyzer. Verify that the license file exists and is stored in the correct location. If you are using the Quartus II Web Edition software, you must turn on the TalkBack feature to use the SignalTap II Logic Analyzer.

Сильно интересуюсь этим устройством:
Цена платы расширения?
Какая лицензия этого устройства ?
Сколько логических элементов занимает устройство?
Интересно ли сотрудничество в области создания стандартов?
0 #1 Mastar24 05.01.2015 20:28
Да, отклик виден! В Москве. Windows 8.
Таким проектом интересуется мой знакомый из института ИТМ и ВТ (Точной Механики и Вычислительной техники). Для получения информации с автономных датчиков с параметрами: Максимальный объем информации 1024 байта, с частотой 1 герц.

Добавить комментарий


Защитный код
Обновить


GitHub YouTube Twitter
Вы здесь: Начало Проекты Проект Марсоход2 Web Server в плате Марсоход2 с Ethernet шилдом.