Вопрос Вопросы по функциям SDK

pvvx

Активный участник сообщества
Тут задавайте вопросы по функциям SDK Espressif.
Если что известно, то отвечу или ответят.
----------
Кто знает зачем wifi_station_set_hostname()?

По старту исполняется wifi_station_set_default_hostname(info.st_mac);
Она выделяет память и назначает имя ESP_XXXXX:
Код:
extern uint8 * hostname; // in eagle_lwip_if.c
bool default_hostname = true;

uint8 * wifi_station_get_hostname(void)
{
    uint32 opmode = wifi_get_opmode();
    if(opmode == 1 || opmode == 3) {
        return hostname;
    }
    return NULL;
}

void wifi_station_set_default_hostname(uint8 * mac)
{
    if(hostname != NULL)    {
        vPortFree(hostname);
        hostname = NULL;
    }
    hostname = pvPortMalloc(32);
    if(hostname == NULL) {
        ets_sprintf(hostname,"ESP_%02X%02X%02X", mac[3], mac[4], mac[5]);
    }
}

bool wifi_station_set_hostname(uint8 * name)
{
    if(name == NULL) return false;
    uint32 len = ets_strlen(name);
    if(len > 32) return false;
    uint32 opmode = wifi_get_opmode();
    if(opmode == 1 || opmode == 3) {
        default_hostname = false;
        if(hostname != NULL) {
            vPortFree(hostname);
            hostname = NULL;
        }
        hostname = pvPortMalloc(len);
        if(hostname == NULL) return false;
        struct netif * nif = eagle_lwip_getif(0);
        ets_strcpy(hostname, name);
        if(nif != NULL) {
            nif->hostname = hostname;
        }
        return true;
    }
    return false;
}
Далее это имя используется в struct netif * nif...
Что это дает?
 
Последнее редактирование:

pvvx

Активный участник сообщества
Всё - нашел. Отображается как имя клиента на роутере:
hostname.gif
 

pvvx

Активный участник сообщества
wifi_station_ap_number_set(wifi_aps_cnt)
wifi_station_ap_change(wifi_aps_cur)
wifi_aps_cur = wifi_station_get_current_ap_id()
wifi_aps_cnt = wifi_station_get_ap_info(config);

