Minor code and documentation cleanups
[libjaylink.git] / libjaylink / swo.c
blob6037f64b8f981a6f0d7e17fca4bed89381de6fed
1 /*
2 * This file is part of the libjaylink project.
4 * Copyright (C) 2015 Marc Schink <jaylink-dev@marcschink.de>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stdint.h>
21 #include <stdbool.h>
23 #include "libjaylink.h"
24 #include "libjaylink-internal.h"
26 /**
27 * @file
29 * Serial Wire Output (SWO) functions.
32 /** @cond PRIVATE */
33 #define CMD_SWO 0xeb
35 #define SWO_CMD_START 0x64
36 #define SWO_CMD_STOP 0x65
37 #define SWO_CMD_READ 0x66
38 #define SWO_CMD_GET_SPEEDS 0x6e
40 #define SWO_PARAM_MODE 0x01
41 #define SWO_PARAM_BAUDRATE 0x02
42 #define SWO_PARAM_READ_SIZE 0x03
43 #define SWO_PARAM_BUFFER_SIZE 0x04
45 #define SWO_ERR 0x80000000
46 /** @endcond */
48 /**
49 * Start SWO capture.
51 * @note This function must be used only if the device has the
52 * #JAYLINK_DEV_CAP_SWO capability.
54 * @param[in,out] devh Device handle.
55 * @param[in] mode Mode to capture data with.
56 * @param[in] baudrate Baudrate to capture data in bit per second.
57 * @param[in] size Device internal buffer size in bytes to use for capturing.
59 * @retval JAYLINK_OK Success.
60 * @retval JAYLINK_ERR_ARG Invalid arguments.
61 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
62 * @retval JAYLINK_ERR_IO Input/output error.
63 * @retval JAYLINK_ERR_DEV Unspecified device error.
64 * @retval JAYLINK_ERR Other error conditions.
66 * @see jaylink_swo_get_speeds()
67 * @see jaylink_get_free_memory()
69 * @since 0.1.0
71 JAYLINK_API int jaylink_swo_start(struct jaylink_device_handle *devh,
72 enum jaylink_swo_mode mode, uint32_t baudrate, uint32_t size)
74 int ret;
75 struct jaylink_context *ctx;
76 uint8_t buf[32];
77 uint32_t status;
79 if (!devh || !baudrate || !size)
80 return JAYLINK_ERR_ARG;
82 if (mode != JAYLINK_SWO_MODE_UART)
83 return JAYLINK_ERR_ARG;
85 ctx = devh->dev->ctx;
86 ret = transport_start_write_read(devh, 21, 4, true);
88 if (ret != JAYLINK_OK) {
89 log_err(ctx, "transport_start_write_read() failed: %s.",
90 jaylink_strerror(ret));
91 return ret;
94 buf[0] = CMD_SWO;
95 buf[1] = SWO_CMD_START;
97 buf[2] = 0x04;
98 buf[3] = SWO_PARAM_MODE;
99 buffer_set_u32(buf, mode, 4);
101 buf[8] = 0x04;
102 buf[9] = SWO_PARAM_BAUDRATE;
103 buffer_set_u32(buf, baudrate, 10);
105 buf[14] = 0x04;
106 buf[15] = SWO_PARAM_BUFFER_SIZE;
107 buffer_set_u32(buf, size, 16);
109 buf[20] = 0x00;
111 ret = transport_write(devh, buf, 21);
113 if (ret != JAYLINK_OK) {
114 log_err(ctx, "transport_write() failed: %s.",
115 jaylink_strerror(ret));
116 return ret;
119 ret = transport_read(devh, buf, 4);
121 if (ret != JAYLINK_OK) {
122 log_err(ctx, "transport_read() failed: %s.",
123 jaylink_strerror(ret));
124 return ret;
127 status = buffer_get_u32(buf, 0);
129 if (status > 0) {
130 log_err(ctx, "Failed to start capture: 0x%x.", status);
131 return JAYLINK_ERR_DEV;
134 return JAYLINK_OK;
138 * Stop SWO capture.
140 * @note This function must be used only if the device has the
141 * #JAYLINK_DEV_CAP_SWO capability.
143 * @param[in,out] devh Device handle.
145 * @retval JAYLINK_OK Success.
146 * @retval JAYLINK_ERR_ARG Invalid arguments.
147 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
148 * @retval JAYLINK_ERR_IO Input/output error.
149 * @retval JAYLINK_ERR_DEV Unspecified device error.
150 * @retval JAYLINK_ERR Other error conditions.
152 * @see jaylink_swo_start()
154 * @since 0.1.0
156 JAYLINK_API int jaylink_swo_stop(struct jaylink_device_handle *devh)
158 int ret;
159 struct jaylink_context *ctx;
160 uint8_t buf[4];
161 uint32_t status;
163 if (!devh)
164 return JAYLINK_ERR_ARG;
166 ctx = devh->dev->ctx;
167 ret = transport_start_write_read(devh, 3, 4, true);
169 if (ret != JAYLINK_OK) {
170 log_err(ctx, "transport_start_write_read() failed: %s.",
171 jaylink_strerror(ret));
172 return ret;
175 buf[0] = CMD_SWO;
176 buf[1] = SWO_CMD_STOP;
177 buf[2] = 0x00;
179 ret = transport_write(devh, buf, 3);
181 if (ret != JAYLINK_OK) {
182 log_err(ctx, "transport_write() failed: %s.",
183 jaylink_strerror(ret));
184 return ret;
187 ret = transport_read(devh, buf, 4);
189 if (ret != JAYLINK_OK) {
190 log_err(ctx, "transport_read() failed: %s.",
191 jaylink_strerror(ret));
192 return ret;
195 status = buffer_get_u32(buf, 0);
197 if (status > 0) {
198 log_err(ctx, "Failed to stop capture: 0x%x.", status);
199 return JAYLINK_ERR_DEV;
202 return JAYLINK_OK;
206 * Read SWO trace data.
208 * @note This function must be used only if the device has the
209 * #JAYLINK_DEV_CAP_SWO capability.
211 * @param[in,out] devh Device handle.
212 * @param[out] buffer Buffer to store trace data on success. Its content is
213 * undefined on failure.
214 * @param[in,out] length Maximum number of bytes to read. On success, the value
215 * gets updated with the actual number of bytes read. The
216 * value is undefined on failure.
218 * @retval JAYLINK_OK Success.
219 * @retval JAYLINK_ERR_ARG Invalid arguments.
220 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
221 * @retval JAYLINK_ERR_PROTO Protocol violation.
222 * @retval JAYLINK_ERR_IO Input/output error.
223 * @retval JAYLINK_ERR_DEV Unspecified device error.
224 * @retval JAYLINK_ERR Other error conditions.
226 * @see jaylink_swo_start()
228 * @since 0.1.0
230 JAYLINK_API int jaylink_swo_read(struct jaylink_device_handle *devh,
231 uint8_t *buffer, uint32_t *length)
233 int ret;
234 struct jaylink_context *ctx;
235 uint8_t buf[32];
236 uint32_t status;
237 uint32_t tmp;
239 if (!devh || !buffer || !length)
240 return JAYLINK_ERR_ARG;
242 ctx = devh->dev->ctx;
243 ret = transport_start_write_read(devh, 9, 8, true);
245 if (ret != JAYLINK_OK) {
246 log_err(ctx, "transport_start_write_read() failed: %s.",
247 jaylink_strerror(ret));
248 return ret;
251 buf[0] = CMD_SWO;
252 buf[1] = SWO_CMD_READ;
254 buf[2] = 0x04;
255 buf[3] = SWO_PARAM_READ_SIZE;
256 buffer_set_u32(buf, *length, 4);
258 buf[8] = 0x00;
260 ret = transport_write(devh, buf, 9);
262 if (ret != JAYLINK_OK) {
263 log_err(ctx, "transport_write() failed: %s.",
264 jaylink_strerror(ret));
265 return ret;
268 ret = transport_read(devh, buf, 8);
270 if (ret != JAYLINK_OK) {
271 log_err(ctx, "transport_read() failed: %s.",
272 jaylink_strerror(ret));
273 return ret;
276 status = buffer_get_u32(buf, 0);
277 tmp = buffer_get_u32(buf, 4);
279 if (tmp > *length) {
280 log_err(ctx, "Received %u bytes but only %u bytes were "
281 "requested.", tmp, *length);
282 return JAYLINK_ERR_PROTO;
285 *length = tmp;
287 if (tmp > 0) {
288 ret = transport_start_read(devh, tmp);
290 if (ret != JAYLINK_OK) {
291 log_err(ctx, "transport_start_read() failed: %s.",
292 jaylink_strerror(ret));
293 return ret;
296 ret = transport_read(devh, buffer, tmp);
298 if (ret != JAYLINK_OK) {
299 log_err(ctx, "transport_read() failed: %s.",
300 jaylink_strerror(ret));
301 return ret;
305 if (status > 0) {
306 log_err(ctx, "Failed to read data: 0x%x.", status);
307 return JAYLINK_ERR_DEV;
310 return JAYLINK_OK;
314 * Retrieve SWO speeds.
316 * The speeds are calculated as follows:
318 * @par
319 * <tt>speeds = @a freq / n</tt> with <tt>n >= @a min_div</tt> and
320 * <tt>n <= @a max_div</tt>, where @p n is an integer
322 * Assuming, for example, a base frequency @a freq of 4500 kHz, a minimum
323 * divider @a min_div of 1 and a maximum divider @a max_div of 8 then the
324 * highest possible SWO speed is 4500 kHz / 1 = 4500 kHz. The next highest
325 * speed is 2250 kHz for a divider of 2, and so on. Accordingly, the lowest
326 * possible speed is 4500 kHz / 8 = 562.5 kHz.
328 * @note This function must be used only if the device has the
329 * #JAYLINK_DEV_CAP_SWO capability.
331 * @param[in,out] devh Device handle.
332 * @param[in] mode Capture mode to retrieve speeds for.
333 * @param[out] speed Speed information on success, and undefined on failure.
335 * @retval JAYLINK_OK Success.
336 * @retval JAYLINK_ERR_ARG Invalid arguments.
337 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
338 * @retval JAYLINK_ERR_PROTO Protocol violation.
339 * @retval JAYLINK_ERR_IO Input/output error.
340 * @retval JAYLINK_ERR_DEV Unspecified device error.
341 * @retval JAYLINK_ERR Other error conditions.
343 * @since 0.1.0
345 JAYLINK_API int jaylink_swo_get_speeds(struct jaylink_device_handle *devh,
346 enum jaylink_swo_mode mode, struct jaylink_swo_speed *speed)
348 int ret;
349 struct jaylink_context *ctx;
350 uint8_t buf[24];
351 uint32_t tmp;
352 uint32_t length;
354 if (!devh || !speed)
355 return JAYLINK_ERR_ARG;
357 if (mode != JAYLINK_SWO_MODE_UART)
358 return JAYLINK_ERR_ARG;
360 ctx = devh->dev->ctx;
361 ret = transport_start_write_read(devh, 9, 4, true);
363 if (ret != JAYLINK_OK) {
364 log_err(ctx, "transport_start_write_read() failed: %s.",
365 jaylink_strerror(ret));
366 return ret;
369 buf[0] = CMD_SWO;
370 buf[1] = SWO_CMD_GET_SPEEDS;
372 buf[2] = 0x04;
373 buf[3] = SWO_PARAM_MODE;
374 buffer_set_u32(buf, mode, 4);
376 buf[8] = 0x00;
378 ret = transport_write(devh, buf, 9);
380 if (ret != JAYLINK_OK) {
381 log_err(ctx, "transport_write() failed: %s.",
382 jaylink_strerror(ret));
383 return ret;
386 ret = transport_read(devh, buf, 4);
388 if (ret != JAYLINK_OK) {
389 log_err(ctx, "transport_read() failed: %s.",
390 jaylink_strerror(ret));
391 return ret;
394 tmp = buffer_get_u32(buf, 0);
396 if (tmp & SWO_ERR) {
397 log_err(ctx, "Failed to retrieve speed information: 0x%x.",
398 tmp);
399 return JAYLINK_ERR_DEV;
402 length = tmp;
404 if (length != 28) {
405 log_err(ctx, "Unexpected number of bytes received: %u.",
406 length);
407 return JAYLINK_ERR_PROTO;
410 length = length - 4;
411 ret = transport_start_read(devh, length);
413 if (ret != JAYLINK_OK) {
414 log_err(ctx, "transport_start_read() failed: %s.",
415 jaylink_strerror(ret));
416 return ret;
419 ret = transport_read(devh, buf, length);
421 if (ret != JAYLINK_OK) {
422 log_err(ctx, "transport_read() failed: %s.",
423 jaylink_strerror(ret));
424 return ret;
427 speed->freq = buffer_get_u32(buf, 4);
428 speed->min_div = buffer_get_u32(buf, 8);
430 if (!speed->min_div) {
431 log_err(ctx, "Minimum frequency divider is zero.");
432 return JAYLINK_ERR_PROTO;
435 speed->max_div = buffer_get_u32(buf, 12);
437 if (speed->max_div < speed->min_div) {
438 log_err(ctx, "Maximum frequency divider is less than minimum "
439 "frequency divider.");
440 return JAYLINK_ERR_PROTO;
443 speed->min_prescaler = buffer_get_u32(buf, 16);
444 speed->max_prescaler = buffer_get_u32(buf, 20);
446 if (speed->max_prescaler < speed->min_prescaler) {
447 log_err(ctx, "Maximum prescaler is less than minimum "
448 "prescaler.");
449 return JAYLINK_ERR_PROTO;
452 return JAYLINK_OK;