17. ESP8266 STA (станция) RTOS

Для реализации режима станции создадим 2 файла wifi.c и wifi.h

Внутри файла wifi.h добавим:

#ifndef MAIN_H_
#define MAIN_H_
//------------------------------------------------
#include "esp_common.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "uart.h"
#include "gpio.h"

#include "wifi.h"

//------------------------------------------------
WIFI_MODE ICACHE_FLASH_ATTR init_esp_wifi();
bool ICACHE_FLASH_ATTR start_wifi_station(const char * ssid, const char * pass);
//------------------------------------------------

//#include "esp_system.h"
//------------------------------------------------
#endif /* MAIN_H_ */

 

Переходим в файл wifi.с и добавим:

#include "wifi.h"
//------------------------------------------------
//
//задаем переменные - указатели на функции
//
wifi_state_cb_t on_station_connect = NULL;
wifi_disco_cb_t on_station_disconnect = NULL;
wifi_state_cb_t on_station_first_connect = NULL;
wifi_state_cb_t on_client_connect = NULL;
wifi_state_cb_t on_client_disconnect = NULL;

Здесь мы создали переменные-указатели на соответствующие функции, и указываем на NULL (в дальнейшем производим присвоение «правильных» ненулевых указателей и внутри функций проверяем что указатель !=NULL)

Далее добавим переменные:

//------------------------------------------------
volatile bool wifi_station_is_connected = false;
volatile bool wifi_station_static_ip = false;
//------------------------------------------------
static os_timer_t timer;
//------------------------------------------------
#define GPIO_LED 2
//------------------------------------------------

 

  • Напишем функции для изменения NULL переменных-указателей
//
//Записываем в переменные-указатели на функции
//
void ICACHE_FLASH_ATTR set_on_station_connect(wifi_state_cb_t cb)
{
    on_station_connect = cb;
}
//----------------------------------------------------------------
void ICACHE_FLASH_ATTR set_on_station_disconnect(wifi_disco_cb_t cb)
{
    on_station_disconnect = cb;
}

 

  • Теперь создадим callback функцию, которая будет вызываться при любом событии, внутри нее обработаем эти события
void ICACHE_FLASH_ATTR wifi_event_handler_cb(System_Event_t *event)
{
  static bool station_was_connected = false;
  if (event == NULL)    return; //если события нет - выходим

  os_printf("[WiFi] event %u\n", event->event_id);
	switch (event->event_id) //перебираем события
	{
		case EVENT_STAMODE_DISCONNECTED:
			wifi_station_is_connected = false;
			GPIO_OUTPUT_SET(GPIO_LED, 1);		//выкл светодиод
			Event_StaMode_Disconnected_t *ev = (Event_StaMode_Disconnected_t *)&event->event_info;
			if(on_station_disconnect) //если такая функция есть, то вызываем ее
			{
			  on_station_disconnect(ev->reason); //выводим причину разрыва соединения
			}
		break;
		case EVENT_STAMODE_CONNECTED:
			if(wifi_station_static_ip)
			{
			  os_printf("STA IP is static\n");
			}
			wifi_station_is_connected = true;
			if(!station_was_connected)	//если соединения не было
			{
				station_was_connected = true;
				//если такая функция есть, то пытаемся создать соединение
				if(on_station_first_connect) on_station_first_connect();
			}
			if(on_station_connect)  on_station_connect();
		break;
		case EVENT_STAMODE_DHCP_TIMEOUT: //если не получили ip и т.д. для работы
			if(wifi_station_is_connected)
			{
			  wifi_station_is_connected = false;
			  if(on_station_disconnect) //если такая функция есть, то
			  {
				  on_station_disconnect(REASON_UNSPECIFIED); //выводим что причина не определена
				  //если такая функция есть, то пытаемся сделать первое соединение
				  if(on_station_first_connect) on_station_first_connect();
			  }
			  //если такая функция есть, то пытаемся соединиться
			  if(on_station_connect) on_station_connect();
			}
		break;
		case EVENT_STAMODE_GOT_IP: //получили IP
			wifi_station_is_connected = true;
			GPIO_OUTPUT_SET(GPIO_LED, 0); //зажгли светодиод
			//выставили флаг что станция создала соединение
			if(!station_was_connected) station_was_connected = true;
		break;
		case EVENT_SOFTAPMODE_STACONNECTED:
			//если такая функция есть, то пытаемся соединится
			if(on_client_connect) on_client_connect();
		break;
		case EVENT_SOFTAPMODE_STADISCONNECTED:
			//если такая функция есть, то пытаемся соединится
			if(on_client_disconnect) on_client_disconnect(); 
		break;

		default:
		break;
	}
}

 

  • Напишем функции для ПРОВЕРКИ соединения wifi :
//
//Проверка соединения и перепроверка по таймеру
//
bool ICACHE_FLASH_ATTR wifi_station_connected()
{
    if(!wifi_station_is_connected)    return false;
    WIFI_MODE mode = wifi_get_opmode();
    if((mode & STATION_MODE) == 0)   return false;
    STATION_STATUS wifistate = wifi_station_get_connect_status();

    //Если получили IP- считаем, что соединились
    wifi_station_is_connected = (wifistate == STATION_GOT_IP ||
        (wifi_station_static_ip && wifistate == STATION_CONNECTING));
    return wifi_station_is_connected;
}
//------------------------------------------------
LOCAL void ICACHE_FLASH_ATTR wait_for_connection_ready(uint8 flag)
{
	//если соединение есть - уходим, иначе реконнект по таймеру
    os_timer_disarm(&timer);
    if(wifi_station_connected())
    {
        os_printf("connected\n");
    }
    else
    {
      os_printf("reconnect after 2s\n");
      os_timer_setfn(&timer, (os_timer_func_t *)wait_for_connection_ready, NULL);
      os_timer_arm(&timer, 2000, 0);
    }
}

 

  • Напишем функции коннекта и дисконнекта:
