Инициализируем службу. информации об устройстве функцией DevInfo_AddService (). Задаем имя.


Чтобы посмотреть этот PDF файл с форматированием и разметкой, скачайте его и откройте на своем компьютере.
Студент

Орешкин Константин Александрович

/…………………/




Факультет

ИВТ

Группа

ИП
-
312



Руководитель


Гонцова Александра Владимировна


/ …………..……/













Федеральное агентство связи

Фе
де
ральное государственное

бюджетное образ
овательное

учреждение

высшего образования

«Сибирский государственный университет телекоммуникаций и информатики»

(СибГУТИ)


ВЫПУСКНАЯ
КВАЛИФИКАЦИОННАЯ РАБОТА
БАКАЛАВРА

Разработка микроконтроллерного устройства



Умные часы



Пояснительная записка






Кафедра ВС

Допустить к защите

зав. кафедрой:

доцент
, д.т.н.


___________
___________

Курносов М. Г.

Н
овосибирск
2017

г.




Содержание

Ведение

3

1 Постановка задачи

................................
................................
................................
....................

4

1.1 Анализ предметной области

................................
................................
................................
...........

4

1.2 Формулировка задачи

................................
................................
................................
.........................

4

2 Средства разработки и аппаратная платформа

................................
..............................

5

2.1 С
пецификация

................................
................................
................................
...................

5

2.2 Выбор аппаратной пл
атформы

................................
................................
................................
......

9

2.
3
Характеристики
CC
2650

................................
................................
................................
...................

9

2.4 Набор разработчика

................................
................................
................................
............................

12

2.5
Операционная система рольного времени TI
-
RTOS

................................
..............

13

3
О
писание разработки программного обеспечения

................................
.....................

15

3.1 Архитектура программного обеспечения микроконтроллерного
устройства

14

3.2 Описание исходного кода
................................
................................
................................
.

21

4 Тестирование устройства

................................
................................
................................
.....

24

Заключение

................................
................................
................................
................................
...

25

Приложение А

................................
................................
................................
.............................

26

Приложение Б

................................
................................
................................
..............................

27













2



Введение

Носимая
электроника и умные часы в частности


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

Носимая
электроника выполняет ряд задач
:



Базовый функционал часов
:
время, дата, будильник
;



Учет метрики: шаги, пульс, пройденное расстояние и т.д.
;



Уведомления о сообщениях и звонках
;



Управление функциями смартфона
;



Сре
дство

идентификации

(роль пропуска и платежного средства).

Большинство
современных
умных ча
сов

могут
выполнять свои задачи

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

AndroidWea
r

и

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

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

Стоит выделить отдельный фитнесс браслеты


это отдельный класс
носимой электроники. Главная задача
фитнесс браслетов


это

подсчёт
физ
ической активности и последующие предоставления аналитической
информации.

Проанализировав рынок подобных устройств было принято решение

разработать аналогичное устройство. Главным отличием устр
ойства должно
быть

низкое энергопотребление. В тоже время устро
йство должно обладать
экраном для отображения информации.


В рамках данного проекта необходимо разобраться в стеке

так
как это наиболее популярный способ обмена информацией с носимыми
устройствами. И подробней разобраться в протокол
Blueto
oth

Low
Energy

так
как наиболее подходящий протокол

стека.


Нужно проанализировать рынок микроконтроллерных решений для
решения подобной задачи. На основе анализа выбрать оптимально аппаратное
решение.

Разработать интерфейс понятный пользователю
. И реализовать обмен
информации с мобильным телефоном по средствам

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






3


1 Постановка задачи

1.1
Анализ предметной о
бласти

Задача заключается в

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

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

На экране устройства должен быть интуитивно понятный интерфейс.
Дата и время должны настроится со смартфона


1.2 Формулировка задачи

Для реализации

Необход
имо выбрать аппаратную платформу

с интегрированным
беспроводным модулем. Также платформа должна обладать низким
энергопотреблением.

Разработать пользовательский интерфейс. Экран устройства должен
отображать: время, дату, иконки уведомлений о звонках и сооб
щения
х.

Устройство должно обладать кнопками для управления
мультимедийными функциями.
















4


2 Средства раз
работки и аппаратная платформа


2.1 Спецификация

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


-

спецификация беспроводных

персональных сетей,

обеспечивающих
обмен информацией
.
Спецификация Bluetooth была
разработана группой

Bluetooth Special Interest Group
,
которая была основана
в

1998 году
. В неё вошли компании

Ericsson
,

IBM
,

Intel
,

Toshiba

и

Nokia
.
Впоследствии Bluetooth SIG и IEEE достигли соглашения, на основе которого
спецификация Bluetooth стала частью стандарта IEEE 802.15.
Принцип
действия основан исп
ользовании радиоволн.


1.0
был представлен в 1998 и имел плохую совместимость
между решения различный компаний.

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


1.1 было множество исправлений, появилась поддержка
нешифрованных каналов и индикации уровня мощности принимаемого сигнала.


1.2 стандарт улучшил скорость подключения, обнаружения
,
стойкость к радиопо
мехам. Скорость передачи данных повышена до ! Мбит/с.
Расширенные Синхронные Подключения, которые улучшали передачу
аудиопотока, позволили повторную передачу пакетов и добавили задержку
аудио для организации лучший поддержки параллельной передачи данных
До
бавлена подержка
UART

и упровления потоками данных и повторной
передачи.


2.0 +
EDR

стандарт был
выпушен 10 ноября 2004 г. Совместим
с приведшими версиями стандарта. Главным нововведением стала поддержка
Enhanced

Data

Rate
.
Этот режим позволял пов
ысить скорость передачи данных
до
3
Мбит
/
c
. Упрошено подключение нескольких устройств, благодаря
дополнительной полосы пропускания. Благодаря уменьшению нагрузки
снижено потребление энергии.


2.1 стандарт
был принят
в 2007 году.
Добелена технологи
я
получения расширенного списка характеристик устройства. Добавлена
технология энергосбережения, которая увеличила время работы от одно заряда
в 3
-
9 раз. Упрошена и ускорены механизмы установления связи. Повышена
замешанность соединения.


2.
1 +
EDR

был показан

в 2008 году. Потребление энергии
снижено в 5 раз, повышен уровень защиты и облегчено распознавание.



3.
0

+

HS

стандарт был представлен в 2009 году. Поддерживает
теоретическую скорость до 24 Мбит/с. Добавлен
AMP

(
Alternate

MA
C
/PHY
)

как
высоко
высокоскоростное сообщение. Модули содержат в себе две
5


радиосистемы. Первая обеспечивает возможность передачи данных на скорости
24 Мбит/с. А вторая с низким энергопотреблением и скоростью 3 Мбит
/
c
.



4.0

был выпушен в 2010 году
включил в себя 3 протокола
:



Классический



Высоко
скоростной




с низким энергопотреблением

Высокоскоростной

реализован на принципах
Wi
-
Fi
.
В свою
очередь классический

построен на протоколах приведшего поколения.

А
протокол

Bluetooth

Low
Energy
(низкое энергопотребление). Главным
достоинством протокола
Bluetooth

Low
Energy

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

от одного заряда
аккумулятора.


Blue
tooth

4.1 стандарт был выпушен в 2013 году. И главное изменения
заключалась в защите от взаимных помех
со связью четвертого поколения
LTE
.


4.2 стандарт 2014 года повысил конфиденциальность и
увеличил скорость передачи данных.


5.
0

станда
рт 2016 года улучшены протоколы низкого
энергопотребления и высокоскоростной. Улучшена скорость и радиус действия.


Подробно рассмотрим протокол

Low
Energy
.

использует частоты
2,402 ГГц
-

2,48 ГГц
.

Три частоты

(на рисунке 2.1.1
, кан
алы
37, 38, 39)

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

является
псевдослучайный

выбор частоты для передач
и следующего пакета
.













Все данные в пакетах

Low
Energy

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

Рисунок
2.1
.1



Линейка используемых частот

6



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

Advertising

пакетах обозначенный
как

Manufacturer Specific Data
. Компьютер или планшет могут принимать
данные с сотен таких передатчиков без лишних предварительных действий по
поиску, установлению соединения, вводу пинкода и проч.


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


пакет

ScanRequest
, ответ модуля


пакет

ScanResponce
). Этим

BLE

существенно отличаются от

Wi
-
Fi
, где даже
для простейшего термометра надо устанавливать соединение, отнимающее
ресурсы
.
[1]

Ниже на рису
нке дано представление

BLE

