linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Szymon Janc <szymon.janc@codecoup.pl>
To: linux-bluetooth@vger.kernel.org
Cc: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
Subject: [PATCH V2 2/3] monitor: Add interface for J-Link library
Date: Tue,  1 Oct 2019 16:09:40 +0200	[thread overview]
Message-ID: <20191001140941.8005-2-szymon.janc@codecoup.pl> (raw)
In-Reply-To: <20191001140941.8005-1-szymon.janc@codecoup.pl>

From: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>

This adds simple interface to libjlinkarm.so which will be used to read
data from RTT buffer. It was mostly made by trial and error since there
is no public documentation for this library so it may lack something,
but seems to work fine with few Cortex-M devices I tried.
---
 monitor/jlink.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++
 monitor/jlink.h |  27 +++++
 2 files changed, 310 insertions(+)
 create mode 100644 monitor/jlink.c
 create mode 100644 monitor/jlink.h

diff --git a/monitor/jlink.c b/monitor/jlink.c
new file mode 100644
index 000000000..956a25159
--- /dev/null
+++ b/monitor/jlink.c
@@ -0,0 +1,283 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2018  Codecoup
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "jlink.h"
+
+#define RTT_CONTROL_START		0
+#define RTT_CONTROL_STOP		1
+#define RTT_CONTROL_GET_DESC		2
+#define RTT_CONTROL_GET_NUM_BUF		3
+#define RTT_CONTROL_GET_STAT		4
+
+#define RTT_DIRECTION_UP		0
+#define RTT_DIRECTION_DOWN		1
+
+static const char * const jlink_so_name[] = {
+	"/usr/lib/libjlinkarm.so",
+	"/usr/lib/libjlinkarm.so.6",
+	"/opt/SEGGER/JLink/libjlinkarm.so",
+	"/opt/SEGGER/JLink/libjlinkarm.so.6",
+};
+
+struct rtt_desc {
+	uint32_t index;
+	uint32_t direction;
+	char name[32];
+	uint32_t size;
+	uint32_t flags;
+};
+
+static struct rtt_desc rtt_desc;
+
+typedef int (*jlink_emu_selectbyusbsn_func) (unsigned int sn);
+typedef int (*jlink_open_func) (void);
+typedef int (*jlink_execcommand_func) (char *in, char *out, int size);
+typedef int (*jlink_tif_select_func) (int);
+typedef void (*jlink_setspeed_func) (long int speed);
+typedef int (*jlink_connect_func) (void);
+typedef unsigned int (*jlink_getsn_func) (void);
+typedef void (*jlink_emu_getproductname_func) (char *out, int size);
+typedef int (*jlink_rtterminal_control_func) (int cmd, void *data);
+typedef int (*jlink_rtterminal_read_func) (int cmd, char *buf, int size);
+
+struct jlink {
+	jlink_emu_selectbyusbsn_func emu_selectbyusbsn;
+	jlink_open_func open;
+	jlink_execcommand_func execcommand;
+	jlink_tif_select_func tif_select;
+	jlink_setspeed_func setspeed;
+	jlink_connect_func connect;
+	jlink_getsn_func getsn;
+	jlink_emu_getproductname_func emu_getproductname;
+	jlink_rtterminal_control_func rtterminal_control;
+	jlink_rtterminal_read_func rtterminal_read;
+};
+
+static struct jlink jlink;
+
+#ifndef NELEM
+#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+int jlink_init(void)
+{
+	void *so;
+	unsigned int i;
+
+	for (i = 0; i < NELEM(jlink_so_name); i++) {
+		so = dlopen(jlink_so_name[i], RTLD_LAZY);
+		if (so)
+			break;
+	}
+
+	if (!so)
+		return -EIO;
+
+	jlink.emu_selectbyusbsn = dlsym(so, "JLINK_EMU_SelectByUSBSN");
+	jlink.open = dlsym(so, "JLINK_Open");
+	jlink.execcommand = dlsym(so, "JLINK_ExecCommand");
+	jlink.tif_select = dlsym(so, "JLINK_TIF_Select");
+	jlink.setspeed = dlsym(so, "JLINK_SetSpeed");
+	jlink.connect = dlsym(so, "JLINK_Connect");
+	jlink.getsn = dlsym(so, "JLINK_GetSN");
+	jlink.emu_getproductname = dlsym(so, "JLINK_EMU_GetProductName");
+	jlink.rtterminal_control = dlsym(so, "JLINK_RTTERMINAL_Control");
+	jlink.rtterminal_read = dlsym(so, "JLINK_RTTERMINAL_Read");
+
+	if (!jlink.emu_selectbyusbsn || !jlink.open || !jlink.execcommand ||
+			!jlink.tif_select || !jlink.setspeed ||
+			!jlink.connect || !jlink.getsn ||
+			!jlink.emu_getproductname ||
+			!jlink.rtterminal_control || !jlink.rtterminal_read)
+		return -EIO;
+
+	return 0;
+}
+
+int jlink_connect(char *cfg)
+{
+	const char *device = NULL;
+	int tif = 1;
+	unsigned int speed = 1000;
+	unsigned int serial_no = 0;
+	char *tok;
+	char buf[64];
+
+	tok = strtok(cfg, ",");
+	device = tok;
+
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto connect;
+	if (strlen(tok)) {
+		if (!strcasecmp("swd", tok))
+			tif = 1;
+		else
+			return -EINVAL;
+	}
+
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto connect;
+	if (strlen(tok))
+		speed = atoi(tok);
+
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto connect;
+	if (strlen(tok))
+		serial_no = atoi(tok);
+
+connect:
+	if (serial_no)
+		if (jlink.emu_selectbyusbsn(serial_no) < 0) {
+			fprintf(stderr, "Failed to select emu by SN\n");
+			return -ENODEV;
+		}
+
+	if (jlink.open() < 0) {
+		fprintf(stderr, "Failed to open J-Link\n");
+		return -ENODEV;
+	}
+
+	snprintf(buf, sizeof(buf), "device=%s", device);
+	if (jlink.execcommand(buf, NULL, 0) < 0) {
+		fprintf(stderr, "Failed to select target device\n");
+		return -ENODEV;
+	}
+
+	if (jlink.tif_select(tif) < 0) {
+		fprintf(stderr, "Failed to select target interface\n");
+		return -ENODEV;
+	}
+
+	jlink.setspeed(speed);
+
+	if (jlink.connect() < 0) {
+		fprintf(stderr, "Failed to open target\n");
+		return -EIO;
+	}
+
+	serial_no = jlink.getsn();
+	jlink.emu_getproductname(buf, sizeof(buf));
+
+	printf("Connected to %s (S/N: %u)\n", buf, serial_no);
+
+	return 0;
+}
+
+int jlink_start_rtt(char *cfg)
+{
+	unsigned int address = 0;
+	unsigned int area_size = 0;
+	const char *buffer = "btmonitor";
+	char *tok;
+	char cmd[64];
+	int rtt_dir;
+	int count;
+	int i;
+
+	if (!cfg)
+		goto find_rttcb;
+
+	tok = strtok(cfg, ",");
+	if (strlen(tok)) {
+		address = strtol(tok, NULL, 0);
+		area_size = 0x1000;
+	}
+
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto find_rttcb;
+	if (strlen(tok))
+		area_size = strtol(tok, NULL, 0);
+
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto find_rttcb;
+	if (strlen(tok))
+		buffer = tok;
+
+find_rttcb:
+	if (address || area_size) {
+		if (!area_size)
+			snprintf(cmd, sizeof(cmd), "SetRTTAddr 0x%x", address);
+		else
+			snprintf(cmd, sizeof(cmd),
+						"SetRTTSearchRanges 0x%x 0x%x",
+						address, area_size);
+
+		if (jlink.execcommand(cmd, NULL, 0) < 0)
+			return -EIO;
+	}
+
+	if (jlink.rtterminal_control(RTT_CONTROL_START, NULL) < 0) {
+		fprintf(stderr, "Failed to initialize RTT\n");
+		return -1;
+	}
+
+	/* RTT may need some time to find control block so we need to wait */
+	do {
+		usleep(100);
+		rtt_dir = RTT_DIRECTION_UP;
+		count = jlink.rtterminal_control(RTT_CONTROL_GET_NUM_BUF,
+								&rtt_dir);
+	} while (count < 0);
+
+	for (i = 0; i < count; i++) {
+		memset(&rtt_desc, 0, sizeof(rtt_desc));
+		rtt_desc.index = i;
+		rtt_desc.direction = RTT_DIRECTION_UP;
+
+		if (jlink.rtterminal_control(RTT_CONTROL_GET_DESC,
+								&rtt_desc) < 0)
+			continue;
+
+		if (rtt_desc.size > 0 && !strcmp(buffer, rtt_desc.name))
+			break;
+	}
+
+	if (i == count)
+		return -ENODEV;
+
+	printf("Using RTT up buffer #%d (size: %d)\n", i, rtt_desc.size);
+
+	return 0;
+}
+
+int jlink_rtt_read(void *buf, size_t size)
+{
+	return jlink.rtterminal_read(rtt_desc.index, buf, size);
+}
diff --git a/monitor/jlink.h b/monitor/jlink.h
new file mode 100644
index 000000000..d7c76704c
--- /dev/null
+++ b/monitor/jlink.h
@@ -0,0 +1,27 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2018  Codecoup
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int jlink_init(void);
+int jlink_connect(char *cfg);
+int jlink_start_rtt(char *cfg);
+int jlink_rtt_read(void *buf, size_t size);
-- 
2.21.0


  reply	other threads:[~2019-10-01 14:10 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-01 14:09 [PATCH V2 1/3] monitor: Extract TTY data processing to separate function Szymon Janc
2019-10-01 14:09 ` Szymon Janc [this message]
2019-10-01 14:09 ` [PATCH V2 3/3] monitor: Add support for reading over J-Link RTT Szymon Janc

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191001140941.8005-2-szymon.janc@codecoup.pl \
    --to=szymon.janc@codecoup.pl \
    --cc=andrzej.kaczmarek@codecoup.pl \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).