1 /*
2  * Copyright (C) 2019-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 #include <helper/log.h>
19 #include <target/rtt.h>
20 
21 #include "rtt.h"
22 
23 #define CHANNEL_NAME_SIZE	128
24 
COMMAND_HANDLER(handle_rtt_setup_command)25 COMMAND_HANDLER(handle_rtt_setup_command)
26 {
27 struct rtt_source source;
28 
29 	if (CMD_ARGC != 3)
30 		return ERROR_COMMAND_SYNTAX_ERROR;
31 
32 	source.find_cb = &target_rtt_find_control_block;
33 	source.read_cb = &target_rtt_read_control_block;
34 	source.start = &target_rtt_start;
35 	source.stop = &target_rtt_stop;
36 	source.read = &target_rtt_read_callback;
37 	source.write = &target_rtt_write_callback;
38 	source.read_channel_info = &target_rtt_read_channel_info;
39 
40 	target_addr_t address;
41 	uint32_t size;
42 
43 	COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], address);
44 	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
45 
46 	rtt_register_source(source, get_current_target(CMD_CTX));
47 
48 	if (rtt_setup(address, size, CMD_ARGV[2]) != ERROR_OK)
49 		return ERROR_FAIL;
50 
51 	return ERROR_OK;
52 }
53 
COMMAND_HANDLER(handle_rtt_start_command)54 COMMAND_HANDLER(handle_rtt_start_command)
55 {
56 	if (CMD_ARGC > 0)
57 		return ERROR_COMMAND_SYNTAX_ERROR;
58 
59 	if (!rtt_configured()) {
60 		command_print(CMD, "RTT is not configured");
61 		return ERROR_FAIL;
62 	}
63 
64 	return rtt_start();
65 }
66 
COMMAND_HANDLER(handle_rtt_stop_command)67 COMMAND_HANDLER(handle_rtt_stop_command)
68 {
69 	if (CMD_ARGC > 0)
70 		return ERROR_COMMAND_SYNTAX_ERROR;
71 
72 	return rtt_stop();
73 }
74 
COMMAND_HANDLER(handle_rtt_polling_interval_command)75 COMMAND_HANDLER(handle_rtt_polling_interval_command)
76 {
77 	if (CMD_ARGC == 0) {
78 		int ret;
79 		unsigned int interval;
80 
81 		ret = rtt_get_polling_interval(&interval);
82 
83 		if (ret != ERROR_OK) {
84 			command_print(CMD, "Failed to get polling interval");
85 			return ret;
86 		}
87 
88 		command_print(CMD, "%u ms", interval);
89 	} else if (CMD_ARGC == 1) {
90 		int ret;
91 		unsigned int interval;
92 
93 		COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], interval);
94 		ret = rtt_set_polling_interval(interval);
95 
96 		if (ret != ERROR_OK) {
97 			command_print(CMD, "Failed to set polling interval");
98 			return ret;
99 		}
100 	} else {
101 		return ERROR_COMMAND_SYNTAX_ERROR;
102 	}
103 
104 	return ERROR_OK;
105 }
106 
COMMAND_HANDLER(handle_rtt_channels_command)107 COMMAND_HANDLER(handle_rtt_channels_command)
108 {
109 	int ret;
110 	char channel_name[CHANNEL_NAME_SIZE];
111 	const struct rtt_control *ctrl;
112 	struct rtt_channel_info info;
113 
114 	if (!rtt_found_cb()) {
115 		command_print(CMD, "rtt: Control block not available");
116 		return ERROR_FAIL;
117 	}
118 
119 	ctrl = rtt_get_control();
120 
121 	command_print(CMD, "Channels: up=%u, down=%u", ctrl->num_up_channels,
122 		ctrl->num_down_channels);
123 
124 	command_print(CMD, "Up-channels:");
125 
126 	info.name = channel_name;
127 	info.name_length = sizeof(channel_name);
128 
129 	for (unsigned int i = 0; i < ctrl->num_up_channels; i++) {
130 		ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info);
131 
132 		if (ret != ERROR_OK)
133 			return ret;
134 
135 		if (!info.size)
136 			continue;
137 
138 		command_print(CMD, "%u: %s %u %u", i, info.name, info.size,
139 			info.flags);
140 	}
141 
142 	command_print(CMD, "Down-channels:");
143 
144 	for (unsigned int i = 0; i < ctrl->num_down_channels; i++) {
145 		ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info);
146 
147 		if (ret != ERROR_OK)
148 			return ret;
149 
150 		if (!info.size)
151 			continue;
152 
153 		command_print(CMD, "%u: %s %u %u", i, info.name, info.size,
154 			info.flags);
155 	}
156 
157 	return ERROR_OK;
158 }
159 
jim_channel_list(Jim_Interp * interp,int argc,Jim_Obj * const * argv)160 static int jim_channel_list(Jim_Interp *interp, int argc,
161 	Jim_Obj * const *argv)
162 {
163 	Jim_Obj *list;
164 	Jim_Obj *channel_list;
165 	char channel_name[CHANNEL_NAME_SIZE];
166 	const struct rtt_control *ctrl;
167 	struct rtt_channel_info info;
168 
169 	if (!rtt_found_cb()) {
170 		Jim_SetResultFormatted(interp, "rtt: Control block not available");
171 		return ERROR_FAIL;
172 	}
173 
174 	ctrl = rtt_get_control();
175 
176 	info.name = channel_name;
177 	info.name_length = sizeof(channel_name);
178 
179 	list = Jim_NewListObj(interp, NULL, 0);
180 	channel_list = Jim_NewListObj(interp, NULL, 0);
181 
182 	for (unsigned int i = 0; i < ctrl->num_up_channels; i++) {
183 		int ret;
184 		Jim_Obj *tmp;
185 
186 		ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info);
187 
188 		if (ret != ERROR_OK)
189 			return ret;
190 
191 		if (!info.size)
192 			continue;
193 
194 		tmp = Jim_NewListObj(interp, NULL, 0);
195 
196 		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
197 			"name", -1));
198 		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
199 			info.name, -1));
200 
201 		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
202 			"size", -1));
203 		Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
204 			info.size));
205 
206 		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
207 			"flags", -1));
208 		Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
209 			info.flags));
210 
211 		Jim_ListAppendElement(interp, channel_list, tmp);
212 	}
213 
214 	Jim_ListAppendElement(interp, list, channel_list);
215 
216 	channel_list = Jim_NewListObj(interp, NULL, 0);
217 
218 	for (unsigned int i = 0; i < ctrl->num_down_channels; i++) {
219 		int ret;
220 		Jim_Obj *tmp;
221 
222 		ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info);
223 
224 		if (ret != ERROR_OK)
225 			return ret;
226 
227 		if (!info.size)
228 			continue;
229 
230 		tmp = Jim_NewListObj(interp, NULL, 0);
231 
232 		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
233 			"name", -1));
234 		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
235 			info.name, -1));
236 
237 		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
238 			"size", -1));
239 		Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
240 			info.size));
241 
242 		Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
243 			"flags", -1));
244 		Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
245 			info.flags));
246 
247 		Jim_ListAppendElement(interp, channel_list, tmp);
248 	}
249 
250 	Jim_ListAppendElement(interp, list, channel_list);
251 	Jim_SetResult(interp, list);
252 
253 	return JIM_OK;
254 }
255 
256 static const struct command_registration rtt_subcommand_handlers[] = {
257 	{
258 		.name = "setup",
259 		.handler = handle_rtt_setup_command,
260 		.mode = COMMAND_ANY,
261 		.help = "setup RTT",
262 		.usage = "<address> <size> <ID>"
263 	},
264 	{
265 		.name = "start",
266 		.handler = handle_rtt_start_command,
267 		.mode = COMMAND_EXEC,
268 		.help = "start RTT",
269 		.usage = ""
270 	},
271 	{
272 		.name = "stop",
273 		.handler = handle_rtt_stop_command,
274 		.mode = COMMAND_EXEC,
275 		.help = "stop RTT",
276 		.usage = ""
277 	},
278 	{
279 		.name = "polling_interval",
280 		.handler = handle_rtt_polling_interval_command,
281 		.mode = COMMAND_EXEC,
282 		.help = "show or set polling interval in ms",
283 		.usage = "[interval]"
284 	},
285 	{
286 		.name = "channels",
287 		.handler = handle_rtt_channels_command,
288 		.mode = COMMAND_EXEC,
289 		.help = "list available channels",
290 		.usage = ""
291 	},
292 	{
293 		.name = "channellist",
294 		.jim_handler = jim_channel_list,
295 		.mode = COMMAND_EXEC,
296 		.help = "list available channels",
297 		.usage = ""
298 	},
299 	COMMAND_REGISTRATION_DONE
300 };
301 
302 const struct command_registration rtt_target_command_handlers[] = {
303 	{
304 		.name = "rtt",
305 		.mode = COMMAND_EXEC,
306 		.help = "RTT target commands",
307 		.usage = "",
308 		.chain = rtt_subcommand_handlers
309 	},
310 	COMMAND_REGISTRATION_DONE
311 };
312