• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Разработка ‘библиотеки’ малого webсервера на esp8266.

vad7

Active member
@pvvx, Вот тут включил отладку LWIP, только не уверен, что поможет:
.....
sct calling h=dns_timer arg=0x00000000
tcpip: dns_tmr()
dns_tmr: dns_check_entries
sys_timeout: 0x3ffeed68 msecs=1000 handler=dns_timer arg=0x00000000
sct calling h=dhcp_timer_fine arg=0x00000000
tcpip: dhcp_fine_tmr()
sys_timeout: 0x3ffeed08 msecs=500 handler=dhcp_timer_fine arg=0x00000000
sct calling h=igmp_timer arg=0x00000000
tcpip: igmp_tmr()
sys_timeout: 0x3ffeed28 msecs=100 handler=igmp_timer arg=0x00000000
sct calling h=igmp_timer arg=0x00000000
tcpip: igmp_tmr()
sys_timeout: 0x3ffeed28 msecs=100 handler=igmp_timer arg=0x00000000
state: 5 -> 2 (4c0)
rm 0
dhcp_release()
pbuf_alloc(length=308)
pbuf_alloc(length=308) == 0x3ffefe10
transaction id xid(abcd0002)
pbuf_header: old 0x3ffefe80 new 0x3ffefe78 (8)
udp_send: added header in given pbuf 0x3ffefe10
udp_send: sending datagram of length 316
udp_send: UDP packet length 316
inet_chksum_pseudo(): checksumming pbuf 0x3ffefe10 (has next 0x00000000)
inet_chksum_pseudo(): pbuf chain lwip_chksum()=a081
udp_send: UDP checksum 0x5f7e
udp_send: ip_output_if (,,,,IP_PROTO_UDP,)
pbuf_header: old 0x3ffefe78 new 0x3ffefe64 (20)
ip_output_if: ew0
IP header:
+-------------------------------+
| 4 | 5 | 0x00 | 336 | (v, hl, tos, len)
+-------------------------------+
| 142 |000| 0 | (id, flags, offset)
+-------------------------------+
| 255 | 17 | 0xe530 | (ttl, proto, chksum)
+-------------------------------+
| 192 | 168 | 20 | 54 | (src)
+-------------------------------+
| 0 | 0 | 0 | 0 | (dest)
+-------------------------------+
netif->output()
pbuf_header: old 0x3ffefe64 new 0x3ffefe56 (14)
etharp_send_ip: sending packet 0x3ffefe10
pbuf_free(0x3ffefe10)
pbuf_free: deallocating 0x3ffefe10
dhcp_release: RELEASED, DHCP_OFF
dhcp_release(): set request timeout 1000 msecs
netif_set_ipaddr: netif address being changed
netif: IP address of interface ew set to 0.0.0.0
netif: GW address of interface ew set to 0.0.0.0
netif: netmask of interface ew set to 0.0.0.0
dhcp_stop()
WiFi event(1): Disconnect from ssid vadw, reason(4): Assoc_expire, count 1
Close all:
tcp_close: closing in State: <null>
WEB: close
 

aloika

Active member
@pvvx, в оверлее tcp_client у меня почему-то не разрешается переменная dns_table:

Код:
    if(dns_table[i].found == (dns_found_callback)tc_dns_found_callback) {
                /* flush this entry */
                dns_table[i].found = NULL;
                dns_table[i].state = DNS_STATE_UNUSED;
где она определена?

Закомментировал пока что это дело, остальное работает. Еще бы разобраться в коде... :)

В общем, работает. Если данные принимает, то следующий запрос идет через 60 секунд, если нет (допустим, запрос на другой сайт) - то каждые 15 сек. Ну это я понял, tc_recv просто не доходит до таймаута, если на сайте не то, что ожидалось.

Самое главное, что при старте через init.ini нормально стартует, это просто здорово.
 
Последнее редактирование:

pvvx

Активный участник сообщества
@pvvx, в оверлее tcp_client у меня почему-то не разрешается переменная dns_table:

Код:
    if(dns_table[i].found == (dns_found_callback)tc_dns_found_callback) {
                /* flush this entry */
                dns_table[i].found = NULL;
                dns_table[i].state = DNS_STATE_UNUSED;
где она определена?

Закомментировал пока что это дело, остальное работает.
dns_table была в dns.c от Lwip. И она там static. DNS драйвер в Lwip не умеет делать откат запроса. Это и сделано - вынесено в lwip/dns.h. esp8266web/dns.h at master · pvvx/esp8266web · GitHub
При вызове запроса к DSN он сохраняет адрес процедуры "калбака". Когда внешний сервер ответит или по истечении времени тайм-аута он её вызывает. Но если оверлей за это время сменен, то адрес будет указывать в неизвестную область и будет "протектед". Данная процедура при закрытии оверлея убирает этот запрос у DNS.
то следующий запрос идет через 60 секунд, если нет (допустим, запрос на другой сайт) - то каждые 15 сек. Ну это я понял, tc_recv просто не доходит до таймаута, если на сайте не то, что ожидалось.
Времена стоят от балды. Это же пример, а не рабочий вариант.
Для рабочего варианта там не хватает счетчика ошибок с уведомлением пользователя, что "всё пропало", а то при смене на внешнем сайте процесс попыток получить желаемое будет вечный.
И обновление данных не 1 минута, а "mdb[50] - время в минутах до следующего чтения данных, = 0 один раз", т.е. от 1 минуты до 45 суток.
 
Последнее редактирование:

aloika

Active member
Разбираюсь с задержками в tcp_client.ovl. Что-то никак понять не могу. Вот алгоритм:
Код:
#define tc_timeout        mdb_buf.ubuf[50] // повтор опроса через tc_timeout минут
uint32 next_start_time DATA_IRAM_ATTR;
...
err_t ICACHE_FLASH_ATTR tc_recv(TCP_SERV_CONN *ts_conn) {
...
// данные приняты

if(tc_timeout) {
                           run_error_timer(60); // повтор через 60 секунд * next_start_time
                       }
                       else {
                           ets_timer_disarm(&error_timer);
                           next_start_time = 0;
                       }
}

err_t tc_go(void)
{
   err_t err = ERR_USE;
    if(next_start_time) {
        run_error_timer(60); // повторить через паузу в 60 секунд
    }
    else { // начали всё делать
         ...}
  return err;
}

void run_error_timer(uint32 tsec)
{
    if(tsec < 60) next_start_time = 0;
    else {
        if(next_start_time == 0) next_start_time = tc_timeout - 1;
    }
    ets_timer_disarm(&error_timer);
    ets_timer_setfn(&error_timer, (os_timer_func_t *)tc_go, NULL);
    ets_timer_arm_new(&error_timer, tsec*1000, 0, 1); // таймер на 5 или 10 секунд
}
Если, например, tc_timeout=3 (3 минуты). Заходим второй раз в void run_error_timer(uint32 tsec). Next_start_time будет равен 2, правильно? Так и будем бесконечно заходить в run_error_timer(), запускать tc_go() и снова до бесконечности с интервалом 60 сек.
Или тут мудрая мысль, которую я не понимаю?
 

aloika

Active member
dns_table была в dns.c от Lwip. И она там static. DNS драйвер в Lwip не умеет делать откат запроса. Это и сделано - вынесено в lwip/dns.h. esp8266web/dns.h at master · pvvx/esp8266web · GitHub
Понял, я-то саму свалку не менял, только оверлей. А по коммитам не посмотрел, что еще изменилось. Да, невнимательно подошел к вопросу :)
 

pvvx

Активный участник сообщества
Разбираюсь с задержками в tcp_client.ovl. Что-то никак понять не могу. Вот алгоритм:
Если, например, tc_timeout=3 (3 минуты). Заходим второй раз в void run_error_timer(uint32 tsec). Next_start_time будет равен 2, правильно? Так и будем бесконечно заходить в run_error_timer(), запускать tc_go() и снова до бесконечности с интервалом 60 сек.
Или тут мудрая мысль, которую я не понимаю?
Ошибка просто. Делал то кое как. ТЗ не было, оно и формировалось на ходу, потом забыл что-то поправить - задачи то нет. :) Таймером большую задержку не сделать...
Наверно там не хватает "else next_start_time--;"
Это всё от лени, как например имена переменных. Написал какое, потом сменил алго, а менять под него названия лень... Так- же и дописывать процедуры под новый алго...
Сложно угадать что вам надо без наличия стандартов или ТЗ. :)
 
Последнее редактирование:

aloika

Active member
Таймером большую задержку не сделать...
Там же uint32 мкс, это 71 минута примерно. Мне хватит, так что счетчик минут вообще уберу, наверное.

Это всё от лени, как например имена переменных. Написал какое, потом сменил алго, а менять под него названия лень... Так- же и дописывать процедуры под новый алго...
Сложно угадать что вам надо без наличия стандартов или ТЗ. :)
Да это всё мелочи, подправлю. Самое главное, что пример рабочий, за что огромное спасибо. :)
 

pvvx

Активный участник сообщества
Там же uint32 мкс, это 71 минута примерно. Мне хватит, так что счетчик минут вообще уберу, наверное.
Если бы всё было так :) Таймер считает в 16/80000000 секунды -> предел для значения uint32 -> 858.993459 секунды.
В примере температуру обновляют 4 раза в сутки... 8 часов...
При задании параметра в ms оно тупо умножается на 1000 и передается как значение в us, без проверок на переполнение. Значение в us тоже не проверяется при умножении (на 5) и передаче к таймеру... :)
859/60=14.3 минуты - известная эпопея в Ардуино предельных коннектов и прочих багов.
 
Последнее редактирование:

vad7

Active member
@pvvx, Попробовал использовать ets_run_new() - при компиляции вылезли ошибки, исправил, - девайс сбрасывается где-то после этого места:
sleep:0, rect:30, maxtpw:78, sthn:[ESP_9CB560]
scandone
 

pvvx

Активный участник сообщества
@pvvx, Попробовал использовать ets_run_new() - при компиляции вылезли ошибки, исправил, - девайс сбрасывается где-то после этого места:
sleep:0, rect:30, maxtpw:78, sthn:[ESP_9CB560]
scandone
Это уже разобрали - нет никакого смысла использования и создания main_loop в данной системе, кроме случая халявного, кое как сделанного портирования всяких Ардуиновских программ и библиотек.
Вы пытаетесь создать "пятую ногу собаке" - она всё равно с пошью неё не полетит.
 

aloika

Active member
Попробовал использовать ets_run_new() - при компиляции вылезли ошибки, исправил
Если речь идет о том, чтобы сделать некое подобие main_loop - почему не завести таймер и уже в его функции что-нить делать? Я, например, таким образом считываю данные из UART (т.к. приходят они туда медленно и мало). Частота запуска таймера выбрана сообразно задаче. Можно, конечно, было использовать прерывания, но у меня ума не хватило, там какие-то нюансы, в которых разобраться не смог.
 

vad7

Active member
почему не завести таймер и уже в его функции что-нить делать?
Потому, что для этого нужно больше кода писать. :)
Мне нужно вызывать раз в минуту, но по определенным условиям, бывает нужно сразу повторить вызовы неограниченное число раз подряд с передачей управления остальным процессам sdk между ними. Вызовы могут быть тяжелыми по времени.
В данном случае проще это реализовать в главном цикле, да и переделывать не хочется.

@pvvx, Временно поборол отваливания девайса от некоторых роутеров, поставил COUNT_RESCONN_ST = 1, костыль, конечно, но хоть работает.

state: 5 -> 2 (4c0)
rm 0
WiFi event(1): Disconnect from ssid vadw, reason(4): Assoc_expire, count 1
state: 2 -> 0 (0)
Set reconnect after 30 sec
Close all:
WEB: close
WiFi event(1): Disconnect from ssid vadw, reason(202): Auth_fail, count 2
Set reconnect after 30 sec
Close all:
WiFi event(7): Probe Request (MAC:54:27:1e:18:c6:e9, RSSI:-87)

.....

New connect ST...
f r0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 8
cnt

connected with vadw, channel 1
dhcp client start...
WiFi event(0): Connect to ssid vadw, channel 1
 

pvvx

Активный участник сообщества
Потому, что для этого нужно больше кода писать. :)
Мне нужно вызывать раз в минуту, но по определенным условиям, бывает нужно сразу повторить вызовы неограниченное число раз подряд с передачей управления остальным процессам sdk между ними. Вызовы могут быть тяжелыми по времени.
В данном случае проще это реализовать в главном цикле, да и переделывать не хочется.

@pvvx, Временно поборол отваливания девайса от некоторых роутеров, поставил COUNT_RESCONN_ST = 1, костыль, конечно, но хоть работает.

state: 5 -> 2 (4c0)
rm 0
WiFi event(1): Disconnect from ssid vadw, reason(4): Assoc_expire, count 1
state: 2 -> 0 (0)
Set reconnect after 30 sec
Close all:
WEB: close
WiFi event(1): Disconnect from ssid vadw, reason(202): Auth_fail, count 2
Set reconnect after 30 sec
Close all:
WiFi event(7): Probe Request (MAC:54:27:1e:18:c6:e9, RSSI:-87)

.....

New connect ST...
f r0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 8
cnt

connected with vadw, channel 1
dhcp client start...
WiFi event(0): Connect to ssid vadw, channel 1
Замучали WiFi модуля своим циклом или AP тормозят?
 

vad7

Active member
Замучали WiFi модуля своим циклом или AP тормозят?
Да нет ничего такого, вся "мощность" цикла проявляется редко, а отваливается всегда в одной сети, даже при нулевой загрузки. В другой сети никогда не отваливается.
 

aloika

Active member
Потому, что для этого нужно больше кода писать. :)
Мне нужно вызывать раз в минуту, но по определенным условиям, бывает нужно сразу повторить вызовы неограниченное число раз подряд с передачей управления остальным процессам sdk между ними. Вызовы могут быть тяжелыми по времени.
В данном случае проще это реализовать в главном цикле, да и переделывать не хочется.
Чё там писать-то?

В init_done_cb где-нибудь в конце пишите:

Код:
my_program_start();
Это будет вход в вашу программу.
Теперь открываете новый файл myprogram.c, куда-нибудь его кладете в app/user/, например. Это будет файл вашей программы. Когда pvvx выпустит новую версию свалки, вы просто этот файл туда перенесете, и всё.

В новом файле пишите инклюды, какие надо (или потом по ходу будете добавлять) например:

Код:
#include "sdk/add_func.h"
.....
.....
Потом определяете функцию таймера и сам таймер, пишите функцию входа в вашу программу, и функцию-обработчик таймера. Всё.

Код:
void my_timer_func(void) ICACHE_FLASH_ATTR;
os_timer_t my_timer DATA_IRAM_ATTR;

void ICACHE_FLASH_ATTR my_timer_func(void)
{
    //os_printf("timer!\n"); // мелкая отладка

   // тут пишем, что фактически программа будет делать. Т.е. вся программа - здесь.

    ets_timer_arm_new(&swbd_uart0_rx_timer, 1000, 0, 1); // заказываем запустить эту же функцию через 1 сек (1000 мс) или сколько там надо, тоже без повтора.
// и задавайте тут разные выдержки времени запуска этой функции в зависимости от ваших условий
}

void ICACHE_FLASH_ATTR my_program_start(void)
{
os_timer_disarm(&my_timer); //останавливаем таймер
os_timer_setfn(&my_timer, (os_timer_func_t *)my_timer_func, NULL);
ets_timer_arm_new(&my_timer, 1000, 0, 0); //запускаем через 1000 мкс, не повторяем.
}
 
Последнее редактирование:

PycLan

New member
Добрый день!
@pvvx, подскажите по поводу сброса настроек по умолчанию.
На RX подаю "0", на RST подаю "0", через 1 ms на RST подаю "1", через 100 ms на RX подаю "1".
В итоге настройки не сбрасываются.
Настройки должны сбросится или эти манипуляции с RX нужно делать только по включению питания?
 
Последнее редактирование:

pvvx

Активный участник сообщества
Добрый день!
@pvvx, подскажите по поводу сброса настроек по умолчанию.
На RX подаю "0", на RST подаю "0", через 1 ms на RST подаю "1", через 100 ms на RX подаю "1".
В итоге настройки не сбрасываются.
Настройки должны сбросится или эти манипуляции с RX нужно делать только по включению питания?
Только по включению питания, воспринимается 25 ms активного уровня RX (т.к. может быть выставлена инверсия RX). 25 ms - это 40 baud и такое обычно не используется, и исключает ложные срабатывания при перезагрузке. Но можете всё сами переназначить в исходниках esp8266web/web_iohw.c at master · pvvx/esp8266web · GitHub
 

PycLan

New member
Только по включению питания, воспринимается 25 ms активного уровня RX (т.к. может быть выставлена инверсия RX). 25 ms - это 40 baud и такое обычно не используется, и исключает ложные срабатывания при перезагрузке. Но можете всё сами переназначить в исходниках esp8266web/web_iohw.c at master · pvvx/esp8266web · GitHub
А есть какаянибудь команда для UART0? Или самому писать и достаточно выполнить это - flash_save_cfg(&x, ID_CFG_WIFI, 0);?
Да, но если будут проблемы с UART0, то тоже не сбросишь....
 
Последнее редактирование:

pvvx

Активный участник сообщества
А есть какаянибудь команда для UART0? Или самому писать и достаточно выполнить это - flash_save_cfg(&x, ID_CFG_WIFI, 0);?
Типа того.
Да, но если будут проблемы с UART0, то тоже не сбросишь....
Ну если Земля попадет в луч близкой нейтронной звезды (пульсара) или сработает система "Периметр" то какая разница? :)
 

PycLan

New member
Типа того.
Ну если Земля попадет в луч близкой нейтронной звезды (пульсара) или сработает система "Периметр" то какая разница? :)
Просто ESP управляется допустим другой железкой, питается от общего питания, вот тогда просто через меню этой железки и не сбросить,
а только вскрывать железку, чтобы передергивать питание ESP с замкнутым RX.
Или вешать управление питанием ESP.
 
Сверху Снизу