Работа с ESP8266: Собираем компилятор и пишем первую прошивку

Sleuthhound 24 ноября 2014 в 22:36 114k
В прошлой статье мы рассмотрели первоначальную настройку и работу модуля ESP-01 с базовой AT-прошивкой. Возможности данной прошивки достаточно ограничены и использовать её для каких-то повседневных задач достаточно сложно. Как я писал в первой статье, для ESP8266 можно написать свою прошивку с нужным функционалом и тем самым сделать плату ESP-01 самодостаточным устройством. Всем кому это интересно, прошу под хабракат.

Как известно, SoC ESP8266 построен на базе процессора Xtensa LX106 фирмы Tensilica, если кому-то интересно, то в сети есть статья про конфигурируемые процессоры этой фирмы. Компания Espressif предоставляет полную документацию, а так же компилятор и среду разработки для SoC ESP8266 только после подписания партнерского соглашения и не со всеми подряд, на мое письмо они так и не ответили. Немного погуглив можно найти утекший в сеть официальный компилятор, среду разработки, основанную на Eclipse, множество документации и лицензии, но это не наш путь. Мы будем использовать неофициальный компилятор на основе Crosstool-NG

В этой статье я расскажу как собрать компилятор под Ubuntu Linux, а так же мы попробуем написать простейшую прошивку. Основной упор я сделаю на работу с компилятором под Windows, а так же настройку среды Eclipse для написания прошивок для ESP8266.

Часть 1: Сборка компилятора под Ubuntu Linux, настройка SDK, сборка стандартных примеров и прошивок.

Установка среды сборки

Для 32-разрядной Debian (Linux) выполняем:
apt-get install git autoconf build-essential gperf bison flex texinfo libtool libncurses5-dev wget gawk libc6-dev-amd64 python-serial libexpat-dev
Для 64-разрядной Debian (Linux) выполняем:
apt-get install git autoconf build-essential gperf bison flex texinfo libtool libncurses5-dev wget gawk libc6-dev-i386 python-serial libexpat-dev
Далее:
USER меняем на логин текущего пользователя.
sudo mkdir /opt/Espressif
sudo chown USER:root /opt/Espressif
cd /opt/Espressif
git clone -b lx106 git://github.com/jcmvbkbc/crosstool-NG.git 
cd crosstool-NG
./bootstrap && ./configure --prefix=`pwd` && make && make install
./ct-ng xtensa-lx106-elf
./ct-ng build
PATH=$PWD/builds/xtensa-lx106-elf/bin:$PATH

После этого можно откинуться на спинку кресла минут на 40-50 и попить кофе. Если все завершится без ошибок, то можно двигаться дальше.

Установка SDK

