Add jaylink_get_device()
[libjaylink.git] / libjaylink / swo.c
blobf8b12d36b96d1bf3833d025d508c0ab6f8e21439
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>
22 #include "libjaylink.h"
23 #include "libjaylink-internal.h"
25 /**
26 * @file
28 * Serial Wire Output (SWO) functions.
31 /** @cond PRIVATE */
32 #define CMD_SWO 0xeb
34 #define SWO_CMD_START 0x64
35 #define SWO_CMD_STOP 0x65
36 #define SWO_CMD_READ 0x66
37 #define SWO_CMD_GET_SPEEDS 0x6e
39 #define SWO_PARAM_MODE 0x01
40 #define SWO_PARAM_BAUDRATE 0x02
41 #define SWO_PARAM_READ_SIZE 0x03
42 #define SWO_PARAM_BUFFER_SIZE 0x04
43 /** @endcond */
45 /**
46 * Start SWO capture.
48 * @note This function must be used only if the device has the
49 * #JAYLINK_DEV_CAP_SWO capability.
51 * @param[in,out] devh Device handle.
52 * @param[in] mode Mode to capture data with.
53 * @param[in] baudrate Baudrate to capture data in bit per second.
54 * @param[in] size Device internal buffer size in bytes to use for capturing.
56 * @retval JAYLINK_OK Success.
57 * @retval JAYLINK_ERR_ARG Invalid arguments.
58 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
59 * @retval JAYLINK_ERR_DEV Unspecified device error.
60 * @retval JAYLINK_ERR Other error conditions.
62 * @see jaylink_get_free_memory() to retrieve free memory size of a device.
64 JAYLINK_API int jaylink_swo_start(struct jaylink_device_handle *devh,
65 enum jaylink_swo_mode mode, uint32_t baudrate, uint32_t size)
67 int ret;
68 struct jaylink_context *ctx;
69 uint8_t buf[32];
70 uint32_t tmp;
72 if (!devh || !baudrate || !size)
73 return JAYLINK_ERR_ARG;
75 if (mode != JAYLINK_SWO_MODE_UART)
76 return JAYLINK_ERR_ARG;
78 ctx = devh->dev->ctx;
79 ret = transport_start_write_read(devh, 21, 4, 1);
81 if (ret != JAYLINK_OK) {
82 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
83 return ret;
86 buf[0] = CMD_SWO;
87 buf[1] = SWO_CMD_START;
89 buf[2] = 0x04;
90 buf[3] = SWO_PARAM_MODE;
91 buffer_set_u32(buf, mode, 4);
93 buf[8] = 0x04;
94 buf[9] = SWO_PARAM_BAUDRATE;
95 buffer_set_u32(buf, baudrate, 10);
97 buf[14] = 0x04;
98 buf[15] = SWO_PARAM_BUFFER_SIZE;
99 buffer_set_u32(buf, size, 16);
101 buf[20] = 0x00;
103 ret = transport_write(devh, buf, 21);
105 if (ret != JAYLINK_OK) {
106 log_err(ctx, "transport_write() failed: %i.", ret);
107 return ret;
110 ret = transport_read(devh, buf, 4);
112 if (ret != JAYLINK_OK) {
113 log_err(ctx, "transport_read() failed: %i.", ret);
114 return ret;
117 tmp = buffer_get_u32(buf, 0);
119 if (tmp > 0) {
120 log_err(ctx, "Failed to start capture: %u.", tmp);
121 return JAYLINK_ERR_DEV;
124 return JAYLINK_OK;
128 * Stop SWO capture.
130 * @note This function must be used only if the device has the
131 * #JAYLINK_DEV_CAP_SWO capability.
133 * @param[in,out] devh Device handle.
135 * @retval JAYLINK_OK Success.
136 * @retval JAYLINK_ERR_ARG Invalid arguments.
137 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
138 * @retval JAYLINK_ERR_DEV Unspecified device error.
139 * @retval JAYLINK_ERR Other error conditions.
141 JAYLINK_API int jaylink_swo_stop(struct jaylink_device_handle *devh)
143 int ret;
144 struct jaylink_context *ctx;
145 uint8_t buf[4];
146 uint32_t tmp;
148 if (!devh)
149 return JAYLINK_ERR_ARG;
151 ctx = devh->dev->ctx;
152 ret = transport_start_write_read(devh, 3, 4, 1);
154 if (ret != JAYLINK_OK) {
155 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
156 return ret;
159 buf[0] = CMD_SWO;
160 buf[1] = SWO_CMD_STOP;
161 buf[2] = 0x00;
163 ret = transport_write(devh, buf, 3);
165 if (ret != JAYLINK_OK) {
166 log_err(ctx, "transport_write() failed: %i.", ret);
167 return ret;
170 ret = transport_read(devh, buf, 4);
172 if (ret != JAYLINK_OK) {
173 log_err(ctx, "transport_read() failed: %i.", ret);
174 return ret;
177 tmp = buffer_get_u32(buf, 0);
179 if (tmp > 0) {
180 log_err(ctx, "Failed to stop capture: %u.", tmp);
181 return JAYLINK_ERR_DEV;
184 return JAYLINK_OK;
188 * Read SWO trace data.
190 * @note This function must be used only if the device has the
191 * #JAYLINK_DEV_CAP_SWO capability.
193 * @param[in,out] devh Device handle.
194 * @param[out] buffer Buffer to store trace data on success. Its content is
195 * undefined on failure.
196 * @param[in,out] length Maximum number of bytes to read. On success, the value
197 * gets updated with the actual number of bytes read. The
198 * value is undefined on failure.
200 * @retval JAYLINK_OK Success.
201 * @retval JAYLINK_ERR_ARG Invalid arguments.
202 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
203 * @retval JAYLINK_ERR_PROTO Protocol violation.
204 * @retval JAYLINK_ERR_DEV Unspecified device error.
205 * @retval JAYLINK_ERR Other error conditions.
207 JAYLINK_API int jaylink_swo_read(struct jaylink_device_handle *devh,
208 uint8_t *buffer, uint32_t *length)
210 int ret;
211 struct jaylink_context *ctx;
212 uint8_t buf[32];
213 uint32_t tmp;
215 if (!devh || !buffer || !length)
216 return JAYLINK_ERR_ARG;
218 ctx = devh->dev->ctx;
219 ret = transport_start_write_read(devh, 9, 8, 1);
221 if (ret != JAYLINK_OK) {
222 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
223 return ret;
226 buf[0] = CMD_SWO;
227 buf[1] = SWO_CMD_READ;
229 buf[2] = 0x04;
230 buf[3] = SWO_PARAM_READ_SIZE;
231 buffer_set_u32(buf, *length, 4);
233 buf[8] = 0x00;
235 ret = transport_write(devh, buf, 9);
237 if (ret != JAYLINK_OK) {
238 log_err(ctx, "transport_write() failed: %i.", ret);
239 return ret;
242 ret = transport_read(devh, buf, 8);
244 if (ret != JAYLINK_OK) {
245 log_err(ctx, "transport_read() failed: %i.", ret);
246 return ret;
249 tmp = buffer_get_u32(buf, 0);
251 if (tmp > 0) {
252 log_err(ctx, "Failed to read data: %u.", tmp);
253 return JAYLINK_ERR_DEV;
256 tmp = buffer_get_u32(buf, 4);
258 if (tmp > *length) {
259 log_err(ctx, "Received %u bytes but only %u bytes were "
260 "requested.", tmp, *length);
261 return JAYLINK_ERR_PROTO;
264 *length = tmp;
266 if (tmp > 0) {
267 ret = transport_start_read(devh, tmp);
269 if (ret != JAYLINK_OK) {
270 log_err(ctx, "transport_start_read() failed: %i.", ret);
271 return ret;
274 ret = transport_read(devh, buffer, tmp);
276 if (ret != JAYLINK_OK) {
277 log_err(ctx, "transport_read() failed: %i.", ret);
278 return ret;
282 return JAYLINK_OK;
286 * Retrieve SWO speeds.
288 * The speeds are calculated as follows:
290 * @par
291 * <tt>speeds = @a freq / n</tt> with <tt>n >= @a min_div</tt> and
292 * <tt>n <= @a max_div</tt>, where @p n is an integer
294 * Assuming, for example, a base frequency @a freq of 4500 kHz, a minimum
295 * divider @a min_div of 1 and a maximum divider @a max_div of 8 then the
296 * highest possible SWO speed is 4500 kHz / 1 = 4500 kHz. The next highest
297 * speed is 2250 kHz for a divider of 2, and so on. Accordingly, the lowest
298 * possible speed is 4500 kHz / 8 = 562.5 kHz.
300 * @note This function must be used only if the device has the
301 * #JAYLINK_DEV_CAP_SWO capability.
303 * @param[in,out] devh Device handle.
304 * @param[in] mode Capture mode to retrieve speeds for.
305 * @param[out] speed Speed information on success, and undefined on failure.
307 * @retval JAYLINK_OK Success.
308 * @retval JAYLINK_ERR_ARG Invalid arguments.
309 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
310 * @retval JAYLINK_ERR_PROTO Protocol violation.
311 * @retval JAYLINK_ERR_DEV Unspecified device error.
312 * @retval JAYLINK_ERR Other error conditions.
314 JAYLINK_API int jaylink_swo_get_speeds(struct jaylink_device_handle *devh,
315 enum jaylink_swo_mode mode, struct jaylink_swo_speed *speed)
317 int ret;
318 struct jaylink_context *ctx;
319 uint8_t buf[24];
320 uint32_t length;
322 if (!devh || !speed)
323 return JAYLINK_ERR_ARG;
325 if (mode != JAYLINK_SWO_MODE_UART)
326 return JAYLINK_ERR_ARG;
328 ctx = devh->dev->ctx;
329 ret = transport_start_write_read(devh, 9, 4, 1);
331 if (ret != JAYLINK_OK) {
332 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
333 return ret;
336 buf[0] = CMD_SWO;
337 buf[1] = SWO_CMD_GET_SPEEDS;
339 buf[2] = 0x04;
340 buf[3] = SWO_PARAM_MODE;
341 buffer_set_u32(buf, mode, 4);
343 buf[8] = 0x00;
345 ret = transport_write(devh, buf, 9);
347 if (ret != JAYLINK_OK) {
348 log_err(ctx, "transport_write() failed: %i.", ret);
349 return ret;
352 ret = transport_read(devh, buf, 4);
354 if (ret != JAYLINK_OK) {
355 log_err(ctx, "transport_read() failed: %i.", ret);
356 return ret;
359 length = buffer_get_u32(buf, 0);
361 if (length == 0xffffffff) {
362 log_err(ctx, "Failed to retrieve speed information.");
363 return JAYLINK_ERR_DEV;
366 if (length != 28) {
367 log_err(ctx, "Unexpected number of bytes received: %u.",
368 length);
369 return JAYLINK_ERR_PROTO;
372 length = length - 4;
373 ret = transport_start_read(devh, length);
375 if (ret != JAYLINK_OK) {
376 log_err(ctx, "transport_start_read() failed: %i.", ret);
377 return ret;
380 ret = transport_read(devh, buf, length);
382 if (ret != JAYLINK_OK) {
383 log_err(ctx, "transport_read() failed: %i.", ret);
384 return ret;
387 speed->freq = buffer_get_u32(buf, 4);
388 speed->min_div = buffer_get_u32(buf, 8);
390 if (!speed->min_div) {
391 log_err(ctx, "Minimum frequency divider is zero.");
392 return JAYLINK_ERR_PROTO;
395 speed->max_div = buffer_get_u32(buf, 12);
397 if (speed->max_div < speed->min_div) {
398 log_err(ctx, "Maximum frequency divider is less than minimum "
399 "frequency divider.");
400 return JAYLINK_ERR_PROTO;
403 speed->min_prescaler = buffer_get_u32(buf, 16);
404 speed->max_prescaler = buffer_get_u32(buf, 20);
406 if (speed->max_prescaler < speed->min_prescaler) {
407 log_err(ctx, "Maximum prescaler is less than minimum "
408 "prescaler.");
409 return JAYLINK_ERR_PROTO;
412 return JAYLINK_OK;