diff options
author | Marc Schink <openocd-dev@marcschink.de> | 2015-09-30 18:58:19 +0200 |
---|---|---|
committer | Paul Fertser <fercerpav@gmail.com> | 2016-12-08 13:32:11 +0000 |
commit | 2e0e11b76645d6b38bc4986d8000e4e47e391596 (patch) | |
tree | b0edd6e3e265e63af932fec3b1d50752049d867c | |
parent | c37a88c92f0234df6206a4b58c23d20563a22afc (diff) |
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>
-rw-r--r-- | doc/openocd.texi | 20 | ||||
-rw-r--r-- | src/jtag/drivers/jlink.c | 143 |
2 files changed, 163 insertions, 0 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi index b47d2c44..440aa04a 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -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 diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 95c6d8db..e5bfd322 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -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 }; |