cd /opt/Espressif
mkdir ESP8266_SDK
cd ESP8266_SDK
wget http://bbs.espressif.com/download/file.php?id=72 -O esp_iot_sdk_v0.9.3_14_11_21.zip
wget http://bbs.espressif.com/download/file.php?id=73 -O esp_iot_sdk_v0.9.3_14_11_21_patch1.zip
unzip esp_iot_sdk_v0.9.3_14_11_21.zip && rm esp_iot_sdk_v0.9.3_14_11_21.zip
rm esp_iot_sdk_v0.9.3/lib/libpp.a
unzip esp_iot_sdk_v0.9.3_14_11_21_patch1.zip && rm esp_iot_sdk_v0.9.3_14_11_21.zip
mv esp_iot_sdk_v0.9.3/* . && rm -r esp_iot_sdk_v0.9.3/

Добавляем библиотеки libc, libhal и заголовочные файлы в SDK

cd /opt/Espressif/ESP8266_SDK
wget -O lib/libc.a https://github.com/esp8266/esp8266-wiki/raw/master/libs/libc.a
wget -O lib/libhal.a https://github.com/esp8266/esp8266-wiki/raw/master/libs/libhal.a
wget -O include.tgz https://github.com/esp8266/esp8266-wiki/raw/master/include.tgz
tar -xvzf include.tgz && rm include.tgz

Установка ESP image tool

ESP tool можно собрать из исходников,
для Linux можно скачать здесь
для Debian/Ubuntu здесь
Готовый пакет для Ubuntu качаем отсюда
cd /opt/Espressif/
wget https://github.com/esp8266/esp8266-wiki/raw/master/deb/esptool_0.0.2-1_i386.deb
sudo dpkg -i esptool_0.0.2-1_i386.deb && rm esptool_0.0.2-1_i386.deb

Установка ESP upload tool

cd /opt/Espressif
git clone https://github.com/themadinventor/esptool esptool-py
sudo ln -s $PWD/esptool-py/esptool.py crosstool-NG/builds/xtensa-lx106-elf/bin/
sudo ln -s $PWD/esptool-py/esptool.py /usr/sbin/

Сборка примеров прошивок

Для начала откройте файл /opt/Espressif/ESP8266_SDK/include/osapi.h и закомментируйте строку #include «user_config.h»

Скачиваем и собираем примеры blinky и basic_example:
cd /opt/Espressif/ESP8266_SDK/examples/
wget https://github.com/esp8266/source-code-examples/archive/master.zip && unzip master.zip && rm -r master.zip
mv source-code-examples-master/* . && rm -r source-code-examples-master
cd blinky
make
Если все шаги были сделаны правильно, то сборка пройдет без ошибок и в каталоге firmware появятся 2 файла прошивки 0x00000.bin и 0x40000.bin

Скачиваем и собираем пример базовой прошивки AT:
cd /opt/Espressif/ESP8266_SDK/examples/
wget -O at_v0.19_14_10_30.zip http://bbs.espressif.com/download/file.php?id=13
unzip at_v0.19_14_10_30.zip && rm at_v0.19_14_10_30.zip
cd at_v0.19_on_SDKv0.9.2/
rm Makefile && cp ../example.Makefile . && mv example.Makefile Makefile

Для правильной сборки AT прошивки необходимо отредактировать базовый Makefile в строке
LIBS = c gcc hal pp phy net80211 lwip wpa main
добавить линковку библиотеки upgrade, итоговая строка будет выглядеть так
LIBS = c gcc hal pp phy net80211 lwip wpa upgrade main
после этого прошивку можно собрать командой make

Cобираем пример прошивки IoT:
cd /opt/Espressif/ESP8266_SDK/examples/IoT_Demo/
rm Makefile && cp ../example.Makefile . && mv example.Makefile Makefile

Так же как и для AT прошивки, для правильной сборки IoT прошивки необходимо отредактировать базовый Makefile в строку
MODULES = driver user
нужно добавить дополнительные модули, итоговая строка будет выглядеть так
MODULES = driver user json ssl upgrade lwip
а в строку
LIBS = c gcc hal pp phy net80211 lwip wpa main
добавить линковку библиотеки json, итоговая строка будет выглядеть так
LIBS = c gcc hal pp phy net80211 lwip wpa main json
после этого прошивку можно собрать командой make

Для того чтобы прошить плату ESP-01 нужно использовать команду make flash
Не забываем, что для переключения в режим обновления прошивки нужно подать низкий уровень на GPIO0 и высокий на CH_PD.
Чтобы понять, что делает make flash стоит открыть любой Makefile и найти строку flash:
после подстановки всех аргументов получаем команду прошивки SoC:
esptool.py --port /dev/ttyUSB0 write_flash 0x00000 firmware/0x00000.bin 0x40000 firmware/0x40000.bin

Формат файла прошивки, собственно и как протокол обмена можно почитать тут на русском или здесь на английском языках.
На этом рассмотрение сборки компилятора и SDK под Linux закончено.

Часть 2: Установка компилятора под Windows, настройка SDK, сборка стандартных примеров и прошивок.

Т.к. моя основная ОС под которой я работаю 90% времени это Windows, то разработка в Linux меня не сильно интересовала.
Ниже я расскажу, как установить и настроить компилятор и SDK в Windows, а так же как настроить среду разработки Eclipse для комфортной разработки прошивок в ней.
Рассматривать процесс сборки компилятора под Windows я не буду, т.к. это довольно сложная процедура, она намного сложнее сборки в Linux.
Дабы избавить Вас от всех тонкостей и нюансов, я подготовил рабочий комплект Espressif DevKit, включающий в себя компилятор, последнюю версию SDK, стандартные примеры прошивок, а так же мои собственные примеры прошивок.

Итак приступим:
1. Cкачиваем (148Mb) и устанавливаем мой комплект Espressif-ESP8266-DevKit-v2.2.1-x86.exe (актуален на 15.11.2016)
2. Скачиваем и устанавливаем Java Runtime x86 или x64 (Например: jre-8u111-windows-x64.exe для Windows x64)
3. Скачиваем и устанавливаем Eclipse Neon x86 или Eclipse Neon x64 для разработки на С++. Распаковываем архив в корень диска С.
4. Скачиваем и устанавливаем MinGW. Запускаем mingw-get-setup.exe, в процессе установки выберите режим без GUI, то есть уберите галочку "...also install support for the graphical user interface".
5. Скачиваем набор моих скриптов для автоматизации установки доп.модулей для MinGW. (актуален на 15.10.2016)
6. Запустите из моего набора файл install-mingw-package.bat. Он скачает с моего сайта закэшированые архивы пакетов для mingw, примерно 90 Mb и установит основные модули для MinGW. Скачивание заранее готового набора файлов пакетов для MinGW гарантирует, что все они будут установлены, иногда сервера, где лежат пакеты MinGW становятся недоступными и необходимые пакеты не ставятся и поэтому сборка прошивок может проходить с разного рода фокусами.
7. Запустите Eclipse из каталога c:\eclipse\eclipse.exe
8. В Eclipse выберите меню File -> Import -> General -> Existing Project into Workspace, в строке Select root directory выберите каталог C:\Espressif\examples\ESP8266 и импортируйте рабочие проекты.
Далее справа в Make Target выберите нужный проект, например hello-world и запустите цель all на сборку,
при этом в окне Console должен отобразиться ход сборки, если все сделано правильно, то будет примерно такая картина:

17:00:00 **** Build of configuration Default for project hello-world ****
mingw32-make.exe -f C:/Espressif/examples/ESP8266/hello-world/Makefile all 
CC driver/uart.c
CC user/user_main.c
AR build/app_app.a
LD build/app.out
FW firmware/0x00000.bin
FW firmware/0x40000.bin
17:00:04 Build Finished (took 3s.740ms)

Это значит, что прошивка для ESP8266 собрана и находится в каталоге C:\Espressif\examples\hello-world\firmware
Для прошивки ESP8266 используйте цель flash, предварительно отредактировав файл сборки проекта Makefile, строка
ESPPORT ?= COM2
, где после COM цифра 2 указывает номер COM-порта к которому подключена плата с ESP8266.

Видео с демонстрацией подключения проектов в Eclipse, сборкой и прошивкой ESP8266.

Видео с демонстрацией создания нового проекта в Eclipse.

Как было сказано выше, для переключения в режим обновления прошивки нужно подать низкий уровень на GPIO0 и высокий на CH_PD, после этого либо передернуть питание платы, либо выполнить Сброс, подачей низкого уровня на EXT_RSTВ (он же RESET). Выполнять эти действия постоянно очень неудобно. Немного подумав, я изменил схему подключения платы ESP-01 к преобразователю USB-to-RS232, смысл изменений сводится к подключению вывода RTS преобразователя USB-to-RS232 к выводу EXT_RSTB (он же RESET) платы ESP-01 и вывода DTR преобразователя USB-to-RS232 к выводу GPIO0 платы ESP-01.

ВНИМАНИЕ! В моей текущей сборке Unofficial Development Kit for Espressif ESP8266 утилита esptool уже содержит эти доработки, поэтому дополнительно патчить ничего не нужно.

Так же я подправил утилиту esptool.py в процедуре connect
Так же я подправил утилиту esptool.py в процедуре connect для того, чтобы при запуске происходил сброс платы по сигналу RTS и вход в режим загрузчика по сигналу DTR.
Изменения в esptool.py
    def connect(self):
	print 'Entering bootloader...'
	self._port.setRTS(True)			#RTS
	self._port.setDTR(True)			#GPIO0
	time.sleep(0.25)
	self._port.setRTS(False)
	self._port.setDTR(True)
	time.sleep(0.25)
	self._port.setRTS(False)
	self._port.setDTR(False)
	print 'Connecting...'

Таким легким финтом ушами я решил проблему ручного перехода в режим обновления прошивки.


Итоговая схема подключения:


Теперь, выполняя цель flash в Eclipse, мы одним кликом мышки шьем плату новой прошивкой. Не нужно ничего перетыкать на макетке и ничего соединять.

Но в связи с этим финтом ушами пришлось поискать нормальную программу Terminal, т.к. то же Putty уже не подходил, в нем нельзя управлять линиями RTS и DTR и более того, сразу после подключения к COM-порту через Putty, он ставил линию DTR в низкий уровень, что приводило к постоянному входу в режим загрузчика. Удобная и в то же время богатая функционалам программа Terminal легко нашлась, она находится в каталоге C:\Espressif\utils\

Часть 3: Написание простейших прошивок.

Для того, чтобы начать писать прошивки нужно изучить документацию на сам чип ESP8266 и на SDK, я не стал включать документацию в состав своей сборки Espressif-ESP8266-DevKit, дабы не нарушать разного рода лицензионных соглашений, все таки вся документация идет с пометкой confidential. Тем не менее, в интернете есть масса источников, где её можно раздобыть, например:
Спецификация на чип ESP8266
Описание SDK ESP8266 — это основной документ, который нам понадобится.

В прошлой статье на примере AT-прошивки мы подключались к Wi-Fi точке доступа и запускали TCP-сервер (TCP-клиент) на ESP8266, а так же отправляли тестовые данные на ПК. Как я писал ранее, данный способ не совсем удобен, т.к. для выполнения AT-команд по запуску TCP-сервера (TCP-клиента) требуется отдельный контроллер. Ниже мы рассмотрим пример написания простейшей прошивки для ESP8266, которая реализует все это без внешнего контроллера.
Итак задание:
1. Плата ESP-01 должна переключаться в режим STA (Wi-Fi клиента), устанавливать соединение с нашей AP.
2. После установки соединения с AP необходимо установить TCP-соединение с ПК и отправить тестовую строку.
3. К GPIO0 подключаем кнопку, при замыкании отправляем текстовую строку.
3. Процедуру отправки повторять каждые 5 сек.

Открываем в Eclipse пример wifi-sta-tcp-client из C:\Espressif\examples\
Типичная структуры папок в любом проекте для ESP8266 примерно такая:
wifi-sta-tcp-client
|-Makefile
|-driver
   |-uart.c
|-include
|-user
   |-user_main.c
   |-user_config.h

, где
— файл Makefile — это набор инструкций для программы make, которая помогает собирать наш проект
— каталог driver — содержит драйвера для различных устройств, пока у нас там только файл uart.c, для работы с портом rs232 чипа ESP8266, в принципе там могут быть драйвера для работы с gpio, i2c, spi, pwm и др., смотрите пример IoT_Demo, там более наглядно видно что может быть.
— каталог include — содержит вспомогательные заголовочные файлы, пока там только файлы для работы с портом rs232
— каталог user — основной каталог, в нем находятся основные файлы прошивки, файл user_main.c и user_config.h

Могут присутствовать и другие каталоги, все зависит от модели и принципов разработки, но Makefile настроен именно на такую структуру, и если Вы начнете что-то менять, то придется переписывать инструкции Makefile'а.
В текущем виде для того чтобы добавить доп. каталог с исходниками в сборку достаточно в Makefile в строку
MODULES = driver user
добавить наш новый каталог, например ssl и он будет участвовать в сборке прошивки.
Для добавления доп. библиотек в Makefile'е нужно дополнить строку
LIBS = c gcc hal phy pp net80211 lwip wpa main
нужными нам библиотеками, например если нам нужна в проекте библиотека по работе с json, то пишем
LIBS = c gcc hal phy pp net80211 lwip wpa main json

Открываем файл user\user_main.c

Основная процедура, которая выполняется при старте прошивке это
//Init function 
void ICACHE_FLASH_ATTR
user_init()
{
}

В начало файла user\user_main.c добавляем заголовочные файлы:
#include "ets_sys.h"
#include "osapi.h"
#include "os_type.h"
#include "user_interface.h"
#include "driver/uart.h"
#include "espconn.h"
#include "mem.h"
#include "gpio.h"
#include "user_config.h"

Данные файлы, за исключением user_config.h и driver/uart.h находятся C:\Espressif\ESP8266_SDK\include\
ets_sys.h — спецефичные структуры и определения для работы с событиями и таймерами
osapi.h — таймеры и некоторые системные функции, например os_strcat, os_memcpy, os_delay_us и т.п.
os_type.h — мапинг структур из ets_sys.h
user_interface.h — множество вспомогательных структур и процедур API, в частности для работы с wi-fi, процедуры system_restart, system_deep_sleep и т.д.
espconn.h — основной файл API со структурами и процедурами по работе с TCP и UDP соединениями
mem.h — работа с памятью, os_malloc, os_free и т.п.
gpio.h — вспомогательные структуры и процедуры API для работы с GPIO

Итак пишем в user_init() следующее:
	// Инициализация uart0 и uart1 со скоростью 115200
	uart_init(BIT_RATE_115200, BIT_RATE_115200);
	// Ждем 100 мсек.
	os_delay_us(100);
	#ifdef PLATFORM_DEBUG
	// Вывод строки в uart о начале запуска, см. определение PLATFORM_DEBUG в user_config.h
	uart0_sendStr("ESP8266 platform starting...\r\n");
	#endif
	// Структура с информацией о конфигурации STA (в режиме клиента AP)
	struct station_config stationConfig;
	char info[150];
	// Проверяем если платы была не в режиме клиента AP, то переводим её в этот режим
	// В версии SDK ниже 0.9.2 после wifi_set_opmode нужно было делать system_restart
	if(wifi_get_opmode() != STATION_MODE)
	{
		#ifdef PLATFORM_DEBUG
		uart0_sendStr("ESP8266 not in STATION mode, restarting in STATION mode...\r\n");
		#endif
		wifi_set_opmode(STATION_MODE);
	}
	// Если плата в режиме STA, то устанавливаем конфигурацию, имя AP, пароль, см. user_config.h
	// Дополнительно читаем MAC адрес нашей платы для режима AP, см. wifi_get_macaddr(SOFTAP_IF, macaddr);
	// В режиме STA у платы будет другой MAC адрес, как у клиента, но мы для себя читаем адрес который у неё был если бы она выступала как точка доступа
	if(wifi_get_opmode() == STATION_MODE)
	{
		wifi_station_get_config(&stationConfig);
		os_memset(stationConfig.ssid, 0, sizeof(stationConfig.ssid));
		os_memset(stationConfig.password, 0, sizeof(stationConfig.password));
		os_sprintf(stationConfig.ssid, "%s", WIFI_CLIENTSSID);
		os_sprintf(stationConfig.password, "%s", WIFI_CLIENTPASSWORD);
		wifi_station_set_config(&stationConfig);
		wifi_get_macaddr(SOFTAP_IF, macaddr);
	}
	// Для отладки выводим в uart данные о настройке режима STA
	#ifdef PLATFORM_DEBUG
	if(wifi_get_opmode() == STATION_MODE)
	{
		wifi_station_get_config(&stationConfig);
		os_sprintf(info,"OPMODE: %u, SSID: %s, PASSWORD: %s\r\n",
			wifi_get_opmode(),
			stationConfig.ssid,
			stationConfig.password);
		uart0_sendStr(info);
	}
	#endif

	// Запускаем таймер проверки соединения по Wi-Fi, проверяем соединение раз в 1 сек., если соединение установлено, то запускаем TCP-клиент и отправляем тестовую строку.
	os_timer_disarm(&WiFiLinker);
	os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
	os_timer_arm(&WiFiLinker, 1000, 0);
	// Инициализируем GPIO, 
	BtnInit();
	// Выводим сообщение о успешном запуске
	#ifdef PLATFORM_DEBUG
	uart0_sendStr("ESP8266 platform started!\r\n");
	#endif

Процедура инициализации GPIO
void BtnInit() {
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
	// Выключаем подтягивающий резистор на - (pull down)
	PIN_PULLDWN_DIS(PERIPHS_IO_MUX_GPIO0_U);
	// Включаем подтягивающий резистор на + (pull up)
	PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO0_U);  
	// Переводим GPIO0 на ввод
	gpio_output_set(0, 0, 0, BIT0);
	// Запуск таймера проверки GPIO
	os_timer_disarm(&BtnTimer);
	os_timer_setfn(&BtnTimer, BtnTimerCb, NULL);
	os_timer_arm(&BtnTimer, 500, 1);
}

Процедура проверки сделана в лоб, без какого либо устранения дребезга контактов, по уму нужно делать иначе, так же ниже будет видно, что в senddata не идет никакой проверки на поднятие интерфейса wi-fi, что тоже следует учитывать.
Процедура проверки GPIO
static void ICACHE_FLASH_ATTR BtnTimerCb(void *arg)
{
	if (!GPIO_INPUT_GET(BTNGPIO))
	{
		GPIO_Time_Active++;
	} else {
		if (GPIO_Time_Active != 0)
		{
			#ifdef PLATFORM_DEBUG
			uart0_sendStr("Start sending data...\r\n");
			#endif
			// Отправляем данные
			senddata();
		}
		GPIO_Time_Active = 0;
	}
}

Процедура проверки Wi-Fi подключения (вызывается по таймеру)
static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg)
{
	// Структура с информацией о полученном, ip адресе клиента STA, маске подсети, шлюзе.
	struct ip_info ipConfig;
	// Отключаем таймер проверки wi-fi
	os_timer_disarm(&WiFiLinker);
	// Получаем данные о сетевых настройках
	wifi_get_ip_info(STATION_IF, &ipConfig);
	// Проверяем статус wi-fi соединения и факт получения ip адреса
	if (wifi_station_get_connect_status() == STATION_GOT_IP && ipConfig.ip.addr != 0)
	{
		// Соединения по wi-fi установлено
		connState = WIFI_CONNECTED;
		#ifdef PLATFORM_DEBUG
	        uart0_sendStr("WiFi connected\r\n");
        #endif
		#ifdef PLATFORM_DEBUG
	        uart0_sendStr("Start TCP connecting...\r\n");
        #endif
		connState = TCP_CONNECTING;
		// Отправляем данные на ПК
		senddata();
		// Запускаем таймер проверки соединения и отправки данных уже раз в 5 сек, см. тех.задание
		os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
		os_timer_arm(&WiFiLinker, 5000, 0);
	}
	else
	{
		// Неправильный пароль
		if(wifi_station_get_connect_status() == STATION_WRONG_PASSWORD)
		{
			connState = WIFI_CONNECTING_ERROR;
			#ifdef PLATFORM_DEBUG
			uart0_sendStr("WiFi connecting error, wrong password\r\n");
			#endif
			os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
			os_timer_arm(&WiFiLinker, 1000, 0);
		}
		// AP не найдены
		else if(wifi_station_get_connect_status() == STATION_NO_AP_FOUND)
		{
			connState = WIFI_CONNECTING_ERROR;
			#ifdef PLATFORM_DEBUG
			uart0_sendStr("WiFi connecting error, ap not found\r\n");
			#endif
			os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
			os_timer_arm(&WiFiLinker, 1000, 0);
		}
		// Ошибка подключения к AP
		else if(wifi_station_get_connect_status() == STATION_CONNECT_FAIL)
		{
			connState = WIFI_CONNECTING_ERROR;
			#ifdef PLATFORM_DEBUG
			uart0_sendStr("WiFi connecting fail\r\n");
			#endif
			os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
			os_timer_arm(&WiFiLinker, 1000, 0);
		}
		// Другая ошибка
		else
		{
			os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
			os_timer_arm(&WiFiLinker, 1000, 0);
			connState = WIFI_CONNECTING;
			#ifdef PLATFORM_DEBUG
			uart0_sendStr("WiFi connecting...\r\n");
			#endif
		}
	}
}

Процедура отправки данных на ПК
static void ICACHE_FLASH_ATTR
senddata()
{
	char info[150];
	char tcpserverip[15];
	struct espconn *pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
	if (pCon == NULL)
	{
		#ifdef PLATFORM_DEBUG
		uart0_sendStr("TCP connect failed\r\n");
		#endif
		return;
	}
	pCon->type = ESPCONN_TCP;
	pCon->state = ESPCONN_NONE;
	// Задаем адрес TCP-сервера, куда будем отправлять данные
	os_sprintf(tcpserverip, "%s", TCPSERVERIP);
	uint32_t ip = ipaddr_addr(tcpserverip);
	pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
	pCon->proto.tcp->local_port = espconn_port();
	// Задаем порт TCP-сервера, куда будем отправлять данные
	pCon->proto.tcp->remote_port = TCPSERVERPORT;
	os_memcpy(pCon->proto.tcp->remote_ip, &ip, 4);
	// Регистрируем callback функцию, вызываемую при установки соединения
	espconn_regist_connectcb(pCon, at_tcpclient_connect_cb);
	// Можно зарегистрировать callback функцию, вызываемую при реконекте, но нам этого пока не нужно
	//espconn_regist_reconcb(pCon, at_tcpclient_recon_cb);
	// Вывод отладочной информации
	#ifdef PLATFORM_DEBUG
	os_sprintf(info,"Start espconn_connect to " IPSTR ":%d\r\n",
		   IP2STR(pCon->proto.tcp->remote_ip),
		   pCon->proto.tcp->remote_port);
	uart0_sendStr(info);
	#endif
	// Установить соединение с TCP-сервером
	espconn_connect(pCon);
}

callback функция, вызываемая после установки соединения
static void ICACHE_FLASH_ATTR
at_tcpclient_connect_cb(void *arg)
{
	struct espconn *pespconn = (struct espconn *)arg;
	#ifdef PLATFORM_DEBUG
	uart0_sendStr("TCP client connect\r\n");
	#endif
	// callback функция, вызываемая после отправки данных
	espconn_regist_sentcb(pespconn, at_tcpclient_sent_cb);
	// callback функция, вызываемая после отключения
	espconn_regist_disconcb(pespconn, at_tcpclient_discon_cb);
	char payload[128];
	// Подготавливаем строку данных, будем отправлять MAC адрес ESP8266 в режиме AP и добавим к нему строку ESP8266
	os_sprintf(payload, MACSTR ",%s\r\n", MAC2STR(macaddr), "ESP8266");
	#ifdef PLATFORM_DEBUG
	uart0_sendStr(payload);
	#endif
	// Отправляем данные
	espconn_sent(pespconn, payload, strlen(payload));
}

callback функции, вызываемые после отправки данных и после отключения

static void ICACHE_FLASH_ATTR
at_tcpclient_sent_cb(void *arg) {
	#ifdef PLATFORM_DEBUG
	uart0_sendStr("Send callback\r\n");
	#endif
	// Данные отправлены, отключаемся от TCP-сервера
	struct espconn *pespconn = (struct espconn *)arg;
	espconn_disconnect(pespconn);
}

static void ICACHE_FLASH_ATTR
at_tcpclient_discon_cb(void *arg) {
	struct espconn *pespconn = (struct espconn *)arg;
	// Отключились, освобождаем память
	os_free(pespconn->proto.tcp);
	os_free(pespconn);
	#ifdef PLATFORM_DEBUG
	uart0_sendStr("Disconnect callback\r\n");
	#endif
}

И в заключении видео, с демонстрацией работы этой прошивки

Как Вы уже заметили, плата на чипе Espressif ESP8266 обладает достаточно внушительным потенциалом для написания собственных прошивок.
В следующей статье я приведу пример работы ESP8266 в связке с модулем передатчика nooLite MT1132 и мы попробуем управлять освещением в реальной квартире. Возможно в этой же статье мы разберем работу простейшего Web-сервера для ESP8266.

P.S. Если у Вас возникли вопросы и пожелания, то я буду рад их выслушать, но ввиду низкой кармы я не смогу отвечать оперативно в комментариях, поэтому пишите в ПМ или на email.
Проголосовать:
+22
Сохранить: