Arduino Mega Server

Модератор: Alex

Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

Re: Arduino Mega Server

Сообщение Alex » Вс авг 23, 2015 8:09 pm

где удобнее, на сегодя, описывать правила или сценарии для автоматизации. В смысле в скриптах или в скетче?
В общем — контроллер — ядро и смысл, скрипты — визуализация. Потому, что как только вы закрыли браузер, то скрипты перестали работать.
Я пока вижу выигрыш от склеивания файлов, но в чем выигрыш от модификации библиотеки?
В статье

http://geektimes.ru/post/259898

есть 2 графика. В них ответ на ваш вопрос
cg_shura
Сообщения: 110
Зарегистрирован: Пт авг 14, 2015 11:24 am
Благодарил (а): 3 раза
Поблагодарили: 6 раз

Re: Arduino Mega Server

Сообщение cg_shura » Вс авг 23, 2015 8:39 pm

Вот проект тоже на W5100, но без библиотеки от ардуино. Может поможет решить проблему с ретрансмиссиями.
https://github.com/meteobox/WebMeteoBox
olehs
Сообщения: 1115
Зарегистрирован: Вс июн 14, 2015 11:08 am
Благодарил (а): 85 раз
Поблагодарили: 342 раза

Re: Arduino Mega Server

Сообщение olehs » Пн авг 24, 2015 12:11 am

Alex писал(а):
В статье

http://geektimes.ru/post/259898

есть 2 графика. В них ответ на ваш вопрос
Вот еще раз перечитал статью, и все же не покидает меня чувство что что-то здесь не так. Даже не столько смущает, что приходится выносить цикл перебора сокетов из библиотеки. А скорей смущает то, что можно было так ошибиться в 90 строках кода, и что никто этого за столько времени не заметил в опенсорсном проекте.

Потому я еще раз решил просто в уме пройтись по алгоритму работы библиотеки EthernetServer.cpp, чтобы понять, как она работает, и вот к чему пришел.
Метод available():

Код: Выделить всё

EthernetClient EthernetServer::available() {
  accept();

  for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
    EthernetClient client(sock);
    if (EthernetClass::_server_port[sock] == _port &&
        (client.status() == SnSR::ESTABLISHED ||
         client.status() == SnSR::CLOSE_WAIT)) {
      if (client.available()) {
        // XXX: don't always pick the lowest numbered socket.
        return client;
      }
    }
  }
  return EthernetClient(MAX_SOCK_NUM);
} 
Вот что здесь происходит:
  1. accept() - принять входящее соединение. Вернусь к нему позже.
  2. Цикл перебора сокетов.
    1. Здесь есть следующие проверки:
    2. _server_port[sock] == _port - проверка, что порт, к которому привязан сокет - это порт нашего сервера. Эта проверка нужна в случае, если поднимается несколько серверов на разных портах (желательно не больше MAX_SOCK_NUM )
    3. (client.status() == SnSR::ESTABLISHED || client.status() == SnSR::CLOSE_WAIT) - клиент либо установил соединение, либо пытается его закрыть. Второй случай возможен, если клиент отправил нам запрос, ответ ему не нужен и он сразу отключается.
    4. client.available() - проверка, что в буфере чтения от клиента есть данные. Здесь логика разная в зависимости от client.status().
      Если клиент подключился (ESTABLISHED), но не передал запрос, нам не имеет смысла его пока что обрабатывать.
      Если клиент уже хочет отключиться, то перед закрытием сокета нужно обработать его запрос, который может быть в буфере.
Именно этот момент и объясняет комментарий //XXX.
Он говорит, что не стоит возвращать первый сокет в подходящем состоянии, а желательно проверить, есть ли в нем запрос. Это позволяет обработать другие сокеты, пока клиент после подключения надумает отправить запрос.

Теперь про метод accept()

Код: Выделить всё

void EthernetServer::accept()
{
  int listening = 0;

  for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
    EthernetClient client(sock);

    if (EthernetClass::_server_port[sock] == _port) {
      if (client.status() == SnSR::LISTEN) {
        listening = 1;
      } 
      else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) {
        client.stop();
      }
    } 
  }

  if (!listening) {
    begin();
  }
}
  1. Цикл перебора сокетов
    1. _server_port[sock] == _port - проходимся только по "своим" сокетам
    2. client.status() == SnSR::LISTEN - ищем хоть один уже слушающий сокет
    3. if (client.status() == SnSR::CLOSE_WAIT && !client.available())
      client.stop();
      - попутно закрываем закрывающиеся сокеты, если их буферы пусты
  2. Если нет ни одного слушающего сокета, вызвать begin()
Переделка именно этого метода и противоречит логике работы оригинальной библиотеки.
Суть метода заключается в переводе одного и только одного для данного сервера сокета в режим LISTEN, если такого нет.
Модифицированная же версия переводит все 4 сокета в режим LISTEN и не оставляет шансов другим возможным серверам занять сокет.
Другими словами библиотека больше не позволит поднять больше одного сервера даже на разных портах (на самом деле поднять позволит, но работать с ними будет невозможно).

Таким образом, переделка библиотеки в текущем виде ломает работу в режиме нескольких серверов. Естественно, это неприемлемо для библиотеки, которая поставляется с Arduino.

С другой стороны, в режиме одного сервера это позволяет скешировать 3 дополнительных запроса (насколько я понимаю после приема соединения W5100 делает это сам) и не дать им уйти в Retransmission Timeout, что, по всей видимости, и дало некий прирост производительности в новой версии AMS
За это сообщение автора olehs поблагодарили (всего 3):
Alex (Пн авг 24, 2015 7:14 am) • killeo (Пн авг 24, 2015 9:49 am) • tammat (Пн авг 24, 2015 5:13 pm)
Рейтинг: 3.49%
Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

Re: Arduino Mega Server

Сообщение Alex » Пн авг 24, 2015 7:07 am

За всё время разборок с библиотекой это первый вменяемый комментарий по сути вопроса, что очень радует.

Во-первых, разница работы с модифицированной библиотекой и немодифицированной колоссальна. В одном случае типичное время загрузки страниц составляет 15 — 35 секунд, в другом — 1,5 — 4 секунды. На этом дискуссию можно было бы закончить, всё остальное вторично (вообще без разницы что и как там работает).

Во-вторых, вы совершенно правы — в библиотеке что-то ОЧЕНЬ СИЛЬНО не так. Ваша версия похожа на правду. Задача только стоит так: нужно выпрямить кривую библиотеку так, чтобы время загрузки страниц упало до 0,7 — 2 секунд и она наконец стала работать ПРАВИЛЬНО, а не через …
olehs
Сообщения: 1115
Зарегистрирован: Вс июн 14, 2015 11:08 am
Благодарил (а): 85 раз
Поблагодарили: 342 раза

Re: Arduino Mega Server

Сообщение olehs » Пн авг 24, 2015 9:54 am

Вы не поняли суть моего поста. С библиотекой ВСЕ ТАК. Она реализует работу с сокетами по всем правилам, с возможностью получения сокетов в режиме конкуренции.

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

Многозадачность позволила бы паралельно обрабатывать запросы и не давать им уходить в таймаут во время длинных передач (по крайней мере 4-ем).
Но функция многозадачности - никак не обязанность библиотеки Ethernet.

Вытесняющую многозадачность на Arduino реализовывать будет очень сложно с ее ограничениями на оперативку.
А вот кооперативную (cooperative multitasking) вы могли бы попробовать организовать на уровне сервера. Arduino с какой-то версии добавила поддержку планировщика (https://www.arduino.cc/en/Reference/Scheduler)
1gor90
Сообщения: 1
Зарегистрирован: Пн авг 24, 2015 4:14 pm
Благодарил (а): 0
Поблагодарили: 0

Re: Arduino Mega Server

Сообщение 1gor90 » Пн авг 24, 2015 4:20 pm

Всем добрый день! Alex'у огромный респект за проделанную работу! среда 1.6.5-r2 W7 все заработало!
Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

Re: Arduino Mega Server

Сообщение Alex » Пн авг 24, 2015 5:49 pm

Возможно вы правы (хотя у меня есть сомнения), но дело тут вот в чём. Меня (и всех пользователей АМС) интересует скорость работы. Как только она вошла в приемлемые рамки, проблема из первоочередной перешла в категорию факультативных.

Конечно интересно в чём там дело и хотелось бы, чтобы всё работало быстрее, но... Если кто-то разберётся с этим будет просто здорово.

-------------------------------

Статья на Гиктаймс о Мега-контроллере

https://geektimes.ru/post/260758/
annakin
Сообщения: 130
Зарегистрирован: Пн окт 28, 2013 5:06 pm
Откуда: Молдова
Благодарил (а): 11 раз
Поблагодарили: 10 раз

Re: Arduino Mega Server

Сообщение annakin » Пн авг 24, 2015 6:59 pm

Алекс ещё раз привет.
У меня тут непонятные данные с измерением тока.
К примеру датчик тока подключён к пину А1 пропускаю его через нагрузку, АМС показывает 0, тоесть никаких данных.
А вот если я к примеру делаю такой скетч с использованием сторонней библиотеки есть результат измерения происходят всё нормально.

Код: Выделить всё

// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3

#include "EmonLib.h"                   // Include Emon Library
EnergyMonitor emon1;                   // Create an instance

void setup()
{  
  Serial.begin(9600);
  
  emon1.current(5, 66);             // Current: input pin, calibration.
}

void loop()
{
  double Irms = emon1.calcIrms(1480);  // Calculate Irms only
  
  Serial.print(Irms*230.0);           // Apparent power
  Serial.print(" ");
  Serial.println(Irms);               // Irms
} 
Так вот в чем может быть проблема ?
Server: Raspberry Pi 3 B+
OS: Rasbian
Alex
Сообщения: 2357
Зарегистрирован: Пт апр 20, 2012 12:53 pm
Благодарил (а): 42 раза
Поблагодарили: 262 раза

Re: Arduino Mega Server

Сообщение Alex » Пн авг 24, 2015 8:03 pm

Там пин 0 это напряжение, пин 1 это первый токовый канал. Максимальное значение каналов можно поставить 3 (на всякий случай) если не заработает, то возможно дело в логике скетча и без напряжения он не работает (я не проверял).

Ещё возможно скетч выдаёт не ток, а мощность, а без напряжения она равна 0.
annakin
Сообщения: 130
Зарегистрирован: Пн окт 28, 2013 5:06 pm
Откуда: Молдова
Благодарил (а): 11 раз
Поблагодарили: 10 раз

Re: Arduino Mega Server

Сообщение annakin » Пн авг 24, 2015 8:35 pm

Alex писал(а):Там пин 0 это напряжение, пин 1 это первый токовый канал. Максимальное значение каналов можно поставить 3 (на всякий случай) если не заработает, то возможно дело в логике скетча и без напряжения он не работает (я не проверял).

Ещё возможно скетч выдаёт не ток, а мощность, а без напряжения она равна 0.
Просмотрев скетч внимательно оказывается, что без датчика напряжения он работать не будет. (((

UPD: Решил проблему.
Лекарство для тех у кого пока нету датчика напряжения, берём мультиметр замеряем напряжение в розетке и вписываем его в код ниже:

Код: Выделить всё

void calcPover(byte STT, byte STP, int cycles) {
  // рассчет напряжения и тока (rms)  
  //UIrms[U] = UI_RATIO[U] * sqrt(sumSquareUI[U] / cycles);
  UIrms[U] = 236; // Сюда вписываем данные с мультиметра.
  for (int i = STT; i < STP; i++) {
    UIrms[i] = UI_RATIO[i] * sqrt(sumSquareUI[i] / cycles);
  }
 
Последний раз редактировалось annakin Пн авг 24, 2015 9:11 pm, всего редактировалось 2 раза.
Server: Raspberry Pi 3 B+
OS: Rasbian
Ответить