Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: whitequark/libfx2
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: elfmimi/libfx2
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ez-dap
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 3 commits
  • 8 files changed
  • 1 contributor

Commits on Jan 16, 2022

  1. Copy the full SHA
    52e2f82 View commit details

Commits on Aug 15, 2022

  1. Support SWD_Sequence command

    Many fixes to improve compatibility
    elfmimi committed Aug 15, 2022
    Copy the full SHA
    ef29481 View commit details

Commits on Aug 16, 2022

  1. Copy the full SHA
    e1c1597 View commit details
Showing with 1,354 additions and 1 deletion.
  1. +1 −1 examples/Makefile
  2. +574 −0 examples/ez-dap/DAP.c
  3. +130 −0 examples/ez-dap/DAP.h
  4. +48 −0 examples/ez-dap/IO_Config.h
  5. +7 −0 examples/ez-dap/Makefile
  6. +270 −0 examples/ez-dap/SW_DP.c
  7. +58 −0 examples/ez-dap/desc.asm
  8. +266 −0 examples/ez-dap/main.c
2 changes: 1 addition & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SUBDIRS = blinky printf cdc-acm boot-uf2-dfu boot-dfu-spiflash
SUBDIRS = blinky printf cdc-acm ez-dap boot-uf2-dfu boot-dfu-spiflash

all:
@set -e; for dir in $(SUBDIRS); do $(MAKE) -C $${dir} all; done
574 changes: 574 additions & 0 deletions examples/ez-dap/DAP.c

Large diffs are not rendered by default.

130 changes: 130 additions & 0 deletions examples/ez-dap/DAP.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2013-2021 ARM Limited. All rights reserved.
* Copyright 2019, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ----------------------------------------------------------------------
*
* $Date: 26. May 2021
* $Revision: V2.1.0
*
* Project: CMSIS-DAP Include
* Title: DAP.h Definitions
*
*---------------------------------------------------------------------------*/
/*
* Modified to adapt to CY7C68013A by Ein Terakawa
*/

#ifndef __DAP_H__
#define __DAP_H__

// DAP Firmware Version
#define DAP_FW_VER "2.1.0"


// DAP Command IDs
#define ID_DAP_Info 0x00U
#define ID_DAP_HostStatus 0x01U
#define ID_DAP_Connect 0x02U
#define ID_DAP_Disconnect 0x03U
#define ID_DAP_TransferConfigure 0x04U
#define ID_DAP_Transfer 0x05U
#define ID_DAP_TransferBlock 0x06U
#define ID_DAP_SWJ_Clock 0x11U
#define ID_DAP_SWJ_Sequence 0x12U
#define ID_DAP_SWD_Configure 0x13U
#define ID_DAP_SWD_Sequence 0x1DU

#define ID_DAP_ExecuteCommands 0x7FU

// DAP Status Code
#define DAP_OK 0U
#define DAP_ERROR 0xFFU

// DAP ID
#define DAP_ID_VENDOR 1U
#define DAP_ID_PRODUCT 2U
#define DAP_ID_SER_NUM 3U
#define DAP_ID_DAP_FW_VER 4U
#define DAP_ID_PRODUCT_FW_VER 9U
#define DAP_ID_CAPABILITIES 0xF0U
#define DAP_ID_PACKET_COUNT 0xFEU
#define DAP_ID_PACKET_SIZE 0xFFU

// DAP Port
#define DAP_PORT_SWD 1U // SWD Port (SWCLK, SWDIO) + nRESET

// DAP Transfer Request
#define DAP_TRANSFER_APnDP (1U<<0)
#define DAP_TRANSFER_RnW (1U<<1)
#define DAP_TRANSFER_A2 (1U<<2)
#define DAP_TRANSFER_A3 (1U<<3)
#define DAP_TRANSFER_MATCH_VALUE (1U<<4)
#define DAP_TRANSFER_MATCH_MASK (1U<<5)

// DAP Transfer Response
#define DAP_TRANSFER_OK (1U<<0)
#define DAP_TRANSFER_WAIT (1U<<1)
#define DAP_TRANSFER_FAULT (1U<<2)
#define DAP_TRANSFER_ERROR (1U<<3)
#define DAP_TRANSFER_MISMATCH (1U<<4)

