open sdk что это
Как работают SDK и API
SDK и API – это инструменты, которые позволяют интегрировать ИТ-продукты с внешними системами. В этой статье мы расскажем, чем отличаются эти два понятия и как разработчики применяют их для своих задач.
Начнём с определений.
API (application programming interface, программный интерфейс приложения) – это набор протоколов и инструментов, которые обеспечивают обмен данными между разными компонентами информационных систем.
Благодаря API мобильные приложения могут легко использовать «Яндекс.Карты» или «Календарь» от Google – обе корпорации предоставляют сторонним разработчикам готовые инструменты, чтобы встраивать эти модули в новые продукты. Это именно интерфейс для подключения к внешней инфраструктуре (в нашем примере – к сервисам Яндекса и Google), который позволяет решать прикладные задачи набором HTTP-запросов.
SDK (software development kit, средства для разработки ПО) решает более масштабную задачу: не просто обеспечить обмен данными между приложением и сторонней инфраструктурой, а реализовать полноценный процесс. Он может включать в себя рабочие компоненты для получения пользовательских данных, их безопасной обработки и хранения, изменения состояний.
В SDK могут входить несколько API, куски вспомогательного кода, обширная документация. Это не просто интерфейс для работы с системой, а готовый набор инструментов для реализации некой бизнес-логики.
Компании создают SDK, чтобы сторонние разработчики могли не погружаться в код, а решать свои задачи через абстракцию – вот этот блок обеспечивает работу личного кабинета, этот позволяет открыть камеру смартфона, и т.д. Безопасность данных, отказоустойчивость вызовов отдельных сервисов реализуются именно через SDK.
Попросту говоря, если API – это рецепт блюда, то SDK – это рецепт, нарезанные продукты, чётко отмеренные специи и набор всех кастрюль-сковородок, которые вам понадобятся в готовке.
В любом нашем продукте используются API заказчиков, чтобы получать данные из клиентской инфраструктуры.
В страховых приложениях мы таким образом подключаемся к бэкенду, чтобы загружать списки полисов, отправлять данные о страховых случаях. В системах учёта продаж и приложениях для кассиров API отвечают за сохранение в бэкенде данных по авиабилетам и выгрузку информации для отчётов.
Это прикладные задачи «местного значения», которые не включают в себя сложную бизнес-логику. Поэтому они решаются посредством API.
Пример, когда возникла необходимость в SDK – это проект по созданию единого модуля для оформления ДТП для страховых приложений. Этот сложный сценарий объединяет авторизацию через ЕСИА, регистрацию происшествия с оформлением европротокола, обмен данными с СТ-ГЛОНАСС АИС ОСАГО, ГИБДД и другими компетентными органами.
Используя SDK, мы можем заключить всю сложную логику в готовый к использованию набор, который затем можно встраивать в любые приложения. Такой модуль включает в себя API для работы с ЕСИА и системами Российского союза автостраховщиков, средства защиты и проверки данных, компоненты для работы с камерой.
В результате у всех страховых компаний, которые будут использовать этот SDK, сценарий оформления происшествий в приложениях будет отвечать единым стандартам. При этом тратить собственные ресурсы на разработку такого сценария им не придётся.
Open sdk что это
Artwork by Hanzheng Tang
Как я уже говорил, ESP8266 можно программировать двумя способами: либо через Arduino IDE, либо через тулчейн esp-open-sdk. Первый вариант я уже рассматривал на примере разработки температурного логера, в этот раз я хочу рассказать о работе с esp-open-sdk.
Тулчейн позволяет программировать на SDK функциях, которые поставляются в закрытых скомпилированных библиотеках называемых SDK. Имеется две версии SDK: RTOS SDK и NONOS SDK. Я буду рассматривать вариант без RTOS, при необходимости, «прикрутить» простенький диспечер задач будет несложно.
Однако, если вы используете фреймворк Arduino, то для вас не доложно быть секретом, что сам он написан на функциях SDK. Т.о. изучение SDK существенно расширит ваши возможности при написании своих библиотек, да и собственно само программирование ESP8266, т.к. функции SDK доступны из Arduino.
Далее речь пойдёт исключительно о тулчейне «esp-open-sdk». В качестве целевой платы я буду использовать плату NodeMCU ESP8266, т.к. там есть автозагрузка прошивки, но в принципе может быть использована любая другая плата на модуле ESP12E/ESP12F.
Посмотреть исходники, сборочные файлы, скачать скомпилированные прошивки, можно с портала GITLAB https://gitlab.com/flank1er/esp8266_sdk_examples
1) Сборка esp-open-sdk
Сборка тулчейна с одной стороны производится легко, всего двумя командами, а с другой стороны, при проблемах со сборкой, все становится очень сложно. Но обо всём по порядку.
Страницей проекта esp-open-sdk является https://github.com/pfalcon/esp-open-sdk, и там же имеется краткая инструкция по сборке тулчейна. Действуя в соответствии с этой инструкцией, перевым делом нужно будет скачать тулчейн:
После чего следует зайти в каталог esp-open-sdk и запустить сборку командой:
Сборка полностью автоматическая и занимает примерно минут 50-60. Первые полчаса происходит скачивание исходников в директорию crosstool-NG/.build/tarballs:
После завершения скачивания, будет распаковка тарболов, наложение патчей и последующая сборка, которая в зависимости от мощности вашего компьютера может занять от 10-15 минут и больше. После завершения сборки, появится сообщение, что для использования тулчейна, следует добавить путь к нему в переменной окружения PATH:
К сожалению, не всегда сборка проходит успешно. Тулчейн нормально собирался у меня в Slackware 14.2 с gcc версии 5.3.0, так же успешно проходила сборка в виртуалке Ubuntu 14.4, которая идёт с официальным тулченом. А вот в Slackware-current с gcc-8.2.0 сборка валится на этапе сборки GDB. В любом случае, если вам не удаётся собрать тулчейн, то следует обратиться к инструкции поэтапной сборки Макса Филипова.
После завершения сборки, также автоматически скачивается и устанавливается SDK версии: ESP8266_NONOS_SDK-2.1.0-18-g61248df.
Чтобы проверить работоспособность тулчейна, следует перейти в директорию examples/blinky, где будет исходник проверочной мигалки:
Командой make собираем прошивку:
Далее имеется неприятный подводный камень. Прошивка будет работать, только если в ESP12 предварительно была записана прошивка AT-интерпретатора (проверьте!).
Подключаем плату NodeMCU к компьютеру и предварительно очищаем флешку командой:
Далее переходим в директорию SDK «sdk/bin» и прошиваем модуль ESP12 AT-интерпретатором:
Теперь возвращаемся в директорию с примером blinky, и загружаем прошивку командой «make flash»:
Если всё было сделано правильно, то светодиод на GPIO_2 начнёт мигать с полупериодом в половину секунды.
Для дальнейших прошивок, загружать прошивку AT-интерпретатора больше не нужно.
2) Создание базового проекта
Сейчас мы напишем свою упрощённую версию тестовой мигалки и свой Makefile для сборки проекта.
Для начала создаём структуру каталогов:
Переходим в каталог 00_blink и создаём файл main.c с исходным текстом мигалки:
Далее добавляем Makefile:
В Makefile я установил стандарт С99, и выставил флаг «-g» для последующей отладки прошивки в gdb. В качестве скрипта компоновщика используется eagle.app.v6.ld.
Структура файлов теперь выглядит так:
Но не все так просто. После пошивки, немого помигав, работа программы остановится. Если перезагрузить esp8266 нажатием на клавишу RST, то мигать будет, но цикл будет иногда сбиваться. ESP8266 постоянно перезагружается и это не дело. С помощью отладчика я выяснил, что происходит сброс по прерыванию Watchdog’а.
Согласно документации на SDK, если какая-либо функция выполняется слишком долго, скажем более 500 мс, то она должна вызывать функцию system_soft_wdt_feed() для сброса сторожевого таймера. Отключение watchdog’а производится вызовом функции system_soft_wdt_stop(), но использовать ее очень сильно не рекомендуют.
В Arduino имеется метод EspClass::wdtDisable(), и если посмотреть его реализацию там есть любопытный комментарий:
Т.е. получается, что совсем отключить watchdog штатными методами не удастся.
С учётом всего вышесказанного, добавляем в главный цикл вызов функции system_soft_wdt_feed():
В каталог inс необходимо будет добавить пока пустой заголовочный файл user_config.h. В этом файле предполагается хранение настроек WiFi: ssid, пароль и т.д. У нас он будет пока пустым.
После пересборки и перепрошивки, перезагрузки eps8266 должны исчезнуть.
В грубом приближении данная программа может служить тестом производительности архитектуры. У esp8266 тактовая частота составляет 80 МГц, у stm32f103c8t6 она равняется 72 МГц. Прошив их одной и той же программой (на уровне Си естественно), и положив обе платы рядом, я бы сказал, что светодиод на esp8266 мигает несколько быстрее.
3) Описание API для работы с GPIO
Наряду с WiFi модулем, GPIO являются для нас самой важной подсистемой в ESP8266. При работе с GPIO нас в первую очередь будет интересовать режим bit-banging на котором строятся программные варианты различных протоколов. С быстродействием у ESP8266 проблем нет, так же как и со свободным местом на флешке, зато есть проблемы со свободными выводами и аппаратными протоколами. На первое время, bit-banging будет у нас вместо лома для ответа на любые технические сложности. Поэтому изучение ESP8266 на мой взгляд логично будет начать с именно с подсистемы GPIO.
Функция gpio_init() которую мы использовали, не описана в ESP8266 Non-OS SDK API Reference, зато её объявление есть в заголовочном gpio.h со следующим комментарием:
Можно предположить, что данная функция сбрасывает GPIO порты в какое-то начальное состояние.
Далее нас будут интересовать следующие макросы:
PIN_PULLUP_DIS(PIN_NAME) Disable pin pull-up /Отключить подтягивающий резистор/. Пример:
//Использовать MTDI пин в качестве GPIO12.
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);PIN_PULLUP_EN(PIN_NAME) Enable pin pull up /Включить подтягивающий резистор/. PIN_FUNC_SELECT(PIN_NAME, FUNC) Select pin function /Выбор функции/. ESP8266 Non-OS SDK API Reference
Используемый в программе макрос PIN_FUNC_SELECT определён в заголовочном файле eagle_soc.h:
Варианты значений FUNC для различных GPIO перечислены тут же:
Честно говоря, мне не понятно, почему в строке:
Функция gpio_output_set
Назначение функции Установка режима GPIO Прототип void gpio_output_set(
uint32 set_mask,
uint32 clear_mask,
uint32 enable_mask,
uint32 disable_mask)Параметры uint32 set_mask : установка высокого логического значения; 1: высокое значение; 0: устанавливать высокое значение не требуется;
uint32 clear_mask : установка низкого логического значения; 1: установить низкое значение; 0: устанавливать низкое значение не требуется;
uint32 enable_mask : включить заданный GPIO на выход
uint32 disable_mask : включить заданный GPIO на вход.Возвращаемое значение отсутствует Примеры gpio_output_set(BIT12, 0, BIT12, 0) : Установить на GPIO12 высокий уровень.
gpio_output_set(0, BIT12, BIT12, 0) : Установить на GPIO12 низкий уровень.
gpio_output_set(BIT12, BIT13, BIT12|BIT13, 0) : Установить на GPIO12 высокий уровен, а на GPIO13 низкий уровень.
gpio_output_set(0, 0, 0, BIT12) : Установить на GPIO12 режим цифрового входа.ESP8266 Non-OS SDK API Reference
Макросы для управления режимом GPIO:
GPIO input and output macros GPIO_OUTPUT_SET(gpio_no, bit_value) Переводит GPIO в режим выхода. GPIO_DIS_OUTPUT(gpio_no) Переводит GPIO в режим входа. GPIO_INPUT_GET(gpio_no) Возвращает логический уровень GPIO находящегося в режиме входа. ESP8266 Non-OS SDK API Reference
Макросы для управления внешними прерываниями:
GPIO interrupt ETS_GPIO_INTR_ATTACH(func, arg) Установить обработчик прерывания ETS_GPIO_INTR_DISABLE() Отключить внешнее прерывание. ETS_GPIO_INTR_ENABLE() Включить внешнее прерывание. ESP8266 Non-OS SDK API Reference
Функция для установки режима внешнего прерывания:
Функция gpio_pin_intr_state_set
Назначение функции установка условия срабатывания внешнего прерывания: по нарастающему фронту, по падающему и т.д. Прототип void gpio_pin_intr_state_set(
uint32 i,
GPIO_INT_TYPE intr_state
)Параметры uint32 i : ID пина. Если вы хотите указать к примеру GPIO14, то пожалуйста тспользуйте: GPIO_ID_PIN(14);
GPIO_INT_TYPE intr_state : условие срабатывания внешнего прерывания:
typedef enum <
GPIO_PIN_INTR_DISABLE = 0,
GPIO_PIN_INTR_POSEDGE = 1,
GPIO_PIN_INTR_NEGEDGE = 2,
GPIO_PIN_INTR_ANYEDGE = 3,
GPIO_PIN_INTR_LOLEVEL = 4,
GPIO_PIN_INTR_HILEVEL = 5
> GPIO_INT_TYPE;Возвращаемое значение отсутствует ESP8266 Non-OS SDK API Reference
Также могут быть интересны функции настойки пробуждения из спящего режима с помощью внешнего прерывания:
Но должен обратить внимание, что они могут работать только в режиме энергосбережения LIGT_SLEEP. Из deep_sleep esp8266 может разбудить только таймер или кнопка Reset.
4) Краткое описание ассемблера Xtensa
На сайте я уже рассматривал ассемблер следующих архитектур: AVR, MSP430, STM8, ARM. Сейчас я предлагаю вкратце познакомиться с ассемблером Xtensa, а точнее, с его вариантом для чипа ESP8266. Как обычно, я ни в коей мере не предлагаю писать прошивки целиком на ассемблере, но считаю, что знание ассемблера целевой архитектуры как минимум полезно. Так же как и в предыдущих случаях, я предлагаю начать знакомство с ассемблером Xtensa через дизассемблирование прошивки.
Основным документом описывающим архитектуру Xtensa является Xtensa Instruction Set Architecture (ISA). Однако, в виду того, что процессоры Xtensa конфигурируемые, а указанный документ описывает общую архитектуру Xtensa, то приходится делать поправки с учётом спецификации esp8266. К счастью, на настоящее время, архитектура esp8266 уже довольно изученная. Хороший обзор основных фишек на английском можно почитать например здесь: http://cholla.mmto.org/esp8266/xtensa.html. Далее я предлагаю вольный перевод этого обзора:
5) Подключение JTAG отладчика на FT232H чипе
FT232H Board
Когда я в последний раз писал о STM32, то упоминал о недорогой плате с чипом FT232H, который может служить одноканальным JTAG отладчиком: «Отладка с помощью JTAG адаптера на чипе FT232H». Я понимаю, что тогда это привлекло мало внимания, т.к. китайские клоны ST-Link выглядят несколько привлекательнее, и ещё один отладчик, это уже не так интересно.
Проект в данное время заброшен, но ребята из VisualGDB сделали форк: https://github.com/sysprogs/esp8266-openocd, в котором была заявлена стабильная работа, им я и предлагаю воспользоваться.
Я собирал проект компилятором gcc-5.3.0. Для корректной сборки пришлось править права на исполняемые файлы, а также в одном заголовочном файле пришлось поправить директиву препроцессора. Преодолев все трудности, я таки заполучил OpenOCD c поддержкой esp8266.
Теперь про подключение esp8266 к JTAG адаптеру. Мне бы не хотелось повторять материал написанный ранее в «Отладка с помощью JTAG адаптера на чипе FT232H», поэтому буду предполагать, что с основами вы уже знакомы.
Для подключения JTAG отладчика будем использовать пины AD0/TCK, AD1/TDI, AD2/TDO, AD3/TMS и пин «земли»:
Для справки, в руководстве на чип можно найти полную распиновку чипа ft232h:
Со стороны esp8266 нам понадобятся следующие пины:
Для подключения JTAG адаптера к NodeMCU нужно соединить «землю» адаптера и «землю» платы NodeMCU. После этого подсоединяем: AD0 к GPIO13/D7, AD1 к GPIO12/D6, AD2 к GPIO15/D8, AD3 к GPIO14/D5. При подключении будем использовать независимое питание на NodeMCU и для JTAG адаптера. Адаптер нужно будет подключить в USB порт компьютера, а NodeMCU можно подключить к компьютеру или зарядке с microUSB.
Я должен предупредить о подводных камнях. В случае подключения JTAG-адаптера и платы NodeMCU к одному компьютеру, подключать следует сначала плату NodeMCU и только потом JTAG-адаптер. Предположим, что у нас в esp8266 залита прошивка мигалки базового проекта. При подключении NodeMCU к компьютеру, на плате начнёт мигать светодиод. Далее, при последующем подключении к компьютеру JTAG-адаптера, светодиод продолжит мигать. И мы будем использовать именно такой порядок подключения.
Если же сделать наоборот, т.е. сначала подключить к компьютеру JTAG-адаптер и только потом NodeMCU, то светодиод мигать не будет, даже если нажать RESET на плате. Такой вариант корректно работать не будет.
Разобравшись с подключением, создадим скрипт для JTAG адаптера:
Назовём его «interface.cfg». Теперь запускаем OpenOCD командой:
В логе получим следующий вывод:
В другом окне запускаем отладчик:
Подключаемся к OpenOCD:
После этого даём команду OpenOCD
В ответ мы должны получить сообщение:
После чего мигание светодиода должно прекратиться, т.к. процессор ESP8266 был остановлен на адресе 0x401000c5.
Командой load загружаем прошивку:
В итоге мы оказываемся в начале выполнения прошиивки:
Если мы поставим точку останова, скажем на функцию dummy_loop, то трассировки у нас не получится, т.к. мы постоянно будем вываливаться в обработчик прерывания watchdog’а.
Вводим команду monitor help и получаем список доступных команд OpenOCD. Нас наиболее будут интересовать эти команды:
Команда esp8266.cpu xtensa_no_interrupts_during_steps enable запретит выполнение прерываний во время трассировки программы.
Теперь ставим точку останова:
И запускаем прошивку на выполнение командой: «continue» или её сокращением: «c«. Далее отладка выполняется обычным образом.
6) Работа с GPIO16 через NonOS-SDK, подключение библиотеки «Driver_Lib»
Теперь, если мы захотим помигать не тем светодиодом, который расположен на модуле ESP12, а тем, что подключен к D0/GPIO16, то на нам придется научится работать с GPIO16.
Пример который у меня впервые заработал, выглядел так:
Это не совсем корректный пример, он работает по тому принципу, что и неисправные часы, которые дважды в день показывают правильное время. Что же здесь происходит?
Первым делом, «мапится» вывод XPD_DCDC (он же GPIO16) в качестве пина ввода-вывода:
Затем GPIO16 переводится в push-pull режим:
В главном цикле, вместо задания GPIO16 высокого или низкого логического уровня, попросту GPIO16 отключается или включается:
Программа некорректная, но создает иллюзию обратного. Что можно сказать по этому коду? Здесь мы имеем сплошное использование макросов, непонятных регистров: PAD_XPD_DCDC_CONF, RTC_GPIO_ENABLE, «магических чисел» навроде: 0xffffffbc или 0xfffffffe.
Определения макросов можно найди в заголовочном файле eagle_soc.h:
Там же можно найти регистры RTC модуля:
Но вот описания этих регистров, вы нигде не найдете.
Корректный вариант программы с последовательным переводом GPIO16 в высокое и низкое логическое значение, выглядит так:
Проблема этого примера в том, что здесь все делается через регистры. Кроме того, по этим регистрам нет никакой документации. Это совсем не то что обещалось в начале: «Данное API позволяет программировать на более высоком уровне не вдаваясь в особенности архитектуры ESP8266». На самом деле, в составе SDK имеется библиотека «driver_lib» c открытыми исходными кодам для работы с GPIO16 и другой периферией. Ее структура выглядит так:
Для примера, файл gpio16.c имеет следующее содержание:
Т.е. весь нужный функционал для работы с GPIO16 в нем уже есть.
Нам потребуется внести изменения в Makefile, чтобы добавить библиотеку в проект:
Тогда программа с использование этой библиотеки будет выглядеть так:
7) Вывод через UART
В ESP8266 имеется два UART интерфейса: UART0 и UART1. UART0 имеет два независимых fifo буфера размером в 128 байт, по опустошению которого или по переполнению, можно вызывать прерывание. К UART0 подключен UART-USB адаптер CP2102 и он является основным интерфейсом. UART1 имеет только одну линию для передачи, он является отладочным интерфесом:
Т.к. к USB у нас подключен UART0, его и попытаемся задействовать. В ESP8266 Non-OS SDK API Reference описаны три функции для работы UART. Первая функция инициализирует UART интерфейс:
Функция uart_init
Назначение функции Устанавливает скорость работы обоих UART интерфейсов Прототип void uart_init (UartBautRateuart0_br, UartBautRate uart1_br) Параметры UartBautRate uart0_br : устанавливаемый битрейт интерфейса uart0;
UartBautRate uart1_br : устанавливаемый битрейт интерфейса uart1;Возможные значения битрейта typedef enum < BIT_RATE_9600 = 9600, BIT_RATE_19200 = 19200, BIT_RATE_38400 = 38400, BIT_RATE_57600 = 57600, BIT_RATE_74880 = 74880, BIT_RATE_115200 = 115200, BIT_RATE_230400 = 230400, BIT_RATE_460800 = 460800, BIT_RATE_921600 = 921600 >UartBautRate; Возвращаемое значение отсутствует. ESP8266 Non-OS SDK API Reference
Следующая функция позволяет переслать содержимое буфера через UART0:
uart0_tx_buffer Назначение Пересылает содержимое буфера через UART0 Прототип void uart0_tx_buffer(uint8 *buf, uint16 len) Параметры uint8 *buf : указатель на буфер, содержимое которого следует переправить через UART0;
uint16 len : длина буфера.Возвращаемое значение отсутствует. ESP8266 Non-OS SDK API Reference
Третья функция может содержать обработчик прерывания интерфейса UART0:
uart0_rx_intr_handler Назначение позволяет установить обработчик прерывания для входящих данных Прототип void uart0_rx_intr_handler(void *para) Параметры void *para: : указатель на RcvMsgBuff структуру. ESP8266 Non-OS SDK API Reference
Остальные функции объявлены в заголовочном файле «driver_lib/include/driver/uart.h«, и никак не документированы:
Но это еще не все неприятности. Дело в том, что просто так добавить в проект файл «driver_lib/driver/uart.c» не получится. В Espressif «забыли» добавить в SDK прототипы функций которые нужны для компиляции модуля. И при попытке компиляции выдаст ошибку об отсутствии объявлений функций ets_isr_mask() и ets_isr_unmask().
Проблема широко известная и легко гуглится, так же как и файл с прототипами недостающих функций. Я взял вариант такого файла у Михаила Григорьева https://github.com/CHERTS/esp8266-devkit/blob/master/Espressif/examples/ESP8266/esphttpd/libesphttpd/include/espmissingincludes.h, закоментировал в нем лишнее для меня пока функции, и положил его в директорию inc текущего проекта.
Т.о. содержимое файла «inc/espmissingincludes.h» получилось таким:
Объявление этого файла нужно будет добавить в «driver_lib/include/driver/uart.h«. Также, модуль uart.o нужно будет добавить в Makefile:
Осталось дело за малым, написать тестовую программу:
Также полезной функцией может os_printf(). C ее помощью можно вывести различную отладочную информацию. Например, составим такую программу: