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