7e755718f1f3b3042e121cd94ea3e29c5ee34912
[fw/openocd] / 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 }