1 /* rtt_console.c - Console messages to a RAM buffer that is then read by
2  * the Segger J-Link debugger
3  */
4 
5 /*
6  * Copyright (c) 2016 Nordic Semiconductor ASA
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 
12 #include <zephyr/kernel.h>
13 #include <zephyr/sys/printk.h>
14 #include <zephyr/device.h>
15 #include <zephyr/init.h>
16 #include <SEGGER_RTT.h>
17 
18 extern void __printk_hook_install(int (*fn)(int));
19 extern void __stdout_hook_install(int (*fn)(int));
20 
21 static bool host_present;
22 
23 /** @brief Wait for fixed period.
24  *
25  */
wait(void)26 static void wait(void)
27 {
28 	if (!IS_ENABLED(CONFIG_MULTITHREADING) || k_is_in_isr()) {
29 		if (IS_ENABLED(CONFIG_RTT_TX_RETRY_IN_INTERRUPT)) {
30 			k_busy_wait(1000*CONFIG_RTT_TX_RETRY_DELAY_MS);
31 		}
32 	} else {
33 		k_msleep(CONFIG_RTT_TX_RETRY_DELAY_MS);
34 	}
35 }
36 
rtt_console_out(int character)37 static int rtt_console_out(int character)
38 {
39 	char c = (char)character;
40 	unsigned int cnt;
41 	int max_cnt = CONFIG_RTT_TX_RETRY_CNT;
42 
43 	do {
44 		SEGGER_RTT_LOCK();
45 		cnt = SEGGER_RTT_WriteNoLock(0, &c, 1);
46 		SEGGER_RTT_UNLOCK();
47 
48 		/* There are two possible reasons for not writing any data to
49 		 * RTT:
50 		 * - The host is not connected and not reading the data.
51 		 * - The buffer got full and will be read by the host.
52 		 * These two situations are distinguished using the following
53 		 * algorithm:
54 		 * At the beginning, the module assumes that the host is active,
55 		 * so when no data is read, it busy waits and retries.
56 		 * If, after retrying, the host reads the data, the module
57 		 * assumes that the host is active. If it fails, the module
58 		 * assumes that the host is inactive and stores that
59 		 * information. On next call, only one attempt takes place.
60 		 * The host is marked as active if the attempt is successful.
61 		 */
62 		if (cnt) {
63 			/* byte processed - host is present. */
64 			host_present = true;
65 		} else if (host_present) {
66 			if (max_cnt) {
67 				wait();
68 				max_cnt--;
69 				continue;
70 			} else {
71 				host_present = false;
72 			}
73 		}
74 
75 		break;
76 	} while (1);
77 
78 	return character;
79 }
80 
rtt_console_init(void)81 static int rtt_console_init(void)
82 {
83 
84 #ifdef CONFIG_PRINTK
85 	__printk_hook_install(rtt_console_out);
86 #endif
87 	__stdout_hook_install(rtt_console_out);
88 
89 	return 0;
90 }
91 
92 SYS_INIT(rtt_console_init, PRE_KERNEL_1, CONFIG_CONSOLE_INIT_PRIORITY);
93