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>
gitignore-build
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

@ -2702,6 +2702,26 @@ Reset the current configuration.
@deffn {Command} {jlink config write}
Write the current configuration to the internal persistent storage.
@end deffn
@deffn {Command} {jlink emucom write <channel> <data>}
Write data to an EMUCOM channel. The data needs to be encoded as hexadecimal
pairs.
The following example shows how to write the three bytes 0xaa, 0x0b and 0x23 to
the EMUCOM channel 0x10:
@example
> jlink emucom write 0x10 aa0b23
@end example
@end deffn
@deffn {Command} {jlink emucom read <channel> <length>}
Read data from an EMUCOM channel. The read data is encoded as hexadecimal
pairs.
The following example shows how to read 4 bytes from the EMUCOM channel 0x0:
@example
> jlink emucom read 0x0 4
77a90000
@end example
@end deffn
@deffn {Config} {jlink usb} <@option{0} to @option{3}>
Set the USB address of the interface, in case more than one adapter is connected
to the host. If not specified, USB addresses are not considered. Device

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
};