// Debug Port Register Addresses
#define DP_RDBUFF 0x0CU // Read Buffer (Read Only)

// DAP Data structure
typedef struct {
struct {
uint8_t retry_count;
uint8_t idle_cycles;
uint8_t match_retry;
uint8_t match_mask[4];
} transfer;
struct {
uint8_t turnaround;
uint8_t data_phase;
} swd_conf;
} DAP_Data_t;

extern DAP_Data_t DAP_Data; // DAP Data
extern volatile uint8_t DAP_TransferAbort; // Transfer Abort Flag

#ifdef __cplusplus
extern "C"
{
#endif

// Functions
extern void SWD_Init();
extern void SWD_WriteSequence(uint8_t num, __xdata const uint8_t *ptr);
extern void SWD_ReadSequence(uint8_t num, __xdata uint8_t *ptr);
extern uint8_t SWD_Transfer(uint8_t request /* , uint32_t *data */);

extern uint16_t dap_execute_command(uint16_t idxidx, uint8_t len);
extern uint16_t dap_execute_swj_sequence(uint16_t idxidx, uint8_t len);
extern uint16_t dap_execute_swd_sequence(uint16_t idxidx, uint8_t len);
extern uint16_t dap_execute_transfer(uint16_t idxidx, uint8_t len);
extern uint16_t dap_execute_transfer_block(uint16_t idxidx, uint8_t len);

extern void led_blink();

#ifdef __cplusplus
}
#endif

#endif /* __DAP_H__ */
48 changes: 48 additions & 0 deletions examples/ez-dap/IO_Config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @file IO_Config.h
* @brief
*
* DAPLink Interface Firmware
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Modified to adapt to CY7C68013A by Ein Terakawa
*/

#ifndef __IO_CONFIG_H__
#define __IO_CONFIG_H__

// SWCLK Pin PB7
#define PIN_SWCLK PB7
#define PIN_SWCLK_OE OEB
#define PIN_SWCLK_MASK (1 << 7)

// SWDIO Pin PB5
#define PIN_SWDIO PB5
#define PIN_SWDIO_OE OEB
#define PIN_SWDIO_MASK (1 << 5)

// LED0 Pin PA0
#define PIN_LED0 PA0
#define PIN_LED0_OE OEA
#define PIN_LED0_MASK (1 << 0)

// LED1 Pin PA1
#define PIN_LED1 PA1
#define PIN_LED1_OE OEA
#define PIN_LED1_MASK (1 << 1)

#endif
7 changes: 7 additions & 0 deletions examples/ez-dap/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
TARGET = ez-dap
LIBRARIES = fx2 fx2usb fx2isrs
MODEL = small
SOURCES = main desc DAP SW_DP

LIBFX2 = ../../firmware/library
include $(LIBFX2)/fx2rules.mk
270 changes: 270 additions & 0 deletions examples/ez-dap/SW_DP.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
* Copyright (c) 2013-2017 ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ----------------------------------------------------------------------
*
* $Date: 1. December 2017
* $Revision: V2.0.0
*
* Project: CMSIS-DAP Source
* Title: SW_DP.c CMSIS-DAP SW DP I/O
*
*---------------------------------------------------------------------------*/
/*
* Modified to adapt to CY7C68013A by Ein Terakawa
*/

#include <fx2lib.h>
#include <fx2regs.h>
#include "DAP.h"
#include "IO_Config.h"

extern uint8_t data[4];

#define PIN_SWCLK_CLR() \
PIN_SWCLK = 0

#define PIN_SWCLK_SET() \
PIN_SWCLK = 1

#define PIN_SWDIO_OUT(bit) \
PIN_SWDIO = (bit & 1)

#define PIN_SWDIO_IN() \
PIN_SWDIO

#define PIN_DELAY() \
do { } while(0)

#define SW_CLOCK_CYCLE() \
PIN_SWCLK_CLR(); \
PIN_DELAY(); \
PIN_SWCLK_SET(); \
PIN_DELAY()

#define SW_WRITE_BIT(bit) \
PIN_SWDIO_OUT(bit); \
PIN_SWCLK_CLR(); \
PIN_DELAY(); \
PIN_SWCLK_SET(); \
PIN_DELAY()

#define SW_READ_BIT(bit) \
PIN_SWCLK_CLR(); \
PIN_DELAY(); \
bit = PIN_SWDIO_IN(); \
PIN_SWCLK_SET(); \
PIN_DELAY()

#define PIN_SWDIO_OUT_DISABLE() \
PIN_SWDIO_OE &= ~PIN_SWDIO_MASK

#define PIN_SWDIO_OUT_ENABLE() \
PIN_SWDIO_OE |= PIN_SWDIO_MASK

void SWD_Init() {
// Configure pins
PIN_SWDIO = 1; // set SWDIO to high
PIN_SWCLK = 1; // set SWCLK to high
PIN_SWDIO_OE |= PIN_SWDIO_MASK;
PIN_SWCLK_OE |= PIN_SWCLK_MASK;
}

void SWD_WriteSequence(uint8_t num, __xdata const uint8_t *ptr) {
PIN_SWDIO_OUT(*ptr);
PIN_SWDIO_OUT_ENABLE();
// num == 0 indicates 256bits
if ((num & 7) != 0) {
num = (num ^ 7) + 9;
}
do {
uint8_t bits = *ptr++;
num -= 8;
uint8_t n = ((num & 0xF8) != 0) ? 8 : 8 - num;
for (uint8_t i=0; i < n; i++) {
SW_WRITE_BIT(bits);
bits >>= 1;
}
} while((num & 0xF8) != 0);
}

void SWD_ReadSequence(uint8_t num, __xdata uint8_t *ptr) {
if (num == 0)
return;

PIN_SWDIO_OUT_DISABLE();
do {
uint8_t bits = 0;
uint8_t bit = 1;
uint8_t n = ((num < 8) ? num : 8);
for (uint8_t i=0; i < n; i++) {
PIN_SWCLK = 0; // set SWCLK to low
if (PIN_SWDIO) {
bits |= bit;
}
PIN_SWCLK = 1; // set SWCLK to high
bit += bit;
}
*ptr++ = bits;
num -= n;
} while(num != 0);
}


// SWD Transfer I/O
// request: A[3:2] RnW APnDP
// data: DATA[31:0]
// return: ACK[2:0]
uint8_t SWD_Transfer (uint8_t request /* , uint32_t *data */) {
uint8_t ack;
uint8_t bit;
uint8_t val;
uint8_t parity;

uint8_t m, n;

/* Packet Request */
PIN_SWDIO_OUT(1);
PIN_SWDIO_OUT_ENABLE();
SW_CLOCK_CYCLE(); /* Start Bit */
parity = 0;
bit = request >> 0;
SW_WRITE_BIT(bit); /* APnDP Bit */
parity += bit;
bit = request >> 1;
SW_WRITE_BIT(bit); /* RnW Bit */
parity += bit;
bit = request >> 2;
SW_WRITE_BIT(bit); /* A2 Bit */
parity += bit;
bit = request >> 3;
SW_WRITE_BIT(bit); /* A3 Bit */
parity += bit;
SW_WRITE_BIT(parity); /* Parity Bit */
SW_WRITE_BIT(0); /* Stop Bit */
SW_WRITE_BIT(1); /* Park Bit */

/* Turnaround */
PIN_SWDIO_OUT_DISABLE();
for (n = DAP_Data.swd_conf.turnaround; n; n--) {
SW_CLOCK_CYCLE();
}

/* Acknowledge response */
SW_READ_BIT(bit);
ack = bit << 0;
SW_READ_BIT(bit);
ack |= bit << 1;
SW_READ_BIT(bit);
ack |= bit << 2;

if (ack == DAP_TRANSFER_OK) { /* OK response */
/* Data transfer */
if (request & DAP_TRANSFER_RnW) {
/* Read data */
parity = 0;
for (m = 0; m < 4; m++) {
val = 0;
for (n = 0; n < 8; n++) {
SW_READ_BIT(bit); /* Read RDATA[0:31] */
val |= bit;
val = (val >> 1) | (val << 7);
}
// 8051 trick here, to calculate parity
ACC = val;
parity += P;
data[m] = val;
}
SW_READ_BIT(bit); /* Read Parity */
if ((parity + bit) & 1) {
ack = DAP_TRANSFER_ERROR;
}
// if (data) { *data = val; }
/* Turnaround */
for (n = DAP_Data.swd_conf.turnaround; n; n--) {
SW_CLOCK_CYCLE();
}
PIN_SWDIO_OUT_ENABLE();
} else {
/* Turnaround */
for (n = DAP_Data.swd_conf.turnaround; n; n--) {
SW_CLOCK_CYCLE();
}
PIN_SWDIO_OUT_ENABLE();
/* Write data */
// val = *data;
parity = 0;
for (m = 0; m < 4; m++) {
val = data[m];
// 8051 trick here, to calculate parity
ACC = val;
parity += P;
for (n = 0; n < 8; n++) {
SW_WRITE_BIT(val); /* Write WDATA[0:31] */
val = (val >> 1) | (val << 7);
}
}
SW_WRITE_BIT(parity); /* Write Parity Bit */
}
#if 0
/* Capture Timestamp */
if (request & DAP_TRANSFER_TIMESTAMP) {
DAP_Data.timestamp = TIMESTAMP_GET();
}
#endif
/* Idle cycles */
n = DAP_Data.transfer.idle_cycles;
if (n) {
PIN_SWDIO_OUT(0);
for (; n; n--) {
SW_CLOCK_CYCLE();
}
}
PIN_SWDIO_OUT(1);
return ((uint8_t)ack);
}

if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) {
/* WAIT or FAULT response */
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0)) {
for (n = 32 + 1; n; n--) {
SW_CLOCK_CYCLE(); /* Dummy Read RDATA[0:31] + Parity */
}
}
/* Turnaround */
for (n = DAP_Data.swd_conf.turnaround; n; n--) {
SW_CLOCK_CYCLE();
}
PIN_SWDIO_OUT_ENABLE();
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) == 0)) {
PIN_SWDIO_OUT(0);
for (n = 32 + 1; n; n--) {
SW_CLOCK_CYCLE(); /* Dummy Write WDATA[0:31] + Parity */
}
}
PIN_SWDIO_OUT(1);
return ((uint8_t)ack);
}

/* Protocol error */
for (n = DAP_Data.swd_conf.turnaround + 32 + 1; n; n--) {
SW_CLOCK_CYCLE(); /* Back off data phase */
}
PIN_SWDIO_OUT_ENABLE();
PIN_SWDIO_OUT(1);
return ((uint8_t)ack);
}
58 changes: 58 additions & 0 deletions examples/ez-dap/desc.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.globl _bos_desc, _msos20_desc
.area DESC (CODE)
VENDOR_MS_OS_20_REQUEST = 0xCC

.even
_bos_desc:
.db 0x05
.db 0x0F
_BOS_DESC_SIZE::
.db <(bos_desc_end - _bos_desc)
.db >(bos_desc_end - _bos_desc)
.db 0x01

.db 0x1C
.db 0x10
.db 0x05
.db 0x00
.db 0xDF
.db 0x60
.db 0xDD
.db 0xD8
.db 0x89
.db 0x45
.db 0xC7
.db 0x4C
.db 0x9C
.db 0xD2
.db 0x65
.db 0x9D
.db 0x9E
.db 0x64
.db 0x8A
.db 0x9F
.db 0x00
.db 0x00
.db 0x03
.db 0x06
.db <(msos20_desc_end - _msos20_desc)
.db >(msos20_desc_end - _msos20_desc)
_VENDOR_MS_OS_20_REQUEST::
.db VENDOR_MS_OS_20_REQUEST
.db 0x00
bos_desc_end:

