aboutsummaryrefslogtreecommitdiff
path: root/src/ble/peripheral.c
blob: f9c5e58e615292b736be16a5915f1de2b84407ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include "CH58xBLE_LIB.h"
#include "setup.h"

#define ADV_UUID    (0xFEE0)

static uint8 taskid = INVALID_TASK_ID;

typedef struct
{
	uint16 connHandle; // Connection handle of current connection
	uint16 connInterval;
	uint16 connSlaveLatency;
	uint16 connTimeout;
} peripheralConnItem_t;

#define SBP_PARAM_UPDATE_DELAY 1600 // Parameter update delay (unit of 0.625ms)
#define SLAVE_LATENCY       0

#define MIN_ADV_INTERVAL    100 // Advertising interval (units of 0.625ms)
#define MAX_ADV_INTERVAL    200 // Advertising interval (units of 0.625ms)

#define MIN_CONN_INTERVAL   20 // Connection interval (units of 1.25ms)
#define MAX_CONN_INTERVAL   100 // Connection interval (units of 1.25ms)

#define CONN_TIMEOUT        100 // Supervision timeout (units of 10ms)

// GAP - SCAN RSP data (max size = 31 bytes)
static uint8 scanRspData[] = {
	// complete name
	16, // length of this section
	GAP_ADTYPE_LOCAL_NAME_COMPLETE,
	'L', 'E','D', ' ',
	'B', 'a','d', 'g', 'e', ' ',
	'M', 'a','g', 'i', 'c',

	// connection interval range
	0x05, // length of this section
	GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
	LO_UINT16(MIN_CONN_INTERVAL),
	HI_UINT16(MIN_CONN_INTERVAL),
	LO_UINT16(MAX_CONN_INTERVAL),
	HI_UINT16(MAX_CONN_INTERVAL),

	// Tx power level
	0x02, // length of this data
	GAP_ADTYPE_POWER_LEVEL,
	9 // 9dBm
};

// GAP - Advertisement data (max size = 31 bytes)
// keep short, save energy, save the planet
static uint8 advertData[] = {
	0x02, // section length
	GAP_ADTYPE_FLAGS,
	GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

	// advertise UUID
	0x03, // section length
	GAP_ADTYPE_16BIT_MORE,
	LO_UINT16(ADV_UUID),
	HI_UINT16(ADV_UUID)
};

// GAP GATT Attributes
static uint8 devName[GAP_DEVICE_NAME_LEN] = "LED Badge Magic";

// Connection item list
static peripheralConnItem_t conn_list;

static void initConn(peripheralConnItem_t *conn)
{
	conn->connHandle = GAP_CONNHANDLE_INIT;
	conn->connInterval = 0;
	conn->connSlaveLatency = 0;
	conn->connTimeout = 0;
}

static void processTMOSMsg(tmos_event_hdr_t *pMsg)
{
	switch(pMsg->event) {
		default:
			break;
	}
}

static void enable_advertising(uint8_t enable)
{
	GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &enable);
}

static void link_onEstablished(gapRoleEvent_t *pe)
{
	gapEstLinkReqEvent_t *e = (gapEstLinkReqEvent_t *)pe;

	// If already connected
	if(conn_list.connHandle != GAP_CONNHANDLE_INIT) {
		// Only allow 1 connection, so the new connection will be dropped:
		GAPRole_TerminateLink(e->connectionHandle);
		GAPRole_PeripheralConnParamUpdateReq(e->connectionHandle,
					MIN_CONN_INTERVAL,
					MAX_CONN_INTERVAL,
					SLAVE_LATENCY,
					CONN_TIMEOUT,
					taskid);
		return;
	}
	conn_list.connHandle = e->connectionHandle;
	conn_list.connInterval = e->connInterval;
	conn_list.connSlaveLatency = e->connLatency;
	conn_list.connTimeout = e->connTimeout;
	enable_advertising(FALSE);
}

static void link_onTerminated(gapRoleEvent_t *pe)
{
	gapTerminateLinkEvent_t *event = (gapTerminateLinkEvent_t *)pe;
	GAPRole_TerminateLink(pe->linkCmpl.connectionHandle);
	enable_advertising(TRUE);

	if(event->connectionHandle == conn_list.connHandle) {
		conn_list.connHandle = GAP_CONNHANDLE_INIT;
		conn_list.connInterval = 0;
		conn_list.connSlaveLatency = 0;
		conn_list.connTimeout = 0;
	} else {
		// Requested connection is not existed in connection list
	}
}

static void gap_onParamUpdate(uint16 connHandle, uint16 connInterval,
				uint16 connSlaveLatency, uint16 connTimeout)
{
	conn_list.connHandle = connHandle;
	conn_list.connInterval = connInterval;
	conn_list.connSlaveLatency = connSlaveLatency;
	conn_list.connTimeout = connTimeout;
}

static void gap_onStateChange(gapRole_States_t newState, gapRoleEvent_t *pEvent)
{
	switch(newState & GAPROLE_STATE_ADV_MASK) {
	case GAPROLE_ADVERTISING:
		if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT) {
			link_onTerminated(pEvent);
		}
		break;

	case GAPROLE_CONNECTED:
		if(pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT) {
			link_onEstablished(pEvent);
		}
		break;

	case GAPROLE_WAITING:
		if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT) {
			link_onTerminated(pEvent);
		} else {
			// refer to pEvent->gap.opcode
		}
		break;

	default:
		break;
	}
}

// GAP Role Callbacks
static gapRolesCBs_t gap_handlers = {
	gap_onStateChange,
	NULL,
	gap_onParamUpdate
};

// Broadcast Callbacks
static gapRolesBroadcasterCBs_t broadcast_handlers = {
	NULL,
	NULL
};

// GAP Bond Manager Callbacks
static gapBondCBs_t bond_managers = {
	NULL,
	NULL
};


static uint16 peripheral_task(uint8 task_id, uint16 events)
{
	if(events & SYS_EVENT_MSG) { // Handle BLE stack message
		uint8 *pMsg = tmos_msg_receive(taskid);
		if(pMsg) {
			processTMOSMsg((tmos_event_hdr_t *)pMsg);
			tmos_msg_deallocate(pMsg);
		}
		return (events ^ SYS_EVENT_MSG);
	}

	return 0;
}

void ble_enable_advertise()
{
	uint8 e = TRUE;
	GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &e);
}

void ble_disable_advertise()
{
	uint8 e = FALSE;
	GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &e);
}

static void gap_init()
{
	GAPRole_PeripheralInit();

	static uint16 desired_min_interval = 6;
	static uint16 desired_max_interval = 500;

	// Set the GAP Role Parameters
	GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
	GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
	GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16), &desired_min_interval);
	GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16), &desired_max_interval);
	
	// Set the GAP Characteristics
	GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, devName);
	GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, MIN_ADV_INTERVAL);
	GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, MAX_ADV_INTERVAL);

	static uint32 passkey = 0; // passkey "000000"
	static uint8  pairMode = GAPBOND_PAIRING_MODE_NO_PAIRING;
	static uint8  mitm = FALSE;
	static uint8  bonding = FALSE;
	static uint8  ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
	GAPBondMgr_SetParameter(GAPBOND_PERI_DEFAULT_PASSCODE, sizeof(uint32), &passkey);
	GAPBondMgr_SetParameter(GAPBOND_PERI_PAIRING_MODE, sizeof(uint8), &pairMode);
	GAPBondMgr_SetParameter(GAPBOND_PERI_MITM_PROTECTION, sizeof(uint8), &mitm);
	GAPBondMgr_SetParameter(GAPBOND_PERI_IO_CAPABILITIES, sizeof(uint8), &ioCap);
	GAPBondMgr_SetParameter(GAPBOND_PERI_BONDING_ENABLED, sizeof(uint8), &bonding);

	GAPRole_BroadcasterSetCB(&broadcast_handlers);

	GGS_AddService(GATT_ALL_SERVICES);
	GATTServApp_AddService(GATT_ALL_SERVICES);
}

void peripheral_init()
{
	taskid = TMOS_ProcessEventRegister(peripheral_task);

	initConn(&conn_list);
	gap_init();

	GAPRole_PeripheralStartDevice(taskid, &bond_managers, &gap_handlers);
}