14. TCP Client

Создадим TCP клиент на микроконтроллере (модуле) ESP8266.

В файле user_config.h напишем дефайны для точки доступа

#define WiFi_Client_SSID "qwe1" //в SSID обязательно должны быть цифры!!!!
#define WiFi_Client_Password "12345678"

#define TCP_SERVER_IP "192.168.0.53"
#define TCP_SERVER_PORT 30000

В файле main.c

Добавляем #include:
#include "driver/uart.h"
#include "espconn.h"
#include "mem.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;
//------------------------------------------------------

Добавляем следующий код:

static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg); //прототип функции

//------------------------------------------------------
//Functions INTERRUPT WiFi
//------------------------------------------------------
static void ICACHE_FLASH_ATTR TCP_client_disconnect_cb(void *arg)
{
  struct espconn *pConn = (struct espconn *)arg;
  //удаляем структуры из динамической памяти
  os_free(pConn->proto.tcp);
  os_free(pConn);
  os_printf("TCP disconnected\r\n");
}

void ICACHE_FLASH_ATTR TCP_client_Tx_cb(void* arg)
{
  os_printf("TCP packet sent\r\n");
}
//------------------------------------------------------
void ICACHE_FLASH_ATTR TCP_client_Rx_cb(void* arg, char* pusrdata, uint16_t length)
{
  struct espconn *pConn = (struct espconn *)arg;
  for(uint16_t idx=0;idx<length;idx++)   uart_tx_one_char(UART0,pusrdata[idx]);
  os_printf("\r\n");
  espconn_disconnect(pConn);
}

static void ICACHE_FLASH_ATTR TCP_client_connect_cb(void *arg)
{
  struct espconn *pConn = (struct espconn *)arg;
  espconn_regist_sentcb(pConn, TCP_client_Tx_cb);
  espconn_regist_recvcb(pConn, TCP_client_Rx_cb);
  espconn_regist_disconcb(pConn, TCP_client_disconnect_cb);

  char msg[]="Hello from ESP8266!!!\r\n";
  espconn_sent(pConn, (uint8_t*) msg, strlen(msg));
}

Напишем функцию создания TCP соединения:

//------------------------------------------------------
//Создание TCP передачи
//------------------------------------------------------
static void ICACHE_FLASH_ATTR TCP_connect()
{
	//выделим память по размеру struct espconn и заполним ее нулями, указатель присвоим pCon
	struct espconn *pConTCP = (struct espconn *)os_zalloc(sizeof(struct espconn));
	if (pConTCP == NULL) //если не присвоили - выходим
	{
	     os_printf("TCP connect failed\r\n");
	     return;
	}

	pConTCP->type = ESPCONN_TCP;		//устанавливаем тип
	pConTCP->state = ESPCONN_NONE;		//текущее состояние

	//формируем IP и порт
	pConTCP->proto.tcp=(esp_tcp*)os_zalloc(sizeof(esp_tcp));	//выделяем в памяти место под структуру для TCP
	pConTCP->proto.tcp->local_port=espconn_port();			//генерируем случайный порт esp8266
	pConTCP->proto.tcp->remote_port=TCP_SERVER_PORT;
	uint32_t ip;
	char tcpserverip[15]={};
	os_sprintf(tcpserverip, "%s", TCP_SERVER_IP);	        //копируем ip
	ip = ipaddr_addr(tcpserverip); 				//превращает в целочисленный формат
	os_memcpy(pConTCP->proto.tcp->remote_ip, &ip, 4);	//копируем ip

	//Устанавливаем соединение
	espconn_regist_connectcb(pConTCP, TCP_client_connect_cb);	//Регистрируем callback функцию для установки соединения
	os_printf("UDP espconn create...\r\n");
	espconn_connect(pConTCP);					//устанавливаем соединение (соединяемся с TCP сервером)
}

Функция прерывания по программному таймеру осталась практически прежней, в нее необходимо дописать функцию для установки TCP соединения:

ConnState=WIFI_CONNECTED;
os_printf("WiFi connected\r\n");
TCP_connect(); //Функция для настройки и установки TCP соединения
return;

main функция осталась без изменений.

//—————————————————————

Принцип работы описанной выше программы:

Большая часть программы аналогична работе UDP Client:

В main настраиваем wifi и включаем программный таймер, через 1с попадаем в прерывание по таймеру, проверяем статус соединения и выставляем новый таймер с тиком 500мс (для проверки соединения)

>>если нет соединения, ставим флаг ошибки и выводим в uart ошибку

>>если соединение есть:

  • при первичном запуске (IpConfig.ip.addr!=0 и ConnState!=WIFI_CONNECTED), т.е. ip получили, но статус не обновили — изменяем статус «ConnState=WIFI_CONNECTED;» и вызываем функцию tcp_connect();
  • при повторных запусках мигаем светодиодом

Отличия:

Функция tcp_connect() — настраивает и устанавливает TCP соединение, также в ДИНАМИЧЕСКОЙ памяти выделяем место для структур espconn и esp_tcp

>>когда TCP соединение установится — вызывается функция TCP_client_connect_cb, в которой прописываются callback функции и отправляется сбщ «Hello from ESP8266!!!»

>>после отправки сбщ попадаем в функцию TCP_client_Tx_cb где пока что просто выводим в uart сбщ. «TCP packet sent»

>>при приеме вызывается функция TCP_client_Rx_cb, в которой в uart выводится полученное сбщ. и вызывается функция TCP_client_disconnect_cb.

>>TCP_client_disconnect_cb — Удаляем из динамической памяти (созданы в функции tcp_connect() ) место под структуры espconn и esp_tcp


Для эмуляции работы сервера:
>> Запустить netcat
>> прописать: nc -l -p 30000 (этим откроем соединение)
>>получить сбщ. от esp8266 (Hello from ESP8266!!!)
>>отправить данные в esp8266 (они также отобразятся в терминальной программе)

Примечание: команды терминальной программы в win7:
Узнать свой ip: win+R ввести cmd и прописать ipconfig
Перейти в папку с netcat: win+R ввести cmd и прописать cd «путь до netcat»

Запускаем netcat в командной строке из папки с программой:
прописываем nc -u -l -p 30000
этим мы открыли 30000 порт и слушаем его, можем что-то в него отправить (вписываем данные +enter)

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

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