#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
#include <sys/types.h>
#include <libusb-1.0/libusb.h>
+#include "stlink-hw.h"
+
+/* endianess related */
+static inline unsigned int is_bigendian(void)
+{
+ static volatile const unsigned int i = 1;
+ return *(volatile const char*) &i == 0;
+}
+
+static void write_uint32(unsigned char* buf, uint32_t ui)
+{
+ if (!is_bigendian()) { // le -> le (don't swap)
+ buf[0] = ((unsigned char*) &ui)[0];
+ buf[1] = ((unsigned char*) &ui)[1];
+ buf[2] = ((unsigned char*) &ui)[2];
+ buf[3] = ((unsigned char*) &ui)[3];
+ } else {
+ buf[0] = ((unsigned char*) &ui)[3];
+ buf[1] = ((unsigned char*) &ui)[2];
+ buf[2] = ((unsigned char*) &ui)[1];
+ buf[3] = ((unsigned char*) &ui)[0];
+ }
+}
+
+static void write_uint16(unsigned char* buf, uint16_t ui)
+{
+ if (!is_bigendian()) { // le -> le (don't swap)
+ buf[0] = ((unsigned char*) &ui)[0];
+ buf[1] = ((unsigned char*) &ui)[1];
+ } else {
+ buf[0] = ((unsigned char*) &ui)[1];
+ buf[1] = ((unsigned char*) &ui)[0];
+ }
+}
+
+static uint32_t read_uint32(const unsigned char *c, const int pt)
+{
+ uint32_t ui;
+ char *p = (char *) &ui;
+
+ if (!is_bigendian()) { // le -> le (don't swap)
+ p[0] = c[pt];
+ p[1] = c[pt + 1];
+ p[2] = c[pt + 2];
+ p[3] = c[pt + 3];
+ } else {
+ p[0] = c[pt + 3];
+ p[1] = c[pt + 2];
+ p[2] = c[pt + 1];
+ p[3] = c[pt];
+ }
+ return ui;
+}
+
+static uint16_t read_uint16(const unsigned char *c, const int pt)
+{
+ uint32_t ui;
+ char *p = (char *) &ui;
+
+ if (!is_bigendian()) { // le -> le (don't swap)
+ p[0] = c[pt];
+ p[1] = c[pt + 1];
+ } else {
+ p[0] = c[pt + 1];
+ p[1] = c[pt];
+ }
+ return ui;
+}
/* libusb transport layer */
if (trans->status != LIBUSB_TRANSFER_COMPLETED)
ctx->flags |= TRANS_FLAGS_HAS_ERROR;
- ctx->flags = TRANS_FLAGS_IS_DONE;
+ ctx->flags |= TRANS_FLAGS_IS_DONE;
}
static int submit_wait(struct libusb_transfer* trans)
{
+ struct timeval start;
+ struct timeval now;
+ struct timeval diff;
struct trans_ctx trans_ctx;
enum libusb_error error;
return -1;
}
- while (!(trans_ctx.flags & TRANS_FLAGS_IS_DONE))
+ gettimeofday(&start, NULL);
+
+ while (trans_ctx.flags == 0)
{
- if (libusb_handle_events(NULL))
+ struct timeval timeout;
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+ if (libusb_handle_events_timeout(libusb_ctx, &timeout))
{
printf("libusb_handle_events()\n");
return -1;
}
+
+ gettimeofday(&now, NULL);
+ timersub(&now, &start, &diff);
+ if (diff.tv_sec >= 3)
+ {
+ printf("libusb_handle_events() timeout\n");
+ return -1;
+ }
+ }
+
+ if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR)
+ {
+ printf("libusb_handle_events() | has_error\n");
+ return -1;
}
return 0;
}
-static int send_recv
+static ssize_t send_recv
(
struct stlink_libusb* handle,
unsigned char* txbuf, size_t txsize,
unsigned char* rxbuf, size_t rxsize
)
{
- /* note: txbuf and rxbuf can point to the same area */
+ /* note: txbuf and rxbuf can point to the same area */
libusb_fill_bulk_transfer
(
0
);
+ printf("submit_wait(req)\n");
+
if (submit_wait(handle->req_trans)) return -1;
+ /* send_only */
+ if (rxsize == 0) return 0;
+
/* read the response */
libusb_fill_bulk_transfer
0
);
- return submit_wait(handle->rep_trans);
+ printf("submit_wait(rep)\n");
+
+ if (submit_wait(handle->rep_trans)) return -1;
+
+ return handle->rep_trans->actual_length;
+}
+
+
+static inline int send_only
+(struct stlink_libusb* handle, unsigned char* txbuf, size_t txsize)
+{
+ return send_recv(handle, txbuf, txsize, NULL, 0);
}
void* libsg;
#endif /* CONFIG_USE_LIBSG */
} transport;
+
+ unsigned char q_buf[64];
+
+ /* layer independant */
+ uint32_t core_id;
};
int stlink_initialize(enum transport_type tt)
libusb_device* dev;
ssize_t i;
ssize_t count;
+ int config;
count = libusb_get_device_list(libusb_ctx, &devs);
if (count < 0)
goto on_libusb_error;
}
- if (libusb_set_configuration(slu->usb_handle, 1))
+ if (libusb_get_configuration(slu->usb_handle, &config))
{
- printf("libusb_set_configuration()\n");
+ /* this may fail for a previous configured device */
+ printf("libusb_get_configuration()\n");
goto on_libusb_error;
}
+ if (config != 1)
+ {
+ printf("setting new configuration (%d -> 1)\n", config);
+ if (libusb_set_configuration(slu->usb_handle, 1))
+ {
+ /* this may fail for a previous configured device */
+ printf("libusb_set_configuration()\n");
+ goto on_libusb_error;
+ }
+ }
+
if (libusb_claim_interface(slu->usb_handle, 0))
{
printf("libusb_claim_interface()\n");
goto on_libusb_error;
}
- slu->ep_req = 1 /* ep req */ | LIBUSB_ENDPOINT_OUT;
- slu->ep_rep = 2 /* ep rep */ | LIBUSB_ENDPOINT_IN;
+ slu->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN;
+ slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT;
+
+ /* libusb_reset_device(slu->usb_handle); */
/* success */
error = 0;
case TRANSPORT_TYPE_LIBUSB:
{
struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
- unsigned int i;
- unsigned char buf[6];
-
- for (i = 0; i < sizeof(buf); ++i) buf[i] = 0;
+ memset(buf, 0, sizeof(sl->q_buf));
+ buf[0] = STLINK_GET_VERSION;
+ buf[1] = 0x80;
- buf[0] = 0xf1;
- if (send_recv(slu, buf, sizeof(buf), buf, sizeof(buf)) == -1)
+ size = send_recv(slu, buf, 16, buf, sizeof(sl->q_buf));
+ if (size == -1)
{
printf("[!] send_recv\n");
return ;
}
- for (i = 0; i < 6; ++i) printf("%02x", buf[i]);
- printf("\n");
+#if 1 /* DEBUG */
+ {
+ unsigned int i;
+ for (i = 0; i < size; ++i) printf("%02x", buf[i]);
+ printf("\n");
+ }
+#endif /* DEBUG */
break ;
}
int stlink_current_mode(struct stlink *sl)
{
- return -1;
+ int mode = -1;
+
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+
+ buf[0] = STLINK_GET_CURRENT_MODE;
+
+ size = send_recv(slu, buf, 16, buf, sizeof(sl->q_buf));
+ if (size == -1)
+ {
+ printf("[!] send_recv\n");
+ return -1;
+ }
+
+ /* mode = (int)read_uint16(buf, 0); */
+ mode = (int)buf[0];
+
+#if 1 /* DEBUG */
+ printf("mode == 0x%x\n", mode);
+#endif /* DEBUG */
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
+
+ return mode;
+}
+
+void stlink_core_id(struct stlink *sl)
+{
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+ buf[0] = STLINK_DEBUG_COMMAND;
+ buf[1] = STLINK_DEBUG_READCOREID;
+
+ size = send_recv(slu, buf, 16, buf, sizeof(sl->q_buf));
+ if (size == -1)
+ {
+ printf("[!] send_recv\n");
+ return ;
+ }
+
+ sl->core_id = read_uint32(buf, 0);
+
+#if 1 /* DEBUG */
+ printf("core_id == 0x%x\n", sl->core_id);
+#endif /* DEBUG */
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
+}
+
+void stlink_status(struct stlink *sl)
+{
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+
+ buf[0] = STLINK_DEBUG_COMMAND;
+ buf[1] = STLINK_DEBUG_GETSTATUS;
+
+ size = send_recv(slu, buf, 16, buf, sizeof(sl->q_buf));
+ if (size == -1)
+ {
+ printf("[!] send_recv\n");
+ return ;
+ }
+
+ /* todo: stlink_core_stat */
+
+#if 1 /* DEBUG */
+ printf("status == 0x%x\n", buf[0]);
+#endif /* DEBUG */
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
}
void stlink_enter_swd_mode(struct stlink *sl)
{
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+
+ buf[0] = STLINK_DEBUG_COMMAND;
+ buf[1] = 0x30; /* magic byte */
+ buf[2] = STLINK_DEBUG_ENTER_JTAG;
+
+ size = send_recv(slu, buf, 16, buf, sizeof(sl->q_buf));
+ if (size == -1)
+ {
+ printf("[!] send_recv\n");
+ return ;
+ }
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
}
-void stlink_enter_jtag_mode(struct stlink *sl)
+void stlink_exit_dfu_mode(struct stlink *sl)
{
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+ buf[0] = STLINK_DFU_COMMAND;
+ buf[1] = STLINK_DFU_EXIT;
+
+ size = send_only(slu, buf, 16);
+ if (size == -1)
+ {
+ printf("[!] send_recv\n");
+ return ;
+ }
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
}
-void stlink_exit_debug_mode(struct stlink *sl)
+void stlink_reset(struct stlink *sl)
{
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+ buf[0] = STLINK_DEBUG_COMMAND;
+ buf[1] = STLINK_DEBUG_RESETSYS;
+
+ size = send_recv(slu, buf, 16, buf, sizeof(sl->q_buf));
+ if (size == -1)
+ {
+ printf("[!] send_recv\n");
+ return ;
+ }
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
}
-void stlink_core_id(struct stlink *sl)
+void stlink_step(struct stlink *sl)
+{
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+ buf[0] = STLINK_DEBUG_COMMAND;
+ buf[1] = STLINK_DEBUG_STEPCORE;
+
+ size = send_recv(slu, buf, 16, buf, sizeof(sl->q_buf));
+ if (size == -1)
+ {
+ printf("[!] send_recv\n");
+ return ;
+ }
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
+}
+
+void stlink_run(struct stlink *sl)
{
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+ buf[0] = STLINK_DEBUG_COMMAND;
+ buf[1] = STLINK_DEBUG_RUNCORE;
+
+ size = send_recv(slu, buf, 16, buf, sizeof(sl->q_buf));
+ if (size == -1)
+ {
+ printf("[!] send_recv\n");
+ return ;
+ }
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
}
-void stlink_status(struct stlink *sl)
+void stlink_exit_debug_mode(struct stlink *sl)
{
+ switch (sl->tt)
+ {
+#if CONFIG_USE_LIBUSB
+ case TRANSPORT_TYPE_LIBUSB:
+ {
+ struct stlink_libusb* const slu = &sl->transport.libusb;
+ unsigned char* const buf = sl->q_buf;
+ ssize_t size;
+
+ memset(buf, 0, sizeof(sl->q_buf));
+ buf[0] = STLINK_DEBUG_COMMAND;
+ buf[1] = STLINK_DEBUG_EXIT;
+
+ size = send_only(slu, buf, 16);
+ if (size == -1)
+ {
+ printf("[!] send_only\n");
+ return ;
+ }
+
+ break ;
+ }
+#endif /* CONFIG_USE_LIBUSB */
+
+ default: break ;
+ }
}
sl = stlink_quirk_open(TRANSPORT_TYPE_LIBUSB, NULL, 0);
if (sl != NULL)
{
+ printf("-- version\n");
stlink_version(sl);
- stlink_status(sl);
+
+ if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
+ {
+ printf("-- exit_dfu_mode\n");
+ stlink_exit_dfu_mode(sl);
+ }
+
+ printf("-- enter_swd_mode\n");
+ stlink_enter_swd_mode(sl);
+
+ printf("-- current_mode\n");
stlink_current_mode(sl);
+
+ printf("-- core_id\n");
+ stlink_core_id(sl);
+
+ printf("-- status\n");
+ stlink_status(sl);
+
+ printf("-- reset\n");
+ stlink_reset(sl);
+
+ printf("-- status\n");
+ stlink_status(sl);
+
+ printf("-- step\n");
+ stlink_step(sl);
+ getchar();
+
+ printf("-- run\n");
+ stlink_run(sl);
+
+ printf("-- exit_debug_mode\n");
+ stlink_exit_debug_mode(sl);
+
stlink_close(sl);
}
stlink_finalize(TRANSPORT_TYPE_LIBUSB);