jlink: Add EMUCOM support

EMUCOM is a way to communicate with a J-Link device via so called
channels. A channel can either be read or written in a single
operation.

Beside the reserved channels for SEGGER, there are channels available to
implement vendor and/or device specific functionalities. For example,
EMUCOM is used on many starter and development kits from Silicon Labs to
access power measurements and various other information and settings.

Change-Id: I6094109c043b34aed4a40ceabe71f30ff896bf1d
Signed-off-by: Marc Schink <openocd-dev@marcschink.de>
Reviewed-on: http://openocd.zylin.com/3794
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
This commit is contained in:
Marc Schink
2015-09-30 18:58:19 +02:00
committed by Paul Fertser
parent c37a88c92f
commit 2e0e11b766
2 changed files with 163 additions and 0 deletions

View File

@@ -1602,6 +1602,125 @@ COMMAND_HANDLER(jlink_handle_config_command)
return ERROR_OK;
}
COMMAND_HANDLER(jlink_handle_emucom_write_command)
{
int ret;
size_t tmp;
uint32_t channel;
uint32_t length;
uint8_t *buf;
size_t dummy;
if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) {
LOG_ERROR("Device does not support EMUCOM.");
return ERROR_FAIL;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel);
tmp = strlen(CMD_ARGV[1]);
if (tmp % 2 != 0) {
LOG_ERROR("Data must be encoded as hexadecimal pairs.");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
buf = malloc(tmp / 2);
if (!buf) {
LOG_ERROR("Failed to allocate buffer.");
return ERROR_FAIL;
}
dummy = unhexify(buf, CMD_ARGV[1], tmp / 2);
if (dummy != (tmp / 2)) {
LOG_ERROR("Data must be encoded as hexadecimal pairs.");
free(buf);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
length = tmp / 2;
ret = jaylink_emucom_write(devh, channel, buf, &length);
free(buf);
if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) {
LOG_ERROR("Channel not supported by the device.");
return ERROR_FAIL;
} else if (ret != JAYLINK_OK) {
LOG_ERROR("Failed to write to channel: %s.",
jaylink_strerror_name(ret));
return ERROR_FAIL;
}
if (length != (tmp / 2))
LOG_WARNING("Only %" PRIu32 " bytes written to the channel.", length);
return ERROR_OK;
}
COMMAND_HANDLER(jlink_handle_emucom_read_command)
{
int ret;
uint32_t channel;
uint32_t length;
uint8_t *buf;
size_t tmp;
if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) {
LOG_ERROR("Device does not support EMUCOM.");
return ERROR_FAIL;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
buf = malloc(length * 3 + 1);
if (!buf) {
LOG_ERROR("Failed to allocate buffer.");
return ERROR_FAIL;
}
ret = jaylink_emucom_read(devh, channel, buf, &length);
if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) {
LOG_ERROR("Channel is not supported by the device.");
free(buf);
return ERROR_FAIL;
} else if (ret == JAYLINK_ERR_DEV_NOT_AVAILABLE) {
LOG_ERROR("Channel is not available for the requested amount of data. "
"%" PRIu32 " bytes are avilable.", length);
free(buf);
return ERROR_FAIL;
} else if (ret != JAYLINK_OK) {
LOG_ERROR("Failed to read from channel: %s.",
jaylink_strerror_name(ret));
free(buf);
return ERROR_FAIL;
}
tmp = hexify((char *)buf + length, buf, length, 2 * length + 1);
if (tmp != 2 * length) {
LOG_ERROR("Failed to convert data into hexadecimal string.");
free(buf);
return ERROR_FAIL;
}
command_print(CMD_CTX, "%s", buf + length);
free(buf);
return ERROR_OK;
}
static const struct command_registration jlink_config_subcommand_handlers[] = {
{
.name = "usb",
@@ -1647,6 +1766,24 @@ static const struct command_registration jlink_config_subcommand_handlers[] = {
COMMAND_REGISTRATION_DONE
};
static const struct command_registration jlink_emucom_subcommand_handlers[] = {
{
.name = "write",
.handler = &jlink_handle_emucom_write_command,
.mode = COMMAND_EXEC,
.help = "write to a channel",
.usage = "<channel> <data>",
},
{
.name = "read",
.handler = &jlink_handle_emucom_read_command,
.mode = COMMAND_EXEC,
.help = "read from a channel",
.usage = "<channel> <length>"
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration jlink_subcommand_handlers[] = {
{
.name = "jtag",
@@ -1696,6 +1833,12 @@ static const struct command_registration jlink_subcommand_handlers[] = {
"this will show the device configuration",
.chain = jlink_config_subcommand_handlers,
},
{
.name = "emucom",
.mode = COMMAND_EXEC,
.help = "access EMUCOM channel",
.chain = jlink_emucom_subcommand_handlers
},
COMMAND_REGISTRATION_DONE
};