From 20ebda5bd820d97d11d1ce12e3e6a2a14067c50c Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Wed, 12 Aug 2020 01:47:38 +0200 Subject: Add 2-wire (C2) target interface support Signed-off-by: Marc Schink --- libjaylink/Makefile.am | 1 + libjaylink/c2.c | 349 ++++++++++++++++++++++++++++++++++++++++++++++++ libjaylink/libjaylink.h | 16 +++ libjaylink/strutil.c | 2 + libjaylink/target.c | 1 + 5 files changed, 369 insertions(+) create mode 100644 libjaylink/c2.c diff --git a/libjaylink/Makefile.am b/libjaylink/Makefile.am index 8e10212..073591a 100644 --- a/libjaylink/Makefile.am +++ b/libjaylink/Makefile.am @@ -30,6 +30,7 @@ endif libjaylink_la_SOURCES = \ buffer.c \ core.c \ + c2.c \ device.c \ discovery.c \ discovery_tcp.c \ diff --git a/libjaylink/c2.c b/libjaylink/c2.c new file mode 100644 index 0000000..c13a0fa --- /dev/null +++ b/libjaylink/c2.c @@ -0,0 +1,349 @@ +/* + * This file is part of the libjaylink project. + * + * Copyright (C) 2021-2022 Marc Schink + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "libjaylink.h" +#include "libjaylink-internal.h" + +/** + * @file + * + * Silicon Labs 2-wire (C2) interface functions. + */ + +/** @cond PRIVATE */ +#define CMD_C2_IO 0x17 + +#define C2_CMD_DATA_READ 0x00 +#define C2_CMD_DATA_WRITE 0x01 +#define C2_CMD_ADDR_READ 0x02 +#define C2_CMD_ADDR_WRITE 0x03 +/** @endcond */ + +/** + * Read the C2 address register. + * + * @note This function must only be used if the #JAYLINK_TIF_C2 interface is + * available and selected. + * + * @param[in,out] devh Device handle. + * @param[out] address Value read from the address register on success, and + * undefined on failure. + * + * @retval JAYLINK_OK Success. + * @retval JAYLINK_ERR_ARG Invalid arguments. + * @retval JAYLINK_ERR_TIMEOUT A timeout occurred. + * @retval JAYLINK_ERR_IO Input/output error. + * @retval JAYLINK_ERR_DEV Unspecified device error. + * @retval JAYLINK_ERR Other error conditions. + * + * @since 0.3.0 + */ +JAYLINK_API int jaylink_c2_read_address(struct jaylink_device_handle *devh, + uint8_t *address) +{ + int ret; + uint8_t buf[6]; + struct jaylink_context *ctx; + + if (!devh || !address) + return JAYLINK_ERR_ARG; + + ctx = devh->dev->ctx; + + ret = transport_start_write_read(devh, 5, 1 + 4, true); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_start_write_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + buf[0] = CMD_C2_IO; + buf[1] = C2_CMD_ADDR_READ; + buf[2] = 0x00; + /* Length is always 1 for this command. */ + buffer_set_u16(buf, 1, 3); + + ret = transport_write(devh, buf, 5); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_write() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + ret = transport_read(devh, address, 1); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + ret = transport_read(devh, buf, 4); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + uint32_t err = buffer_get_u32(buf, 0); + + if (err != 0) { + return JAYLINK_ERR_DEV; + } + + return JAYLINK_OK; +} + +/** + * Write to the C2 address register. + * + * @note This function must only be used if the #JAYLINK_TIF_C2 interface is + * available and selected. + * + * @param[in,out] devh Device handle. + * @param[in] address Value to write into the address register. + * + * @retval JAYLINK_OK Success. + * @retval JAYLINK_ERR_ARG Invalid arguments. + * @retval JAYLINK_ERR_TIMEOUT A timeout occurred. + * @retval JAYLINK_ERR_IO Input/output error. + * @retval JAYLINK_ERR_DEV Unspecified device error. + * @retval JAYLINK_ERR Other error conditions. + * + * @since 0.3.0 + */ +JAYLINK_API int jaylink_c2_write_address(struct jaylink_device_handle *devh, + uint8_t address) +{ + int ret; + uint8_t buf[6]; + struct jaylink_context *ctx; + + if (!devh) + return JAYLINK_ERR_ARG; + + ctx = devh->dev->ctx; + + ret = transport_start_write_read(devh, 5 + 1, 4, true); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_start_write_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + buf[0] = CMD_C2_IO; + buf[1] = C2_CMD_ADDR_WRITE; + /* Length is always 1 for this command. */ + buffer_set_u16(buf, 1, 2); + buf[4] = 0x00; + buf[5] = address; + + ret = transport_write(devh, buf, 6); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_write() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + ret = transport_read(devh, buf, 4); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + uint32_t err = buffer_get_u32(buf, 0); + + if (err != 0) { + return JAYLINK_ERR_DEV; + } + + return JAYLINK_OK; +} + +/** + * Read the C2 data register. + * + * @note This function must only be used if the #JAYLINK_TIF_C2 interface is + * available and selected. + * + * @param[in,out] devh Device handle. + * @param[out] data Buffer to store the read data on success. Its content is + * undefined on failure. + * @param[in] length Number of bytes to read, but not more than + * #JAYLINK_C2_MAX_LENGTH. + * + * @retval JAYLINK_OK Success. + * @retval JAYLINK_ERR_ARG Invalid arguments. + * @retval JAYLINK_ERR_TIMEOUT A timeout occurred. + * @retval JAYLINK_ERR_IO Input/output error. + * @retval JAYLINK_ERR_DEV Unspecified device error. + * @retval JAYLINK_ERR Other error conditions. + * + * @since 0.3.0 + */ +JAYLINK_API int jaylink_c2_read_data(struct jaylink_device_handle *devh, + uint8_t *data, uint8_t length) +{ + int ret; + struct jaylink_context *ctx; + uint8_t buf[5]; + + if (!devh || !data) + return JAYLINK_ERR_ARG; + + if (length > JAYLINK_C2_MAX_LENGTH) + return JAYLINK_ERR_ARG; + + ctx = devh->dev->ctx; + + ret = transport_start_write_read(devh, 5, 4 + length, true); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_start_write_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + buf[0] = CMD_C2_IO; + buf[1] = C2_CMD_DATA_READ; + buf[2] = 0x00; + buffer_set_u16(buf, length, 3); + + ret = transport_write(devh, buf, 5); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_write() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + ret = transport_read(devh, data, length); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + ret = transport_read(devh, buf, 4); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + uint32_t err = buffer_get_u32(buf, 0); + + if (err != 0) { + return JAYLINK_ERR_DEV; + } + + return JAYLINK_OK; +} + +/** + * Write to the C2 data register. + * + * @note This function must only be used if the #JAYLINK_TIF_C2 interface is + * available and selected. + * + * @param[in,out] devh Device handle. + * @param[in] data Buffer to be written into the data register. + * @param[in] length Number of bytes to write, but not more than + * #JAYLINK_C2_MAX_LENGTH. + * + * @retval JAYLINK_OK Success. + * @retval JAYLINK_ERR_ARG Invalid arguments. + * @retval JAYLINK_ERR_TIMEOUT A timeout occurred. + * @retval JAYLINK_ERR_IO Input/output error. + * @retval JAYLINK_ERR_DEV Unspecified device error. + * @retval JAYLINK_ERR Other error conditions. + * + * @since 0.3.0 + */ +JAYLINK_API int jaylink_c2_write_data(struct jaylink_device_handle *devh, + const uint8_t *data, uint8_t length) +{ + int ret; + uint8_t buf[5]; + struct jaylink_context *ctx; + + if (!devh || !data) + return JAYLINK_ERR_ARG; + + if (length > JAYLINK_C2_MAX_LENGTH) + return JAYLINK_ERR_ARG; + + ctx = devh->dev->ctx; + + ret = transport_start_write_read(devh, 5 + length, 4, true); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_start_write_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + buf[0] = CMD_C2_IO; + buf[1] = C2_CMD_DATA_WRITE; + buffer_set_u16(buf, length, 2); + buf[4] = 0x00; + + ret = transport_write(devh, buf, 5); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_write() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + ret = transport_write(devh, data, length); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_write() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + ret = transport_read(devh, buf, 4); + + if (ret != JAYLINK_OK) { + log_err(ctx, "transport_read() failed: %s", + jaylink_strerror(ret)); + return ret; + } + + uint32_t err = buffer_get_u32(buf, 0); + + if (err != 0) { + return JAYLINK_ERR_DEV; + } + + return JAYLINK_OK; +} diff --git a/libjaylink/libjaylink.h b/libjaylink/libjaylink.h index d89913c..22fc825 100644 --- a/libjaylink/libjaylink.h +++ b/libjaylink/libjaylink.h @@ -246,6 +246,8 @@ enum jaylink_target_interface { JAYLINK_TIF_2W_JTAG_PIC32 = 4, /** Serial Peripheral Interface (SPI). */ JAYLINK_TIF_SPI = 5, + /** Silicon Labs 2-wire interface (C2). */ + JAYLINK_TIF_C2 = 6, /** Compact JTAG (cJTAG). **/ JAYLINK_TIF_CJTAG = 7, }; @@ -425,6 +427,9 @@ struct jaylink_connection { */ #define JAYLINK_EMUCOM_CHANNEL_USER 0x10000 +/** Maximum length of a 2-wire (C2) interface data transfer. */ +#define JAYLINK_C2_MAX_LENGTH 64 + /** * @struct jaylink_context * @@ -475,6 +480,17 @@ JAYLINK_API int jaylink_init(struct jaylink_context **ctx); JAYLINK_API int jaylink_exit(struct jaylink_context *ctx); JAYLINK_API bool jaylink_library_has_cap(enum jaylink_capability cap); +/*--- c2.c ------------------------------------------------------------------*/ + +JAYLINK_API int jaylink_c2_read_address(struct jaylink_device_handle *devh, + uint8_t *address); +JAYLINK_API int jaylink_c2_write_address(struct jaylink_device_handle *devh, + uint8_t address); +JAYLINK_API int jaylink_c2_read_data(struct jaylink_device_handle *devh, + uint8_t *data, uint8_t length); +JAYLINK_API int jaylink_c2_write_data(struct jaylink_device_handle *devh, + const uint8_t *data, uint8_t length); + /*--- device.c --------------------------------------------------------------*/ JAYLINK_API int jaylink_get_devices(struct jaylink_context *ctx, diff --git a/libjaylink/strutil.c b/libjaylink/strutil.c index 0f344c1..913a5a5 100644 --- a/libjaylink/strutil.c +++ b/libjaylink/strutil.c @@ -118,6 +118,8 @@ JAYLINK_API const char *jaylink_target_interface_string( return "2-wire JTAG for PIC32"; case JAYLINK_TIF_SPI: return "SPI"; + case JAYLINK_TIF_C2: + return "C2"; case JAYLINK_TIF_CJTAG: return "cJTAG"; default: diff --git a/libjaylink/target.c b/libjaylink/target.c index c51ebcd..6715662 100644 --- a/libjaylink/target.c +++ b/libjaylink/target.c @@ -218,6 +218,7 @@ JAYLINK_API int jaylink_select_interface(struct jaylink_device_handle *devh, case JAYLINK_TIF_FINE: case JAYLINK_TIF_2W_JTAG_PIC32: case JAYLINK_TIF_SPI: + case JAYLINK_TIF_C2: case JAYLINK_TIF_CJTAG: break; default: -- cgit v1.1