• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ets_timer_arm_new vs sys_timeout

Apollo

New member
Привет всем.

Народ, подскажите, пож-та, в чем разница в реализации таймеров между core (ets_timer_arm_new) и lwip (sys_timeout)?

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

А так же хочется знать, чем отличается реализация tcp-стека core (espconn.h) от lwip. И почему заголовки lwip вообще не поставляются в составе Espressif IoT SDK? :)

Заранее благодарю за ответ.
 

pvvx

Активный участник сообщества
Какие-то странные вопросы. :)
Похоже не изучены основы, а беретесь сразу за верхи.
ets_timer_arm_new - это управление программным таймером на основе аппаратного. _new по причине что у аппаратного таймера переключают делитель на счет в us. У ROM-BIOS ets_timer_arm() расчет идет на другой делитель в аппаратном таймере. Процедуры ets_timer_arm создают добавляют в связный список новый программный таймер и вычисляет задержку до срабатывания следующего программного таймера и записывают её в регистр alarm аппаратного таймера. Когда будет работать процедура ets_run(), то она определит срабатывание alarm у аппартного таймера и вызовет код вашего программного таймера... Это упрощенно.
У Lwip нет таймеров. Ему при старте система назначает отрабатывать его процедуру каждые 25ms через программный таймер. Эта процедура опрашивает состояния соединений и т.д. и у неё свои программные счетчики. В режиме wifi sleep LIGHT китайцы увеличивают этот таймер в сотни раз и Lwip не может правильно работать - у него возникают переполнения в TCP стеке и т.д..
 

pvvx

Активный участник сообщества
А так же хочется знать, чем отличается реализация tcp-стека core (espconn.h) от lwip. И почему заголовки lwip вообще не поставляются в составе Espressif IoT SDK? :)
В первую и главную очередь у espconn отличия в глючности - это же китай-код от Espressif :) Является нагромождением над Lwip для большего потребления памяти при обработке соединений, увеличения времени исполнения вашего кода, введения ограничений по массе параметров управления соединениями и служит для увеличения размера прошивки. Lwip же глюков не имеет... Вот Espressif и добавил espconn, а Lwip хидеры закрыл.
espconn - это подобие упрощения работы с Lwip. Было создано китайцами в надежде скрыть, что в нутре находится Lwip, на первых стадиях, когда все их либы были закрыты...
 
Последнее редактирование:

Apollo

New member
Какие-то странные вопросы. :) Похоже не изучены основы, а беретесь сразу за верхи.
Возможно, вы правы. Было бы прекрасно увидеть ссылки на основы, которые бы проливали свет на "странные вопросы" :)

... Это упрощенно.
Это было понятно. По-сути, это следует из API. В принципе, и то, что обработка таймерного колбека производится не в прерывании, тоже просматривается.

У Lwip нет таймеров.
Вы имеете ввиду в таймерах lwip не используются аппаратные таймеры? Потому что таймеры как таковые там есть, см. lwip/timers.h (функции sys_timeout & sys_untimeout).

[На правах офтопа] Китайский таймерный API, как это ни странно, эффективнее lwip-шного, т.к. не требует динамического распределения памяти внутри процедуры установки таймера; временем жизни контекста таймера управляет клиент. Поскольку кол-во таймеров зачастую определяется в дизайн-тайм, то достаточно статического распределения памяти.
 

Apollo

New member
espconn - это подобие упрощения работы с Lwip. Было создано китайцами в надежде скрыть, что в нутре находится Lwip, на первых стадиях, когда все их либы были закрыты...
Понятно. Спасибо! А с API lwip такая беда: как клиент, я не имею возможности зарядить операцию recv, следовательно, не имею возможности управлять памятью, в которую данные должны быть записаны. lwip распределяет память самостоятельно, вызывая колбек с... одним-двумя байтами в посылке (пишу telnet сервер, данные приходят практически посимвольно), и, вместо того, чтобы скользить по буферу, заряжая в recv смещенные указатели, приходится накапливать данные в отдельном буфере. Для моих задач некритично, конечно, но в принципе, неоптимально.
 