; -----------------------------------------------------------------------------
; MS OS 2.0 ( Microsoft OS 2.0 Descriptors )
; -----------------------------------------------------------------------------
.even
_msos20_desc:
.db 0x0A, 0x00, 0x00, 0x00
.db 0x00, 0x00, 0x03, 0x06
_MSOS20_DESC_SIZE::
.db <(msos20_desc_end - _msos20_desc)
.db >(msos20_desc_end - _msos20_desc)
.db 0x14, 0x00, 0x03, 0x00
.db 'W, 'I, 'N, 'U, 'S, 'B, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0
msos20_desc_end:
266 changes: 266 additions & 0 deletions examples/ez-dap/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
/*
Copyright (C) 2022 Ein Terakawa <applause@elfmimi.jp>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

// This example is a minimally functional CMSIS-DAP ported to CY7C68013A.
//
// By means of Microsoft OS 2.0 Descriptors, MS-OS-2.0 for short,
// WinUSB driver will automatically get attached to the device.

#include <fx2lib.h>
#include <fx2delay.h>
#include <fx2usb.h>
#include <usbcdc.h>
#include "DAP.h"
#include "IO_Config.h"

usb_desc_device_c usb_device = {
.bLength = sizeof(struct usb_desc_device),
.bDescriptorType = USB_DESC_DEVICE,
.bcdUSB = 0x0210,
.bDeviceClass = USB_DEV_CLASS_PER_INTERFACE,
.bDeviceSubClass = USB_DEV_SUBCLASS_PER_INTERFACE,
.bDeviceProtocol = USB_DEV_PROTOCOL_PER_INTERFACE,
.bMaxPacketSize0 = 64,
.idVendor = 0x04b4, // 0x0d28,
.idProduct = 0x8613, // 0x0204,
.bcdDevice = 0x0000,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1,
};

usb_desc_interface_c usb_iface_vendor = {
.bLength = sizeof(struct usb_desc_interface),
.bDescriptorType = USB_DESC_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_IFACE_CLASS_VENDOR,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 4,
};

usb_desc_endpoint_c usb_endpoint_ep2_out = {
.bLength = sizeof(struct usb_desc_endpoint),
.bDescriptorType = USB_DESC_ENDPOINT,
.bEndpointAddress = 2,
.bmAttributes = USB_XFER_BULK,
.wMaxPacketSize = 512,
.bInterval = 0,
};

usb_desc_endpoint_c usb_endpoint_ep6_in = {
.bLength = sizeof(struct usb_desc_endpoint),
.bDescriptorType = USB_DESC_ENDPOINT,
.bEndpointAddress = 6|USB_DIR_IN,
.bmAttributes = USB_XFER_BULK,
.wMaxPacketSize = 512,
.bInterval = 0,
};

usb_configuration_c usb_config = {
{
.bLength = sizeof(struct usb_desc_configuration),
.bDescriptorType = USB_DESC_CONFIGURATION,
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = USB_ATTR_RESERVED_1,
.bMaxPower = 50,
},
{
{ .interface = &usb_iface_vendor },
{ .endpoint = &usb_endpoint_ep2_out },
{ .endpoint = &usb_endpoint_ep6_in },
{ 0 }
}
};

usb_configuration_set_c usb_configs[] = {
&usb_config,
};

usb_ascii_string_c usb_strings[] = {
[0] = "libfx2",
[1] = "FX2 series CMSIS-DAP example",
[2] = "0011223344556677",
[3] = "CMSIS-DAP v2",
};

usb_descriptor_set_c usb_descriptor_set = {
.device = &usb_device,
.config_count = ARRAYSIZE(usb_configs),
.configs = usb_configs,
.string_count = ARRAYSIZE(usb_strings),
.strings = usb_strings,
};

extern __xdata uint8_t bos_desc[];
extern __xdata uint8_t msos20_desc[];
extern __xdata uint16_t BOS_DESC_SIZE;
extern __xdata uint16_t MSOS20_DESC_SIZE;
// #define VENDOR_MS_OS_20_REQUEST 0xCC
extern __xdata uint8_t VENDOR_MS_OS_20_REQUEST;

void handle_usb_get_descriptor(enum usb_descriptor type, uint8_t index) {
// At this point following conditions are satisfied.
// req->bmRequestType == (USB_RECIP_DEVICE|USB_TYPE_STANDARD|USB_DIR_IN) &&
// req->bRequest == USB_REQ_GET_DESCRIPTOR
if(type == 15 /* USB_DESC_BOS */) {
// SETUP_EP0_IN_DATA(bos_desc, sizeof(bos_desc));
// uint16_t length = 33; // sizeof(bos_desc);
uint16_t length = BOS_DESC_SIZE;
xmemcpy(EP0BUF, bos_desc, length);
SETUP_EP0_BUF(length);
return;
}

usb_serve_descriptor(&usb_descriptor_set, type, index);
}

void handle_usb_setup(__xdata struct usb_req_setup *req) {
if(req->bmRequestType == (USB_RECIP_DEVICE|USB_TYPE_VENDOR|USB_DIR_IN) &&
req->bRequest == VENDOR_MS_OS_20_REQUEST &&
req->wIndex == 7 /* MS_OS_20_DESCRIPTOR_INDEX */) {
// SETUP_EP0_IN_DATA(msos20_desc, sizeof(msos20_desc));
// uint16_t length = 30; // sizeof(msos20_desc);
uint16_t length = MSOS20_DESC_SIZE;
xmemcpy(EP0BUF, msos20_desc, length);
SETUP_EP0_BUF(length);
return;
}

STALL_EP0();
}


volatile bool pending_ep6_in;

void isr_IBN() __interrupt {
pending_ep6_in = true;
CLEAR_USB_IRQ();
NAKIRQ = _IBN;
IBNIRQ = _IBNI_EP6;
}

static uint8_t led_connected = 0;
static int led_timer = 0;
// Register an interrupt handler for TIMER0 overflow
void isr_TF0() __interrupt(_INT_TF0) {
if (led_timer != 0) {
led_timer -= 1;
if (led_timer == 0) {
PIN_LED1 = led_connected & 1;
PIN_LED0 = 0;
}
}
}

void led_blink() {
PIN_LED0 = 1;
PIN_LED1 = (led_connected ^ 1) & 1;
led_timer = 8;
}

int main() {
// Run core at 48 MHz fCLK.
CPUCS = _CLKSPD1;

// IO-pins to GPIO mode
IFCONFIG = 0x80;

// Configure TIMER0
TMOD = _M0_0; // use 16-bit counter mode for TIMER0
ET0 = 1; // generate an interrupt
TR0 = 1; // run

// Use newest chip features.
REVCTL = _ENH_PKT|_DYN_OUT;

// NAK all transfers.
SYNCDELAY;
FIFORESET = _NAKALL;

// EP1IN is configured as INTERRUPT IN.
EP1INCFG = _VALID|_TYPE1|_TYPE0;
// EP1OUT is not used.
EP1OUTCFG &= ~_VALID;

// EP2 is configured as 512-byte double buffed BULK OUT.
EP2CFG = _VALID|_TYPE1|_BUF1;
EP2CS = 0;
// EP6 is configured as 512-byte double buffed BULK IN.
EP6CFG = _VALID|_DIR|_TYPE1|_BUF1;
EP6CS = 0;
// EP4/8 are not used.
EP4CFG &= ~_VALID;
EP8CFG &= ~_VALID;

// Enable IN-BULK-NAK interrupt for EP6.
IBNIE = _IBNI_EP6;
NAKIE = _IBN;

// Reset and prime EP2, and reset EP6.
SYNCDELAY;
FIFORESET = _NAKALL|2;
SYNCDELAY;
OUTPKTEND = _SKIP|2;
SYNCDELAY;
OUTPKTEND = _SKIP|2;
SYNCDELAY;
FIFORESET = _NAKALL|6;
SYNCDELAY;
FIFORESET = 0;

PIN_LED0_OE |= PIN_LED0_MASK; // Set LED0 pin as output
PIN_LED1_OE |= PIN_LED1_MASK; // Set LED1 pin as output
PIN_LED0 = 0; // Red LED (v1.1 and v1.2 only)
PIN_LED1 = 0; // Blue LED

{
DAP_Data.transfer.retry_count = 255;
DAP_Data.transfer.idle_cycles = 2;
DAP_Data.transfer.match_retry = 255;
DAP_Data.swd_conf.turnaround = 1;
DAP_Data.swd_conf.data_phase = 1;
}

// Re-enumerate, to make sure our descriptors are picked up correctly.
usb_init(/*disconnect=*/true);
// usb_init() will enable all interrupts. ( EA = 1 )
{
uint16_t length = 0;
while(1) {
if(length == 0 && !(EP2CS & _EMPTY)) {
length = (EP2BCH << 8) | EP2BCL;
// read from EP2FIFOBUF , write to scratch
length = dap_execute_command(0, length) & 0xFF;
EP2BCL = 0;
}

if(length != 0 && pending_ep6_in) {
xmemcpy(EP6FIFOBUF, scratch, length);
EP6BCH = length >> 8;
SYNCDELAY;
EP6BCL = length;

length = 0;
pending_ep6_in = false;
}
}
}
}