Создадим UDP сервер (НЕ ТОЧКУ ДОСТУПА) с фиксированными IP и портом.
(Точка доступа — это DHCP сервер, который сам присуждает IP и порт)
Настроим соединение по UDP протоколу и обменяемся датаграммами.
В файле user_config.h напишем дефайны для точки доступа
#define WiFi_Client_SSID "qwe1" //в SSID обязательно должны быть цифры!!!!
#define WiFi_Client_Password "12345678"
#define UDP_SERVER_PORT 30000
В файле main.c добавляем код:
#include "espconn.h"
//------------------------------------------------------
//User_Variables
//------------------------------------------------------
static os_timer_t os_timer01;
static uint8_t led_state=0;
//for wifi
struct espconn pConn;
esp_udp ConnUDP;
//------------------------------------------------------
//перечисление и переменная с состоянием Wifi
typedef enum{
WIFI_CONNECTING,
WIFI_CONNECTING_ERROR,
WIFI_CONNECTED
} tConnState;
static tConnState ConnState=WIFI_CONNECTING;
//------------------------------------------------------
Далее прописываем прототип функции проверки соединения и callback функции (обозначают окончание приема/передачи по UDP)
static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg); //прототип функции
//------------------------------------------------------
//Functions INTERRUPT WiFi
//------------------------------------------------------
//Вызывается после окончания передачи
void ICACHE_FLASH_ATTR udp_client_Tx(void* arg)
{
}
//------------------------------------------------------
//Вызывается после окончания приема
void ICACHE_FLASH_ATTR udp_client_Rx(void* arg, char* pusrdata, uint16_t length)
{
//совмещаем структуру с arg (struct espconn *pesp_conn=arg;),
//тем самым получая данные о типе соединения и тд
struct espconn *pEspconn=(struct espconn*)arg;
if(pEspconn->type==ESPCONN_UDP) //если UDP
{
remot_info *pinfo=NULL; //указатель на структуру с данными об отправителе
if(espconn_get_connection_info(pEspconn, &pinfo, 0)==0) //копируем информацию об отправителе
{
os_printf("Remote IP: ");
for(uint8_t i=0;i<4;i++) os_printf("%d.",pinfo->remote_ip[i]);
os_printf("\r\n");
os_printf("Remote port: %d.\r\n",pinfo->remote_port);
}
else
{
os_printf("Cannot get sender ID\r\n");
return;
}
//Выводим полученные данные
os_printf("UDP : DATA RECEIVED : LEN = %d\n", length);
os_printf("UDP : DATA: ");
for(uint16_t idx=0;idx<length;idx++) uart_tx_one_char(UART0,pusrdata[idx]); os_printf("\r\n"); os_printf("___________\r\n"); //заносим данные о отправителе в адрес "получателя" os_memcpy(pConn.proto.udp->remote_ip,pinfo->remote_ip,4); //копируем ip
pConn.proto.udp->remote_port=pinfo->remote_port;
espconn_send(&pConn, (uint8_t*)"Hello from ESP8266!!!\r\n", 23);
}
else
{
os_printf("It is not UDP ask\r\n");
}
}
Примечание: Использовать буфер в виде структуры remot_info *pinfo необходимо, по крайней мере я не смог получить НЕНУЛЕВЫЕ данные из структуры pEspconn.
Далее необходимо написать функцию создания UDP передачи
//------------------------------------------------------
//Создание UDP передачи
//------------------------------------------------------
static void ICACHE_FLASH_ATTR udp_connect()
{
os_timer_disarm(&os_timer01);
pConn.proto.udp = &ConnUDP;
os_memset(pConn.proto.udp,0,sizeof(pConn.proto.udp)); //обнуляем поле UDP (ip и порты)
pConn.type = ESPCONN_UDP; //устанавливаем тип
pConn.state = ESPCONN_NONE; //тукущее состояние
//Вводим порт отправителя
pConn.proto.udp->local_port = UDP_SERVER_PORT; //создаем заданный порт для ESP8266
//создаем "соединение" по факту - открываем канал связи.
os_printf("UDP espconn create...\r\n");
espconn_create(&pConn); //создаем UDP передачу
espconn_regist_sentcb(&pConn, udp_client_Tx); //указываем callback функцию для передачи (вызывается после отправки)
espconn_regist_recvcb(&pConn, udp_client_Rx); //указываем callback функцию для приема (вызывается после приема)
//Запускаем таймер для проверки что соединение все еще есть
os_timer_setfn(&os_timer01, (os_timer_func_t *)wifi_check_ip, NULL);
os_timer_arm(&os_timer01, 1000, 0);
}
Допишем функцию, отвечающую за wifi соединение (см. Wi-Fi STA (станция/клиент))
//------------------------------------------------------
//Functions INTERRUPT
//------------------------------------------------------
static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg)
{
struct ip_info IpConfig; //структура, в которую "складируются" данные о текущем соединении
os_timer_disarm(&os_timer01); //деинициализировать (обнулить) структуру / отключаем таймер
uint8_t WiFi_status=wifi_station_get_connect_status(); //проверяем статус соединения
if(WiFi_status==STATION_GOT_IP)
{
wifi_get_ip_info(STATION_IF, &IpConfig); //получаем ip и другую информацию о esp8266
if (IpConfig.ip.addr!=0) //если получили IP, то меняем статус и выходим
{
if(ConnState!=WIFI_CONNECTED) //если есть соединение, то выходим в функцию udp_connect()
{
ConnState=WIFI_CONNECTED;
os_printf("WiFi connected\r\n");
udp_connect();
return;
}
else {led_state=(led_state==0) ? 1:0; GPIO_OUTPUT_SET(2,led_state); } //мигаем светодиодом
}
}
else
{
espconn_delete(&pConn); //разрываем соединение с хостом (точнее удаляем передачу)
switch (WiFi_status)
{
case STATION_WRONG_PASSWORD:
ConnState=WIFI_CONNECTING_ERROR;
os_printf("STATION_WRONG_PASSWORD\r\n");
break;
case STATION_NO_AP_FOUND:
ConnState=WIFI_CONNECTING_ERROR;
os_printf("STATION_NO_AP_FOUND\r\n");
break;
case STATION_CONNECT_FAIL:
ConnState=WIFI_CONNECTING_ERROR;
os_printf("STATION_CONNECT_FAIL\r\n");
break;
default:
ConnState=WIFI_CONNECTING;
os_printf("STATION_IDLE\r\n");
break;
}
}
os_timer_setfn(&os_timer01, (os_timer_func_t*)wifi_check_ip, NULL); //указываем структура и функцию обратного вызова
os_timer_arm(&os_timer01, 500, 0); //инициализировать (обнулить) структуру
}
Последний шаг — напишем функцию main
//------------------------------------------------------
void ICACHE_FLASH_ATTR user_init()
{
uart_init(BIT_RATE_115200, BIT_RATE_115200);
//-----
gpio_init();
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
Set_GPIOs_As_Output(BIT2, 0);
//-----
ets_delay_ms(100);
os_printf("\r\n");
//
//WiFi UDP Client
//
struct station_config stationConf; //структура для настроек wifi
wifi_set_opmode(STATION_MODE); //режим станции (настройка м.б. изменена "на лету")
wifi_station_disconnect(); //разрываем соединение
wifi_station_dhcpc_stop(); //Остановим DHCP клиент
if(wifi_station_get_config(&stationConf))
{
os_memset(stationConf.ssid, 0, sizeof(stationConf.ssid));
os_memset(stationConf.password, 0, sizeof(stationConf.password));
os_sprintf(stationConf.ssid, "%s", WiFi_Client_SSID);
os_sprintf(stationConf.password, "%s", WiFi_Client_Password);
if(!wifi_station_set_config(&stationConf))
{
os_printf("Not set station config!\r\n");
}
}
wifi_set_sleep_type(NONE_SLEEP_T); //отключаем пониженное энергопотребление
wifi_station_connect(); //присоединяемся к wifi
wifi_station_dhcpc_start(); //запускаем DHCP клиент
if(wifi_get_phy_mode() != PHY_MODE_11N) wifi_set_phy_mode(PHY_MODE_11N); //Включаем режим 802.11n
if(wifi_station_get_auto_connect() ==0) wifi_station_set_auto_connect(1); //включаем автоконнект
//используем программный таймер
os_timer_disarm(&os_timer01); //деинициализировать (обнулить) структуру
os_timer_setfn(&os_timer01, (os_timer_func_t*)wifi_check_ip, NULL); //указываем структура и функцию обратного вызова
os_timer_arm(&os_timer01, 1000, 0); //0-однократно, 1-циклический
}
Принцип работы описанной выше программы:
Большая часть программы аналогична работе UDP Client:
В main настраиваем wifi и включаем программный таймер, через 1с попадаем в прерывание по таймеру, проверяем статус соединения и выставляем новый таймер с тиком 500мс (для проверки соединения)
>>если нет соединения, ставим флаг ошибки и выводим в uart ошибку
>>если соединение есть:
- при первичном запуске (IpConfig.ip.addr!=0 и ConnState!=WIFI_CONNECTED), т.е. ip получили, но статус не обновили — изменяем статус «ConnState=WIFI_CONNECTED;» и вызываем функцию udp_connect();
- при повторных запусках мигаем светодиодом
Функция udp_connect() — настраиваем порт отправителя для UDP (30000 порт).
При получении сбщ. от сервера вызывается функция «udp_client_Rx», ВНУТРИ НЕЕ получаются данные об отправителе (ip и порт) и в ответ посылается сообщение «Hello from ESP8266!!!».
Для эмуляции работы клиента:
>> Запустить netcat
>> прописать: nc -u ip 30000 (этим откроем соединение)
где ip esp8266 берется из терминальной программы
>>отправить данные в esp8266 (они также отобразятся в терминальной программе)
>>получить ответ от esp8266 (Hello from ESP8266!!!)
Примечание: команды терминальной программы в win7:
Узнать свой ip: win+R ввести cmd и прописать ipconfig
Перейти в папку с netcat: win+R ввести cmd и прописать cd «путь до netcat»
Запускаем netcat в командной строке из папки с программой:
прописываем nc -u -l -p 30000
этим мы открыли 30000 порт и слушаем его, можем что-то в него отправить (вписываем данные +enter)