pvvx

Активный участник сообщества
Вы имеете ввиду в таймерах lwip не используются аппаратные таймеры? Потому что таймеры как таковые там есть, см. lwip/timers.h (функции sys_timeout & sys_untimeout).
Это больше задание и изменение счетчиков для основной процедуры вызываемой у Lwip по таймеру ETSTimer check_timeouts_timer назначенной при старте SDK и вызывающей void sys_check_timeouts(void).
Пример в моем meSDK ->
https://github.com/pvvx/esp8266web/blob/master/app/sdklib/system/app_main.c#L581
https://github.com/pvvx/esp8266web/blob/master/app/sdklib/lwip/core/timers.c#L374
Никакого отношения к API... NO_SYS

Китайский таймерный API, как это ни странно, эффективнее lwip-шного, т.к. не требует динамического распределения памяти внутри процедуры установки таймера; временем жизни контекста таймера управляет клиент. Поскольку кол-во таймеров зачастую определяется в дизайн-тайм, то достаточно статического распределения памяти.
Lwip не низкий уровень управления аппаратурой (не драйвер hard уровня), или не ROM-BIOS, или не ...
Что за "дизайн-тайм, то достаточно статического распределения памяти."? :confused:
Разжевывать каждую процедуру невозможно - на это потребуется посвятить всю жизнь :p
Я вам и говорю - вы зашли не с того уровня. На MCU такого класса как ESP8266 нет понтов уровней API и прочих абстракций. На них элементарно не хватает ресурсов. По этому всякие Ардуино и прочие проекты оперирующие высокими уровнями обречены на провал.
Как пример - классический TCP сокет должен иметь от 160 килобайт памяти RAM (сумма с TCP стеком) - это чисто требования для полного обслуживания по TCP. Их нет у ESP8266 и приходиться переходить к не классической схеме написания ПО, по методу "свалки" - всё подряд в единой куче. Более похоже на "патч". По этому, если вы размышляете на уровне API и прочей абстракции - ничего хорошего не выйдет.
В моих проектах на базе meSDK espconn вырезан из библиотек, как часть другого никчемного китай-кода расходующего память...
 
Последнее редактирование:

pvvx

Активный участник сообщества
Понятно. Спасибо! А с API lwip такая беда: как клиент, я не имею возможности зарядить операцию recv, следовательно, не имею возможности управлять памятью, в которую данные должны быть записаны. lwip распределяет память самостоятельно, вызывая колбек с... одним-двумя байтами в посылке (пишу telnet сервер, данные приходят практически посимвольно), и, вместо того, чтобы скользить по буферу, заряжая в recv смещенные указатели, приходится накапливать данные в отдельном буфере. Для моих задач некритично, конечно, но в принципе, неоптимально.
Lwip всё делает правильно. По другому представляется сложнее. TCP - это вам не UART. :) Это блочный драйвер, а не последовательный. :p
Он нормально кеширует ваши данные хоть побайтно и имеет процедуры доступа к ним в своем буфере, так-же и все процедуры управления этими буферами... Через espconn это невозможно, и она дублирует эти буфера в блоках heap...
 

Apollo

New member
Ой, огромное вам спасибо за исходники sdk. Признаться, не ожидал их увидеть в публичном доступе :) Поэтому даже не делал попытки поискать. Еще раз спасибо.

Lwip не низкий уровень управления аппаратурой (не драйвер hard уровня), или не ROM-BIOS, или не ...
Что за "дизайн-тайм, то достаточно статического распределения памяти."? :confused:
PS: Ваши аргументы понятны, я не стараюсь их оспорить, я о другом. Попробую пояснить. API и уровнь абстрации - вещи несвязанные, аппаратные регистры, конфигурирующие тот или иной железный модуль - тоже API. А вот библиотека lwip - уже уровнь абстракции, скрывающий эти железные потроха. И у этой библиотеки еcть свой API. Он может позволять писать эффективный код, а может и не позволять этого делать. В частности, то, что этот API не позволяет клиенту управлять памятью, предназначенной для приема данных - это большой минус, препятствующий написанию эффективного кода, ибо невозможно сделать zero-copy процедуру приема и обработки данных, плюс клиенту необходимо подчищать динамически выделенные на стороне библиотеки блоки памяти. Каждая аллокация - это поиск подходящего блока памяти, фрагментация памяти. Зачем это делать частью API? Вовсе необязательно.

PPS: Кстати, посмотрел реализацию systimeout - ну точно, контекст таймера аллокируется динамически :) Дизайн-тайм - это время разработки (до компиляции и запуска), на этом этапе разработчик может принять решение, в частности, о том, как будут созданы те или иные объекты его программы, они могут быть статические, либо распределены динамически. При этом число и время жизни некоторых объектов может быть известно точно и эти объекты можно сделать статическими. В подавляющем большинстве случаев, к ним относится и таймер.
 

pvvx

Активный участник сообщества
Ой, огромное вам спасибо за исходники sdk. Признаться, не ожидал их увидеть в публичном доступе :) Поэтому даже не делал попытки поискать. Еще раз спасибо.
Это не исходники - это мой реверс (дизассемблирование и перевод в СИ). Часть, Lwip, выкладывалась китайцами, но в непотребном виде - без заголовков и трасляцией только с выключенными всеми варнингами - только так и пишут в Espressif (от этого встречается масса неинициализированных указателей и уже более года лапатят свои баги в SDK с тысячной аудиторией проверки - у меня Lwip доделан для нормальной трансляции...
В подавляющем большинстве случаев, к ним относится и таймер.
Таймер в ROM-BIOS с динамическим распределением. Какая статика, если открыто сотня TCP портов и к ним назначены свои таймеры в пользовательском коде? Держать вечно забитую bss память? bss вычитает из heap и по тому безразлично, если только не пользуетесь чистым китайским SDK. У них распределитель памяти отжирает на заголовки более чем в два раза больше чем в моем meSDK - чистая встроенная китай-фича (просто взяли добавили для понту - чтобы было неповадно :) ), т.к. исходники менеджера памяти из одного колодцу... :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
В частности, то, что этот API не позволяет клиенту управлять памятью, предназначенной для приема данных - это большой минус, препятствующий написанию эффективного кода, ибо невозможно сделать zero-copy процедуру приема и обработки данных, плюс клиенту необходимо подчищать динамически выделенные на стороне библиотеки блоки памяти. Каждая аллокация - это поиск подходящего блока памяти, фрагментация памяти. Зачем это делать частью API? Вовсе необязательно.
Есть другое более лучшее решение?
Остальные (малые TCP стеки) используют статическое распределение памяти и на них ничего не сделать. По тому я в корне с вами не согласен заменять динамическую на статическую... Тем более исходники Lwip даны. Как при этом обслужить хоть эти одновременные 63 соединения в секунду в Web-свалке? -> Кол-во и скорость открытия множественных Web соединений (JMeter)
Взять так и зарезервировать на начальном этапе 63*ОкноTCP стека (в базе TCP_WND = 4*TCP_MSS = 1460*4 байт)? У ESP всего после "обгрызанного" китай кода основных библиотек остается до 50 килобайт на всё про всё и стеку не желательно отъедать более 2 кило (с вычетом под SDK) - затирает данные ROM-BIOS.
Не нравиться - рассмотрите этот модуль Убийцы ESP8266: Часть 2 - Nufront NL6621, но там тоже Lwip, но памяти больше и т.д..
 
Последнее редактирование:
Сверху Снизу