Add initial RTT support
[fw/openocd] / src / server / rtt_server.c
1 /*
2  * Copyright (C) 2016-2017 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 <stdint.h>
19 #include <rtt/rtt.h>
20
21 #include "server.h"
22 #include "rtt_server.h"
23
24 /**
25  * @file
26  *
27  * RTT server.
28  *
29  * This server allows access to Real Time Transfer (RTT) channels via TCP
30  * connections.
31  */
32
33 struct rtt_service {
34         unsigned int channel;
35 };
36
37 static int read_callback(unsigned int channel, const uint8_t *buffer,
38                 size_t length, void *user_data)
39 {
40         int ret;
41         struct connection *connection;
42         size_t offset;
43
44         connection = (struct connection *)user_data;
45         offset = 0;
46
47         while (offset < length) {
48                 ret = connection_write(connection, buffer + offset, length - offset);
49
50                 if (ret < 0) {
51                         LOG_ERROR("Failed to write data to socket.");
52                         return ERROR_FAIL;
53                 }
54
55                 offset += ret;
56         }
57
58         return ERROR_OK;
59 }
60
61 static int rtt_new_connection(struct connection *connection)
62 {
63         int ret;
64         struct rtt_service *service;
65
66         service = connection->service->priv;
67
68         LOG_DEBUG("rtt: New connection for channel %u", service->channel);
69
70         ret = rtt_register_sink(service->channel, &read_callback, connection);
71
72         if (ret != ERROR_OK)
73                 return ret;
74
75         return ERROR_OK;
76 }
77
78 static int rtt_connection_closed(struct connection *connection)
79 {
80         struct rtt_service *service;
81
82         service = (struct rtt_service *)connection->service->priv;
83         rtt_unregister_sink(service->channel, &read_callback, connection);
84
85         LOG_DEBUG("rtt: Connection for channel %u closed", service->channel);
86
87         return ERROR_OK;
88 }
89
90 static int rtt_input(struct connection *connection)
91 {
92         int bytes_read;
93         unsigned char buffer[1024];
94         struct rtt_service *service;
95         size_t length;
96
97         service = (struct rtt_service *)connection->service->priv;
98         bytes_read = connection_read(connection, buffer, sizeof(buffer));
99
100         if (!bytes_read)
101                 return ERROR_SERVER_REMOTE_CLOSED;
102         else if (bytes_read < 0) {
103                 LOG_ERROR("error during read: %s", strerror(errno));
104                 return ERROR_SERVER_REMOTE_CLOSED;
105         }
106
107         length = bytes_read;
108         rtt_write_channel(service->channel, buffer, &length);
109
110         return ERROR_OK;
111 }
112
113 COMMAND_HANDLER(handle_rtt_start_command)
114 {
115         int ret;
116         struct rtt_service *service;
117
118         if (CMD_ARGC != 2)
119                 return ERROR_COMMAND_SYNTAX_ERROR;
120
121         service = malloc(sizeof(struct rtt_service));
122
123         if (!service)
124                 return ERROR_FAIL;
125
126         COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel);
127
128         ret = add_service("rtt", CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED,
129                 rtt_new_connection, rtt_input, rtt_connection_closed, service, NULL);
130
131         if (ret != ERROR_OK) {
132                 free(service);
133                 return ERROR_FAIL;
134         }
135
136         return ERROR_OK;
137 }
138
139 COMMAND_HANDLER(handle_rtt_stop_command)
140 {
141         if (CMD_ARGC != 1)
142                 return ERROR_COMMAND_SYNTAX_ERROR;
143
144         remove_service("rtt", CMD_ARGV[0]);
145
146         return ERROR_OK;
147 }
148
149 static const struct command_registration rtt_server_subcommand_handlers[] = {
150         {
151                 .name = "start",
152                 .handler = handle_rtt_start_command,
153                 .mode = COMMAND_ANY,
154                 .help = "Start a RTT server",
155                 .usage = "<port> <channel>"
156         },
157         {
158                 .name = "stop",
159                 .handler = handle_rtt_stop_command,
160                 .mode = COMMAND_ANY,
161                 .help = "Stop a RTT server",
162                 .usage = "<port>"
163         },
164         COMMAND_REGISTRATION_DONE
165 };
166
167 static const struct command_registration rtt_server_command_handlers[] = {
168         {
169                 .name = "server",
170                 .mode = COMMAND_ANY,
171                 .help = "RTT server",
172                 .usage = "",
173                 .chain = rtt_server_subcommand_handlers
174         },
175         COMMAND_REGISTRATION_DONE
176 };
177
178 static const struct command_registration rtt_command_handlers[] = {
179         {
180                 .name = "rtt",
181                 .mode = COMMAND_ANY,
182                 .help = "RTT",
183                 .usage = "",
184                 .chain = rtt_server_command_handlers
185         },
186         COMMAND_REGISTRATION_DONE
187 };
188
189 int rtt_server_register_commands(struct command_context *ctx)
190 {
191         return register_commands(ctx, NULL, rtt_command_handlers);
192 }