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