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:
parent
c37a88c92f
commit
2e0e11b766
|
@ -2702,6 +2702,26 @@ Reset the current configuration.
|
||||||
@deffn {Command} {jlink config write}
|
@deffn {Command} {jlink config write}
|
||||||
Write the current configuration to the internal persistent storage.
|
Write the current configuration to the internal persistent storage.
|
||||||
@end deffn
|
@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}>
|
@deffn {Config} {jlink usb} <@option{0} to @option{3}>
|
||||||
Set the USB address of the interface, in case more than one adapter is connected
|
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
|
to the host. If not specified, USB addresses are not considered. Device
|
||||||
|
|
|
@ -1602,6 +1602,125 @@ COMMAND_HANDLER(jlink_handle_config_command)
|
||||||
return ERROR_OK;
|
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[] = {
|
static const struct command_registration jlink_config_subcommand_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "usb",
|
.name = "usb",
|
||||||
|
@ -1647,6 +1766,24 @@ static const struct command_registration jlink_config_subcommand_handlers[] = {
|
||||||
COMMAND_REGISTRATION_DONE
|
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[] = {
|
static const struct command_registration jlink_subcommand_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "jtag",
|
.name = "jtag",
|
||||||
|
@ -1696,6 +1833,12 @@ static const struct command_registration jlink_subcommand_handlers[] = {
|
||||||
"this will show the device configuration",
|
"this will show the device configuration",
|
||||||
.chain = jlink_config_subcommand_handlers,
|
.chain = jlink_config_subcommand_handlers,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "emucom",
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help = "access EMUCOM channel",
|
||||||
|
.chain = jlink_emucom_subcommand_handlers
|
||||||
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue