2 * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de>
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.
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.
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/>.
22 #include <helper/log.h>
23 #include <helper/list.h>
24 #include <target/target.h>
25 #include <target/rtt.h>
30 struct rtt_source source
;
32 struct rtt_control ctrl
;
33 struct target
*target
;
34 /** Start address to search for the control block. */
36 /** Size of the control block search area. */
38 /** Control block identifier. */
39 char id
[RTT_CB_MAX_ID_LENGTH
];
40 /** Whether RTT is configured. */
42 /** Whether RTT is started. */
44 /** Whether configuration changed. */
46 /** Whether the control block was found. */
49 struct rtt_sink_list
**sink_list
;
50 size_t sink_list_length
;
52 unsigned int polling_interval
;
57 rtt
.sink_list_length
= 1;
58 rtt
.sink_list
= calloc(rtt
.sink_list_length
,
59 sizeof(struct rtt_sink_list
*));
64 rtt
.sink_list
[0] = NULL
;
67 rtt
.polling_interval
= 100;
79 static int read_channel_callback(void *user_data
)
83 ret
= rtt
.source
.read(rtt
.target
, &rtt
.ctrl
, rtt
.sink_list
,
84 rtt
.sink_list_length
, NULL
);
86 if (ret
!= ERROR_OK
) {
87 target_unregister_timer_callback(&read_channel_callback
, NULL
);
88 rtt
.source
.stop(rtt
.target
, NULL
);
95 int rtt_setup(target_addr_t address
, size_t size
, const char *id
)
97 size_t id_length
= strlen(id
);
99 if (!id_length
|| id_length
>= RTT_CB_MAX_ID_LENGTH
) {
100 LOG_ERROR("rtt: Invalid control block ID");
101 return ERROR_COMMAND_ARGUMENT_INVALID
;
106 strncpy(rtt
.id
, id
, id_length
+ 1);
108 rtt
.configured
= true;
113 int rtt_register_source(const struct rtt_source source
,
114 struct target
*target
)
116 if (!source
.find_cb
|| !source
.read_cb
|| !source
.read_channel_info
)
119 if (!source
.start
|| !source
.stop
)
122 if (!source
.read
|| !source
.write
)
134 target_addr_t addr
= rtt
.addr
;
139 if (!rtt
.found_cb
|| rtt
.changed
) {
140 rtt
.source
.find_cb(rtt
.target
, &addr
, rtt
.size
, rtt
.id
,
141 &rtt
.found_cb
, NULL
);
146 LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR
,
148 rtt
.ctrl
.address
= addr
;
150 LOG_INFO("rtt: No control block found");
155 ret
= rtt
.source
.read_cb(rtt
.target
, rtt
.ctrl
.address
, &rtt
.ctrl
, NULL
);
160 ret
= rtt
.source
.start(rtt
.target
, &rtt
.ctrl
, NULL
);
165 target_register_timer_callback(&read_channel_callback
,
166 rtt
.polling_interval
, 1, NULL
);
176 if (!rtt
.configured
) {
177 LOG_ERROR("rtt: Not configured");
181 target_unregister_timer_callback(&read_channel_callback
, NULL
);
184 ret
= rtt
.source
.stop(rtt
.target
, NULL
);
192 static int adjust_sink_list(size_t length
)
194 struct rtt_sink_list
**tmp
;
196 if (length
<= rtt
.sink_list_length
)
199 tmp
= realloc(rtt
.sink_list
, sizeof(struct rtt_sink_list
*) * length
);
204 for (size_t i
= rtt
.sink_list_length
; i
< length
; i
++)
208 rtt
.sink_list_length
= length
;
213 int rtt_register_sink(unsigned int channel_index
, rtt_sink_read read
,
216 struct rtt_sink_list
*tmp
;
218 if (channel_index
>= rtt
.sink_list_length
) {
219 if (adjust_sink_list(channel_index
+ 1) != ERROR_OK
)
223 LOG_DEBUG("rtt: Registering sink for channel %u", channel_index
);
225 tmp
= malloc(sizeof(struct rtt_sink_list
));
231 tmp
->user_data
= user_data
;
232 tmp
->next
= rtt
.sink_list
[channel_index
];
234 rtt
.sink_list
[channel_index
] = tmp
;
239 int rtt_unregister_sink(unsigned int channel_index
, rtt_sink_read read
,
242 struct rtt_sink_list
*prev_sink
;
244 LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index
);
246 if (channel_index
>= rtt
.sink_list_length
)
249 prev_sink
= rtt
.sink_list
[channel_index
];
251 for (struct rtt_sink_list
*sink
= rtt
.sink_list
[channel_index
]; sink
;
252 prev_sink
= sink
, sink
= sink
->next
) {
253 if (sink
->read
== read
&& sink
->user_data
== user_data
) {
255 if (sink
== rtt
.sink_list
[channel_index
])
256 rtt
.sink_list
[channel_index
] = sink
->next
;
258 prev_sink
->next
= sink
->next
;
269 int rtt_get_polling_interval(unsigned int *interval
)
274 *interval
= rtt
.polling_interval
;
279 int rtt_set_polling_interval(unsigned int interval
)
284 if (rtt
.polling_interval
!= interval
) {
285 target_unregister_timer_callback(&read_channel_callback
, NULL
);
286 target_register_timer_callback(&read_channel_callback
, interval
, 1,
290 rtt
.polling_interval
= interval
;
295 int rtt_write_channel(unsigned int channel_index
, const uint8_t *buffer
,
298 if (channel_index
>= rtt
.ctrl
.num_up_channels
) {
299 LOG_WARNING("rtt: Down-channel %u is not available", channel_index
);
303 return rtt
.source
.write(rtt
.target
, &rtt
.ctrl
, channel_index
, buffer
,
307 bool rtt_started(void)
312 bool rtt_configured(void)
314 return rtt
.configured
;
317 bool rtt_found_cb(void)
322 const struct rtt_control
*rtt_get_control(void)
327 int rtt_read_channel_info(unsigned int channel_index
,
328 enum rtt_channel_type type
, struct rtt_channel_info
*info
)
330 return rtt
.source
.read_channel_info(rtt
.target
, &rtt
.ctrl
,
331 channel_index
, type
, info
, NULL
);