Как стать автором
Обновить

Диплом специалиста ИБ. Часть №3 — Портативное устройство SmartPulse

Уровень сложностиПростой
Время на прочтение19 мин
Количество просмотров3.9K

Небольшое предисловие

Привет, Хабр!

Данная статья является третьей в цикле “Диплом специалиста ИБ”, в рамках которого я рассказываю про свой опыт написания выпускной квалификационной работы на программе высшего образования “Компьютерная безопасность”. В предыдущей статье я описывал процесс разработки стационарного IoT-устройства “SmartLight” без реализации механизмов защиты из методики обеспечения безопасности устройств Интернета вещей, которая была предложена мной в первой части данного цикла статей. В текущей статье речь пойдет про создание портативного устройства "SmartPulse", в разработку которого была включена реализация наиболее приоритетных механизмов защиты методики.

Если вы не успели ознакомиться с предыдущими статьями данного цикла, советую сначала прочитать их для того, чтобы лучше понимать контекст происходящего.

Портативное устройство SmartPulse

Умный пульсометр по версии нейросети DALL-E
Умный пульсометр по версии нейросети DALL-E

После того, как мной было собрано стационарное устройство SmartLight, я приступил к реализации второго устройства Интернета вещей.

По моей задумке первое устройство должно было быть стационарным, а второе - портативным, для того, чтобы показать разные подходы к демонстрации устройств на защите дипломной работе (а еще я хотел использовать небольшой литий-полимерный аккумулятор, который лежал у меня без дела). Если первым устройством для меня стал умный светильник SmartLight, то вторым я планировал реализовать умный пульсометр SmartPulse.

Задача SmartLight заключалась в демонстрации устройства Интернета вещей, совершенно лишенного каких-либо механизмов защиты. То есть, воссоздание ситуации, когда разработчик вообще не задумывался о безопасности своего устройства.

Со вторым же устройством все должно было быть иначе. SmartPulse должен был выполнить роль в достаточной мере защищенного устройства. Причем защищенного теми механизмами, которые получилось определить как наиболее приоритетные посредством математической модели в процессе реализации методики обеспечения безопасности устройств Интернета вещей. Данное устройство должно было стать физическим доказательством эффективности предложенной мной методики. Поэтому передо мной стояла задача создать небольшой портативный пульсометр, который передавал бы данные по BLE на смартфон и при этом соответствовал бы требованиям безопасности, сочетая в себе наиболее приоритетные механизмы защиты, которые я ранее определил.

Концепт пульсометра с механизмами безопасности

Пульсометр со встроенными механизмами защиты звучит крайне неадекватно. Я осознаю этот момент. Может показаться, что нет смысла обеспечивать безопасность такого рода устройств. Ведь тогда можно шифровать и данные о температуре воды в умном чайнике, или информацию об уровне освещенности в том же SmartLight. Но я хотел бы пояснить свою позицию.

Проблема безопасности Интернета вещей как раз заключается в том, что многие люди не видят смысла защищать хоть как-то условный умный холодильник, который подключен к домашнему Wi-Fi (зачем вообще холодильнику нужен выход интернет - вопрос для дискуссий), или умную лампочку, которой вы можете управлять со своего смартфона по тому же BLE. А это большая ошибка.

В интернете можно найти достаточное количество различных историй о том, как хакеры использовали взломанное IoT устройство для получения доступа к куда более ценным данным пользователя (пример небольшой новостной статьи на эту тему). Зачастую, умные устройства не являются конечной целью взлома, а представляют из себя возможность получить доступ к вашему смартфону, ноутбуку, маршрутизатору или аккаунтам в социальных сетях. К чему-то, где может находиться более ценная информация, чем частота вашего сердцебиения или температура воздуха в вашей квартире. Поэтому идея реализовать хоть какие-то минимальные механизмы защиты в умной люстре на вашей кухне или розетке не лишена здравого смысла. Также я очень часто сталкиваюсь с тем, что многие люди не понимают, каким образом и какую информацию о них можно использовать с целью причинения им какого-либо вреда.

Я не хочу заявлять, что мой итоговый вариант защиты умного пульсометра является наиболее верным и правильным. Цель заключается в ином: продемонстрировать, как это можно сделать. На данный момент я могу исключительно предлагать варианты решения, что я и сделал в первой части.

С концепцией самого SmartPulse на мой взгляд все достаточно просто. Я решил, что хочу, чтобы данное устройство размещалось на запястье пользователя и передавало данные о частоте его сердцебиения, а также уровне заряда аккумулятора (потому что устройство портативное, а это как минимум логично) на небольшой экран на самом устройстве и в мобильное приложение на смартфоне. Ничего сложного и необычного, как в случае с SmartLight и электрохромной пленкой. Решил не усложнять, так как помимо функционала устройства необходимо было реализовать механизмы защиты из методики.

Безопасность SmartPulse

В части обеспечения безопасности устройства мной были выбраны следующие механизмы защиты:

  1. Защищенное подключение: настройка конфигурации модуля спецификации BLE 5.0;

  2. Шифрование данных и прошивки;

  3. Генераторы случайных числовых последовательностей: будет реализовано с помощью библиотеки;

  4. Ограничение доступа к критическим областям памяти;

  5. Ограничение физического взаимодействия: устройство реализовано в формате напульсника, надеваемого на руку;

  6. Распределение ключей шифрования при сопряжении;

  7. Ограничение на количество подключений: программно будет ограничено до одного подключения к устройству;

  8. Использование новейших спецификаций BLE: будет использован модуль, поддерживающий BLE 5.0;

  9. Динамический пин-код для аутентификации: пин-код будет обновляться при каждом включении устройства;

Отмечу, что все вышеупомянутые механизмы защиты принадлежат к классу “наиболее приоритетные” в предложенной мной методике. Специализированный корпус не стал реализовывать из-за сложностей работы с гибкими материалами для возможности ношения устройства на руке. Можно было бы так же разработать пластмассовый корпус, как в случае SmartLight, но решил обойтись без него. Слишком сильно поджимало время.

В данной статье я хочу подробно разобрать пин-код, ограничение на количество подключений, физическое взаимодействие и генератор случайных (скорее все же псевдослучайных) чисел, так как мне нравится связка механизмов, которая из них сформировалась. На мой взгляд, у меня получилось заставить их работать комплексно, а значит более эффективно.

Я руководствовался следующей логикой:

  • во время включения устройства, оно находится на руке пользователя, который его включает;

  • когда устройство включается, срабатывает скрипт генерирования рандомного шестизначного пин-кода, который отображается на экране устройства 5 секунд. Данный пин-код никуда больше не передается. Посмотреть его в дальнейшем будет невозможно. То есть, доступ к нему есть только у человека, который физически надел на себя устройство, а без этого пин-кода не получится получать данные с устройства в мобильном приложении;

  • если к данному устройству была предпринята попытка подключения и чтения значений характеристик сервиса BLE без ввода аутентификационного пин-кода, устройство ограничивает дальнейшее подключение к нему со смартфона пока не будет произведен перезапуск SmartPulse физически. То есть, это может сделать сам пользователь, у которого пульсометр находится на запястье. При этом во время перезапуска устройства будет сгенерирован новый пин-код из 6 цифр;

  • если к данному устройству уже подключен смартфон, то есть осуществляется отправка данных по BLE, SmartPulse выходит из рассылки пакетов на другие возможные устройства в зоне покрытия Bluetooth Low Energy. Иными словами, если к пульсометру уже подключен смартфон пользователя, он не будет отображаться на других смартфонах в принципе. А значит в таком случае не может быть возможности подключиться к нему в то время, как устройство уже передает данные в приложение на смартфоне пользователя.

В последней части статей данного цикла я продемонстрирую процесс НСД на данное устройство, где и будет практически подтверждено все вышесказанное. Еще я хотел бы попробовать совершить атаку на SmartPulse с помощью моего Flipper Zero и понять для себя, насколько я сам смогу обойти защиту на нем. Если хватит времени заняться всем этим, обязательно напишу еще одну статью.

Аппаратная часть

Перейдем к аппаратной части устройства. Не буду изобретать что-то новое, поэтому пойду по той же схеме, что и в статье про SmartLight.

Для начала сопоставим класс электронного компонента с функциональной частью устройства, чтобы понять, что в принципе необходимо для реализации всех его функций.

Электронный компонент

Функционал устройства

Микроконтроллер

Управление устройством и передача данных с помощью технологии BLE

OLED дисплей

Вывод данных о заряде аккумулятора и пульсе, а также кратковременный вывод случайного пин-кода при включении устройства для аутентификации в процессе сопряжения

Датчик пульса

Определение частоты сердечного ритма

Датчик напряжения

Мониторинг напряжения на аккумуляторе, на основании чего в дальнейшем происходит расчет уровня его заряда

Модуль контроллера заряда

Функция зарядки аккумулятора

Литий-полимерный аккумулятор

Автономное питание устройства

Сенсорный датчик прикосновения

Включение и выключение OLED дисплея

Тактовая кнопка

Включение и выключение устройства

Датчик напряжения, модуль заряда, аккумулятор и кнопка по сути своей входят в один логический блок, поэтому рассмотрим их вместе.

Питание устройства

SmartPulse является портативным устройством, а значит ему необходим аккумулятор. Как я уже писал ранее, у меня под рукой был только литий-полимерный аккумулятор на 320 mAh, поэтому я решил использовать его.

Литий-полимерные (Li-Po) аккумуляторы представляют собой тип литий-ионных батарей, которые используют полимерный электролит вместо жидкого. Эта технология была разработана для улучшения характеристик и безопасности по сравнению с традиционными литий-ионными аккумуляторами.

Данный аккумулятор нужно было каким-то образом заряжать, поэтому я добавил в схему модуль контроллера заряда аккумулятора типа TP4056, который представляет из себя эффективное устройство для управления подзарядкой подобного рода источников питания. Этот модуль обеспечивает оптимальную зарядку, адаптируясь к специфическим характеристикам аккумулятора, а также имеет встроенные функции защиты от перезаряда и глубокого разряда, которые гарантируют безопасность аккумулятора, предотвращая его повреждение и обеспечивая надежность в использовании (по словам производителя).

Так как в устройстве используется аккумулятор, то существует необходимость знать уровень его заряда, чтобы вовремя осуществлять подзарядку. Для этих целей я решил воспользоваться датчиком напряжения и тока CJMCU-219 на чипе INA219. Для определения уровня заряда аккумулятора я использую метод расчета параметров тока, потребляемого аккумулятором, и напряжения на его контактах, что как раз и фиксирует датчик. Таким образом можно определять, работает ли аккумулятор в полную силу или нет, по оценке чего возможно сделать выводы об уровне его заряда. Метод далеко не точный, и в коммерческих продуктах используются другие средства, но тем не менее, он оказался рабочим, а большего мне было и ненужно в рамках дипломной работы.

Естественно, SmartPulse нужно было каким-то образом включать и выключать, чтобы экономить заряд аккумулятора. Поэтому я добавил в схему кнопку. Про нее добавить нечего, так как она просто пускает ток к микроконтроллеру при замыкании цепи.

Отображение информации

Для вывода информации о пульсе и заряде аккумулятора я решил использовать OLED дисплей 0.96 дюйма с разрешением 128х64 пикселей. Не думаю, что есть смысл особенно подробно что-то писать про технологию OLED или про сам дисплей, так как учитывая то, что вы в данный момент читаете эту статью на экране вашего устройства, про такие вещи вы явно слышали, а более глубокого понимания в рамках проекта не требуется.

Датчик прикосновения (touch sensor) я решил добавить для того, чтобы у пользователя была возможность включать или выключать дисплей, не выключая при этом устройство. Это нужно, к примеру, если у пользователя нет потребности в данный момент фиксировать свой пульс на запястье во время выполнения тренировки, а за показателями его сердцебиения наблюдает тренер с помощью смартфона.

Микроконтроллер

В качестве управляющей платы для портативного устройства я выбрал WeAct Studio ESP32-C3Fx4 Mini Core, основанную на чипе ESP32-C3FH4. Основным фактором для такого решения является реализация более новой версии BLE по сравнению с микроконтроллером в устройстве SmartLight. Также размеры микроконтроллера сыграли определенную роль в пользу выбора данного чипа и конкретно этой платы.

Распиновка WeAct Studio ESP32-C3Fx4 Mini Core
Распиновка WeAct Studio ESP32-C3Fx4 Mini Core

Схема подключения компонентов

После того, как были подобраны все необходимые электронные компоненты для будущего устройства, я разработал схему их подключения к плате микроконтроллера.

Схема подключения электронных компонентов
Схема подключения электронных компонентов

Этап с реализацией данной схемы на макетной плате также как и в случае с предыдущим устройством придется опустить, потому что я имею вредную привычку не делать фотографии макеток.

Программная часть

Так же как и в случае со стационарным устройством, после сборки схемы на макетной плате, я приступил к написанию программной части устройства.

Среда разработки и язык программирования

Здесь есть четкие различия между устройствами. Напомню, что для программирования SmartLight я использовал среду разработки Arduino IDE и версию C++, которая в ней интегрирована. Для написания программной части SmartPulse было необходимо спуститься на уровень ниже для реализации механизмов защиты и наиболее эффективного использования возможностей ESP32-C3.

Чтобы воплотить это в жизнь, я решил воспользоваться средой разработки ESP-IDF, которая идеально подходит к микроконтроллерам серии ESP (потому что она была написана для них), а также языком программирования C. Подробно писать про ESP-IDF не буду, поэтому просто оставлю ссылку на официальную документацию.

Для того, чтобы начать использовать данную среду разработки для написания прошивки, необходимо подключить микроконтроллер к компьютеру и выбрать соответствующий COM-порт. После выбора порта и создания репозитория с прошивкой, загрузить код на устройство возможно с помощью команды idf.py flash после предварительной сборки проекта.

Если кому-то нужно чуть более подробно и понятно почитать про среду разработки, оставлю туториал. Но вообще советую читать официальную документацию (больно, но полезно).

Прошивка

Также как и в случае стационарного устройства, не вижу смысла выкладывать здесь полный код устройства. Он доступен в приложениях к ВКР и в репозитории проекта SmartPulse на GitHub. В рамках статьи разберем только ключевые моменты реализации механизмов безопасности и наиболее основные фрагменты кода.

Предлагаю вновь разбить код на структурные блоки по функционалу:

Структурный блок

Назначение и функционал

Подключение библиотек

Импорт стандартных библиотек C и специализированных библиотек для FreeRTOS, ESP32, BLE

Определение констант и переменных

Объявление глобальных переменных

Функционал BLE

Настройка и управление BLE-сервером и характеристиками, использование стека NimBLE на ESP32 для управления соединениями и обработки событий BLE

Дисплей

Работа с OLED дисплеем через библиотеку SSD1306

Обработка данных с пульсометра

Считывание и обработка данных пульса через, фильтрация и усреднение сигналов

Обработка данных об уровне заряда аккумулятора

Измерение напряжения аккумулятора, вычисление уровня его заряда

Обработка данных с датчика касания

Включение и выключение дисплея на основе данных с датчика касания

Обеспечение безопасности

Реализация механизмов защиты: генерация случайного пин-кода, настройка параметров безопасности BLE, доступ к данным о пульсе и заряде аккумулятора только для аутентифицированных пользователей

В первом блоке подключаются стандартные библиотеки C: stdio.h, stdlib.h и string.h, которые обеспечивают базовые функции для ввода-вывода, работы с памятью и строками, а также специализированные библиотеки для работы с FreeRTOS, ESP32 и BLE: freertos/FreeRTOS.h, freertos/task.h, esp_log.h, driver/i2c.h, driver/adc.h, driver/gpio.h, и так далее.

Для работы с Bluetooth Low Energy на ESP32 используются библиотеки ESP-NimBLE. Этот фреймворк представляет собой порт стека NimBLE, адаптированный для работы с чипами семейства ESP32. Основная библиотека esp_nimble_hci.h обеспечивает функциональность интерфейса хоста контроллера (HCI), позволяя взаимодействовать с контроллером Bluetooth на данном уровне.

Для интеграции стека NimBLE с операционной системой FreeRTOS используются библиотеки nimble/nimble_port.h и nimble/nimble_port_freertos.h.

Библиотека host/ble_hs.h является основным инструментом для работы со стеком NimBLE на уровне хоста. Она включает в себя функции для управления состоянием BLE, к примеру, управление соединениями и рассылкой. Для управления GAP и GATT используются соответственно services/gap/ble_svc_gap.h и services/gatt/ble_svc_gatt.h.

Для тех, кого пугают аббревиатуры GAP, GATT, SMP и прочее, оставляю ссылку на разбор стека протоколов технологии BLE.

В данном устройстве реализованы наиболее приоритетные механизмы защиты из методики обеспечения безопасности, но подробно рассмотрим те, что наиболее эффективно работают в связке: генерация случайного пин-кода, а также механизмы для обеспечения доступа к данным только аутентифицированными пользователями.

Для повышения безопасности соединения между устройствами используется метод генерации случайного пин-кода. Для формирования случайной (или все же псевдослучайной) последовательности, я решил использовать библиотеку esp_random.h. Возможности данной библиотеки я реализую посредством функции generate_random_passkey, которая создает шестизначный код для аутентификации пользователя.

void generate_random_passkey() 
{
    uint32_t random_num = (esp_random() % 900000) + 100000; // Генерация случайного числа 
    snprintf(passkey, sizeof(passkey), "%06lu", random_num); // Форматирование числа в строку
    ESP_LOGI(TAG, "Generated passkey: %s", passkey); // Логирование сгенерированного кода
}

Данную комбинацию необходимо ввести на подключенном устройстве для возможности чтения значений характеристик пульса и уровня заряда аккумулятора. Случайность пин-кода значительно усложняет потенциальные попытки несанкционированного доступа, так как каждое новое соединение требует ввода нового пароля.

Как можно видеть в разбираемом фрагменте кода, я немного схитрил и вместо реализации 1000000 различных вариаций пин-кода от 000000 до 999999 по факту использую комбинации от 100000 до 999999. Это сокращает количество всевозможных вариантов, но данное решение не отражается на безопасности устройства, так как сгенерированный код необходимо ввести сразу после включения устройства, а после успешного сопряжения со смартфоном, SmartPulse более будет недоступен для подключения к нему с любых других устройств, что делает бессмысленным перебор различных комбинаций пин-кода для аутентификации.

Далее этот пин-код будет храниться в переменной passkey. Когда пользователю в процессе сопряжения необходимо будет ввести пароль, он по сути, сделает запись в значение характеристики BLE устройства, которое будет сравниваться с passkey. На основе данного действия и будет произведена аутентификация.

Пришлось реализовать “в лоб”, но по хорошему, я бы советовал все же подключать хоть какую-то легковесную криптографию или просто хэширование подобных вещей. Не должно быть настолько явных проверок аутентификационных комбинаций. Такой способ все же является небезопасным сам по себе, но когда времени на более сложную защиту недостаточно (как раз мой случай), можно реализовать это хотя бы так.

static int device_write_pincode(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) 
{
    size_t om_len = OS_MBUF_PKTLEN(ctxt->om); // Получение длины пакета из контекста GATT
    char pincode[7]; // Массив для хранения пин-кода
    // Преобразование данных из mbuf в массив
    int rc = ble_hs_mbuf_to_flat(ctxt->om, pincode, sizeof(pincode) - 1, &om_len); 
    if (rc != 0) {
        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; // Возврат ошибки
    }
    pincode[om_len] = '\0';

    if (strcmp(pincode, passkey) == 0) { // Сравнение полученного пин-кода с сохраненным
        is_authenticated = true; // Установка флага аутентификации в случае успеха
	 // Логирование успешной аутентификации
        ESP_LOGI(TAG, "Authenticated with pincode: %s", pincode); 
    } else {
        is_authenticated = false; // Сброс флага аутентификации в случае несовпадения
        ESP_LOGE(TAG, "Invalid pincode: %s", pincode); // Логирование ошибки
    }

    return 0; // Возврат 0 в случае успешной обработки функции
}

После записи аутентификационного пин-кода пользователем в мобильном приложении, происходит проверка флага true или false в характеристиках значений сердцебиения и уровня заряда аккумулятора. Передача переменных в значения характеристик происходит только после проверки значения флага аутентификации.

Снова скажу, что я бы не рекомендовал проделывать такие операции в явном виде, так как если постараться найти возможность изменить значение самого флага is_authenticated, можно получить доступ к передаваемой информации без введения пин-кода вообще, чего быть не должно ни при каком условии. Я реализовал таким образом, потому что разрабатывал устройство для экспериментального стенда в рамках дипломной работы в условиях сильной нехватки времени. Если речь идет про разработку коммерческого продукта даже в рамках условного стартапа и при наличии относительно небольшой командой, я совершенно не рекомендую делать так, как сделал я.

Напомню, что цель моей работы - продемонстрировать новый подход к обеспечению безопасности устройств Интернета вещей на основе расчета показателей приоритета механизмов защиты с помощью математической модели в рамках ограниченных ресурсов для разработки, а не осуществить идеальный цикл безопасной разработки устройства IoT (хотя я бы очень хотел).

static int device_read_Pulse(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    if (!is_authenticated) { // Проверка состояния аутентификации
        return BLE_ATT_ERR_INSUFFICIENT_AUTHEN; // Возвращение ошибки
    } else {
	 // Добавление значения пульса в буфер передачи
        os_mbuf_append(ctxt->om, &Pulse, sizeof(int)); 
        return 0; // Возвращение 0, указывая на успешное выполнение
    }
}

static int device_read_Bat(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    if (!is_authenticated) { // Проверка, прошел ли пользователь аутентификацию
        return BLE_ATT_ERR_INSUFFICIENT_AUTHEN; // Возвращение ошибки
    }
    else {
	 // Добавление значения заряда батареи в буфер передачи
        os_mbuf_append(ctxt->om, &Bat, sizeof(int)); 
        return 0;
    }
}

Как было описано ранее, для отображения аутентификационного пин-кода я использовал OLED дисплей самого устройства, чтобы код изначально мог видеть только пользователь устройства, на котором оно надето. При каждом новом включении устройства пин-код генерируется заново и на 5 секунд отображается на дисплее SmartPulse.

Код для вывода пин-кода на дисплей устройства с задержкой в 5 секунд можно увидеть ниже.

  ssd1306_clear_screen(&dev, false); // Очистка экрана OLED дисплея
  ssd1306_contrast(&dev, 0xff); // Установка контрастности экрана
  ssd1306_display_text(&dev, 0, "PIN", 3, false); // Отображение текста "PIN" на экране
  ssd1306_display_text(&dev, 2, passkey, 6, false); // Отображение сгенерированного пин-кода
  vTaskDelay(5000 / portTICK_PERIOD_MS); // Задержка на 5 секунд
  ssd1306_clear_screen(&dev, false); // Очистка экрана после задержки

Ограничение на возможное количество подключений к устройству SmartPulse было реализовано в меню конфигурации ESP-IDF посредством sdkconfig (можно использовать команду idf.py menuconfig, тут кому что больше нравится). Так как в данном проекте используется технология BLE, в настройках необходимо включить Bluetooth и выставить режим NimBLE – только BLE. Здесь же реализуются некоторые настройки безопасности BLE.

Содержимое sdkconfig
Содержимое sdkconfig

Перейдем к реализации BLE в коде устройства. Некоторые фрагменты, связанные с Bluetooth Low Energy, я уже продемонстрировал на этапе с разбором пин-кода. К ним возвращаться не будем. Если вспомнить, как происходило написание кода для реализации BLE в SmartLight, то можно понять, что по сути, необходимо задать BLE сервер, которому нужно дать название, отображаемое в списке доступных для подключения устройств. Это профиль устройства. В данном случае инициализация сервера будет происходить следующим образом.

  nimble_port_init(); // Инициализация порта NimBLE 
  ble_svc_gap_device_name_set("SmartPulse"); // Установка имени устройства
  ble_svc_gap_init(); // Инициализация GAP для Bluetooth
  ble_svc_gatt_init(); // Инициализация GATT для Bluetooth
  rc = ble_gatts_count_cfg(gatt_svcs); // Подсчет конфигураций GATT сервисов
  assert(rc == 0); // Проверка успешности операции подсчета
  rc = ble_gatts_add_svcs(gatt_svcs); // Добавление GATT сервисов
  assert(rc == 0); // Проверка успешности операции добавления
  ble_hs_cfg.sync_cb = ble_app_on_sync; // Установка функции обратного вызова
  nimble_port_freertos_init(host_task); // Инициализация NimBLE с использованием FreeRTOS  

Далее должны быть созданы сервисы, которые будут хранить в себе характеристики с тремя доступными свойствами, значениями и дискрипторами. Аналогичным образом реализуем данный этап для SmartPulse.

static const struct ble_gatt_svc_def gatt_svcs[] = 
{
    {
        .type = BLE_GATT_SVC_TYPE_PRIMARY, // Тип сервиса
        .uuid = BLE_UUID16_DECLARE(0x180), // UUID сервиса
        .characteristics = (struct ble_gatt_chr_def[]){ // Массив характеристик сервиса
            {
                .uuid = BLE_UUID16_DECLARE(0xFEF3), // UUID характеристики для пин-кода
                .flags = BLE_GATT_CHR_F_WRITE, // Свойства характеристики: только запись
                .access_cb = device_write_pincode, // Функция обратного вызова
                .val_handle = &auth_handle, // Указатель на дескриптор значения
            },
            {
                .uuid = BLE_UUID16_DECLARE(0xFEF4), // UUID характеристики для пульса
                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, // Чтение и уведомление
                .access_cb = device_read_Pulse, // Функция обратного вызова для чтения пульса
                .val_handle = &pulse_val_handle, // Указатель на дескриптор значения пульса
            },
            {
                .uuid = BLE_UUID16_DECLARE(0xFEF5), // UUID характеристики для заряда батареи
                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, // Чтение и уведомление
                .access_cb = device_read_Bat, // Функция обратного вызова
                .val_handle = &bat_val_handle, // Указатель на дескриптор значения заряда батареи
            },
            {0}, // Обнуление массива характеристик
        },
    },
    {0}, // Обнуление массива сервисов
};

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

void ble_notify(uint16_t attr_handle, int value)
{
    if (!is_authenticated) { // Проверка, аутентифицирован ли пользователь
        return; // Выход из функции, если пользователь не аутентифицирован
    }
    else {
	 // Создание буфера сообщений из значения
        struct os_mbuf *om = ble_hs_mbuf_from_flat(&value, sizeof(value)); 
	 // Отправка уведомления с использованием измененного значения
        int rc = ble_gattc_notify_custom(conn_handle, attr_handle, om); 
        if (rc) {
            ESP_LOGE(TAG, "Error sending notification; rc=%d", rc); // Логирование ошибки
        }
    }
}

Именно данную функцию с параметрами в дальнейшем вызываем при работе устройства для изменения значений в соответствующих характеристиках сервиса BLE. 

if (conn_handle != 0){ // Проверка на наличие активного BLE подключения
  ble_notify(pulse_val_handle, Pulse); // Отправка уведомления о пульсе
  ble_notify(bat_val_handle, Bat); // Отправка уведомления об уровне заряда батареи
}

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

Корпус

Как таковой корпус для SmartPulse я решил не делать. Стараться делать аналог фитнес-трекера или умных часов, наслаивая платы друг на друга, мне не хотелось. Для меня было важно обеспечить себе доступ ко всем электронным компонентам устройства, чтобы была возможность их заменить или перепаять в случае чего. Вдобавок, мне хотелось, чтобы вся реализация схемы, которую я в этой статье уже размещал, была в явном виде продемонстрирована у меня на запястье во время защиты выпускной квалификационной работы. Поэтому я решил воспользоваться достаточно простым способом - прикрепить все платы к тканному напульснику Nike одного известного спортивного бренда, названного в честь греческой богини победы, Ники, который я специально ради этого купил.

Мне не хотелось пришивать сами платы, потому что это было как минимум неудобно. К примеру, тот же touch сенсор было бы проблематично пришивать к напульснику, так как в его плате нет даже намека на какие-либо отверстия или крепления, которые бы позволили мне сделать что-то подобное. Поэтому я нашел другой выход из это ситуации и купил ленты липучек.

Я действовал из той логики, что можно не пришивать сами платы к напульснику, а для их крепления достаточно будет пришить только липучку, на которую уже нужно будет прикрепить плату с цепкой частью липучки. В итоге так я и сделал. Так как мои навыки шитья оставляют желать лучшего, я безумно благодарен Ане (@ShabrovaAS), которая проделала этот процесс за меня.

Очень удобно, когда твоя девушка умеет чертить (что помогло в подготовке чертежей корпуса для SmartLight) и шить (что облегчило мне жизнь уже в рамках подготовки напульсника для SmartPulse).

Устройство перед монтажом компонентов и подготовленная основа напульсника
Устройство перед монтажом компонентов и подготовленная основа напульсника

Финальная сборка устройства

После того, как напульсник был готов для монтажа на него всех электронных компонентов, я приступил к пайке. Это был достаточно долгий этап, так как паять было не особо удобно, а контакты находились очень близко друг к другу (простите за не особо аккуратную пайку). Но в итоге у меня получилось собрать финальную версию SmartPulse.

Процесс пайки электронных компонентов и прошивка готового устройства
Процесс пайки электронных компонентов и прошивка готового устройства

Так же как и в случае со SmartLight, я не хочу называть его готовым устройством и предпочитаю слово “прототип”. Потому что по моему личному мнению, готовое устройство не может выглядеть, как напульсник с прикрепленными к нему микросхемами. В любом случае, для демонстрации такого рода устройств в рамках дипломной работы на защите этого было более чем достаточно, и результатом я остался удовлетворен.

Собранное устройство SmartPulse
Собранное устройство SmartPulse

Как я уже упоминал, в статье не будет продемонстрирован сам функционал устройства в процессе его работы. Данная часть будет раскрыта в следующей статье, в рамках которой будет рассмотрен процесс создания мобильного приложения для управления созданными в предыдущих частях устройствами Интернета вещей SmartLight и SmartPulse. Но для того, чтобы все же показать то, как именно выглядит работающее устройство SmartPulse у меня на запястье, прикрепляю фотографии с демонстрацией этого.

Генерирование динамического пин-кода при включении устройства и вывод показателей пульса и заряда аккумулятора на экран
Генерирование динамического пин-кода при включении устройства и вывод показателей пульса и заряда аккумулятора на экран

В следующей части данного цикла статей будет рассмотрен процесс создания мобильного приложения Smart Connect для управления ранее созданными IoT-устройствами SmartLight и SmartPulse.

Я благодарен всем, кто уделил время для прочтения данной статьи. Был бы безумно рад получить фидбек в виде комментариев, чтобы улучшать качество материала.

Что дальше?

Так как дипломная работа получилась достаточно объемной, я решил разбить ее на несколько связанных статей: 
1. Диплом специалиста ИБ. Часть №1 - Методика обеспечения безопасности устройств Интернета вещей 
2. Диплом специалиста ИБ. Часть №2 - Стационарное устройство SmartLight 
3. Диплом специалиста ИБ. Часть №3 - Портативное устройство SmartPulse 
4. Диплом специалиста ИБ. Часть №4 - Мобильное приложение Smart Connect 
5. Диплом специалиста ИБ. Часть №5 - Несанкционированный доступ к IoT-устройствам с BLE

С оригиналом ВКР можно ознакомиться тут

Теги:
Хабы:
Всего голосов 5: ↑5 и ↓0+5
Комментарии6

Публикации

Истории

Работа

Ближайшие события