Кто понимает китайскую логику работы этих функций?
Если ставим wifi_station_ap_number_set(2) (http://aesp8266/web.cgi?wifi_aps_cnt=2)
И читаем wifi_station_get_ap_info(config) (http://aesp8266/protect/aps.xml)
XML:
<?xml version="1.0" encoding="WINDOWS-1251"?>
<response>
<total>2</total>
<cur>0</cur> --> это wifi_station_get_current_ap_id()
<aps id="0">
<ss>AP_HOME</ss>
<ps>1234567890</ps>
<bs>ff:ff:ff:ff:ff:ff</bs>
<bt>0</bt>
<aps id="1">
<ss>AP_HOME</ss>
<ps>1234567890</ps>
<bs>ff:ff:ff:ff:ff:ff</bs>
<bt>0</bt>
</aps>
</response>
Далее задаем соединение с новой AP и читаем значения структуры wifi_station_get_ap_info(config):
XML:
<?xml version="1.0" encoding="WINDOWS-1251"?>
<response>
<total>2</total>
<cur>0</cur>
<aps id="0">
<ss>AP_HOME</ss>
<ps>1234567890</ps>
<bs>ff:ff:ff:ff:ff:ff</bs>
<bt>0</bt>
<aps id="1">
<ss>ESP8266B</ss>
<ps>0123456789</ps>
<bs>ff:ff:ff:ff:ff:ff</bs>
<bt>0</bt>
</aps>
</response>
Переключаем wifi_station_ap_change(1) (http://aesp8266/web.cgi?wifi_aps_cur=1)
Перезагружаем модуль и он коннектится к последнему (ESP8266B), т.к. и был последний раз подключен к нему. Ставь, не ставь wifi_station_ap_change(x) - всё равно.
Читаем опять wifi_station_get_ap_info(config) (http://aesp8266/protect/aps.xml):
XML:
<?xml version="1.0" encoding="WINDOWS-1251"?>
<response>
<total>1</total>
<cur>0</cur>
<aps id="0">
<ss>ESP8266B</ss>
<ps>0123456789</ps>
<bs>ff:ff:ff:ff:ff:ff</bs>
<bt>0</bt>
</aps>
</response>
Если переключаем wifi_station_ap_change(), когда есть записи, то всё равно не коннектится по списку.
Ещё это всё задает путаницу, которую без китайской логики не разобрать...
Ну и нафига это всё надо? :confused: Переключать соединения самим в китай-SDK по событиям WiFi всё равно не дано - там живет жирная бага... И вторая, в том что модуль не шарит в некоторых случаях, что он отвалился от базы, если задана шифрация (WPA и т.д.).
В итоге использовать эти безобразия для подключения модуля по списку AP никак. :mad:
PS: для наглядности и теста функций через Web операции производились с Web-свалкой 01.09.15
 
Последнее редактирование:

Vitaly

Member
Далее это имя используется в struct netif * nif...
Всё - нашел. Отображается как имя клиента на роутере:
а, так netif же в том же самом dhcp.c проверяется на наличие и длину netif->hostname и если все ок в запросе к dhcp прописывает опцию 12 DHCP_OPTION_HOSTNAME
соотвественно роутер потом знает о имени устройства отсюда
 

Vitaly

Member
больше не вижу где бы это имя использовалось, в mdns и netbios имена задаются явно и не отсюда
 

pvvx

Активный участник сообщества
Разобрался с wifi_station_aps. wifi_station_ap_change() работает, но непосредственной записи для замены выбранных AP в структуры нет и использовать это для списка подключения не возможно. Тем более дополнительно протирает дырку в flash, при каждом переключении (как и другие переключения опций WiFi каждый раз стирает и пишет последние 3 сектора flash).
 

Vitaly

Member
а вот реально прыжки по списку АП какие могут иметь сценарии использования? мобильный esp? не смогу пока себе этого представить
 

pvvx

Активный участник сообщества
а вот реально прыжки по списку АП какие могут иметь сценарии использования? мобильный esp? не смогу пока себе этого представить
Делаем список AP к которым разрешено подключаться модулю. При отключении (отваливании от AP) начинаем пробовать подключаться всегда с начала списка. Это самый простой вариант, который решает и приоритет подключения. Можно перед подключением сканировать и выбирать сразу по списку с учетом приоритета для ускорения процесса переподключения... Но надо ждать патч ремонта для SDK по поводу невозможности остановить или изменить задержку процесса подключения ST модуля к внешней AP. Если остановить процесс штатными средствами SDK, то AP модуля в 40% случаев отключается и модуль в каком-то зависшем состоянии с WiFi.
Так-же при потере связи на пару секунд, если включена шифрация (WPA и т.д.), то модуль отваливается от AP, но сам об этом не знает. Модуль соображает о потере связи в режиме с ключами WPA и т.д. только если произошла явная потеря сигналов beacon (REASON_BEACON_TIMEOUT) на время более 5 сек. Если менее - то получаем глюко модуль, считающий что он соединен с AP, но сессионный ключ может быть утерян и новой синхронизации не происходит. Так-же есть ещё китай-глюкодром связанный с разными типами шифрации, при их переключении. В итоге ESP8266 на сегодня использовать вообще никак - гарантия что он работает менее 10%. :) Только под строжайшим контролем над ним с молотком... Это итог писанины китайцами закрытого SDK в течении года.
А простейший сценарий для чего это всё надо - автомобиль. Подъехал к дому и подключился к домашней AP, на месте работы к ... ну и т.д.
 
Последнее редактирование:

Andrey

New member
Подскажите пожалуйста
1. Как правильно отключить нагла? При пакетах меньше 1460 байт задержка 200мс. Отключаю его функцией espconn_set_opt. Функция возвращает 0. Но он всё равно работает. Может есть какая то хитрость?
2. Можно как то регулировать время перезапроса в ТСР? Если пропадает пакет, то ретрейн длится 300мс.
 

pvvx

Активный участник сообщества
Подскажите пожалуйста
1. Как правильно отключить нагла? При пакетах меньше 1460 байт задержка 200мс. Отключаю его функцией espconn_set_opt. Функция возвращает 0. Но он всё равно работает. Может есть какая то хитрость?
2. Можно как то регулировать время перезапроса в ТСР? Если пропадает пакет, то ретрейн длится 300мс.
1. Установить правильные атрибуты для открытой (созданной) TCP структуры. tcp_nagle_disable ( struct tcp_pcb * pcb ); // disable the nagle algorithm
2. Время зависит от двух сторон. Обычно задержку дает приемная сторона, а не модуль. Потерю пакета определить в 300 ms невозможно, т.к. учитывается что пинг обычно бывает до 60 сек и более (от этого и выбирается TIME_WAIT равный 60..120 сек в сетевых приложениях). Может он затерялся в просторах инет :) Вы что-то путаете про 300 ms.
 

Andrey

New member
1. Извините я не уточнил. Я использую функцию SDK. Не Lwip
2. Не совсем понял про интернет. Я имею ввиду. что если пропадает пакет, то происходит его перезапрос. Интерсует можно ли изменить время, через которое он происходит.
 

pvvx

Активный участник сообщества
1. Извините я не уточнил. Я использую функцию SDK. Не Lwip
На это уже отвечал. Espconn использует sint8 espconn_set_opt(struct espconn *espconn, uint8 opt);
См 2C-ESP8266__SDK__Programming Guide__EN_v1.3.0.pdf.
Так-же все функции LwIP доступны в китай-SDK.
2. Не совсем понял про интернет. Я имею ввиду. что если пропадает пакет, то происходит его перезапрос. Интерсует можно ли изменить время, через которое он происходит.
Ответьте на вопрос: как узнать что пропал последний пакет, который не дошел к нам? :)
И второй вариант - когда возникнет перезапрос приемником пропавшего (не пришедшего в группе) пакета в TCP стек приемника?
Без этого уточнения ваш вопрос не имеет смысла.
PS: В дополнение к вопросам - алгоритм передачи всего одного пропавшего пакета из TCP стека не работает на всех реализациях TCP стека. Передается всё снова, что было после пропавшего пакета. В SDK окно TCP = 4*MSS = 5840 по умолчанию.
 
Последнее редактирование:

pvvx

Активный участник сообщества
И по вопросу 1 - пробуйте отключить опцию пониженного потребления для WiFi wifi_set_sleep_type(NONE_SLEEP_T)
C опцией wifi_set_sleep_type(LIGHT_SLEEP_T) передача нескольких непрерывных отсылок пакетов на китаё-SDK не работает и приводит к ошибке в LwIP и т.д. Ошибке не критической, но связь обрывается :) По умолчанию китаё включили wifi_set_sleep_type(MODEM_SLEEP_T) - в ней возникают другие ошибки, т.к. тамер вызова процедур LwIP для опроса открытых соединений и прочего критически увеличен. Вместо 25ms - там 3000 ms :)

