[nRF52BLE][4]C Development with SoftDevice API
4) Actual Code / API Use
개발환경 : Seggar Embedded Studio (SES)
개발보드 : nRF52DK (PCA10040)
i) - SDK폴더\examples에 폴더 생성 (폴더 이름은 마음대로)
ii) - 첨부된 파일의 압축을 풀고 폴더 안에 위치
(모든 dependency가 상대경로로 지정되어 있기 때문에 정확한 디렉토리 위치에 있지 않을 경우 컴파일되지 않는다)
iii) - 컴파일
수정하고 추가한 모든 파일이 Application 폴더 안에 존재하게끔 되어 있다.
CTRL + F 로 각 numbering 된 단계를 따라가시면서 코드를 봐주시면 된다.
주기적으로 송신되는 센서의 값은 nRF 에 내장된 프로세서 온도이고, 이를 응용해 GPIO로 받아지는 센서 출력을 받게끔 변경할 수 있다.
1. Service 생성
1.A) Service 구조체 선언 [\main.c]
1.B) Service 초기화 [\main.c\services_init()]
1.C) BLE Stack Table에 UUID 추가 [\our_service.c\our_service_init()]
1.D) sd_ble_gatts_service_add() 로 Service 추가 [\our_service.c\our_service_init()]
1.E) Service UUID를 가지는 ble_uuid_t 구조체 변수 선언 [\main.c]
1.F) Scan Response 선언 / 인스턴스화 [\main.c\advertising_init()]
2. Characteristics 생성
2.A) Custom Characteristic UUID [\our_service.c\our_char_add()]
2.B) 메모리 어느 부분에 Attribute 저장할 것인지 설정 [\our_service.c\our_char_add()]
2.C) Characteristic value Attribute를 생성해 UUID를 저장할 수 있도록 sd_ble_gatts_characteristic_add() 로 Characteristics 추가 [\our_service.c\our_char_add()]
2.D) ble_os_t 구조체에 characteristic 위한 handle 추가 [\our_service.h]
2.E) sd_blegatts_characteristic_add()로 service에 Characteristic 추가 [\our_service.c\our_char_add()]
2.F) Read/Write Property 추가 [\our_service.c\our_char_add()]
2.G) Read/Write Permission 추가 [\our_service.c\our_char_add()]
2.H) Characteristic Length 설정 (기본이 0으로 되어있어 Write 불가했었음) [\our_service.c\our_char_add()]
3. CCCD를 설정하고 Characteristic에 추가하여 sensor value 바뀔때마다 주기적으로 notification 송신 & Housekeeping.
Housekeeping : Bluetooth Connection 관리를 뜻한다
3.A) CCCD Metadata 설정 [\our_service.c\our_char_add()]
3.B) Housekeeping: Service connection handle 을 기본값으로(BLE_CONN_HANDLE_INVALID) 설정 [\our_service.c\our_service_init()]
3.C) Housekeeping: Responding to Connect and Disconnect Events [\main.c\ble_stack_init()]
여기서 Observer는 event를 듣고 있는 코드로 이루어져 있다. 안드로이드의 broadcasting, iOS의 notification 과 비슷한 느낌...
3.D) Switch 문으로 BLE Event 처리. 정확히는 Connection 시 BLE Stack에서 제공하는 현재의 connection handle로 Service 구조체의 connection handle을 업데이트.[\our_service.c\ble_our_service_on_ble_evt()]
3.E) Characteristic Value 업데이트 [\our_service.c\our_characteristic_update()]
Housekeeping을 한 이유는 connection을 확인 후 notification을 보내기 위함이었다. connection if문으로 확인 후 진행한다. 진행 시 hvx 라는 것을 마주치게 되는데 이는 Handle Value X 의 축약어이며, X는 구조체로 정의된 notification 또는 indication을 뜻한다. [\our_service.c\our_sensor_characteristic_update()]
여기서부터는 Sensor 데이터를 제시간에 제공하기만 하면 되는데, 타이머를 써야 한다.
3.F) timer가 일정 시간에 도달했을때 불려지는 함수 정의 - characteristic update [\main.c\timer_timeout_handler()]
3.G) timer ID 설정 및 시간 간격 설정 [\main.c]
3.H) timer app_timer_create()로 생성 [\main.c\application_timers_init()]
3.I) timer app_timer_start()로시작 [\main.c\application_timers_start()]
부록 - 함수 정보
- observer
다음과 같이 구성되어 있다.
NRF_SDH_BLE_OBSERVER(_name, _prio, _handler, _context)
name: observer의 이름 설정
handler: BLE Stack의 Event가 생기면 handler function이 불러짐 .
context: Event Handler의 인자로 들어간다.
- hvx_param의 멤버
handle : 어떤 characteristic value를 다루는지
type: notification (BLE_GATT_HVX_NOTIFICATION)인지 indication(BLE_GATT_HVX_INDICATION)인지
offset: 송신하고 싶은 정보의 byte 수가 많고, 적당한 곳에서 추출하고 싶을 경우
p_len: Softdevice는 송신하는 정보의 바이트 크기를 알아야 한다. 예를 들어 0x01, 0x02, 0x03, 0x04, 0x05 를 BLE를 통해 보내고 싶은데, 3번째와 4번째 바이트만 보내고 싶다면 offset = 2, len = 2 가 된다.
p_data: 실제 보내고자 하는 데이터를 가리키는 포인터
- app_timer_create(&m_our_char_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
m_our_char_timer_id : Timer ID
APP_TIMER_MODE_REPEATED : enumeration
timer_timeout_handler : timer event 실행 시 실행되는 함수
- app_timer_start(m_our_char_timer_id, OUR_CHAR_TIMER_INTERVAL, NULL);
m_our_char_timer_id : ID Variable :
timer interval : OUR_CHAR_TIMER_INTERVAL
timer expire 되면 불려지는 함수 - 신경 안쓰기 때문에 NULL
- advertising_init() 함수
advdata 변수에는 첫 advertising packet을 구성할 때 이용하는 정보가 들어있다. Advertising packet 은 31바이트보다 클 수 없다는 것을 기억해야 한다. Device Name 을 길게하면 글자가 잘리는 이유가 되기 때문이다. ble_advertising_init_t 의 속성 중 하나인 advdata 의 멤버를 원하는 advertising 되는 방식에 맞게 설정해주어야 한다.