openocd: src: replace the GPL-2.0-or-later license tag
[openocd.git] / src / rtt / rtt.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /*
4 * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de>
5 */
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include <stdint.h>
12 #include <stdbool.h>
13 #include <string.h>
14
15 #include <helper/log.h>
16 #include <helper/list.h>
17 #include <target/target.h>
18 #include <target/rtt.h>
19
20 #include "rtt.h"
21
22 static struct {
23 struct rtt_source source;
24 /** Control block. */
25 struct rtt_control ctrl;
26 struct target *target;
27 /** Start address to search for the control block. */
28 target_addr_t addr;
29 /** Size of the control block search area. */
30 size_t size;
31 /** Control block identifier. */
32 char id[RTT_CB_MAX_ID_LENGTH];
33 /** Whether RTT is configured. */
34 bool configured;
35 /** Whether RTT is started. */
36 bool started;
37 /** Whether configuration changed. */
38 bool changed;
39 /** Whether the control block was found. */
40 bool found_cb;
41
42 struct rtt_sink_list **sink_list;
43 size_t sink_list_length;
44
45 unsigned int polling_interval;
46 } rtt;
47
48 int rtt_init(void)
49 {
50 rtt.sink_list_length = 1;
51 rtt.sink_list = calloc(rtt.sink_list_length,
52 sizeof(struct rtt_sink_list *));
53
54 if (!rtt.sink_list)
55 return ERROR_FAIL;
56
57 rtt.sink_list[0] = NULL;
58 rtt.started = false;
59
60 rtt.polling_interval = 100;
61
62 return ERROR_OK;
63 }
64
65 int rtt_exit(void)
66 {
67 free(rtt.sink_list);
68
69 return ERROR_OK;
70 }
71
72 static int read_channel_callback(void *user_data)
73 {
74 int ret;
75
76 ret = rtt.source.read(rtt.target, &rtt.ctrl, rtt.sink_list,
77 rtt.sink_list_length, NULL);
78
79 if (ret != ERROR_OK) {
80 target_unregister_timer_callback(&read_channel_callback, NULL);
81 rtt.source.stop(rtt.target, NULL);
82 return ret;
83 }
84
85 return ERROR_OK;
86 }
87
88 int rtt_setup(target_addr_t address, size_t size, const char *id)
89 {
90 size_t id_length = strlen(id);
91
92 if (!id_length || id_length >= RTT_CB_MAX_ID_LENGTH) {
93 LOG_ERROR("rtt: Invalid control block ID");
94 return ERROR_COMMAND_ARGUMENT_INVALID;
95 }
96
97 rtt.addr = address;
98 rtt.size = size;
99 strncpy(rtt.id, id, id_length + 1);
100 rtt.changed = true;
101 rtt.configured = true;
102
103 return ERROR_OK;
104 }
105
106 int rtt_register_source(const struct rtt_source source,
107 struct target *target)
108 {
109 if (!source.find_cb || !source.read_cb || !source.read_channel_info)
110 return ERROR_FAIL;
111
112 if (!source.start || !source.stop)
113 return ERROR_FAIL;
114
115 if (!source.read || !source.write)
116 return ERROR_FAIL;
117
118 rtt.source = source;
119 rtt.target = target;
120
121 return ERROR_OK;
122 }
123
124 int rtt_start(void)
125 {
126 int ret;
127 target_addr_t addr = rtt.addr;
128
129 if (rtt.started)
130 return ERROR_OK;
131
132 if (!rtt.found_cb || rtt.changed) {
133 rtt.source.find_cb(rtt.target, &addr, rtt.size, rtt.id,
134 &rtt.found_cb, NULL);
135
136 rtt.changed = false;
137
138 if (rtt.found_cb) {
139 LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR,
140 addr);
141 rtt.ctrl.address = addr;
142 } else {
143 LOG_INFO("rtt: No control block found");
144 return ERROR_OK;
145 }
146 }
147
148 ret = rtt.source.read_cb(rtt.target, rtt.ctrl.address, &rtt.ctrl, NULL);
149
150 if (ret != ERROR_OK)
151 return ret;
152
153 ret = rtt.source.start(rtt.target, &rtt.ctrl, NULL);
154
155 if (ret != ERROR_OK)
156 return ret;
157
158 target_register_timer_callback(&read_channel_callback,
159 rtt.polling_interval, 1, NULL);
160 rtt.started = true;
161
162 return ERROR_OK;
163 }
164
165 int rtt_stop(void)
166 {
167 int ret;
168
169 if (!rtt.configured) {
170 LOG_ERROR("rtt: Not configured");
171 return ERROR_FAIL;
172 }
173
174 target_unregister_timer_callback(&read_channel_callback, NULL);
175 rtt.started = false;
176
177 ret = rtt.source.stop(rtt.target, NULL);
178
179 if (ret != ERROR_OK)
180 return ret;
181
182 return ERROR_OK;
183 }
184
185 static int adjust_sink_list(size_t length)
186 {
187 struct rtt_sink_list **tmp;
188
189 if (length <= rtt.sink_list_length)
190 return ERROR_OK;
191
192 tmp = realloc(rtt.sink_list, sizeof(struct rtt_sink_list *) * length);
193
194 if (!tmp)
195 return ERROR_FAIL;
196
197 for (size_t i = rtt.sink_list_length; i < length; i++)
198 tmp[i] = NULL;
199
200 rtt.sink_list = tmp;
201 rtt.sink_list_length = length;
202
203 return ERROR_OK;
204 }
205
206 int rtt_register_sink(unsigned int channel_index, rtt_sink_read read,
207 void *user_data)
208 {
209 struct rtt_sink_list *tmp;
210
211 if (channel_index >= rtt.sink_list_length) {
212 if (adjust_sink_list(channel_index + 1) != ERROR_OK)
213 return ERROR_FAIL;
214 }
215
216 LOG_DEBUG("rtt: Registering sink for channel %u", channel_index);
217
218 tmp = malloc(sizeof(struct rtt_sink_list));
219
220 if (!tmp)
221 return ERROR_FAIL;
222
223 tmp->read = read;
224 tmp->user_data = user_data;
225 tmp->next = rtt.sink_list[channel_index];
226
227 rtt.sink_list[channel_index] = tmp;
228
229 return ERROR_OK;
230 }
231
232 int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read,
233 void *user_data)
234 {
235 struct rtt_sink_list *prev_sink;
236
237 LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index);
238
239 if (channel_index >= rtt.sink_list_length)
240 return ERROR_FAIL;
241
242 prev_sink = rtt.sink_list[channel_index];
243
244 for (struct rtt_sink_list *sink = rtt.sink_list[channel_index]; sink;
245 prev_sink = sink, sink = sink->next) {
246 if (sink->read == read && sink->user_data == user_data) {
247
248 if (sink == rtt.sink_list[channel_index])
249 rtt.sink_list[channel_index] = sink->next;
250 else
251 prev_sink->next = sink->next;
252
253 free(sink);
254
255 return ERROR_OK;
256 }
257 }
258
259 return ERROR_OK;
260 }
261
262 int rtt_get_polling_interval(unsigned int *interval)
263 {
264 if (!interval)
265 return ERROR_FAIL;
266
267 *interval = rtt.polling_interval;
268
269 return ERROR_OK;
270 }
271
272 int rtt_set_polling_interval(unsigned int interval)
273 {
274 if (!interval)
275 return ERROR_FAIL;
276
277 if (rtt.polling_interval != interval) {
278 target_unregister_timer_callback(&read_channel_callback, NULL);
279 target_register_timer_callback(&read_channel_callback, interval, 1,
280 NULL);
281 }
282
283 rtt.polling_interval = interval;
284
285 return ERROR_OK;
286 }
287
288 int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer,
289 size_t *length)
290 {
291 if (channel_index >= rtt.ctrl.num_up_channels) {
292 LOG_WARNING("rtt: Down-channel %u is not available", channel_index);
293 return ERROR_OK;
294 }
295
296 return rtt.source.write(rtt.target, &rtt.ctrl, channel_index, buffer,
297 length, NULL);
298 }
299
300 bool rtt_started(void)
301 {
302 return rtt.started;
303 }
304
305 bool rtt_configured(void)
306 {
307 return rtt.configured;
308 }
309
310 bool rtt_found_cb(void)
311 {
312 return rtt.found_cb;
313 }
314
315 const struct rtt_control *rtt_get_control(void)
316 {
317 return &rtt.ctrl;
318 }
319
320 int rtt_read_channel_info(unsigned int channel_index,
321 enum rtt_channel_type type, struct rtt_channel_info *info)
322 {
323 return rtt.source.read_channel_info(rtt.target, &rtt.ctrl,
324 channel_index, type, info, NULL);
325 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)