И наверно espconn_set_opt требуется запускать для каждого TCP соединения. Я китай-багом-espconn не пользуюсь, т.к. 90% функций написанных самими китаё-Espressif содержат ошибки. Ошибок и недочетов мало только в украденных китаями open-source функциях, куда они не вставили свои вставки.

И в 100500 раз - Паузу в 200 ms делает приемник! https://support.microsoft.com/ru-ru/kb/214397
"Пример 1
Обзор:
Клиент Winsock TCP должен отправлять 10000 записей на сервер Winsock TCP для хранения в базе данных. Размер записей меняется от 20 байт до 100 байт.
Производительность:
Во время тестирования, разработчик обнаруживает, что клиент может отправлять на сервер только пять записей в секунду. "
Отправка на сервер 10000 записей занимает более полу-часа. :D:D:D Мелкомягкие :)
 
Последнее редактирование:

Andrey

New member
1. Спасибо за помошь. Оказывается нагл отключился. У нас ещё одна задержка была которая оказалась похожа на нагл.
2. Хотел вам дапм от шарка сделать, но мы тут немного всё разломали, по этому не могу сейчас сделать.
 

brailovskii

New member
Добрый день! Пытаюсь понять логику китайского sdk. В кратце нужно постоянно отправлять строку данных. Нашел пример тут.


Код:
LOCAL os_timer_t test_timer;
LOCAL struct espconn user_tcp_conn;
LOCAL struct _esp_tcp user_tcp;
ip_addr_t tcp_server_ip;

/******************************************************************************
* FunctionName : user_tcp_recv_cb
* Description  : receive callback.
* Parameters   : arg -- Additional argument to pass to the callback function
* Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_tcp_recv_cb(void *arg, char *pusrdata, unsigned short length)
{
   //received some data from tcp connection
  
    os_printf("tcp recv !!! %s \r\n", pusrdata);
  
}
/******************************************************************************
* FunctionName : user_tcp_sent_cb
* Description  : data sent callback.
* Parameters   : arg -- Additional argument to pass to the callback function
* Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_tcp_sent_cb(void *arg)
{
   //data sent successfully

}
/******************************************************************************
* FunctionName : user_tcp_discon_cb
* Description  : disconnect callback.
* Parameters   : arg -- Additional argument to pass to the callback function
* Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_tcp_discon_cb(void *arg)
{
   //tcp disconnect successfully
  
    os_printf("tcp disconnect succeed !!! \r\n");
}

/******************************************************************************
* FunctionName : user_tcp_write_finish
* Description  : Data need to be sent by espconn_sent has been written into write buffer successfully,
                         call espconn_sent to send next packet is allowed.
* Parameters   : pespconn -- the espconn used to connetion with the host
* Returns      : none
*******************************************************************************/