как его видит программист
микроконтроллеров. Стек BLE состоит из двух программных
частей:

Host

и

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

Host

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

Controll
er

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

интерфейсом

HCI

(
Host Controller Interface
).
В реализации для ПК
часть

Host

работает
на компьютере, а часть

Controller

работает в аппаратном
приемо
-
передатчике

Bluetooth
, а протокол

HCI

чаще всего передаётся по

USB
.
В реализации на микроконтроллере обе части работают на одном чипе, а
интерфейс

HCI

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




















Рисунок 2
.1
.2


Структура
BLE
стека.

7


По сути программист видит несколько наборов API работающих на
уровне

Host
: называемые

GATT
,

GAP, L2CA, SMP, HCI
.
С помощью

GAP

API

устанавлива
ется режим работы устройства


Central
,
Peripheral
,
Observer
,
Broadcaster

и устанавливается соединение, когда нужно. А с помощью

GATT
API

выполняется непосредственная передача и приём полезных данных и их
разбор.

Большинство существующих устройств пока поддерживают версию
BLE 4.1, несмотря на существование версии 4.2.

Все отличия версии 4.2 от предыдущей касаются именно улучшений в
части B
LE: увеличение скорости, возможность передачи IP протокола и HTTP
трафика, усиление криптографической защиты и неопознаваемости для
внешних наблюдателей.


Важной особенностью BLE по сравнению с Wi
-
Fi является
специфицирование не только канала связи, но и
самих прикладных приложений
его использующих. Это называется профилями и сервисами. Профили с
сервисами описывают роли устройств, предназначение данных, состав и
формат данных, защиту данных, порядок, типы и события обмена, а не только
то, как передаются д
анные. Это позволяет не изобретать велосипед из
протоколов при разработке, например, датчика температуры тела или
измерителя пульса. Спецификации уже даны, остаётся на стороне устройства
только заполнить нужные поля для отправки результатов измерений. Клие
нты
таких устройств в виде смартфонов, планшетов, ПК или кухонной техники
распознают эти данные автоматически и отобразят их или используют
соответствующим образом. Все благодаря тому, что все производители
руководствуются одними и теми же спецификациями B
LE по поводу того, как
представлены данные о температуре или пульсе и как с ними работать. Но
остаётся место и для фантазии разработчика, так как профили имеют
механизмы для расширений функциональности.
[1]

Рассмотрим дерево атрибутов на рисунке 2.1.3
Цветами выделяются
уровни дерева, каждый атрибут имеет уникальный номер


UUID. Запись
стандартных номеров сокращается до 16
-
и бит. На данном
рисунке все номера
стандартные. Профили GAP и GATT тоже представлены как сервисы со своими
Рисунок 2
.1
.3



Дерево ат
рибутов
.

8


стандартными характеристиками. У каждого сервиса может быть своя модель
защиты и авторизация. Все дерево целиком в устройстве хранится как база
данных называемая баз
ой GATT, обычно в виде простой таблицы с
перекрёстными ссылками.

У характеристик сервисов есть множество характеристик, как показано
ниже
. Здесь придётся извиниться за тавтологию, но в BLE действительно
существует какой
-
то кризис терминологии. Одним словом, у характеристики
принадлежащей сервису могут специфицироваться допуски на чтение, запись,
необходимость извещений, подтверждений, подпи
сей и проч.


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


Обмен данными между BLE устройствами производится записью и
чтением з
начений характеристик. Потоковых каналов таких как TCP или UART
здесь нет. А если устройства их имеют, то значит их организуют программные
надстройки более высокого уровня.
[1]



2.2

Выбор аппаратной платформы

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

Было рассмотрено несколько вариантов
:



A
tmel

BTLC
1000;



Dialog

DA14583
;



Nordic

nRF52823
;



Texas

Instruments

CC
2650;

В результате оценки предложенных вариантов было выбрано решение
Texas

Instruments

CC
2650. Преимуществом данного решения является
доступность комплекта разработчика и подробная сопроводительная
документация.


2.
3
Характеристики
CC
2650

Texas

Instruments

CC
2
650 включает

в се
бя
производительное ядро

Cortex
-
M3

для прикладных задач и высокоуровневых сетевых взаимодействий,
экономичное ядро

Cortex
-
M0

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



Cortex
-
M3 и

контролер сенсоров
.

9



Радиочастотный блок
RFcore
.

Радиочастотный блок, благодаря техпроцессу 65

нм, выходит на новый
уровень по энергоэффективност
и.

Основные параметры встроенного трансивера:



высокая чувствительность, селективность;



чувствительность:
-
121

дБм (2,4

кбит/с),
-
111

дБм (50

кбит/с,
модуляция GFSK);



поддержка модуляций: MSK, FSK, GFSK, OOK, ASK, 4GFSK, CPM
(shaped 8 FSK);



программируемая
выходная мощность: до +14

дБм;



поддержка нескольких антенн;



программируемое усиление аналогового тракта.

Структура радиоядра представлена на
рисунке

2.
3.1.

В дополнении к
трансиверу, сочетающему в себе аналоговую часть и цифровую обработку
сигналов, радиом
одуль содержит процессорное ядро Cortex M0 и выделенный
таймер. Это позволяет легко обрабатывать несколько протоколов PHY
-
уровня,
осуществлять управление модемом, заниматься формированием пакетов.
Основной процессор обращается к сервисам радиоядра посредст
вом API
-
команд.
[2]

Рисунок
2.3
.1



Функциональная

схема
cc2650
.

10


Основное ядро контролера
ARM

Cortex

M
3

Приложения пользователя и верхние уровни стека протоколов (сам стек
протоколов, в случае сетевого процессора) выполняются на 32
-
битном
процесс
орном ядре ARM® Cortex™ M3
.

Flash
-
память предназначена д
ля хранения прикладных программ и может
быть перезаписана, в том числе, и в готовом устройстве. В оперативной памяти
могут располагаться и выполняемый код, и данные. Оперативная память
разделена на блоки по 4

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

В ROM
-
памяти прошиты драйверы периферии, а такж
е стеки протоколов
и Bluetooth Lo
w Energy Controller
. В постоянной памяти располагается
начальный загрузчик, позволяющий перепрограммировать устройство
посредством SPI или
UART.

Контроллерное ядро Cortex M3 имеет богатый набор периферийных
устройств:



датчик температуры;



четыре таймерных модуля общего назначения (2×16
-

или 1×32
-
битных, с режимом ШИМ);



8
-
канальный 12
-
битный АЦП (до 200

квыб/с);



сторожевой таймер;



аналоговый ко
мпаратор;



интерфейсы: UART, I2C;



три SPI
-
интерфейса (один из них



микромощный);



AES
-
модуль;



10…31 линия ввода
-
вывода (в зависимости от корпуса).

Контролер датчиков

Контроллер датчиков (ULP Sensor Controller) отвечает за управление
периферийными устройства
ми независимо от основного ядра. Периферийные
устройства, подключенные к данному домену, могут быть сконфигурированы
таким образом, что будут активны даже в режиме Power
-
down.

Сам контроллер представляет собой специализированный
малопотребляющий 16
-
разрядн
ый RISC
-
процессор. ULP Sensor controller
освобождает основной контроллер от задач опроса датчиков, что позволяет
сохранять общее низкое потребление при одновременном выполнении задач
сбора данных. Структура контроллера датчиков представлена на рисунке

3. В

его состав входит несколько аналоговых и цифровых узлов.

Аналоговые узлы:



8
-
канальный 12
-
битный АЦП (200

квыб/с);



FIFO
-
буфер на четыре слова;



два компаратора: микромощный и высокоскоростной;



программируемый источник тока: 0,25…20

мкА.



Цифровые узлы:



прео
бразователь «время
-
код»;

11




два 8
-
битных таймера с предделителями;16 линий ввода
-
вывода;



интерфейсы: SPI, I2C.

Контроллер датчиков программируется отдельно от основного
контроллера утилитой Sensor Controller Studio.

Типовые задачи, выполняемые контроллером да
тчиков:



опрос аналоговых датчиков;



опрос цифровых датчиков посредством линий ввода
-
вывода и
интерфейсов I2C и SPI;



реализация емкостных датчиков;



генерация сигналов;



калибровка генераторов;



квадратурный декодер датчиков угла поворота;



датчики движения;



ска
неры клавиатуры и так далее.


2.4
Набор разработчика

Для разработки использовался набор разработчика
SimpleLink

CC
2650
Wireless

MCU

LaunchPad

Kit

(
LAUNCHXL
-
CC
2650).

На пате набора
размешены: п
рограмматор
XDS
110
, м
икроконтроллер
CC2650F128RGZR

антенна, цепь

питания,

пара кнопок,

пара
светодиодов

разъем

для подключения
периферии
.
[2]














Рисунок
2.5



LaunchPad

Kit

CC
2650
.


12


Для отображения графической информации используется модуль дисплей
Sharp

Memory

LCD

BoosterPack

(430
BOOST
-
SHARP
96
)
. Экран имеет диагональ
1.3
"

дюйма и разрешение

96
x
96
пикселей. Обладает очень низким
энергопотреблением и хорошими углами обзора. Управляется по интерфейсу
SPI
.
















2.
5

Операционная система рольного времени

TI
-
RTOS


На устройстве использоваться
TI
-
RTOS
,

это операционная система
рольного в
ремени, разработанная
Texas

Instruments
.
Она упрощает разработку
сложных проектов, выступая посредником между прикладной программой и
аппаратными средствами

[3
]
.

TI
-
RTOS

по своей сути являет
ся библиотекой сервисов, которые
пользователь может добавлять в св
ою систему

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


Сформулируем принципы построения и действия этой ОС [2]:



Стремление к как можно меньшему потреблению ресурсов;



Встроенный планиро
вщик


приоритетный. Это означает, что процесс
с наивысшим приоритетом в данный момент времени всегда
выполняется в первую очередь;



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




Методы BIOS оперируют объектами


структурами языка C. Когда вы
создаете или изменяете какую
-
либо структуру, это не затрагивает
остальные;

Рисунок

2.
6



Sharp Memory LCD BoosterPack
.



13




BIOS


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



Встроенные в BIOS средства журналирования выполнены
прозрачными и потребляющими мало ресурсов, поэтому их
рекомендуется оставлять даже в конечной «прошивке» устройства.
[3]

Основные компоненты операционной системы:



TI
-
RTOS Kernel



SYS/BIOS



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



Драйвера периферийных уст
рой
ств и конфигурации отладочных плат
и наб
оров



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



Unified Instrumentation Ar
chi
tec
ture (UIA)



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



CC26xxWare



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



XDCtools



инструментарий для конфигурирования и сборки TI
-
RTOS
и ее компонент при сборке программного проекта.

Управление питанием является интегрированной частью TI
-
RTOS.
Операционная система учитывает, какие именно периферийные устройства
активны в данный момент.

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










14


3 Описание

разработки программного
обеспечения

3.1 Архитектура программного обеспечен
ия

микроконтроллерного устройства

На рисунки 3.1 блок схема

взаимодействия с
BLE

стеком.



















SYS
/
BIOS

это ядро операционной системы реального времени.

TI
-
RTOS

является оберткой
SYS
/
BIOS

и представляет набор библиотек

для функционирования о
перационной системы рольного времени.

GAPRole

отдельная задача которая упрощает разработку, обрабат
ы
вая
большую часть уровня
GAP
.

Application в этой задаче задаются настройки стека и выполняются
пользовательские задачи
.

iCall

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

LE
.

BLE

Host

занимается высокоуровневыми функциям организации и
управления данными
.
[4]


3.2 Описание исходного кода


Рассмотрим

функцию

main
()
в листинге 3.2.1
.
Инициализируем

ICall

c

п
омощью функции
ICall
_
init
()
и

формируем задачу вызывая функцию
ICall

обеспечивает взаимодействие приложения с
верхним уровнем протокола
Bluetooth

LE
.
Главной частью
ICall

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

Инициализируем
Рисунок

3.1



Программная архитектура



15


задачу GAPRole она отвечает за большую часть работы уровня
GAP
. Это
облегчает разработку, в частности многие события стека
BLE

обрабатывайся
GAPRole

и никогда
не передаются в приложение. Формируем

пользовательскую

задачу
Application

в это
й задачи реализованы все
пользовательские функции и задаются параметры уровней
:
GAP
, GATT
.

После
вызова функции
BIOS_start()
задачи начинают выполнятся.

Листинг

3.2.
1



Функция
main()

Task

это вид потока
TI
-
RTOS

предназначен для не прерывного и
параллельного выполнения весте с другими потоками типа
Task
.

Рассмотрим
процесс формирования на примере задачи
Application_taskFxn

листинг 3.2.2
.
Создаем структуру типа
Task
_
Params

и
инициализируем

па
раметры. Далее
передаем структуру типа
Task_Struct

и указываем ее размер.

Задаем приоритете
задачи, чем выше
значение т
ем выше приоритет выполнения.
Максимальное
значение приоритете 32, также возможно динамическое изменения приоритета.

Листинг

3.
2.2


Ини
циализация задачи

Application_taskFxn





int

main
()

{



PIN
_
init
(
BoardGpioInitTable
);


#
ifndef

POWER
_
SAVING



Power
_
(
Power
_
SB
_
DISALLOW
);


Power
_

#endif



UartLog_init(UART_open(Board_UART, NULL));



ICall_init();













BIOS_start();




}

void

Application
_
(
void
)

{


Task
_
Params

taskParams
;



Task
_
Params
_
init
(&
taskParams
);


taskParams
.
stack

=
APPTaskStack
;


taskParams
.
stackSize = APP_TASK_STACK_SIZE;


taskParams.priority = APP_TASK_
PRIORITY;



Task_construct(&APPTask, Application_taskFxn, &taskParams,
NULL);

}

16


Рассмотрим инициализацию

B
luetooth

стека

листинг 3.2.3. Настройка
профиля
GAPRole
:
приглашения, интервалы рассылки оповещений
автоматического подключения.
Передаем в функцию
G
APRole
_

с
параметром
GAPROLE
_
ADVERT
_
ENABLED

значение
TRUE
, этот параметр
задает видимость упрямства вовремя поиска. Аналогичным образом, но уже с
параметром
GAPROLE
_
ADVERT
_
OFF
_
TIME

задаем время паузы между
сессиями видимости.

Передаем
структ
уру
advertData

с заданным именем
устройства в функцию
GAPRole
_

с параметром
GAPROLE
_
ADVERT
_
DATA
.

Это имя будет отображается всем устройствам
в
режиме поиска.

Устанавливаем длину сессии

30 секунд
GAP
_
(
TGAP
_
LIM
_
ADV
_
TIMEOUT
, 30
).

Лист
инг

3.2.3


Инициализация


стека
.







uint
8_
t

initialAdvertEnable

=
TRUE
;



uint
16_
t

advertOffTime

= 0;



sizeof(uint8_t),


&initialAdvertEnable);



_ADVERT_OFF_TIME,
sizeof(uint16_t),


&advertOffTime);



sizeof(scanRspData), scanRspData);



sizeof(advertData), advertData);



Log_info1("Name i
n advertData array:
\
x1b[33m%s
\
x1b[0m",





uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;















uint32_t passkey = 0;

17


Устанавливаем параметры соединения с устройством листинг 3.3.4.
П
ередаем в функцию

GAPBondMgr
_

с параметром
GAPBOND
_
DEFAULT
_
PASSCODE

значение пароля ранее нулю.

Аналогичным
образом задаем режим соединение значение
GAPBOND
_
PAIRING
_
MODE
_
WAIT
_
FOR
_
REQ

указывает на указывает о
отправки запроса на соединение после

подключения. Также с помощью этого
параметра можно задать запрет на соединение.
Включаем защиту от подмены
сообщений передавая
GAPBOND
_
MITM
_
PROTECTION

значение
TRUE
.
Далее
надо указать возможности вода вывода устройства, оставим значение по
умолчанию
GAPB
OND
_
IO
_
CAP
_
DISPLAY
_
ONLY
. Следующий

значение

отвечает за сохранение
соединение в случае разрыва связи.
Задаем
GAPBOND
_
BONDING
_
ENABLED

с значением
TRUE
.
В противном случаем
придется регистрировать устройство каждый раз после потери связи.

Листинг

3.2.
4



На
стройка менеджера
соединения с устройством
.

Рассмотрим

инициализацию


сервисов
,
листинг

3.2.5.
Добавл
ение

сервисов на сервер
GATT
.

GGS_AddService
(GATT_ALL_SERVICES)
добавляет

GAP.
GATTServApp_AddService
(GATT_ALL_SERVICES)

добавляет

атрибуты

GATT
.
И
нициализир
уем

службу

информации

об

устрой
стве

функцией

DevInfo_AddService ().
Задаем

имя

устройства

в

профиле

GAP
функцией

(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName)
,
где

attDeviceName

структура

с

именем

устройства
.
Добавляем

свои

сервисы

допустим

ButtonService_

Запускам

стек

в

периферийном

режиме

VOID GAPRole_StartDevice
().
Запускаем

диспетчер

связей

VOID
GAPBondMgr_Register().

Регистрируем

получение

сообщений

HCI


GAP_RegisterForMsgs (selfEntity)
Регистрация

событий

GATT

и

ответов

ATT

GATT_Register
ForMsgs (selfEntity)





uint
32_
t

passkey

= 0;

uint
8_
t

pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;

uint8_t mitm = TRUE;

uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;

uint8_t bonding = TRUE;


ODE,
sizeof(uint32_t),


&passkey);

&pairMode);

sizeof(uint8_t), &mitm);

,
sizeof(uint8_t), &ioCap);

sizeof(uint8_t), &bonding);

18


Листинг

3.2.5


Инициализация


сервисов
.

Рассмотрим

цикл

ожидания

внутреннего

сообщения
, листинг 3.2.6
.

Ждем

получения

сообщение. Обрабатываем сообщение. Освобождаем сообщение
прикладного уровня и освобождаем.

Листинг 3.
2.6



Цикл ожидание внутреннего сообщения


Рассмотрим алгоритм обработки внутренних сообщений
, листинг 3.2.7.
Рассмотрим на примере обработки сообщения
APP
_
MSG
_
SERVIC
E
_
WRITE
,
сообщение

несёт в себе новое значение сервиса, полученное от смартфона.
Сначала мы создаем указатель на структуру для удобной работы с данными.
GGS
_
AddService
(
GATT
_
ALL
_
SERVICES
);

GATTServApp
_
AddService
(
GATT
_
ALL
_
SERVICES);

DevInfo_AddService();


NAME_LEN,
attDeviceName);


PushService_AddService( selfEntity );

ButtonService_AddService( selfEntity );

DataService_AddService( selfEntity );


PushService_RegisterAppCBs( &user_Push_ServiceCBs );

ButtonService_RegisterAppCBs( &user_Button_ServiceCBs );

Da
taService_RegisterAppCBs( &user_Data_ServiceCBs );


uint8_t initVal[40] = {0};

uint32_t initTimeVal[] = "1497863172";





ButtonServic
initVal);

initVal);


initTimeVal);


VOID GAPRole_StartDevice(&user_gapRoleCBs);


VOID GAPBondM
gr_Register(&user_bondMgrCBs);


GAP_RegisterForMsgs(selfEntity);


GATT_RegisterForMsgs(selfEntity);

while

(!
Queue
_
empty
(
hApplicationMsgQ
))

{

app
_
msg
_
t

*
pMsg

=
Queue
_
dequeue
(
hApplicationMs
gQ
);


user
_
processApplicationMessage(pMsg);


ICall_free(pMsg);

}

19


Мы определяем тип сообщения и передаем функции нужного сервиса
используя
UUID
.



Листинг

3.2.7


Обработка внутренних сообщений




Использование
системного времени
.

Д
ля реализации
измерения

времени
используется внутренние часы рольного времени.

Подсчёт времени ведётся в
UNIX

формате, поэтому удобно использовать
структуру

библиотеки
time
.
h
,

представленную в листинге 3.2.8
. Для изменения времени испо
льзуется
функция Seconds_set()
,

а для получения значения



Листинг

3.2.8



Структура представления времени



Вывод информации на дисплей.

Инициализируем дисплей с помощью
функции
Display
_
Params
_
init
()
И создаем указатель на дисплей
hDisplayLcd
.
Используя функцию
Display
_
print
0

выводи информацию сообщение на экран. В
функцию передаем указатель, кардиналы

и текст.

Ставим

задержку

и

очищаем

экпан
.

Листинг

3.2.
9



Инициализация

дисплея

и

вывод

информации
.


static

void

user
_
processApplicationMessage
(
app
_
msg
_
t

*
pMsg)

{


char_data_t *pCharData = (char_data_t *)pMsg
-
�pdu;



switch (pMsg
-
�type)


{


case APP_MSG_SERVICE_WRITE:


switch(pCharData
-
�svcUUID) {



case Push_SERVICE_SERV_UUID:


user_PushService_ValueChangeHandler(pCharData);


break;


case DATA_SERVICE_SERV_UUID:


user_DataService_ValueChangeHandler(pCharData);


break;



}


break;

struct tm

{

int tm_sec; /* seconds after the minute
-

[0,59] */

int tm_min; /* minutes after the hour
-

[0,59
] */

int tm_hour; /* hours after the midnight
-

[0,23] */

int tm_mday; /* day of the month
-

[1,31] */

int tm_mon; /* months since January
-

[0,11] */

int tm_year; /* years since 1900 */

int tm_wda
y; /* days since Sunday
-

[0,6] */

int tm_yday; /* days since Jan 1st
-

[0,365] */

int tm_isdst; /* Daylight Savings Time flag */

#if _AEABI_PORTABILITY_CHECK

int __extra_1, __extra_2; /* ABI
-
required extr
a
fields */

#endif

};

20



Для рисован
ия примитивов использовалась библиотека
DisplayExt.h
. В
листинге 3.2.10

рисуется иконка сообщения.

Листинг

3.2.
10



Вывод иконки на экран













Display
_
Params

params
;

Display
_
Params
_
init
(&
params
);

params
.
lineCl
earMode

=
DISPLAY_CLEAR_BOTH;


Display_Handle hDisplayLcd = Display_open(Display_Type_LCD,
¶ms);

if (hDisplayLcd) {

Display_print0(hDisplayLcd, 3, 3, "Smart Watch");

Task_sleep(1000 * (1000/Clock_tickPeriod));

Display_clear(hDisplayLcd);

}

myRectangle
1 = { 55, 10, 75, 22};

tContext

*
pContext

=
DisplayExt
_
(
hDisplayLcd
);

if

(
pConte
xt
) {

GrRectDraw
(
pContext, &myRectangle1);



GrLineDraw(pContext, 55, 10, 65, 16);

GrLineDraw
(pContext, 65, 16, 75, 10);

}

21


4
Тестирование

устройства


Для

тестирования используем программу
BLE

Scanner

для смартфонов на
базе операционной
системы
Android
. Главной задачей
является проверка
взаимодействия с устройством по
Bluetooth
.

Запускаем
BLE

Scanner
. Найдено устройство
Smart

Watch
.
Подключимся
и получаем список атрибутов и сервисов.

























Рисунок

4.1



LaunchPad


Рисунок

4.2



Поиск устройства


Рисунок

4.3



Сгруппированные сервисы и атрибуты


22


Используя сервис с
UUID

0
x
1111

отправляем значение
“01”
, что
соответствует функции отображения иконки не прочитанного сообщения.

А
“00”

выключает отображение иконки. Сервис
UUID

0
x1112
управляет иконкой
телефона
.












Наживаем на устройстве кнопку
BTN
1.

И в сервисе 0
x
112
0
мы получаем значение 0
x
01.

Стоит обратить
внимание на значение свойства сервиса

Notify

Это значение говорит о том,
что
уст
ройство
будет инициализировать

передачу без запроса со стороны
смартфона.









Передаем через сервис 0
x
1131
время в
формат
е UNIX
-
time

1600000000

(12
:26/09/13/2020
) на экране устройства мы видим новое значение даты и
времени.




Рисунок

4.4



Сервис уведомлений


Рисунок

4.5



Отображение иконки


Рисунок

4.6



Сервис кнопок


Рисунок

4.7



Нажатая кнопка


23





























Рисунок

4.4



Сервис данных


Рисунок

4.4



Часы с новым
значением времени


24


Заключение

В ходе выполненного дипломного проекта на тему «
Разработка
микроконтроллерного устройства “Умные часы”
» был
и изучены особенности
разработки программного обеспечения для микроконтроллеров серии
cc
26
xx
.

Осуществлена

задача по установлению

связи смартфона с устройством
средства протокола

Low

Energy
.






Часы выполняют ряд задач
:



Базовый функционал

часов
:
время, дата



Уведомления о сообщениях и звонках



Передача сигнала о нажатие кнопок
;

Для разработки были выбраны доступные по цене аппаратные средства
разработки умных

часов
:
Texas

Instruments

LAUNCHXL
-
CC
2650,
430
BOOST
-
SHARP
96
. Все программные продукт
ы использование в разработки
предоставляются бесплатно
:
TI
-
RTOS
, BLE stack.

Во вре
мя практики я ознакомился

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

возможности специального программного обеспе
чения для
решения задач моего дипломного исследования.

В дальнейшим планируется продолжить разработку устройства, в
частности расширить функционал

и разработать клиентско
е приложения для
полноценного функционирования устройства.














25


Приложение А

Список использованных источников

1.

Разработка
IoT

устройств с использованием
Bluetooth

LE

[
Электронный

ресурс
].


https
://
geektimes
.
ru
/
post
/276558/

2.

SimpleLink™ CC2650 Wi
reless MCU LaunchPad™ Kit [
Электронный

ресурс
].


http
://
www
.
ti
.
com
/
tool
/
launchxl
-
cc
2650

3.

Чуфырев А.Е., Устюгов В.А. Технический обзор особенностей
операционной системы реального времени ti
-
rtos // Juvenisscientia. 2016.
№1.

[
Электронный

ресурс
]
.



http
://
c
yberleninka
.
ru
/
article
/
n
/
tehnicheskiy
-
obzor
-
osobennostey
-
operatsionnoy
-
sistemy
-
realnogo
-
vremeni
-
ti
-
rtos
.

4.

CC2640 and CC2650 SimpleLink™ Bluetooth® low energy Software Stack
2.2.1 Developer's Guide
[
Электронный

ресурс
]
.

http://www.ti.com/lit/ug/swru393d/swr
u393d.pdf

5.

TI
-
RTOS

2.20
User

s

Guide

[
Электронный

ресурс
].


http
://
www
.
ti
.
com
/
lit
/
ug
/
spruhd
4
m
/
spruhd
4
m
.
pdf






















26


Приложение
Б

Листинг программы


main
.
c

&#xxdc/;&#xrunt;&#xime/;rro;&#xr.h0;#include xdc/runtime/Error.h


&#xti/s;&#xysbi;&#xos/f; mil;&#xy/ar;&#xm/cc;&xx;&#x/Pow;r.h;#include ti/sysbios/family/arm/cc26xx/Power.h

#include

&#xti/s;&#xysbi;&#xos/B;&#xIOS.;&#xh000;ti/sysbios/BIOS.h


#include "ICall.h"

#include "bcomdef.h"

#include "peripheral.h"

#include "Application.h"


&#xti/d;&#xrive;&#xrs/U; RT.;&#xh000;#include ti/drivers/UART.h

&#xuart;&#x_log;&#xs.h0;#include uart_logs.h


#ifndef USE_DEFAULT_USER_CFG

#include "bleUserConfig.h"

bleUserCfg_t user0Cfg = BLE_USER_CF
G;

#endif


void exceptionHandler()

{


volatile uint8_t i = 1;


while(i){}

}


int main()

{


PIN_init(BoardGpioInitTable);


#ifndef POWER_SAVING





#endif



UartL
og_init(UART_open(Board_UART, NULL));



ICall_init();












BIOS_start();




27


}


Void smallErrorHook(Error_Block *eb)

{


for (;;);

}


void halAssertHand
ler(void)

{


for (;;);












































28


Application
.c

&#xstri;&#xng.h;#include string.h

&#xtime;&#x.h00;#include time.h


&#xti/s;&#xysbi;&#xos/k;&#xnl/T; sk.;&#xh000;#include ti/sysbios/knl/Task.h

&#xti/s;&#xysbi;&#xos/k;&#xnl/S;map;&#xhore;&#x.h00;#include ti/sysbios/knl/Semaphore.h

&#xti/s;&#xysbi;&#xos/k;&#xnl/Q;&#xueue;&#x.h00;#include ti/sysbios/knl/Queue.h

#include ti/sysbios/hal/Second
�s.h

&#xti/s;&#xysbi;&#xos/k;&#xnl/C;&#xlock;&#x.h00;#include ti/sysbios/knl/Clock.h


&#xti/d;&#xrive;&#xrs/P;&#xIN.h;#include ti/drivers/PIN.h

&#xti/m;&#xw/di;&#xspla;&#xy/Di;&#xspla;&#xy.h0;#include ti/mw/display/Display.h

&#xti/m;&#xw/di;&#xspla;&#xy/Di;&#xspla;&#xyExt;&#x.h00;#include ti/mw/display/DisplayExt.h


&#xxdc/;&#xrunt;&#xime/;&#xLog.;&#xh000;#include xdc/runtime/Log.h

&#xxdc/;&#xrunt;&#xime/; iag;&#xs.h0;#include xdc/runtime/Diags.h

&#xxdc/;&#xrunt;&#xime/;&#xSyst;m.h;#include xdc/runtime/System.h

&#xxdc/;&#xstd.;&#xh000;#include xdc/std.h


&#xhci_;&#xtl.h;#include hci_tl.h

&#xgap.;&#xh000;#include gap.h

&#xgatt;&#x.h00;#include gatt.h

&#xgapg; tts;rve;&#xr.h0;#include gapgattserver.h

&#xgatt;&#xserv; pp.;&#xh000;#include gattservapp.h

&#xosal;&#x_snv;&#x.h00;#include osal_snv.h

&#xgapb;&#xondm;&#xgr.h;#include gapbondmgr.h

&#xperi;&#xpher; l.h;#include peripheral.h

&#xICal;&#xlBle; PIM;&#xSG.h;#include ICallBleAPIMSG.h


Þvi;&#xnfos;rvi;Î.h;#include devinfoservice.h


#include "util.h"


#i
nclude "Board.h"

#include "Application.h"


#include "Push_Service.h"

#include "Button_Service.h"

#include "Data_Service.h"


#define DEFAULT_ADVERTISING_INTERVAL 160


#define DEFAULT_DISCOVERABLE_MODE
GAP_ADTYPE_FLAGS_GENERAL


#define D
EFAULT_PASSCODE 000000


#define APP_TASK_PRIORITY 1


#ifndef APP_TASK_STACK_SIZE

#define APP_TASK_STACK_SIZE 800

#endif


29


#define APP_STATE_CHANGE_EVT 0x0001

#define APP_CHAR_CHANGE
_EVT 0x0002

#define APP_PERIODIC_EVT 0x0004

#define APP_CONN_EVT_END_EVT 0x0008


const tRectangle myRectangle1 = { 55, 10, 75, 22};


typedef enum

{


APP_MSG_SERVICE_WRITE = 0,


APP_MSG_SERVICE_CFG,



APP_MSG_UPDATE_CHARVAL,


APP_MSG_GAP_STATE_CHANGE,


APP_MSG_BUTTON_DEBOUNCED,


APP_MSG_SEND_PASSCODE,

} app_msg_types_t;


typedef struct

{


Queue_Elem _elem;


app_msg_types_t type;


uint8_t pdu[];

} app_
msg_t;


typedef struct

{


uint16_t svcUUID;


uint16_t dataLen;


uint8_t paramID;


uint8_t data[];

} char_data_t;


typedef struct

{


uint16_t connHandle;


uint8_t uiInputs;


uint8_t uiOutputs;

} passcode_req_t;


typedef struct

{


PIN_Id pin
Id;


uint8_t state;

} button_state_t;


static ICall_EntityID selfEntity;


static ICall_Semaphore sem;


static Queue_Struct applicationMsgQ;

static Queue_Handle hApplicationMsgQ;


Task_Struct APPTask;

30


Char APPTaskStack[APP_TASK_STACK_SIZE];


static uint8_
t scanRspData[] =

{


0x00

};


static uint8_t advertData[] =

{


0x02,


GAP_ADTYPE_FLAGS,


DEFAULT_DISCOVERABLE_MODE |
GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,


12,




'S', 'm', 'a', 'r', 't', ' ', 'W', 'a', 't', 'c', 'h',


};


static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Smart
Watch";


static gattMsgEvent_t *pAttRsp = NULL;



static PIN_Handle buttonPinHandle;


static PIN_State buttonPinState;


PIN_Config buttonPinTable[] = {


Board_
BUTTON0 | PIN_INPUT_EN | PIN_PULLUP |
PIN_IRQ_NEGEDGE,


Board_BUTTON1 | PIN_INPUT_EN | PIN_PULLUP |
PIN_IRQ_NEGEDGE,


PIN_TERMINATE

};


static Clock_Struct button0DebounceClock;

static Clock_Struct button1DebounceClock;


static uint8_t button0State =

0;

static uint8_t button1State = 0;


static UInt32 t;

static time_t t1;

static struct tm *ltm;

static char *curTime;


static Display_Handle hDisplayLcd;


static void Application_init( void );

static void Application_taskFxn(UArg a0, UArg a1);


31


static void

user_processApplicationMessage(app_msg_t *pMsg);

static uint8_t Application_processStackMsg(ICall_Hdr *pMsg);

static uint8_t Application_processGATTMsg(gattMsgEvent_t
*pMsg);


static void Application_sendAttRsp(void);

static uint8_t Application_processGAT
TMsg(gattMsgEvent_t
*pMsg);

static void Application_freeAttRsp(uint8_t status);


static void user_processGapStateChangeEvt(gaprole_States_t
newState);

static void user_gapStateChangeCB(gaprole_States_t newState);

static void user_gapBondMgr_passcodeCB(uint
8_t *deviceAddr,
uint16_t connHandle,


uint8_t uiInputs,
uint8_t uiOutputs);

static void user_gapBondMgr_pairStateCB(uint16_t connHandle,
uint8_t state,


uint8_t status);


static
void buttonDebounceSwiFxn(UArg buttonId);

static void user_handleButtonPress(button_state_t *pState);


static void user_service_ValueChangeCB( uint16_t connHandle,
uint16_t svcUuid, uint8_t paramID, uint8_t *pValue, uint16_t len
);

static void user_service
_CfgChangeCB( uint16_t connHandle,
uint16_t svcUuid, uint8_t paramID, uint8_t *pValue, uint16_t len
);


static void user_PushService_ValueChangeHandler(char_data_t
*pCharData);

static void user_ButtonService_CfgChangeHandler(char_data_t
*pCharData);

static

void user_DataService_ValueChangeHandler(char_data_t
*pCharData);


static void user_updateCharVal(char_data_t *pCharData);


static void user_enqueueRawAppMsg(app_msg_types_t appMsgType,
uint8_t *pData, uint16_t len );

static void user_enqueueCharDataMsg(a
pp_msg_types_t
appMsgType, uint16_t connHandle,


uint16_t serviceUUID,
uint8_t paramID,


uint8_t *pValue, uint16_t
len);

static void buttonCallbackFxn(PIN_Handle handle, PIN_Id
pinId);


static char *Util_convertArrayToHexString(uint8_t const *src,
uint8_t src_len,

32



uint8_t *dst,
uint8_t dst_len);



static gapRolesCBs_t user_gapRoleCBs =

{


use
r_gapStateChangeCB

};


static gapBondCBs_t user_bondMgrCBs =

{


user_gapBondMgr_passcodeCB,


user_gapBondMgr_pairStateCB

};


static PushServiceCBs_t user_Push_ServiceCBs =

{


.pfnChangeCb = user_service_ValueChangeCB,


.pfnCfgChangeCb = NULL,

};


static ButtonServiceCBs_t user_Button_ServiceCBs =

{


.pfnChangeCb = NULL,


.pfnCfgChangeCb = user_service_CfgChangeCB,

};


static DataServiceCBs_t user_Data_ServiceCBs =

{


.pfnChangeCb = user_service_ValueChangeCB,


.pfnCfgChangeCb = user_ser
vice_CfgChangeCB,

};



{


Task_Params taskParams;



Task_Params_init(&taskParams);


taskParams.stack = APPTaskStack;


taskParams.stackSize = APP_TASK_STACK_SIZE;


taskParams.priority = APP_TASK_PRIORITY;



Task_constr
uct(&APPTask, Application_taskFxn, &taskParams,
NULL);

}


static void Application_init(void)

{


ICall_registerApp(&selfEntity, &sem);



Log_info0("Initializing the user task, hardware, BLE stack
and services.");


33



Queue_construct(&applicationMsgQ, NULL)
;


hApplicationMsgQ = Queue_handle(&applicationMsgQ);



buttonPinHandle = PIN_open(&buttonPinState,
buttonPinTable);


if(!buttonPinHandle) {


Log_error0("Error initializing button pins");


Task_exit();


}



if (PIN_registerIntCb(buttonPinHandle,

&buttonCallbackFxn)
!= 0) {


Log_error0("Error registering button callback function");


Task_exit();


}



Clock_Params clockParams;


Clock_Params_init(&clockParams);



clockParams.arg = Board_BUTTON0;



Clock_construct(&button0DebounceClock,
bu
ttonDebounceSwiFxn,


50 * (1000/Clock_tickPeriod),


&clockParams);



clockParams.arg = Board_BUTTON1;


Clock_construct(&button1DebounceClock,
buttonDebounceSwiFxn,


50 * (1000/Clock_tickPeriod),



&clockParams);



uint8_t initialAdvertEnable = TRUE;



uint16_t advertOffTime = 0;



sizeof(uint8_t),


&initialAdvertEnable);




sizeof(uint16_t),


&advertOffTime);



sizeof(scanRspData), scanRspData);



sizeof(advertData), advertData);



Log_info1("Name in advertData arra
y:
\
x1b[33m%s
\
x1b[0m",




34



uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;







lue(TGAP_GEN_DISC_ADV_INT_MIN, advInt);








uint32_t passkey = 0;


uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;


uint8_t mitm = TRUE;


uint8_
t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;


uint8_t bonding = TRUE;



sizeof(uint32_t),


&passkey);


sizeof(uint8_t), &pairMode);


GAPB
sizeof(uint8_t), &mitm);


sizeof(uint8_t), &ioCap);


sizeof(uint8_t), &bonding);



GGS_AddService(GATT_ALL_SER
VICES);


GATTServApp_AddService(GATT_ALL_SERVICES);


DevInfo_AddService();



attDeviceName);



PushService_AddService( selfEntity );


ButtonService_AddService( s
elfEntity );


DataService_AddService( selfEntity );



PushService_RegisterAppCBs( &user_Push_ServiceCBs );


ButtonService_RegisterAppCBs( &user_Button_ServiceCBs );


DataService_RegisterAppCBs( &user_Data_ServiceCBs );



uint8_t initVal[40] = {0};


u
int32_t initTimeVal[] = "1497863172";



initVal);


initVal);



initVal);

35



ButtonService_Se
initVal);



initTimeVal);



VOID GAPRole_StartDevice(&user_gapRoleCBs);



VOID GAPBondMgr_Register(&user_bondMgrCBs);



GAP_RegisterForMsgs(selfEntity);



GATT_RegisterForMsgs(selfEntity);




Display_Params params;


Display_Params_init(¶ms);


params.lineClearMode = DISPLAY_CLEAR_BOTH;




hDisplayLcd = Display_open(Display_Type_LCD, ¶ms);

}


static void Application_ta
skFxn(UArg a0, UArg a1)

{


Application_init();



if (hDisplayLcd) {


Display_print0(hDisplayLcd, 3, 3, "Smart Watch");


Display_print0(hDisplayLcd, 6, 6, "Hello");


Task_sleep(1000 * (1000/Clock_tickPeriod));


Display_clear(hDisplayLcd);


}




for (;;)


{


ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER);



if (errno == ICALL_ERRNO_SUCCESS)


{


ICall_EntityID dest;


ICall_ServiceEnum src;


ICall_HciExtEvt *pMsg = NULL;



st,


(void **)&pMsg) ==
ICALL_ERRNO_SUCCESS)


{





if ((src == ICALL_SERVICE_CLASS_BLE) && (dest ==
selfEntity))


{


ICall_Event *pEvt = (ICall_Event *)pMsg;


36




if (pEvt
-
�signature == 0xffff)


{


if (pEvt
-
�event_flag & APP_CONN_EVT_END_EVT)


{


Application_sendAttRsp();


}


}


else


{


Application_pr
ocessStackMsg((ICall_Hdr *)pMsg);


}


}





{


ICall_freeMsg(pMsg);


}


}



while (!Queue_empty(hApplicationMsgQ))


{



if (hDisplayLcd) {







t1 = time(NULL);


ltm = localtime(&t1);


Display_print2(hDisplayLcd, 4, 6,"%02d:%02d",
ltm
-
�tm_hour, ltm
-
�tm_min);


Display_print3(hDisplayLcd, 6, 3,"%02d %02d
%04d", ltm
-
�tm_mday, ltm
-
�tm_mon+1, ltm
-
�tm_year+1900);



}





app_msg_t *pMsg = Queue_dequeue(hApplicationMsgQ);



user_processApplicationMessage(pMsg);



ICall_free(pMsg);


}


}


}

}


static void user_processApplicationMessage(app_msg_t *pMsg)

{


char_data_t *pCharData = (char_dat
a_t *)pMsg
-
�pdu;



switch (pMsg
-
�type)


{


case APP_MSG_SERVICE_WRITE:


switch(pCharData
-
�svcUUID) {


case Push_SERVICE_SERV_UUID:


user_PushService_ValueChangeHandler(pCharData);


break;

37



case DATA_SERVICE_SERV_UU
ID:


user_DataService_ValueChangeHandler(pCharData);


break;



}


break;



case APP_MSG_SERVICE_CFG:


switch(pCharData
-
�svcUUID) {


case BUTTON_SERVICE_SERV_UUID:


user_ButtonService_CfgChangeHandler(pCha
rData);


break;


case DATA_SERVICE_SERV_UUID:


user_DataService_CfgChangeHandler(pCharData);


break;


}


break;



case APP_MSG_UPDATE_CHARVAL:


user_updateCharVal(pCharData);


break;



case APP_MS
G_GAP_STATE_CHANGE:


user_processGapStateChangeEvt( *(gaprole_States_t
*)pMsg
-
�pdu );


break;



case APP_MSG_SEND_PASSCODE:


{


passcode_req_t *pReq = (passcode_req_t *)pMsg
-
�pdu;


Log_info2("BondMgr Requested passcode. We a
re %s
passcode %06d",


(IArg)(pReq
-
�uiInputs?"Sending":"Displaying"),


DEFAULT_PASSCODE);


GAPBondMgr_PasscodeRsp(pReq
-
�connHandle, SUCCESS,
DEFAULT_PASSCODE);


}


break;



case APP_MSG_BUTTON_DEBOUNCED
:


{


button_state_t *pButtonState = (button_state_t
*)pMsg
-
�pdu;


user_handleButtonPress(pButtonState);


}


break;


}

}


static void user_processGapStateChangeEvt(gaprole_States_t
newState)

{

38



switch ( newState )


{


cas
e GAPROLE_STARTED:


{


uint8_t ownAddress[B_ADDR_LEN];


uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];






systemId[0] = ownAddress[0];


systemId[1] = ownAddress[1];



systemId[2] = ownAddress[2];



systemId[4] = 0x00;


systemId[3] = 0x00;



systemId[7] = ownAddress[5];


systemId[6] = ownAddress[4];


systemId[5] = ownAddress[3];



DEVINF
O_SYSTEM_ID_LEN, systemId);



char *cstr_ownAddress =
Util_convertBdAddr2Str(ownAddress);


Log_info1("GAP is started. Our address:
\
x1b[32m%s
\
x1b[0m", (IArg)cstr_ownAddress);


}


break;



case GAPROLE_ADVERTISING:


Log_info0
("Advertising");


break;



case GAPROLE_CONNECTED:


{


uint8_t peerAddress[B_ADDR_LEN];



peerAddress);



char *cstr_peerAddress =
Util_convertBdAddr2Str(peerAddress);


Log
_info1("Connected. Peer address:
\
x1b[32m%s
\
x1b[0m", (IArg)cstr_peerAddress);


}


break;



case GAPROLE_CONNECTED_ADV:


Log_info0("Connected and advertising");


break;



case GAPROLE_WAITING:

39



Log_info0("Disconnected / Idle"
);


break;



case GAPROLE_WAITING_AFTER_TIMEOUT:


Log_info0("Connection timed out");


break;



case GAPROLE_ERROR:


Log_info0("Error");


break;



default:


break;


}

}


static void user_handleButtonPress(button_state
_t *pState)

{


Log_info2("%s %s",


(IArg)(pState
-
�pinId == Board_BUTTON0?"Button 0":"Button
1"),


(IArg)(pState
-
�state?"
\
x1b[32mpressed
\
x1b[0m":


"
\
x1b[33mreleased
\
x1b[0m"));



switch (pState
-
�pinId)


{


case Board_BUTTO
N0:




sizeof(pState
-
�state),


&pState
-
�state);


break;


case Board_BUTTON1:





sizeof(pState
-
�state),


&pState
-
�state);


break;


}

}


void user_PushService_ValueChangeHandler(char_data_t
*pCharData)

{




Util_convertArrayToHexString(pCha
rData
-
�data, pCharData
-
�dataLen,





switch (pCharData
-
�paramID)


{


case LS_Push0_ID:


Log_info3("Value Change msg: %s %s: %s",


(IArg)"Push Service",

40




(IArg)"Push0",





if (pCharData
-
�data[0]=="on")




Push_Print0



else




Display_clear(hDisplayLcd);


Log_info2("Turning %s",


(IArg)(pCharData
-
�data[0]?"on":"off"));



break;



case LS_Push1_ID:


Log_info3("Value Change msg: %s %s: %s",


(IArg)"Push Service",


(IArg)"Push1",





if (pCharData
-
�data[0]=="on")



Push_Print1 ();



else



D
isplay_clear(hDisplayLcd);


Log_info2("Turning %s",


(IArg)(pCharData
-
�data[0]?"on":"off"));


break;



default:




}

}


void Push_Print0 (void)

{


tContext *pContext =


if (pCo
ntext) {


GrRectDraw(pContext, &myRectangle1);


GrLineDraw(pContext, 55, 10, 65, 16);


GrLineDraw(pContext, 65, 16, 75, 10);



GrFlush(pContext);


}

}


void Push_Print1 (void)

{


tContext *pContext =
Lcd);


if (pContext) {


GrLineDraw(pContext, 20+3, 10+0, 20+5, 10+2);


GrLineDraw(pContext, 20+5, 10+3, 20+4, 10+4);


GrLineDraw(pContext, 20+4, 10+5, 20+5, 10+6);


GrLineDraw(pContext, 20+5, 10+7, 20+8, 10+10);


GrLin
eDraw(pContext, 20+9, 10+10, 20+10, 10+11);


GrLineDraw(pContext, 20+11, 10+11, 20+12, 10+10);

41



GrLineDraw(pContext, 20+13, 10+10, 20+15, 10+12);


GrLineDraw(pContext, 20+14, 10+13, 20+13, 10+14);


GrLineDraw(pContext, 20+12, 10
+14, 20+9, 10+14);


GrLineDraw(pContext, 20+8, 10+13, 20+7, 10+13);


GrLineDraw(pContext, 20+6, 10+12, 20+3, 10+9);


GrLineDraw(pContext, 20+2, 10+8, 20+2, 10+7);


GrLineDraw(pContext, 20+1, 10+6, 20+1, 10+3);


GrLineDraw
(pContext, 20+1, 10+2, 20+2, 10+1);



GrFlush(pContext);


}

}


void user_ButtonService_CfgChangeHandler(char_data_t
*pCharData)

{


uint16_t configValue = *(uint16_t *)pCharData
-
�data;


char *configValString;



switch(configValue)


{


case GATT_CFG_NO_
OPERATION:


configValString = "Noti/Ind disabled";


break;


case GATT_CLIENT_CFG_NOTIFY:


configValString = "Notifications enabled";


break;


case GATT_CLIENT_CFG_INDICATE:


configValString = "Indications enabled";


break;


}



switch

(pCharData
-
�paramID)


{


case BS_BUTTON0_ID:


Log_info3("CCCD Change msg: %s %s: %s",


(IArg)"Button Service",


(IArg)"BUTTON0",


(IArg)configValString);


break;



case BS_BUTTON1_ID:


Log
_info3("CCCD Change msg: %s %s: %s",


(IArg)"Button Service",


(IArg)"BUTTON1",


(IArg)configValString);


break;


}

}


void user_DataService_ValueChangeHandler(char_data_t
*pCharData)

{


switch (pCharData
-
�paramID)

42



{


case DS_TIME_ID:


-
�data);


Log_info3("Value Change msg: %s %s: %s",


(IArg)"Data Service",




(IArg)pCharData
-
�data);


break;


default:





}

}


static uint8_t Application_processStackMsg(ICall_Hdr *pMsg)

{





switch (pMsg
-
�event)


{


case GATT_MSG_EVENT:


Application_processGATTMsg((gattMsgEvent_t *)pMsg);


break;




case HCI_GAP_EVENT_EVENT:


{


switch(pMsg
-
�status)


{






break;



default:


break;


}



}


break;



default:


break;


}




}


static uint8_t Application_processGATTMsg(gattMsgEvent_t
*pMsg)

{


if (pMsg
-
�hdr.status == blePending)


{


Log_warning1("Outgoing RF FIFO full. Re
-
schedule
transmission of m
sg with opcode 0x%02x",


pMsg
-

43




if (HCI_EXT_ConnEventNoticeCmd(pMsg
-
�connHandle,
selfEntity,


APP_CONN_EVT_END_EVT) ==
SUCCESS)


{


Application_freeAttRsp(FAILURE);



pAttRsp = pMsg;



r


}


}


else if (pMsg
-


{


Log_error1("Flow control violated. Opcode of offending
ATT msg: 0x%02x",


pMsg
-
�msg.flowCtrlEvt.opcode);


}


else if (pMsg
-


{


Log_info1("MTU Size change: %d bytes", pMsg
-
�msg.mtuEvt.MTU);


}


else


{


Log_info1("Recevied GATT Message. Opcode: 0x%02x", pMsg
-


}



GATT_bm_free(&pMsg
-
�msg, pMsg
-




}


static void Application_sendAttRsp(
void)

{


if (pAttRsp != NULL)


{


uint8_t status;






status = GATT_SendRsp(pAttRsp
-
�connHandle, pAttRsp
-
-
�msg));


if ((status != blePending) && (status !=
MSG_BUFFER_NOT_AVAIL))


{


HCI_EXT_ConnEventNo
ticeCmd(pAttRsp
-
�connHandle,
selfEntity, 0);



Application_freeAttRsp(status);


}

44



else


{


Attempt %d",


pAttRsp
-


}


}

}


static void Application_freeAt
tRsp(uint8_t status)

{


if (pAttRsp != NULL)


{


if (status == SUCCESS)


{


Log_info2("Sent message with opcode 0x%02x. Attempt
%d",


pAttRsp
-


}


else


{


Log_error2("Gave up message with opcode 0x%02
x. Status:
%d",


pAttRsp
-



GATT_bm_free(&pAttRsp
-
�msg, pAttRsp
-


}



ICall_freeMsg(pAttRsp);



pAttRsp = NULL;




}

}


static void user_gapStateChangeCB(gaprole_States_t newState)

{


Log_i
nfo1("(CB) GAP State change: %d, Sending msg to app.",
(IArg)newState);


user_enqueueRawAppMsg( APP_MSG_GAP_STATE_CHANGE, (uint8_t
*)&newState, sizeof(newState) );

}


static void user_gapBondMgr_passcodeCB(uint8_t *deviceAddr,
uint16_t connHandle,



uint8_t uiInputs,
uint8_t uiOutputs)

{


passcode_req_t req =


{


.connHandle = connHandle,


.uiInputs = uiInputs,


.uiOutputs = uiOutputs

45



};



user_enqueueRawAppMsg(APP_MSG_SEND_PASSCODE, (uint8_t
*)&req, sizeo
f(req));

}


static void user_gapBondMgr_pairStateCB(uint16_t connHandle,
uint8_t state,


uint8_t status)

{


if (state == GAPBOND_PAIRING_STATE_STARTED)


{


Log_info0("Pairing started");


}


else if (state == GA


{


if (status == SUCCESS)


{




}


else


{


Log_error1("Pairing failed. Error: %02x", status);


}


}


else if (state == GAPBOND_PAIRING_STATE_BONDED)


{


if (status == SUCCESS)


{


Log_info0("Re
-
established pairing from stored bond
info.");


}


}

}


static void user_service_ValueChangeCB( uint16_t connHandle,
uint16_t svcUuid,


uint8_t paramID,
uint
8_t *pValue,


uint16_t len )

{


Log_info2("(CB) Characteristic value change: svc(0x%04x)
paramID(%d). "


"Sending msg to app.", (IArg)svcUuid,
(IArg)paramID);


user_enqueueCharDataMsg(APP_MSG_SERVICE_WRIT
E, connHandle,
svcUuid, paramID,


pValue, len);

}


static void user_service_CfgChangeCB( uint16_t connHandle,
uint16_t svcUuid,

46



uint8_t paramID,
uint8_t *pValue,



uint16_t len )

{


Log_info2("(CB) Char config change: svc(0x%04x)
paramID(%d). "


"Sending msg to app.", (IArg)svcUuid,
(IArg)paramID);


user_enqueueCharDataMsg(APP_MSG_SERVICE_CFG, connHandle,
svcUuid,


paramID
, pValue, len);

}


static void buttonDebounceSwiFxn(UArg buttonId)

{


button_state_t buttonMsg = { .pinId = buttonId };


uint8_t sendMsg = FALSE;






if (buttonPinVal)


{


uttonPinHandle, PIN_BM_IRQ, buttonId |
PIN_IRQ_NEGEDGE);


}


else


{


PIN_IRQ_POSEDGE);


}



switch(buttonId)


{


case Board_BUTTON0:


if (buttonPinVal && button0State)


{


buttonMsg.state = button0State = 0;


sendMsg = TRUE;


}


else if (!buttonPinVal && !button0State)


{


buttonMsg.state = button0State = 1;


sendMsg = TRUE;


}


break;



case Board_BUTTON1:)


if (buttonPi
nVal && button1State)


{


buttonMsg.state = button1State = 0;


sendMsg = TRUE;


}


else if (!buttonPinVal && !button0State)

47



{


buttonMsg.state = button1State = 1;


sendMsg = TRUE;


}


break;


}




if (sendMsg == TRUE)


{


user_enqueueRawAppMsg(APP_MSG_BUTTON_DEBOUNCED,


(uint8_t *)&buttonMsg,
sizeof(buttonMsg));


}

}


static void buttonCallbackFxn(PIN_Handle handle, PIN_Id
pinId)

{


Log_info1("Button interrupt: %s",



(IArg)((pinId == Board_BUTTON0)?"Button
0":"Button 1"));






switch (pinId)


{


case Board_BUTTON0:


Clock_start(Clock_handle(&button0DebounceClock));


break;


case Board_BUT
TON1:


Clock_start(Clock_handle(&button1DebounceClock));


break;


}

}


static void user_enqueueCharDataMsg( app_msg_types_t
appMsgType,


uint16_t connHandle,


uint16_t servi
ceUUID,
uint8_t paramID,


uint8_t *pValue,
uint16_t len )

{


uint16_t readLen = len;



app_msg_t *pMsg = ICall_malloc( sizeof(app_msg_t) +
sizeof(char_data_t) +


readLen );



if (pMsg
!= NULL)


{


pMsg
-
�type = appMsgType;


48



char_data_t *pCharData = (char_data_t *)pMsg
-
�pdu;


pCharData
-
�svcUUID = serviceUUID; // Use 16
-
bit part of
UUID.


pCharData
-
�paramID = paramID;


memcpy(pCharData
-
�data, pValue, readLen);


pCharDat
a
-
�dataLen = readLen;


Queue_enqueue(hApplicationMsgQ, &pMsg
-
�_elem);


Semaphore_post(sem);


}

}


static void user_enqueueRawAppMsg(app_msg_types_t appMsgType,
uint8_t *pData,


uint16_t len)

{


app_msg_t *pMsg = ICa
ll_malloc( sizeof(app_msg_t) + len );



if (pMsg != NULL)


{


pMsg
-
�type = appMsgType;



memcpy(pMsg
-
�pdu, pData, len);



Queue_enqueue(hApplicationMsgQ, &pMsg
-
�_elem);



Semaphore_post(sem);


}

}


static void user_updateCharVal(char_data_t
*pCharData)

{


switch(pCharData
-
�svcUUID) {


case PUSH_SERVICE_SERV_UUID:


-
�paramID, pCharData
-
�dataLen,


pCharData
-
�data);


break;



case BUTTON_SERVICE_SERV_UUID:


Button
-
�paramID,
pCharData
-
�dataLen,


pCharData
-
�data);


break;



}

}


static char *Util_convertArrayToHexString(uint8_t const *src,
uint8_t src_len,


uint
8_t *dst,
uint8_t dst_len)

{


char hex[] = "0123456789ABCDEF";

49



uint8_t *pStr = dst;


uint8_t avail = dst_len
-
1;






�while (src_len && avail 3)


{


if (avail dst_len
-
1) { *pStr++ = ':'; avail
-
= 1; };


��*pStr++ = hex[*src 4];


*pStr++ = hex[*src++ & 0x0F];


avail
-
= 2;


src_len
--
;


}



if (src_len && avail)


*pStr++ = ':';




}






uint8_t



uint8_t advIdx = 0;



static char localNameStr[32] = { 0 };





for (advIdx = 0; advIdx 32;) {










-

1);


break;


} else {




}


}




}


Приложенные файлы

  • pdf 7812993
    Размер файла: 2 MB Загрузок: 2

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