ble.c 11.5 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 68
extern void StackInit(void);
extern void AppInit(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
/*************************************************************************************************/
void PalSysAssertTrap(void)
76
{
schneider's avatar
schneider committed
77 78
	while (1) {
	}
79
}
80 81
/*************************************************************************************************/
static bool_t myTrace(const uint8_t *pBuf, uint32_t len)
82
{
schneider's avatar
schneider committed
83
	extern uint8_t wsfCsNesting;
84

schneider's avatar
schneider committed
85 86 87 88
	if (wsfCsNesting == 0) {
		fwrite(pBuf, len, 1, stdout);
		return TRUE;
	}
89

schneider's avatar
schneider committed
90
	return FALSE;
91
}
92 93 94 95 96 97

/*************************************************************************************************/
void WsfPDump(wsfPDumpType_t pdType, uint16_t length, uint8_t *pBuffer)
{
	uint32_t direction;
	uint8_t type;
98
	int ret;
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

	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:
119 120
			LOG_WARN("ble", "Unknown packet type to be logged");
			return;
121 122 123 124 125 126 127 128 129 130 131 132 133 134
		}

		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)
		};

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
		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;
		}

150 151
		log_dirty = true;
	}
152 153 154 155 156 157

	return;

out_err:
	LOG_WARN("ble", "Log file write failed. Logging diabled");
	log_enabled = false;
158
}
159
/*************************************************************************************************/
160 161
static void WsfInit(void)
{
162
	uint32_t bytesUsed __attribute__((unused));
schneider's avatar
schneider committed
163 164 165 166 167 168 169 170 171
	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);
172 173 174

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

183 184
	int result = fs_read_text_file("mac.txt", buf, sizeof(buf));

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

schneider's avatar
schneider committed
201 202 203 204 205 206 207 208 209
	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;
	}
210

211 212 213 214 215 216 217 218 219 220
	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
221
	HciVsSetBdAddr(bdAddr);
222
}
schneider's avatar
schneider committed
223
/*************************************************************************************************/
224
static void vTimerCallback(xTimerHandle pxTimer)
225
{
schneider's avatar
schneider committed
226 227 228 229 230 231
	//printf("wake\n");
	int tick = xTaskGetTickCount();
	//printf("WsfTimerUpdate(%d)\n", tick - lasttick);
	WsfTimerUpdate(tick - lasttick);
	lasttick = tick;
	//printf("done\n");
232
}
schneider's avatar
schneider committed
233
/*************************************************************************************************/
234 235 236
static void notify(void)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
schneider's avatar
schneider committed
237 238 239 240 241 242
	if (xPortIsInsideInterrupt()) {
		vTaskNotifyGiveFromISR(ble_task_id, &xHigherPriorityTaskWoken);
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	} else {
		xTaskNotifyGive(ble_task_id);
	}
243
}
schneider's avatar
schneider committed
244
/*************************************************************************************************/
245 246
void WsfTimerNotify(void)
{
schneider's avatar
schneider committed
247 248 249
	//printf("WsfTimerNotify\n");
	// TODO: Can we do this without waking up the task?
	// xTimerChangePeriodFromISR exists
250
	NVIC->STIR = RSV11_IRQn;
251
}
schneider's avatar
schneider committed
252
/*************************************************************************************************/
253 254
void wsf_ble_signal_event(void)
{
schneider's avatar
schneider committed
255
	//printf("wsf_ble_signal_event\n");
256 257 258 259 260
	NVIC->STIR = RSV11_IRQn;
}
/*************************************************************************************************/
void RSV11_IRQHandler(void)
{
schneider's avatar
schneider committed
261
	notify();
262
}
schneider's avatar
schneider committed
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 289 290 291 292 293 294
#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;
	}
}
/*************************************************************************************************/
295
static void scheduleTimer(void)
296
{
schneider's avatar
schneider committed
297 298 299 300 301 302 303 304 305
	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");
306 307 308 309 310 311 312
		/* 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
313 314 315 316 317 318 319 320
		if (timerWakeup != NULL) {
			xTimerChangePeriod(
				timerWakeup,
				pdMS_TO_TICKS(time_to_next_expire),
				0
			);
			//printf("insert done\n");
		} else {
321
			LOG_ERR("ble", "Could not create timer");
schneider's avatar
schneider committed
322 323
		}
	} else {
324
		APP_TRACE_INFO0("No timer running");
schneider's avatar
schneider committed
325
	}
326
}
schneider's avatar
schneider committed
327
/*************************************************************************************************/
328 329 330 331 332 333 334 335 336 337 338 339 340
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);
		}
	}
}
/*************************************************************************************************/
341
static int log_rotate(void)
342 343 344 345 346
{
	int i;
	char filename_old[16];
	char filename_new[16];
	struct epic_stat stat;
347
	int ret;
348

349 350 351 352 353 354 355 356 357 358 359
	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;
		}
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
	}

	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");
	}
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 409 410 411 412 413 414

	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;
	}
415 416
}
/*************************************************************************************************/
schneider's avatar
schneider committed
417
void vBleTask(void *pvParameters)
418
{
419
	ble_task_id = xTaskGetCurrentTaskHandle();
Rahix's avatar
Rahix committed
420 421 422 423 424 425

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

426
	log_init();
427

428 429 430 431 432 433
	/* 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
434
	WsfInit();
435 436 437 438
	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
	 * if BHI160 and -Ddebug_prints=true is enabled*/
schneider's avatar
schneider committed
439
	StackInit();
440
	taskEXIT_CRITICAL();
441
	BbBleDrvSetTxPower(0);
schneider's avatar
schneider committed
442 443 444 445 446 447 448
	setAddress();

	AppInit();
	BleStart();
	AttsDynInit();

	bleuart_init();
Hauke Mehrtens's avatar
Hauke Mehrtens committed
449
	bleFileTransfer_init();
450
	bleCard10_init();
schneider's avatar
schneider committed
451 452 453 454 455 456 457 458 459 460 461 462

	lasttick = xTaskGetTickCount();

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

	while (1) {
463
		ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000);
schneider's avatar
schneider committed
464 465
		wsfOsDispatcher();
		scheduleTimer();
466 467 468
		if (log_enabled) {
			log_flush();
		}
schneider's avatar
schneider committed
469
	}
470
}