LOCAL void ICACHE_FLASH_ATTR
user_tcp_write_finish(void *arg)
{
    struct espconn *pespconn = arg;
   
    espconn_sent(pespconn, "Hello World!", 12);
}

/******************************************************************************
* FunctionName : user_sent_data
* Description  : Processing the application data and sending it to the host
* Parameters   : pespconn -- the espconn used to connetion with the host
* Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_sent_data(struct espconn *pespconn)
{

   espconn_sent(pespconn, "Hello World!", 12);
  
}

/******************************************************************************
* FunctionName : user_tcp_connect_cb
* Description  : A new incoming tcp connection has been connected.
* Parameters   : arg -- Additional argument to pass to the callback function
* Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_tcp_connect_cb(void *arg)
{
    struct espconn *pespconn = arg;

    os_printf("connect succeed !!! \r\n");

    espconn_regist_recvcb(pespconn, user_tcp_recv_cb);
    espconn_regist_sentcb(pespconn, user_tcp_sent_cb);
    espconn_regist_disconcb(pespconn, user_tcp_discon_cb);

    espconn_set_opt(pespconn, 0x04); // enable write buffer

    espconn_regist_write_finish(pespconn, user_tcp_write_finish); // register write finish callback
  
    user_sent_data(pespconn);
}

/******************************************************************************
* FunctionName : user_tcp_recon_cb
* Description  : reconnect callback, error occured in TCP connection.
* Parameters   : arg -- Additional argument to pass to the callback function
* Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_tcp_recon_cb(void *arg, sint8 err)
{
   //error occured , tcp connection broke. user can try to reconnect here.
  
    os_printf("reconnect callback, error code %d !!! \r\n",err);
}


/******************************************************************************
* FunctionName : user_check_ip
* Description  : check whether get ip addr or not
* Parameters   : none
* Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_check_ip(void)
{
    struct ip_info ipconfig;

   //disarm timer first
    os_timer_disarm(&test_timer);

   //get ip info of ESP8266 station
    wifi_get_ip_info(STATION_IF, &ipconfig);

    if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0)
   {
      os_printf("got ip !!! \r\n");

      // Connect to tcp server as NET_DOMAIN
      user_tcp_conn.proto.tcp = &user_tcp;
      user_tcp_conn.type = ESPCONN_TCP;
      user_tcp_conn.state = ESPCONN_NONE;
     
      const char esp_server_ip[4] = {X, X, X, X}; // remote IP of tcp server

      os_memcpy(user_tcp_conn.proto.tcp->remote_ip, esp_server_ip, 4); // remote ip of tcp server
     
      user_tcp_conn.proto.tcp->remote_port = TCP_SERVER_PORT; // remote port of tcp server
     
      user_tcp_conn.proto.tcp->local_port = espconn_port(); //local port of ESP8266
     
      espconn_regist_connectcb(&user_tcp_conn, user_tcp_connect_cb); // register connect callback
      espconn_regist_reconcb(&user_tcp_conn, user_tcp_recon_cb); // register reconnect callback as error handler
     
      espconn_connect(&user_tcp_conn); // tcp connect


    }
   else
   {
      
        if ((wifi_station_get_connect_status() == STATION_WRONG_PASSWORD ||
                wifi_station_get_connect_status() == STATION_NO_AP_FOUND ||
                wifi_station_get_connect_status() == STATION_CONNECT_FAIL))
        {
         os_printf("connect fail !!! \r\n");
        }
      else
      {
           //re-arm timer to check ip
            os_timer_setfn(&test_timer, (os_timer_func_t *)user_check_ip, NULL);
            os_timer_arm(&test_timer, 100, 0);
        }
    }
}


/******************************************************************************
* FunctionName : user_set_station_config
* Description  : set the router info which ESP8266 station will connect to
* Parameters   : none
* Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_set_station_config(void)
{
   // Wifi configuration
   char ssid[32] = "SSID";
   char password[64] = "PASSWORD";
   struct station_config stationConf;

   //need not mac address
   stationConf.bssid_set = 0;
  
   //Set ap settings
   os_memcpy(&stationConf.ssid, ssid, 32);
   os_memcpy(&stationConf.password, password, 64);
   wifi_station_set_config(&stationConf);

   //set a timer to check whether got ip from router succeed or not.
   os_timer_disarm(&test_timer);
    os_timer_setfn(&test_timer, (os_timer_func_t *)user_check_ip, NULL);
    os_timer_arm(&test_timer, 100, 0);

}


/******************************************************************************
* FunctionName : user_init
* Description  : entry of user application, init user function here
* Parameters   : none
* Returns      : none
*******************************************************************************/
void user_init(void)
{
    os_printf("SDK version:%s\n", system_get_sdk_version());
  
   //Set softAP + station mode
   wifi_set_opmode(STATIONAP_MODE);

   //ESP8266 connect to router
   user_set_station_config();

}

Проблема в том, что эта программа отправляет данные 8 раз. После этого просто ждет приема данных. Автор кода использовал функцию user_tcp_write_finish. Можете подсказать, как очистить буффер write buffer, чтобы можно было дальше отправлять данные. Либо подсказать совсем другой подход.
 

nikolz

Well-known member
Возможно у кого-нибудь есть исходник функции read_sar_dout?
киньте, если не жалко.
 

pvvx

Активный участник сообщества
Возможно у кого-нибудь есть исходник функции read_sar_dout?
киньте, если не жалко.
C:\Espressif\xtensa-lx106-elf\bin\xtensa-lx106-elf-objdump -S .\app\.output\eagle\image\eagle.app.v6.out > eagle.app.v6.asm
SDK 1.5.0
Код:
    ...

4021841c <read_sar_dout>:
4021841c:    ef9291           l32r    a9, 40214264 <=0x60000A00>
4021841f:    fffe81           l32r    a8, 40218418 <=0xF00>
40218422:    0b0c         movi.n    a11, 0
40218424:    f0c112           addi    a1, a1, -16
40218427:    11c9         s32i.n    a12, a1, 4
40218429:    0109         s32i.n    a0, a1, 0
4021842b:    21d9         s32i.n    a13, a1, 8
4021842d:    000c         movi.n    a0, 0
4021842f:    ffa0d2           movi    a13, 255
40218432:    fc7c         movi.n    a12, -1
40218434:    a06090           addx4    a6, a0, a9
40218437:    907020           addx2    a7, a0, a2
4021843a:    0d5d         mov.n    a5, a13
4021843c:    0bad         mov.n    a10, a11
4021843e:    0020c0           memw
40218441:    17a132           movi    a3, 0x117
40218444:    e02662           l32i    a6, a6, 0x380
40218447:    001b         addi.n    a0, a0, 1
40218449:    740000           extui    a0, a0, 0, 8
4021844c:    3066c0           xor    a6, a6, a12
4021844f:    744060           extui    a4, a6, 0, 8
40218452:    ebc442           addi    a4, a4, -21
40218455:    a46060           extui    a6, a6, 0, 11
40218458:    005762           s16i    a6, a7, 0
4021845b:    b3a440           movgez    a10, a4, a4
4021845e:    82aa30           mull    a10, a10, a3
40218461:    103680           and    a3, a6, a8
40218464:    21a8a0           srai    a10, a10, 8
40218467:    012da7           blt    a13, a10, 4021846c <read_sar_dout+0x50>
4021846a:    0a5d         mov.n    a5, a10
4021846c:    353a         add.n    a3, a5, a3
4021846e:    005732           s16i    a3, a7, 0
40218471:    bf8066           bnei    a0, 8, 40218434 <read_sar_dout+0x18>
40218474:    11c8         l32i.n    a12, a1, 4
40218476:    21d8         l32i.n    a13, a1, 8
40218478:    0108         l32i.n    a0, a1, 0
4021847a:    10c112           addi    a1, a1, 16
4021847d:    f00d         ret.n
    ...
 
Последнее редактирование:

nikolz

Well-known member
pvvx,
Если не сложно,
поясните следующее:
---------------------
1) SAR - реализован аппаратно?
2) обращение к ацп происходит по интерфейсу I2C ?
3) функция read_sar_dout лишь читает 8 значений, а не управляет их вводом?
4) Каким образом указывается, что надо 8 раз запустить SAR для последующего чтения функцией read_sar_dout?
-------------------
Спасибо
 
Сверху Снизу