ble.c 11.3 KB
Newer Older
1
#include "epicardium.h"
2
#include "modules/log.h"
3
#include "modules/config.h"
4

5
#include "fs/fs_util.h"
6
7
8
#include "wsf_types.h"
#include "wsf_buf.h"
#include "wsf_trace.h"
schneider's avatar
schneider committed
9
#include "ble_api.h"
10
#include "hci_vs.h"
11
12
#include "att_api.h"

13
14
15
#include "FreeRTOS.h"
#include "timers.h"

16
#include <machine/endian.h>
17
18
#include <stdio.h>
#include <string.h>
19
20
#include <stdbool.h>

Tobias Schneider's avatar
Tobias Schneider committed
21
#define FACTOR 2
schneider's avatar
schneider committed
22
#define WSF_BUF_POOLS 6
schneider's avatar
schneider committed
23
#define WSF_BUF_SIZE (0x1048 * FACTOR)
24

25
26
27
28
29
30
31
32
33
34
35
36
struct log_packet_header {
	uint32_t original_length;
	uint32_t included_length;
	uint32_t packet_flags;
	uint32_t cumulative_drops;
	uint32_t timestamp_us_h;
	uint32_t timestamp_us_l;
};
static const uint8_t log_header[] = {
	'b', 't', 's', 'n', 'o', 'o', 'p', 0, 0, 0, 0, 1, 0, 0, 0x03, 0xea
};

schneider's avatar
schneider committed
37
38
uint32_t SystemHeapSize = WSF_BUF_SIZE;
uint32_t SystemHeap[WSF_BUF_SIZE / 4];
39
uint32_t SystemHeapStart;
40

41
42
43
/* Task ID for the ble handler */
static TaskHandle_t ble_task_id = NULL;

44
/*! Default pool descriptor. */
schneider's avatar
schneider committed
45
/* clang-format off */
46
47
static wsfBufPoolDesc_t mainPoolDesc[WSF_BUF_POOLS] =
{
schneider's avatar
schneider committed
48
49
50
51
52
53
  {  16,  8*FACTOR },
  {  32,  4*FACTOR },
  {  64,  4*FACTOR },
  { 128,  4*FACTOR },
  { 256,  4*FACTOR },
  { 512,  4*FACTOR }
54
};
schneider's avatar
schneider committed
55
56
57
58
59
/* clang-format on */

static StaticTimer_t x;
static TimerHandle_t timerWakeup = NULL;
static int lasttick              = 0;
60

61
62
63
64
65
static int log_fd;
static bool log_dirty        = false;
static bool log_enabled      = false;
static int log_lastflushtick = 0;

66
/*! \brief  Stack initialization for app. */
67
extern void LlStackInit(void);
68
extern void StackInit(void);
schneider's avatar
schneider committed
69
extern void bleuart_init(void);
Hauke Mehrtens's avatar
Hauke Mehrtens committed
70
extern void bleFileTransfer_init(void);
71
extern void bleCard10_init(void);
72
extern void BbBleDrvSetTxPower(int8_t power);
73

74
75
/*************************************************************************************************/
static bool_t myTrace(const uint8_t *pBuf, uint32_t len)
76
{
schneider's avatar
schneider committed
77
	extern uint8_t wsfCsNesting;
78

schneider's avatar
schneider committed
79
80
81
82
	if (wsfCsNesting == 0) {
		fwrite(pBuf, len, 1, stdout);
		return TRUE;
	}
83

schneider's avatar
schneider committed
84
	return FALSE;
85
}
86
87
88
89
90
91

/*************************************************************************************************/
void WsfPDump(wsfPDumpType_t pdType, uint16_t length, uint8_t *pBuffer)
{
	uint32_t direction;
	uint8_t type;
92
	int ret;
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

	if (log_enabled) {
		switch (pdType) {
		case WSF_PDUMP_TYPE_HCI_CMD:
			direction = 0;
			type      = 0x01;
			break;
		case WSF_PDUMP_TYPE_HCI_EVT:
			direction = 1;
			type      = 0x04;
			break;
		case WSF_PDUMP_TYPE_HCI_TX_ACL:
			direction = 0;
			type      = 0x02;
			break;
		case WSF_PDUMP_TYPE_HCI_RX_ACL:
			direction = 1;
			type      = 0x02;
			break;
		default:
113
114
			LOG_WARN("ble", "Unknown packet type to be logged");
			return;
115
116
117
118
119
120
121
122
123
124
125
126
127
128
		}

		uint64_t tick         = xTaskGetTickCount();
		uint64_t timestamp_us = tick * 1000;

		struct log_packet_header header = {
			.original_length  = __htonl(length + 1),
			.included_length  = __htonl(length + 1),
			.packet_flags     = __htonl(direction),
			.cumulative_drops = __htonl(0),
			.timestamp_us_h   = __htonl(timestamp_us >> 32),
			.timestamp_us_l   = __htonl(timestamp_us & 0xFFFFFFFF)
		};

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
		ret = epic_file_write(log_fd, &header, sizeof(header));
		if (ret != sizeof(header)) {
			goto out_err;
		}

		ret = epic_file_write(log_fd, &type, sizeof(type));
		if (ret != sizeof(type)) {
			goto out_err;
		}

		ret = epic_file_write(log_fd, pBuffer, length);
		if (ret != length) {
			goto out_err;
		}

144
145
		log_dirty = true;
	}
146
147
148
149
150
151

	return;

out_err:
	LOG_WARN("ble", "Log file write failed. Logging diabled");
	log_enabled = false;
152
}
153
/*************************************************************************************************/
154
155
static void WsfInit(void)
{
156
	uint32_t bytesUsed __attribute__((unused));
schneider's avatar
schneider committed
157
158
159
160
161
162
163
164
165
	WsfTimerInit();

	SystemHeapStart = (uint32_t)&SystemHeap;
	memset(SystemHeap, 0, sizeof(SystemHeap));
	//printf("SystemHeapStart = 0x%x\n", SystemHeapStart);
	//printf("SystemHeapSize = 0x%x\n", SystemHeapSize);

	WsfTraceRegisterHandler(myTrace);
	WsfTraceEnable(TRUE);
166
167
168

	bytesUsed = WsfBufInit(WSF_BUF_POOLS, mainPoolDesc);
	APP_TRACE_INFO1("bytesUsed = %u", (unsigned int)bytesUsed);
169
}
schneider's avatar
schneider committed
170
/*************************************************************************************************/
171
/* TODO: We need a source of MACs */
172
static void setAddress(void)
173
{
174
	uint8_t bdAddr[6] = { 0xCA, 0x4D, 0x10, 0x00, 0x00, 0x00 };
schneider's avatar
schneider committed
175
176
	char buf[32];

177
178
	int result = fs_read_text_file("mac.txt", buf, sizeof(buf));

179
	if (result < 0) {
180
		APP_TRACE_INFO0("mac.txt not found, generating random MAC");
181
		epic_trng_read(bdAddr + 3, 3);
182
183
184
185
186
187
188
189
		sprintf(buf,
			"%02x:%02x:%02x:%02x:%02x:%02x\n",
			bdAddr[0],
			bdAddr[1],
			bdAddr[2],
			bdAddr[3],
			bdAddr[4],
			bdAddr[5]);
190
191
192
193
194
		fs_write_file("mac.txt", buf, strlen(buf));
	} else {
		APP_TRACE_INFO1("mac file contents: %s", buf);
	}

schneider's avatar
schneider committed
195
196
197
198
199
200
201
202
203
	int a, b, c, d, e, f;
	if (sscanf(buf, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f) == 6) {
		bdAddr[0] = f;
		bdAddr[1] = e;
		bdAddr[2] = d;
		bdAddr[3] = c;
		bdAddr[4] = b;
		bdAddr[5] = a;
	}
204

205
206
207
208
209
210
211
212
213
214
	LOG_INFO(
		"ble",
		"Setting MAC address to %02X:%02X:%02X:%02X:%02X:%02X",
		bdAddr[5],
		bdAddr[4],
		bdAddr[3],
		bdAddr[2],
		bdAddr[1],
		bdAddr[0]
	);
schneider's avatar
schneider committed
215
	HciVsSetBdAddr(bdAddr);
216
}
schneider's avatar
schneider committed
217
/*************************************************************************************************/
218
static void vTimerCallback(xTimerHandle pxTimer)
219
{
schneider's avatar
schneider committed
220
221
222
223
224
225
	//printf("wake\n");
	int tick = xTaskGetTickCount();
	//printf("WsfTimerUpdate(%d)\n", tick - lasttick);
	WsfTimerUpdate(tick - lasttick);
	lasttick = tick;
	//printf("done\n");
226
}
schneider's avatar
schneider committed
227
/*************************************************************************************************/
228
229
230
static void notify(void)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
schneider's avatar
schneider committed
231
232
233
234
235
236
	if (xPortIsInsideInterrupt()) {
		vTaskNotifyGiveFromISR(ble_task_id, &xHigherPriorityTaskWoken);
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	} else {
		xTaskNotifyGive(ble_task_id);
	}
237
}
schneider's avatar
schneider committed
238
/*************************************************************************************************/
239
240
void WsfTimerNotify(void)
{
schneider's avatar
schneider committed
241
242
243
	//printf("WsfTimerNotify\n");
	// TODO: Can we do this without waking up the task?
	// xTimerChangePeriodFromISR exists
244
	NVIC->STIR = RSV11_IRQn;
245
}
schneider's avatar
schneider committed
246
/*************************************************************************************************/
247
248
void wsf_ble_signal_event(void)
{
schneider's avatar
schneider committed
249
	//printf("wsf_ble_signal_event\n");
250
251
252
253
254
	NVIC->STIR = RSV11_IRQn;
}
/*************************************************************************************************/
void RSV11_IRQHandler(void)
{
schneider's avatar
schneider committed
255
	notify();
256
}
schneider's avatar
schneider committed
257
/*************************************************************************************************/
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#define BLEMAXCFGBYTES 100
bool ble_shall_start(void)
{
	int bleConfigFile = epic_file_open("ble.txt", "r");
	if (bleConfigFile < 0) {
		LOG_INFO("ble", "can not open ble.txt -> BLE is not started");
		epic_file_close(bleConfigFile);
		return false;
	}

	char cfgBuf[BLEMAXCFGBYTES + 1];
	int readNum = epic_file_read(bleConfigFile, cfgBuf, BLEMAXCFGBYTES);
	epic_file_close(bleConfigFile);
	if (readNum < 0) {
		LOG_WARN("ble", "can not read ble.txt -> BLE is not started");
		return false;
	}
	cfgBuf[readNum] = '\0';

	char bleActiveStr[]              = "active=true";
	cfgBuf[sizeof(bleActiveStr) - 1] = '\0';

	if (strcmp(cfgBuf, "active=true") != 0) {
		LOG_INFO("ble", "BLE is disabled.");
		return false;
	} else {
		LOG_INFO("ble", "BLE is enabled.");
		return true;
	}
}
/*************************************************************************************************/
289
static void scheduleTimer(void)
290
{
schneider's avatar
schneider committed
291
292
293
294
295
296
297
298
299
	bool_t timerRunning;
	wsfTimerTicks_t time_to_next_expire;

	vTimerCallback(NULL);
	time_to_next_expire = WsfTimerNextExpiration(&timerRunning);

	if (timerRunning) {
		//printf("time_to_next_expire = %d\n", time_to_next_expire);
		//printf("change period\n");
300
301
302
303
304
305
306
		/* We need to make sure not to schedule a 0 ticks timer.
		 * Maybe it would also be enough to simply call the dispatcher
		 * in this case... */
		if (time_to_next_expire == 0) {
			time_to_next_expire = 1;
		}

schneider's avatar
schneider committed
307
308
309
310
311
312
313
314
		if (timerWakeup != NULL) {
			xTimerChangePeriod(
				timerWakeup,
				pdMS_TO_TICKS(time_to_next_expire),
				0
			);
			//printf("insert done\n");
		} else {
315
			LOG_ERR("ble", "Could not create timer");
schneider's avatar
schneider committed
316
317
		}
	} else {
318
		APP_TRACE_INFO0("No timer running");
schneider's avatar
schneider committed
319
	}
320
}
schneider's avatar
schneider committed
321
/*************************************************************************************************/
322
323
324
325
326
327
328
329
330
331
332
333
334
static void log_flush(void)
{
	int tick = xTaskGetTickCount();
	if (tick - log_lastflushtick > 5000) {
		log_lastflushtick = tick;
		if (log_dirty) {
			log_dirty = false;
			LOG_INFO("ble", "Flushing log");
			epic_file_flush(log_fd);
		}
	}
}
/*************************************************************************************************/
335
static int log_rotate(void)
336
337
338
339
340
{
	int i;
	char filename_old[16];
	char filename_new[16];
	struct epic_stat stat;
341
	int ret;
342

343
344
345
346
347
348
349
350
351
352
353
	epic_file_stat("logs", &stat);

	if (stat.type == EPICSTAT_FILE) {
		return -1;
	}

	if (stat.type == EPICSTAT_NONE) {
		ret = epic_file_mkdir("logs");
		if (ret < 0) {
			return ret;
		}
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
	}

	if (epic_file_stat("logs/ble9.log", &stat) == 0) {
		epic_file_unlink("logs/ble9.log");
	}

	for (i = 8; i > 0; i--) {
		sprintf(filename_old, "logs/ble%d.log", i);
		sprintf(filename_new, "logs/ble%d.log", i + 1);

		if (epic_file_stat(filename_old, &stat) == 0) {
			epic_file_rename(filename_old, filename_new);
		}
	}

	if (epic_file_stat("logs/ble.log", &stat) == 0) {
		epic_file_rename("logs/ble.log", "logs/ble1.log");
	}
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408

	return 0;
}
/*************************************************************************************************/
static void log_init(void)
{
	int ret;
	log_enabled = config_get_boolean_with_default("ble_log_enable", false);

	if (!log_enabled) {
		return;
	}

	LOG_INFO("ble", "Log is enabled");

	if (log_rotate() < 0) {
		log_enabled = false;
		LOG_WARN("ble", "Can not rotate logs. Logging disabled.");
		return;
	}

	log_fd = epic_file_open("logs/ble.log", "w");
	if (log_fd < 0) {
		log_enabled = false;
		LOG_WARN("ble", "Can not create log file. Logging disabled.");
		return;
	}

	ret = epic_file_write(log_fd, log_header, sizeof(log_header));
	if (ret != sizeof(log_header)) {
		log_enabled = false;
		LOG_WARN(
			"ble",
			"Can not create log file header. Logging disabled."
		);
		return;
	}
409
410
}
/*************************************************************************************************/
schneider's avatar
schneider committed
411
void vBleTask(void *pvParameters)
412
{
413
	ble_task_id = xTaskGetCurrentTaskHandle();
Rahix's avatar
Rahix committed
414
415
416
417
418
419

	/*
	 * Delay BLE startup by a bit because it locks up Epicardium otherwise.
	 */
	vTaskDelay(pdMS_TO_TICKS(500));

420
	log_init();
421

422
423
424
425
426
427
	/* We are going to execute FreeRTOS functions from callbacks
	 * coming from this interrupt. Its priority needs to be
	 * reduced to allow this. */
	NVIC_SetPriority(RSV11_IRQn, 2);
	NVIC_EnableIRQ(RSV11_IRQn);

schneider's avatar
schneider committed
428
	WsfInit();
429

430
431
432
	taskENTER_CRITICAL();
	/* Critical section to prevent a loop in iq_capture2 / meas_freq in
	 * /home/maxim/Documents/src/BLE/mcbusw/Hardware/Micro/ME14/Firmware/trunk/NDALibraries/BTLE/phy/dbb/prot/ble/pan2g5/afe/max32665/board_config.c:275
433
434
	 * if BHI160 and -Ddebug_prints=true is enabled. See #115. */
	LlStackInit();
435
	taskEXIT_CRITICAL();
436
437

	StackInit();
438
	BbBleDrvSetTxPower(0);
schneider's avatar
schneider committed
439
440
441
442
443
444
	setAddress();

	BleStart();
	AttsDynInit();

	bleuart_init();
Hauke Mehrtens's avatar
Hauke Mehrtens committed
445
	bleFileTransfer_init();
446
	bleCard10_init();
schneider's avatar
schneider committed
447
448
449
450
451
452
453
454
455
456
457
458

	lasttick = xTaskGetTickCount();

	timerWakeup = xTimerCreateStatic(
		"timerWakeup",    /* name */
		pdMS_TO_TICKS(1), /* period/time */
		pdFALSE,          /* auto reload */
		NULL,             /* timer ID */
		vTimerCallback,
		&x); /* callback */

	while (1) {
459
		ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000);
schneider's avatar
schneider committed
460
461
		wsfOsDispatcher();
		scheduleTimer();
462
463
464
		if (log_enabled) {
			log_flush();
		}
schneider's avatar
schneider committed
465
	}
466
}