//
//Функции коннекта и дисконнекта
//
LOCAL void ICACHE_FLASH_ATTR on_wifi_connect()
{
    os_printf("on_wifi_connect();\n");
    os_timer_disarm(&timer);
    os_timer_setfn(&timer, (os_timer_func_t *)wait_for_connection_ready, NULL);
    os_timer_arm(&timer, 100, 0);
}
//------------------------------------------------
LOCAL void ICACHE_FLASH_ATTR on_wifi_disconnect(uint8_t reason)
{
    os_printf("disconnect %d\n", reason);
}

 

  • Напишем функцию изменения режима работы модуля:
//
//Изменение режима работы wifi модуля
//
bool ICACHE_FLASH_ATTR wifi_set_mode(WIFI_MODE mode)
{
    if(!mode)
    {
        bool s = wifi_set_opmode(mode);
        wifi_fpm_open();
        wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
        wifi_fpm_do_sleep(0xFFFFFFFF);
        return s;
    }
    wifi_fpm_close();
    return wifi_set_opmode(mode);
}
//------------------------------------------------

 

  • Теперь напишем функцию запуска в режиме станции:
//
//запуск в режиме станции
//
bool ICACHE_FLASH_ATTR start_wifi_station(const char * ssid, const char * pass)
{
    WIFI_MODE mode = wifi_get_opmode();
    if((mode & STATION_MODE) == 0)
    {
        mode |= STATION_MODE; //точно через или???
        if(!wifi_set_mode(mode))
        {
            os_printf("Failed to enable Station mode!\n");
            return false;
        }
    }
    if(!ssid) //если нет ssid
    {
        os_printf("No SSID Given. Will connect to the station saved in flash\n");
        return true;
    }
    struct station_config config;
    memset(&config, 0, sizeof(struct station_config)); //обнуление структуры
    strcpy(config.ssid, ssid);
    //если есть пароль - копируем пароль
    if(pass) strcpy(config.password, pass);

    if(!wifi_station_set_config(&config))
    {
        os_printf("Failed to set Station config!\n");
        return false;
    }

    wifi_set_sleep_type(NONE_SLEEP_T);
    if(!wifi_station_dhcpc_status())
    {
        os_printf("DHCP is not started. Starting it...\n");
        if(!wifi_station_dhcpc_start()) {
            os_printf("DHCP start failed!\n");
            return false;
        }
    }
    if(wifi_get_phy_mode() != PHY_MODE_11N) wifi_set_phy_mode(PHY_MODE_11N);
    return wifi_station_connect();
}

 

  • По умолчанию модуль находится в режиме точка доступа, поэтому напишем функцию убирающую этот режим.
//------------------------------------------------
bool ICACHE_FLASH_ATTR stop_wifi_ap()
{
    WIFI_MODE mode = wifi_get_opmode();
    mode &= ~SOFTAP_MODE;
    if(!wifi_set_mode(mode))
    {
        os_printf("Failed to disable AP mode!\n");
        return false;
    }
    return true;
}

 

  • Напишем функцию инициализации ESP в режиме станции
WIFI_MODE ICACHE_FLASH_ATTR init_esp_wifi()
{
	//Записываем в переменные-указатели на функции
	set_on_station_connect(on_wifi_connect);
	set_on_station_disconnect(on_wifi_disconnect);

	//"прописываем" Callback функцию
	wifi_set_event_handler_cb(wifi_event_handler_cb);

	WIFI_MODE mode = wifi_get_opmode_default(); //определяем текущий режим работы
	wifi_set_mode(mode); //
	stop_wifi_ap(); //отключение режима точка доступа
	return mode;
}

 

 

  • Теперь в файле main.c можно использовать написанные функции
//------------------------------------------------------
void ICACHE_FLASH_ATTR user_init()
{
        UART_SetBaudrate(UART0,BIT_RATE_115200);
        UART_SetBaudrate(UART1,BIT_RATE_115200);
	//Init_something();
	init_esp_wifi();
	start_wifi_station(WiFi_Client_SSID, WiFi_Client_Password);
}

Принцип работы:
В функции init_esp_wifi(); прописываются указатели на соответствующие функции в переменные, а также event callback функция.
При запуске функции start_wifi_station(); проверяется наличие и копируются SSID и password, в самом конце вызывается функция wifi_station_connect(); завершающая настройку wifi.

В дальнейшем работа ведется через event/события в функции wifi_event_handler_cb();
В ней проверяются текущие события (а также что указатели на функции !=NULL) и вызываются соответствующие функции.

Наиболее интересная функция:
if(on_station_connect)  on_station_connect(); //проверяет наличие и запускает функцию on_wifi_connect();
функция on_wifi_connect(); запускает таймер, а в прерывании по таймеру вызывается функция wait_for_connection_ready(); внутри которой проверяется наличие соединения и если не установилось, то перезапускается таймер.

Примечание:
В терминальную программу выводится IP адрес, на основе полученного IP можно «пропинговать» микроконтроллер.
в windows 7 нажать ctrl+R ввести cmd и потом ввести ping «ip»

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *