From f01c40a5e0bca267ea6fcc1a2cf4eb0e3b71c3cd Mon Sep 17 00:00:00 2001 From: eddyem Date: Mon, 29 Apr 2019 18:44:05 +0300 Subject: [PATCH] add USBHID (not working) --- F0-nolib/Readme.md | 1 + F0-nolib/USBHID/Makefile | 149 ++++++++++ F0-nolib/USBHID/Readme.md | 1 + F0-nolib/USBHID/hardware.c | 49 ++++ F0-nolib/USBHID/hardware.h | 67 +++++ F0-nolib/USBHID/keycodes.c | 74 +++++ F0-nolib/USBHID/keycodes.h | 138 +++++++++ F0-nolib/USBHID/main.c | 162 ++++++++++ F0-nolib/USBHID/usart.c | 254 ++++++++++++++++ F0-nolib/USBHID/usart.h | 60 ++++ F0-nolib/USBHID/usb.c | 96 ++++++ F0-nolib/USBHID/usb.h | 36 +++ F0-nolib/USBHID/usb_defs.h | 104 +++++++ F0-nolib/USBHID/usb_lib.c | 588 +++++++++++++++++++++++++++++++++++++ F0-nolib/USBHID/usb_lib.h | 208 +++++++++++++ F0-nolib/USBHID/usbhid.bin | Bin 0 -> 6564 bytes F0-nolib/pl2303/Makefile | 3 +- F0-nolib/pl2303/pl2303.bin | Bin 6484 -> 6100 bytes F0-nolib/pl2303/usb_lib.c | 1 - F0-nolib/pl2303/usb_lib.h | 405 +++++++++++++------------ 20 files changed, 2190 insertions(+), 206 deletions(-) create mode 100644 F0-nolib/USBHID/Makefile create mode 100644 F0-nolib/USBHID/Readme.md create mode 100644 F0-nolib/USBHID/hardware.c create mode 100644 F0-nolib/USBHID/hardware.h create mode 100644 F0-nolib/USBHID/keycodes.c create mode 100644 F0-nolib/USBHID/keycodes.h create mode 100644 F0-nolib/USBHID/main.c create mode 100644 F0-nolib/USBHID/usart.c create mode 100644 F0-nolib/USBHID/usart.h create mode 100644 F0-nolib/USBHID/usb.c create mode 100644 F0-nolib/USBHID/usb.h create mode 100644 F0-nolib/USBHID/usb_defs.h create mode 100644 F0-nolib/USBHID/usb_lib.c create mode 100644 F0-nolib/USBHID/usb_lib.h create mode 100755 F0-nolib/USBHID/usbhid.bin diff --git a/F0-nolib/Readme.md b/F0-nolib/Readme.md index e09067a..46c2290 100644 --- a/F0-nolib/Readme.md +++ b/F0-nolib/Readme.md @@ -15,3 +15,4 @@ This directory contains examples for F0 without any library - uart_blink - code for STM32F030F4, echo data on USART1 and blink LEDS on PA4 and PA5 - uart_nucleo - USART over DMA for STM32F042-nucleo - usbcdc - CDC for STM32F042 (emulation of PL2303) with working CAN bus +- USBHID - USB HID keyboard + mouse (not working yet) diff --git a/F0-nolib/USBHID/Makefile b/F0-nolib/USBHID/Makefile new file mode 100644 index 0000000..b3a135a --- /dev/null +++ b/F0-nolib/USBHID/Makefile @@ -0,0 +1,149 @@ +BINARY = usbhid +BOOTPORT ?= /dev/ttyUSB0 +BOOTSPEED ?= 57600 +# MCU FAMILY +FAMILY = F0 +# MCU code +MCU = F042x6 +# hardware definitions +DEFS += -DUSARTNUM=1 +#DEFS += -DCHECK_TMOUT +DEFS += -DEBUG +# change this linking script depending on particular MCU model +LDSCRIPT = stm32f042k.ld + +INDEPENDENT_HEADERS= + +FP_FLAGS ?= -msoft-float +ASM_FLAGS = -mthumb -mcpu=cortex-m0 -march=armv6-m -mtune=cortex-m0 +ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS) + +############################################################################### +# Executables +OPREFIX ?= /opt/bin/arm-none-eabi +PREFIX ?= $(OPREFIX) + +RM := rm -f +RMDIR := rmdir +CC := $(PREFIX)-gcc +LD := $(PREFIX)-gcc +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +SIZE := $(PREFIX)-size +OBJCOPY := $(OPREFIX)-objcopy +OBJDUMP := $(OPREFIX)-objdump +GDB := $(OPREFIX)-gdb +STFLASH := $(shell which st-flash) +STBOOT := $(shell which stm32flash) +DFUUTIL := $(shell which dfu-util) + +############################################################################### +# Source files +OBJDIR = mk +LDSCRIPT ?= $(BINARY).ld +SRC := $(wildcard *.c) +OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o)) +STARTUP = $(OBJDIR)/startup.o +OBJS += $(STARTUP) +DEPS := $(OBJS:.o=.d) + +INC_DIR ?= ../inc + +INCLUDE := -I$(INC_DIR)/F0 -I$(INC_DIR)/cm +LIB_DIR := $(INC_DIR)/ld + +############################################################################### +# C flags +CFLAGS += -O2 -g -MD -D__thumb2__=1 +CFLAGS += -Wall -Werror -Wextra -Wshadow -Wimplicit-function-declaration +CFLAGS += -Wredundant-decls $(INCLUDE) +# -Wmissing-prototypes -Wstrict-prototypes +CFLAGS += -fno-common -ffunction-sections -fdata-sections +#CGLAGS += -fno-stack-protector + +############################################################################### +# Linker flags +LDFLAGS += --static -nostartfiles --specs=nano.specs +#LDFLAGS += -fno-stack-protector +LDFLAGS += -L$(LIB_DIR) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(OBJDIR)/$(BINARY).map +LDFLAGS += -Wl,--gc-sections + +############################################################################### +# Used libraries +LDLIBS += -Wl,--start-group -lc -lgcc -Wl,--end-group +LDLIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) + +#.SUFFIXES: .elf .bin .hex .srec .list .map .images +#.SECONDEXPANSION: +#.SECONDARY: + +ELF := $(OBJDIR)/$(BINARY).elf +LIST := $(OBJDIR)/$(BINARY).list +BIN := $(BINARY).bin +HEX := $(BINARY).hex + +all: bin list size + +elf: $(ELF) +bin: $(BIN) +hex: $(HEX) +list: $(LIST) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif + +$(OBJDIR): + mkdir $(OBJDIR) + +$(STARTUP): $(INC_DIR)/startup/vector.c + $(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $< + +$(OBJDIR)/%.o: %.c + @echo " CC $<" + $(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $< + +$(BIN): $(ELF) + @echo " OBJCOPY $(BIN)" + $(OBJCOPY) -Obinary $(ELF) $(BIN) + +$(HEX): $(ELF) + @echo " OBJCOPY $(HEX)" + $(OBJCOPY) -Oihex $(ELF) $(HEX) + +$(LIST): $(ELF) + @echo " OBJDUMP $(LIST)" + $(OBJDUMP) -S $(ELF) > $(LIST) + +$(ELF): $(OBJDIR) $(OBJS) + @echo " LD $(ELF)" + $(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(ELF) + +size: $(ELF) + $(SIZE) $(ELF) + +clean: + @echo " CLEAN" + $(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST) $(OBJDIR)/*.map *.d + @rmdir $(OBJDIR) 2>/dev/null || true + +dfuboot: $(BIN) + @echo " LOAD $(BIN) THROUGH DFU" + $(DFUUTIL) -a0 -D $(BIN) -s 0x08000000 + +flash: $(BIN) + @echo " FLASH $(BIN)" + $(STFLASH) write $(BIN) 0x8000000 + +boot: $(BIN) + @echo " LOAD $(BIN) through bootloader" + $(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN) + +gentags: + CFLAGS="$(CFLAGS) $(DEFS)" geany -g $(BINARY).c.tags *[hc] 2>/dev/null + +.PHONY: clean flash boot gentags diff --git a/F0-nolib/USBHID/Readme.md b/F0-nolib/USBHID/Readme.md new file mode 100644 index 0000000..ab97b8a --- /dev/null +++ b/F0-nolib/USBHID/Readme.md @@ -0,0 +1 @@ +USB HID mouse + keyboard diff --git a/F0-nolib/USBHID/hardware.c b/F0-nolib/USBHID/hardware.c new file mode 100644 index 0000000..56d8fa9 --- /dev/null +++ b/F0-nolib/USBHID/hardware.c @@ -0,0 +1,49 @@ +/* + * geany_encoding=koi8-r + * hardware.c - hardware-dependent macros & functions + * + * Copyright 2018 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include "hardware.h" +#include "usart.h" + +static uint8_t brdADDR = 0; + +void gpio_setup(void){ + // here we turn on clocking for all periph. + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_DMAEN; + // Set LEDS (PC13/14) as output + GPIOC->MODER = (GPIOC->MODER & ~(GPIO_MODER_MODER13 | GPIO_MODER_MODER14) + ) | + GPIO_MODER_MODER13_O | GPIO_MODER_MODER14_O; + // PB14(0), PB15(1), PA8(2) - board address, pullup inputs + GPIOA->PUPDR = (GPIOA->PUPDR & ~(GPIO_PUPDR_PUPDR8) + ) | + GPIO_PUPDR_PUPDR8_0; + GPIOB->PUPDR = (GPIOB->PUPDR & ~(GPIO_PUPDR_PUPDR14 | GPIO_PUPDR_PUPDR15) + ) | + GPIO_PUPDR_PUPDR14_0 | GPIO_PUPDR_PUPDR15_0; + pin_set(LED0_port, LED0_pin); // clear LEDs + pin_set(LED1_port, LED1_pin); + uint8_t addr = READ_BRD_INV_ADDR(); + brdADDR = ~addr & 0x7; +} + +uint8_t getBRDaddr(){return brdADDR;} diff --git a/F0-nolib/USBHID/hardware.h b/F0-nolib/USBHID/hardware.h new file mode 100644 index 0000000..a393821 --- /dev/null +++ b/F0-nolib/USBHID/hardware.h @@ -0,0 +1,67 @@ +/* + * geany_encoding=koi8-r + * hardware.h + * + * Copyright 2018 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#pragma once +#ifndef __HARDWARE_H__ +#define __HARDWARE_H__ + +#include "stm32f0.h" + +#define CONCAT(a,b) a ## b +#define STR_HELPER(s) #s +#define STR(s) STR_HELPER(s) + +#define FORMUSART(X) CONCAT(USART, X) +#define USARTX FORMUSART(USARTNUM) +#if USARTNUM == 2 + #define USARTDMA DMA1_Channel4 + #define DMAIRQn DMA1_Channel4_5_IRQn + #define USARTIRQn USART2_IRQn +#elif USARTNUM == 1 + #define USARTDMA DMA1_Channel2 + #define DMAIRQn DMA1_Channel2_3_IRQn + #define USARTIRQn USART1_IRQn +#else +#error "Wrong USARTNUM" +#endif + +// LEDS: 0 - PC13, 1 - PC14 +// LED0 +#define LED0_port GPIOC +#define LED0_pin (1<<13) +// LED1 +#define LED1_port GPIOC +#define LED1_pin (1<<14) + +#define LED_blink(x) pin_toggle(x ## _port, x ## _pin) +#define LED_on(x) pin_clear(x ## _port, x ## _pin) +#define LED_off(x) pin_set(x ## _port, x ## _pin) + + +// Board address - PB14(0), PB15(1), PA8(2) +#define READ_BRD_INV_ADDR() (((GPIOA->IDR & (1<<8))>>6)|((GPIOB->IDR & (3<<14))>>14)) + +void gpio_setup(void); + +uint8_t getBRDaddr(); + +#endif // __HARDWARE_H__ diff --git a/F0-nolib/USBHID/keycodes.c b/F0-nolib/USBHID/keycodes.c new file mode 100644 index 0000000..39b09b0 --- /dev/null +++ b/F0-nolib/USBHID/keycodes.c @@ -0,0 +1,74 @@ +/* + * keycodes.c + * + * Copyright 2015 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "keycodes.h" +/* + * Keyboard buffer: + * buf[1]: MOD + * buf[2]: reserved + * buf[3]..buf[8] - keycodes 1..6 + */ +static uint8_t buf[9] = {2,0,0,0,0,0,0,0,0}; + +#define _(x) (x|0x80) +// array for keycodes according to ASCII table; MSB is MOD_SHIFT flag +static const uint8_t keycodes[] = { + // space !"#$%&' + KEY_SPACE, _(KEY_1), _(KEY_QUOTE), _(KEY_3), _(KEY_4), _(KEY_5), _(KEY_7), KEY_QUOTE, + // ()*+,-./ + _(KEY_9), _(KEY_0), _(KEY_8), _(KEY_EQUAL), KEY_COMMA, KEY_MINUS, KEY_PERIOD, KEY_SLASH, + // 0..9 + 39, 30, 31, 32, 33, 34, 35, 36, 37, 38, + // :;<=>?@ + _(KEY_SEMICOLON), KEY_SEMICOLON, _(KEY_COMMA), KEY_EQUAL, _(KEY_PERIOD), _(KEY_SLASH), _(KEY_2), + // A..Z: for a in $(seq 0 25); do printf "$((a+132)),"; done + 132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157, + // [\]^_` + KEY_LEFT_BRACE, KEY_BACKSLASH, KEY_RIGHT_BRACE, _(KEY_6), _(KEY_MINUS), KEY_TILDE, + // a..z: for a in $(seq 0 25); do printf "$((a+4)),"; done + 4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29, + // {|}~ + _(KEY_LEFT_BRACE), _(KEY_BACKSLASH), _(KEY_RIGHT_BRACE), _(KEY_TILDE) +}; + +uint8_t *set_key_buf(uint8_t MOD, uint8_t KEY){ + buf[1] = MOD; + buf[3] = KEY; + return buf; +} + +/** + * return buffer for sending symbol "ltr" with addition modificator mod + */ +uint8_t *press_key_mod(char ltr, uint8_t mod){ + uint8_t MOD = 0; + uint8_t KEY = 0; + if(ltr > 31){ + KEY = keycodes[ltr - 32]; + if(KEY & 0x80){ + MOD = MOD_SHIFT; + KEY &= 0x7f; + } + }else if (ltr == '\n') KEY = KEY_ENTER; + buf[1] = MOD | mod; + buf[3] = KEY; + return buf; +} diff --git a/F0-nolib/USBHID/keycodes.h b/F0-nolib/USBHID/keycodes.h new file mode 100644 index 0000000..98a2fa1 --- /dev/null +++ b/F0-nolib/USBHID/keycodes.h @@ -0,0 +1,138 @@ +/* + * keycodes.h + * + * Copyright 2015 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __KEYKODES_H__ +#define __KEYKODES_H__ + +#include + +uint8_t *set_key_buf(uint8_t MOD, uint8_t KEY); +#define release_key() set_key_buf(0,0) +uint8_t *press_key_mod(char key, uint8_t mod); +#define press_key(k) press_key_mod(k, 0) + +#define MOD_CTRL 0x01 +#define MOD_SHIFT 0x02 +#define MOD_ALT 0x04 +#define MOD_GUI 0x08 + +#define LEFT(mod) (mod) +#define RIGHT(mod) ((mod << 4)) + +#define KEY_A 4 +#define KEY_B 5 +#define KEY_C 6 +#define KEY_D 7 +#define KEY_E 8 +#define KEY_F 9 +#define KEY_G 10 +#define KEY_H 11 +#define KEY_I 12 +#define KEY_J 13 +#define KEY_K 14 +#define KEY_L 15 +#define KEY_M 16 +#define KEY_N 17 +#define KEY_O 18 +#define KEY_P 19 +#define KEY_Q 20 +#define KEY_R 21 +#define KEY_S 22 +#define KEY_T 23 +#define KEY_U 24 +#define KEY_V 25 +#define KEY_W 26 +#define KEY_X 27 +#define KEY_Y 28 +#define KEY_Z 29 +#define KEY_1 30 +#define KEY_2 31 +#define KEY_3 32 +#define KEY_4 33 +#define KEY_5 34 +#define KEY_6 35 +#define KEY_7 36 +#define KEY_8 37 +#define KEY_9 38 +#define KEY_0 39 +#define KEY_ENTER 40 +#define KEY_ESC 41 +#define KEY_BACKSPACE 42 +#define KEY_TAB 43 +#define KEY_SPACE 44 +#define KEY_MINUS 45 +#define KEY_EQUAL 46 +#define KEY_LEFT_BRACE 47 +#define KEY_RIGHT_BRACE 48 +#define KEY_BACKSLASH 49 +#define KEY_NUMBER 50 +#define KEY_SEMICOLON 51 +#define KEY_QUOTE 52 +#define KEY_TILDE 53 +#define KEY_COMMA 54 +#define KEY_PERIOD 55 +#define KEY_SLASH 56 +#define KEY_CAPS_LOCK 57 +#define KEY_F1 58 +#define KEY_F2 59 +#define KEY_F3 60 +#define KEY_F4 61 +#define KEY_F5 62 +#define KEY_F6 63 +#define KEY_F7 64 +#define KEY_F8 65 +#define KEY_F9 66 +#define KEY_F10 67 +#define KEY_F11 68 +#define KEY_F12 69 +#define KEY_PRINTSCREEN 70 +#define KEY_SCROLL_LOCK 71 +#define KEY_PAUSE 72 +#define KEY_INSERT 73 +#define KEY_HOME 74 +#define KEY_PAGE_UP 75 +#define KEY_DELETE 76 +#define KEY_END 77 +#define KEY_PAGE_DOWN 78 +#define KEY_RIGHT 79 +#define KEY_LEFT 80 +#define KEY_DOWN 81 +#define KEY_UP 82 +#define KEY_NUM_LOCK 83 +#define KEYPAD_SLASH 84 +#define KEYPAD_ASTERIX 85 +#define KEYPAD_MINUS 86 +#define KEYPAD_PLUS 87 +#define KEYPAD_ENTER 88 +#define KEYPAD_1 89 +#define KEYPAD_2 90 +#define KEYPAD_3 91 +#define KEYPAD_4 92 +#define KEYPAD_5 93 +#define KEYPAD_6 94 +#define KEYPAD_7 95 +#define KEYPAD_8 96 +#define KEYPAD_9 97 +#define KEYPAD_0 98 +#define KEYPAD_PERIOD 99 + +#endif // __KEYKODES_H__ diff --git a/F0-nolib/USBHID/main.c b/F0-nolib/USBHID/main.c new file mode 100644 index 0000000..a3749bb --- /dev/null +++ b/F0-nolib/USBHID/main.c @@ -0,0 +1,162 @@ +/* + * main.c + * + * Copyright 2017 Edward V. Emelianoff + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include "hardware.h" +#include "keycodes.h" +#include "usart.h" +#include "usb.h" +#include "usb_lib.h" +#include // memcpy + +volatile uint32_t Tms = 0; + +/* Called when systick fires */ +void sys_tick_handler(void){ + ++Tms; +} + +void iwdg_setup(){ + uint32_t tmout = 16000000; + /* Enable the peripheral clock RTC */ + /* (1) Enable the LSI (40kHz) */ + /* (2) Wait while it is not ready */ + RCC->CSR |= RCC_CSR_LSION; /* (1) */ + while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} /* (2) */ + /* Configure IWDG */ + /* (1) Activate IWDG (not needed if done in option bytes) */ + /* (2) Enable write access to IWDG registers */ + /* (3) Set prescaler by 64 (1.6ms for each tick) */ + /* (4) Set reload value to have a rollover each 2s */ + /* (5) Check if flags are reset */ + /* (6) Refresh counter */ + IWDG->KR = IWDG_START; /* (1) */ + IWDG->KR = IWDG_WRITE_ACCESS; /* (2) */ + IWDG->PR = IWDG_PR_PR_1; /* (3) */ + IWDG->RLR = 1250; /* (4) */ + tmout = 16000000; + while(IWDG->SR){if(--tmout == 0) break;} /* (5) */ + IWDG->KR = IWDG_REFRESH; /* (6) */ +} + +void move_mouse(int8_t x, int8_t y){ + /* + * buf[0]: 1 - report ID + * buf[1]: bit2 - middle button, bit1 - right, bit0 - left + * buf[2]: move X + * buf[3]: move Y + * buf[4]: wheel + */ + int8_t buf[5] = {1,0,0,0,0}; + buf[2] = x; buf[3] = y; + USB_send((uint8_t*)buf, 5); +} + +/* + * Keyboard buffer: + * buf[1]: MOD + * buf[2]: reserved + * buf[3]..buf[8] - keycodes 1..6 + */ +void send_word(char *wrd){ + do{ + USB_send(press_key(*wrd), 9); + USB_send(release_key(), 9); + }while(*(++wrd)); +} + +int main(void){ + uint32_t lastT = 0; + int L = 0; + char *txt; + sysreset(); + SysTick_Config(6000, 1); + gpio_setup(); + usart_setup(); + + SEND("Hello!\n"); + + if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured + SEND("WDGRESET=1\n"); + } + if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured + SEND("SOFTRESET=1\n"); + } + RCC->CSR |= RCC_CSR_RMVF; // remove reset flags + + USB_setup(); + //iwdg_setup(); + + while (1){ + IWDG->KR = IWDG_REFRESH; // refresh watchdog + if(lastT > Tms || Tms - lastT > 499){ + LED_blink(LED0); + lastT = Tms; + transmit_tbuf(); // non-blocking transmission of data from UART buffer every 0.5s + } + usb_proc(); + if(usartrx()){ // usart1 received data, store in in buffer + L = usart_getline(&txt); + char _1st = txt[0]; + if(L == 2 && txt[1] == '\n'){ + L = 0; + switch(_1st){ + case 'C': + SEND("USB "); + if(!USB_configured()) SEND("dis"); + SEND("connected\n"); + break; + case 'K': + send_word("Hello!"); + SEND("Write hello\n"); + break; + case 'M': + move_mouse(100, 10); + SEND("Move mouse\n"); + break; + case 'R': + SEND("Soft reset\n"); + NVIC_SystemReset(); + break; + case 'W': + SEND("Wait for reboot\n"); + while(1){nop();}; + break; + default: // help + SEND( + "'C' - test if USB is configured\n" + "'K' - emulate keyboard\n" + "'M' - move mouse\n" + "'R' - software reset\n" + "'W' - test watchdog\n" + ); + break; + } + } + transmit_tbuf(); + } + if(L){ // echo all other data + txt[L] = 0; + usart_send(txt); + L = 0; + } + } + return 0; +} + diff --git a/F0-nolib/USBHID/usart.c b/F0-nolib/USBHID/usart.c new file mode 100644 index 0000000..e6f8df0 --- /dev/null +++ b/F0-nolib/USBHID/usart.c @@ -0,0 +1,254 @@ +/* + * usart.c + * + * Copyright 2017 Edward V. Emelianoff + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include "stm32f0.h" +#include "hardware.h" +#include "usart.h" +#include + +extern volatile uint32_t Tms; +static volatile int idatalen[2] = {0,0}; // received data line length (including '\n') +static volatile int odatalen[2] = {0,0}; + +volatile int linerdy = 0, // received data ready + dlen = 0, // length of data (including '\n') in current buffer + bufovr = 0, // input buffer overfull + txrdy = 1 // transmission done +; + + +int rbufno = 0, tbufno = 0; // current rbuf/tbuf numbers +static char rbuf[2][UARTBUFSZI], tbuf[2][UARTBUFSZO]; // receive & transmit buffers +static char *recvdata = NULL; + +/** + * return length of received data (without trailing zero + */ +int usart_getline(char **line){ + if(bufovr){ + bufovr = 0; + linerdy = 0; + return 0; + } + *line = recvdata; + linerdy = 0; + return dlen; +} + +// transmit current tbuf and swap buffers +void transmit_tbuf(){ + uint32_t tmout = 16000000; + while(!txrdy){if(--tmout == 0) break;}; // wait for previos buffer transmission + register int l = odatalen[tbufno]; + if(!l) return; + txrdy = 0; + odatalen[tbufno] = 0; + USARTDMA->CCR &= ~DMA_CCR_EN; + USARTDMA->CMAR = (uint32_t) tbuf[tbufno]; // mem + USARTDMA->CNDTR = l; + USARTDMA->CCR |= DMA_CCR_EN; + tbufno = !tbufno; +} + +void usart_putchar(const char ch){ + if(odatalen[tbufno] == UARTBUFSZO) transmit_tbuf(); + tbuf[tbufno][odatalen[tbufno]++] = ch; +} + +void usart_send(const char *str){ + uint32_t x = 512; + while(*str && --x){ + if(odatalen[tbufno] == UARTBUFSZO) transmit_tbuf(); + tbuf[tbufno][odatalen[tbufno]++] = *str++; + } +} + +void usart_sendn(const char *str, uint8_t L){ + for(uint8_t i = 0; i < L; ++i){ + if(odatalen[tbufno] == UARTBUFSZO) transmit_tbuf(); + tbuf[tbufno][odatalen[tbufno]++] = *str++; + } +} + +void newline(){ + usart_putchar('\n'); + transmit_tbuf(); +} + + +void usart_setup(){ + uint32_t tmout = 16000000; +// Nucleo's USART2 connected to VCP proxy of st-link +#if USARTNUM == 2 + // setup pins: PA2 (Tx - AF1), PA15 (Rx - AF1) + // AF mode (AF1) + GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER2|GPIO_MODER_MODER15))\ + | (GPIO_MODER_MODER2_AF | GPIO_MODER_MODER15_AF); + GPIOA->AFR[0] = (GPIOA->AFR[0] &~GPIO_AFRH_AFRH2) | 1 << (2 * 4); // PA2 + GPIOA->AFR[1] = (GPIOA->AFR[1] &~GPIO_AFRH_AFRH7) | 1 << (7 * 4); // PA15 + RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // clock +// USART1 of main board +#elif USARTNUM == 1 + // PA9 - Tx, PA10 - Rx (AF1) + GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10))\ + | (GPIO_MODER_MODER9_AF | GPIO_MODER_MODER10_AF); + GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2)) | + 1 << (1 * 4) | 1 << (2 * 4); // PA9, PA10 + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; +#else +#error "Wrong USARTNUM" +#endif + // USARTX Tx DMA + USARTDMA->CPAR = (uint32_t) &USARTX->TDR; // periph + USARTDMA->CMAR = (uint32_t) tbuf; // mem + USARTDMA->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq + // Tx CNDTR set @ each transmission due to data size + NVIC_SetPriority(DMAIRQn, 3); + NVIC_EnableIRQ(DMAIRQn); + NVIC_SetPriority(USARTIRQn, 0); + // setup usart1 + USARTX->BRR = 480000 / 1152; + USARTX->CR3 = USART_CR3_DMAT; // enable DMA Tx + USARTX->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART + while(!(USARTX->ISR & USART_ISR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission + USARTX->ICR |= USART_ICR_TCCF; // clear TC flag + USARTX->CR1 |= USART_CR1_RXNEIE; + NVIC_EnableIRQ(USARTIRQn); +} + +#if USARTNUM == 2 +void usart2_isr(){ +// USART1 +#elif USARTNUM == 1 +void usart1_isr(){ +#else +#error "Wrong USARTNUM" +#endif + #ifdef CHECK_TMOUT + static uint32_t tmout = 0; + #endif + if(USARTX->ISR & USART_ISR_RXNE){ // RX not emty - receive next char + #ifdef CHECK_TMOUT + if(tmout && Tms >= tmout){ // set overflow flag + bufovr = 1; + idatalen[rbufno] = 0; + } + tmout = Tms + TIMEOUT_MS; + if(!tmout) tmout = 1; // prevent 0 + #endif + // read RDR clears flag + uint8_t rb = USARTX->RDR; + if(idatalen[rbufno] < UARTBUFSZI){ // put next char into buf + rbuf[rbufno][idatalen[rbufno]++] = rb; + if(rb == '\n'){ // got newline - line ready + linerdy = 1; + dlen = idatalen[rbufno]; + recvdata = rbuf[rbufno]; + // prepare other buffer + rbufno = !rbufno; + idatalen[rbufno] = 0; + #ifdef CHECK_TMOUT + // clear timeout at line end + tmout = 0; + #endif + } + }else{ // buffer overrun + bufovr = 1; + idatalen[rbufno] = 0; + #ifdef CHECK_TMOUT + tmout = 0; + #endif + } + } +} + +// print 32bit unsigned int +void printu(uint32_t val){ + char bufa[11], bufb[10]; + int l = 0, bpos = 0; + if(!val){ + bufa[0] = '0'; + l = 1; + }else{ + while(val){ + bufb[l++] = val % 10 + '0'; + val /= 10; + } + int i; + bpos += l; + for(i = 0; i < l; ++i){ + bufa[--bpos] = bufb[i]; + } + } + bufa[l + bpos] = 0; + usart_send(bufa); +} + +// print 32bit unsigned int as hex +void printuhex(uint32_t val){ + usart_send("0x"); + uint8_t *ptr = (uint8_t*)&val + 3, start = 1; + int i, j; + for(i = 0; i < 4; ++i, --ptr){ + if(!*ptr && start) continue; + for(j = 1; j > -1; --j){ + start = 0; + register uint8_t half = (*ptr >> (4*j)) & 0x0f; + if(half < 10) usart_putchar(half + '0'); + else usart_putchar(half - 10 + 'a'); + } + } + if(start){ + usart_putchar('0'); + usart_putchar('0'); + } +} + +// dump memory buffer +void hexdump(uint8_t *arr, uint16_t len){ + for(uint16_t l = 0; l < len; ++l, ++arr){ + for(int16_t j = 1; j > -1; --j){ + register uint8_t half = (*arr >> (4*j)) & 0x0f; + if(half < 10) usart_putchar(half + '0'); + else usart_putchar(half - 10 + 'a'); + } + if(l % 16 == 15) usart_putchar('\n'); + else if(l & 1) usart_putchar(' '); + } +} + +#if USARTNUM == 2 +void dma1_channel4_5_isr(){ + if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx + DMA1->IFCR |= DMA_IFCR_CTCIF4; // clear TC flag + txrdy = 1; + } +} +// USART1 +#elif USARTNUM == 1 +void dma1_channel2_3_isr(){ + if(DMA1->ISR & DMA_ISR_TCIF2){ // Tx + DMA1->IFCR |= DMA_IFCR_CTCIF2; // clear TC flag + txrdy = 1; + } +} +#else +#error "Wrong USARTNUM" +#endif diff --git a/F0-nolib/USBHID/usart.h b/F0-nolib/USBHID/usart.h new file mode 100644 index 0000000..fc9c5ff --- /dev/null +++ b/F0-nolib/USBHID/usart.h @@ -0,0 +1,60 @@ +/* + * usart.h + * + * Copyright 2017 Edward V. Emelianoff + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once +#ifndef __USART_H__ +#define __USART_H__ + +#include "hardware.h" + +// input and output buffers size +#define UARTBUFSZI (32) +#define UARTBUFSZO (512) +// timeout between data bytes +#ifndef TIMEOUT_MS +#define TIMEOUT_MS (1500) +#endif + +// macro for static strings +#define SEND(str) usart_send(str) + +#ifdef EBUG +#define MSG(str) do{SEND(__FILE__ " (L" STR(__LINE__) "): " str);}while(0) +#else +#define MSG(str) +#endif + +#define usartrx() (linerdy) +#define usartovr() (bufovr) + +extern volatile int linerdy, bufovr, txrdy; + +void transmit_tbuf(); +void usart_setup(); +int usart_getline(char **line); +void usart_send(const char *str); +void usart_sendn(const char *str, uint8_t L); +void newline(); +void usart_putchar(const char ch); +void printu(uint32_t val); +void printuhex(uint32_t val); +void hexdump(uint8_t *arr, uint16_t len); + +#endif // __USART_H__ diff --git a/F0-nolib/USBHID/usb.c b/F0-nolib/USBHID/usb.c new file mode 100644 index 0000000..c89b808 --- /dev/null +++ b/F0-nolib/USBHID/usb.c @@ -0,0 +1,96 @@ +/* + * geany_encoding=koi8-r + * usb.c - base functions for different USB types + * + * Copyright 2018 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include "usb.h" +#include "usb_lib.h" +#include "usart.h" +#include // memcpy, memmove + +static int8_t usbON = 0; // ==1 when USB fully configured + +// interrupt IN handler (never used?) +static uint16_t EP1_Handler(ep_t ep){ + uint8_t epbuf[10]; + if (ep.rx_flag){ + MSG("EP1 OUT\n"); + EP_Read(1, epbuf); + ep.status = SET_VALID_TX(ep.status); + ep.status = KEEP_STAT_RX(ep.status); + }else if (ep.tx_flag){ + MSG("EP1 IN\n"); + ep.status = SET_VALID_RX(ep.status); + ep.status = SET_STALL_TX(ep.status); + } + return ep.status; +} + +void USB_setup(){ + RCC->APB1ENR |= RCC_APB1ENR_CRSEN | RCC_APB1ENR_USBEN; // enable CRS (hsi48 sync) & USB + RCC->CFGR3 &= ~RCC_CFGR3_USBSW; // reset USB + RCC->CR2 |= RCC_CR2_HSI48ON; // turn ON HSI48 + uint32_t tmout = 16000000; + while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break;} + FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY; + CRS->CFGR &= ~CRS_CFGR_SYNCSRC; + CRS->CFGR |= CRS_CFGR_SYNCSRC_1; // USB SOF selected as sync source + CRS->CR |= CRS_CR_AUTOTRIMEN; // enable auto trim + CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only + RCC->CFGR |= RCC_CFGR_SW; + // allow RESET and CTRM interrupts + USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM; + // clear flags + USB->ISTR = 0; + // and activate pullup + USB->BCDR |= USB_BCDR_DPPU; + NVIC_EnableIRQ(USB_IRQn); +} + +void usb_proc(){ + if(USB_GetState() == USB_CONFIGURE_STATE){ // USB configured - activate other endpoints + if(!usbON){ // endpoints not activated + SEND("Configure endpoints\n"); + EP_Init(1, EP_TYPE_INTERRUPT, 10, 10, EP1_Handler); // IN1 - transmit + usbON = 1; + } + }else{ + usbON = 0; + } +} + +void USB_send(uint8_t *buf, uint16_t size){ + uint16_t ctr = 0; + while(size){ + uint16_t s = (size > USB_TXBUFSZ) ? USB_TXBUFSZ : size; + EP_Write(1, (uint8_t*)&buf[ctr], s); + size -= s; + ctr += s; + } +} + +/** + * @brief USB_configured + * @return 1 if USB is in configured state + */ +int USB_configured(){ + return usbON; +} diff --git a/F0-nolib/USBHID/usb.h b/F0-nolib/USBHID/usb.h new file mode 100644 index 0000000..501058d --- /dev/null +++ b/F0-nolib/USBHID/usb.h @@ -0,0 +1,36 @@ +/* + * geany_encoding=koi8-r + * usb.h + * + * Copyright 2018 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#pragma once +#ifndef __USB_H__ +#define __USB_H__ + +#include "hardware.h" + +#define BUFFSIZE (64) + +void USB_setup(); +void usb_proc(); +void USB_send(uint8_t *buf, uint16_t size); +int USB_configured(); + +#endif // __USB_H__ diff --git a/F0-nolib/USBHID/usb_defs.h b/F0-nolib/USBHID/usb_defs.h new file mode 100644 index 0000000..ed8bb4b --- /dev/null +++ b/F0-nolib/USBHID/usb_defs.h @@ -0,0 +1,104 @@ +/* + * geany_encoding=koi8-r + * usb_defs.h + * + * Copyright 2018 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#pragma once +#ifndef __USB_DEFS_H__ +#define __USB_DEFS_H__ + +#include + +/** + * Buffers size definition + **/ +// !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! +#define USB_BTABLE_SIZE 1024 +// first 64 bytes of USB_BTABLE are registers! +#define USB_EP0_BASEADDR 64 +// for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303) +#define USB_EP0_BUFSZ 64 +// USB transmit buffer size +#define USB_TXBUFSZ 10 + +#define USB_BTABLE_BASE 0x40006000 +#undef USB_BTABLE +#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE)) +#define USB_ISTR_EPID 0x0000000F +#define USB_FNR_LSOF_0 0x00000800 +#define USB_FNR_lSOF_1 0x00001000 +#define USB_LPMCSR_BESL_0 0x00000010 +#define USB_LPMCSR_BESL_1 0x00000020 +#define USB_LPMCSR_BESL_2 0x00000040 +#define USB_LPMCSR_BESL_3 0x00000080 +#define USB_EPnR_CTR_RX 0x00008000 +#define USB_EPnR_DTOG_RX 0x00004000 +#define USB_EPnR_STAT_RX 0x00003000 +#define USB_EPnR_STAT_RX_0 0x00001000 +#define USB_EPnR_STAT_RX_1 0x00002000 +#define USB_EPnR_SETUP 0x00000800 +#define USB_EPnR_EP_TYPE 0x00000600 +#define USB_EPnR_EP_TYPE_0 0x00000200 +#define USB_EPnR_EP_TYPE_1 0x00000400 +#define USB_EPnR_EP_KIND 0x00000100 +#define USB_EPnR_CTR_TX 0x00000080 +#define USB_EPnR_DTOG_TX 0x00000040 +#define USB_EPnR_STAT_TX 0x00000030 +#define USB_EPnR_STAT_TX_0 0x00000010 +#define USB_EPnR_STAT_TX_1 0x00000020 +#define USB_EPnR_EA 0x0000000F +#define USB_COUNTn_RX_BLSIZE 0x00008000 +#define USB_COUNTn_NUM_BLOCK 0x00007C00 +#define USB_COUNTn_RX 0x0000003F + +#define USB_TypeDef USB_TypeDef_custom + +typedef struct{ + __IO uint32_t EPnR[8]; + __IO uint32_t RESERVED1; + __IO uint32_t RESERVED2; + __IO uint32_t RESERVED3; + __IO uint32_t RESERVED4; + __IO uint32_t RESERVED5; + __IO uint32_t RESERVED6; + __IO uint32_t RESERVED7; + __IO uint32_t RESERVED8; + __IO uint32_t CNTR; + __IO uint32_t ISTR; + __IO uint32_t FNR; + __IO uint32_t DADDR; + __IO uint32_t BTABLE; + __IO uint32_t LPMCSR; + __IO uint32_t BCDR; +} USB_TypeDef; + +typedef struct{ + __IO uint16_t USB_ADDR_TX; + __IO uint16_t USB_COUNT_TX; + __IO uint16_t USB_ADDR_RX; + __IO uint16_t USB_COUNT_RX; +} USB_EPDATA_TypeDef; + +typedef struct{ + __IO USB_EPDATA_TypeDef EP[8]; +} USB_BtableDef; + +#endif // __USB_DEFS_H__ diff --git a/F0-nolib/USBHID/usb_lib.c b/F0-nolib/USBHID/usb_lib.c new file mode 100644 index 0000000..a4f431b --- /dev/null +++ b/F0-nolib/USBHID/usb_lib.c @@ -0,0 +1,588 @@ +/* + * geany_encoding=koi8-r + * usb_lib.c + * + * Copyright 2018 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include +#include "usb_lib.h" +#include // memcpy +#include "usart.h" + +ep_t endpoints[ENDPOINTS_NUM]; + +//static uint8_t set_featuring; +static usb_dev_t USB_Dev; +static usb_LineCoding lineCoding = {115200, 0, 0, 8}; +static config_pack_t setup_packet; +static uint8_t ep0databuf[EP0DATABUF_SIZE]; +static uint8_t ep0dbuflen = 0; + +usb_LineCoding getLineCoding(){return lineCoding;} + +// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor +#define bcdUSB_L 0x00 +#define bcdUSB_H 0x02 +#define bDeviceClass 0 +#define bDeviceSubClass 0 +#define bDeviceProtocol 0 +#define bNumConfigurations 1 + +static const uint8_t USB_DeviceDescriptor[] = { + 18, // bLength + 0x01, // bDescriptorType - Device descriptor + bcdUSB_L, // bcdUSB_L - 2.00 + bcdUSB_H, // bcdUSB_H + bDeviceClass, // bDeviceClass - USB_COMM + bDeviceSubClass, // bDeviceSubClass + bDeviceProtocol, // bDeviceProtocol + USB_EP0_BUFSZ, // bMaxPacketSize0 + 0x5e, // idVendor: Microsoft + 0x04, // idVendor_H + 0x5c, // idProduct: Office Keyboard (106/109) + 0x00, // idProduct_H + 0x00, // bcdDevice_Ver_L + 0x02, // bcdDevice_Ver_H + 0x01, // iManufacturer + 0x02, // iProduct + 0x03, // iSerialNumber + bNumConfigurations // bNumConfigurations +}; + +static const uint8_t USB_DeviceQualifierDescriptor[] = { + 10, //bLength + 0x06, // bDescriptorType - Device qualifier + bcdUSB_L, // bcdUSB_L + bcdUSB_H, // bcdUSB_H + bDeviceClass, // bDeviceClass + bDeviceSubClass, // bDeviceSubClass + bDeviceProtocol, // bDeviceProtocol + USB_EP0_BUFSZ, // bMaxPacketSize0 + bNumConfigurations, // bNumConfigurations + 0x00 // Reserved +}; +#if 0 +static const uint8_t HID_ReportDescriptor[] = { + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xA1, 0x00, /* Collection (Physical) */ + 0x85, 0x01, /* Report ID */ + 0x05, 0x09, /* Usage Page (Buttons) */ + 0x19, 0x01, /* Usage Minimum (01) */ + 0x29, 0x03, /* Usage Maximum (03) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (0) */ + 0x95, 0x03, /* Report Count (3) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input (Constant) ;5 bit padding */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x15, 0x81, /* Logical Minimum (-127) */ + 0x25, 0x7F, /* Logical Maximum (127) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0xC0, 0xC0,/* End Collection,End Collection */ +// + 0x09, 0x06, /* Usage (Keyboard) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x02, /* Report ID */ + 0x05, 0x07, /* Usage (Key codes) */ + 0x19, 0xE0, /* Usage Minimum (224) */ + 0x29, 0xE7, /* Usage Maximum (231) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x08, /* Report Count (8) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x08, /* Report Size (8) */ + 0x81, 0x01, /* Input (Constant) ;5 bit padding */ + 0x95, 0x05, /* Report Count (5) */ + 0x75, 0x01, /* Report Size (1) */ + 0x05, 0x08, /* Usage Page (Page# for LEDs) */ + 0x19, 0x01, /* Usage Minimum (01) */ + 0x29, 0x05, /* Usage Maximum (05) */ + 0x91, 0x02, /* Output (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x03, /* Report Size (3) */ + 0x91, 0x01, /* Output (Constant) */ + 0x95, 0x06, /* Report Count (1) */ + 0x75, 0x08, /* Report Size (3) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x65, /* Logical Maximum (101) */ + 0x05, 0x07, /* Usage (Key codes) */ + 0x19, 0x00, /* Usage Minimum (00) */ + 0x29, 0x65, /* Usage Maximum (101) */ + 0x81, 0x00, /* Input (Data, Array) */ + 0xC0 /* End Collection,End Collection */ +}; +#endif + +const uint8_t HID_ReportDescriptor[] = { + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x06, /* Usage (Keyboard) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x05, 0x07, /* Usage (Key codes) */ + 0x19, 0xE0, /* Usage Minimum (224) */ + 0x29, 0xE7, /* Usage Maximum (231) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x08, /* Report Count (8) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x08, /* Report Size (8) */ + 0x81, 0x01, /* Input (Constant) ;5 bit padding */ + 0x95, 0x05, /* Report Count (5) */ + 0x75, 0x01, /* Report Size (1) */ + 0x05, 0x08, /* Usage Page (Page# for LEDs) */ + 0x19, 0x01, /* Usage Minimum (01) */ + 0x29, 0x05, /* Usage Maximum (05) */ + 0x91, 0x02, /* Output (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x03, /* Report Size (3) */ + 0x91, 0x01, /* Output (Constant) */ + 0x95, 0x06, /* Report Count (1) */ + 0x75, 0x08, /* Report Size (3) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x65, /* Logical Maximum (101) */ + 0x05, 0x07, /* Usage (Key codes) */ + 0x19, 0x00, /* Usage Minimum (00) */ + 0x29, 0x65, /* Usage Maximum (101) */ + 0x81, 0x00, /* Input (Data, Array) */ + 0x09, 0x05, /* Usage (Vendor Defined) */ + 0x15, 0x00, /* Logical Minimum (0)) */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255)) */ + 0x75, 0x08, /* Report Count (2)) */ + 0x95, 0x02, /* Report Size (8 bit)) */ + 0xB1, 0x02, /* Feature (Data, Variable, Absolute) */ + 0xC0 /* End Collection,End Collection */ + +}; + +static const uint8_t USB_ConfigDescriptor[] = { + /*Configuration Descriptor*/ + 0x09, /* bLength: Configuration Descriptor size */ + 0x02, /* bDescriptorType: Configuration */ + 34, /* wTotalLength */ + 0x00, + 0x01, /* bNumInterfaces: 1 interface */ + 0x01, /* bConfigurationValue: Configuration value */ + 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ + 0xa0, /* bmAttributes - Bus powered */ + 0x32, /* MaxPower 100 mA */ + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: Interface */ + 0x00, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: 1 endpoint used */ + 0x03, /* bInterfaceClass: USB_CLASS_HID */ + 0x01, /* bInterfaceSubClass: boot */ + 0x01, /* bInterfaceProtocol: keyboard */ + 0x00, /* iInterface: */ + /* HID device descriptor */ + 0x09, /* bLength: HID Device Descriptor size */ + 0x21, /* bDescriptorType: HID */ + 0x10, /* bcdHID: 1.10 */ + 0x01, /* bcdHIDH */ + 0x00, /* bCountryCode: Not supported */ + 0x01, /* bNumDescriptors: 1 */ + 0x22, /* bDescriptorType: Report */ + sizeof(HID_ReportDescriptor), /* wDescriptorLength */ + 0x00, /* wDescriptorLengthH */ + /*Endpoint 1 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ + 0x81, /* bEndpointAddress IN1 */ + 0x03, /* bmAttributes: Interrupt */ + USB_TXBUFSZ, /* wMaxPacketSize LO: */ + 0x00, /* wMaxPacketSize HI: */ + 0x01, /* bInterval: */ +}; + +_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US); +// these descriptors are not used in PL2303 emulator! +_USB_STRING_(USB_StringSerialDescriptor, u"0"); +_USB_STRING_(USB_StringManufacturingDescriptor, u"SAO RAS"); +_USB_STRING_(USB_StringProdDescriptor, u"HID mouse+keyboard"); + +#ifdef EBUG + uint8_t _2wr = 0; + #define WRITEDUMP(str) do{MSG(str); _2wr = 1;}while(0) +#else + #define WRITEDUMP(str) +#endif +static void wr0(const uint8_t *buf, uint16_t size){ + if(setup_packet.wLength < size) size = setup_packet.wLength; + EP_WriteIRQ(0, buf, size); +} + +static inline void get_descriptor(){ + switch(setup_packet.wValue){ + case DEVICE_DESCRIPTOR: + WRITEDUMP("DEVICE_DESCRIPTOR"); + wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor)); + break; + case CONFIGURATION_DESCRIPTOR: + WRITEDUMP("CONFIGURATION_DESCRIPTOR"); + wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor)); + break; + case STRING_LANG_DESCRIPTOR: + WRITEDUMP("STRING_LANG_DESCRIPTOR"); + wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE); + break; + case STRING_MAN_DESCRIPTOR: + WRITEDUMP("STRING_MAN_DESCRIPTOR"); + wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength); + break; + case STRING_PROD_DESCRIPTOR: + WRITEDUMP("STRING_PROD_DESCRIPTOR"); + wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength); + break; + case STRING_SN_DESCRIPTOR: + WRITEDUMP("STRING_SN_DESCRIPTOR"); + wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength); + break; + case DEVICE_QUALIFIER_DESCRIPTOR: + WRITEDUMP("DEVICE_QUALIFIER_DESCRIPTOR"); + wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); + break; + default: + WRITEDUMP("UNK_DES"); + break; + } +} + +static uint8_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured) +static inline void std_d2h_req(){ + uint16_t status = 0; // bus powered + switch(setup_packet.bRequest){ + case GET_DESCRIPTOR: + get_descriptor(); + break; + case GET_STATUS: + WRITEDUMP("GET_STATUS"); + EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered + break; + case GET_CONFIGURATION: + WRITEDUMP("GET_CONFIGURATION"); + EP_WriteIRQ(0, &configuration, 1); + break; + default: + WRITEDUMP("80:WR_REQ"); + break; + } +} + +static inline void std_h2d_req(){ + switch(setup_packet.bRequest){ + case SET_ADDRESS: + WRITEDUMP("SET_ADDRESS"); + // new address will be assigned later - after acknowlegement or request to host + USB_Dev.USB_Addr = setup_packet.wValue; + break; + case SET_CONFIGURATION: + WRITEDUMP("SET_CONFIGURATION"); + // Now device configured + USB_Dev.USB_Status = USB_CONFIGURE_STATE; + configuration = setup_packet.wValue; + break; + default: + WRITEDUMP("0:WR_REQ"); + break; + } +} + +/* +bmRequestType: 76543210 +7 direction: 0 - host->device, 1 - device->host +65 type: 0 - standard, 1 - class, 2 - vendor +4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other +*/ +/** + * Endpoint0 (control) handler + * @param ep - endpoint state + * @return data written to EP0R + */ +static uint16_t EP0_Handler(ep_t ep){ + uint16_t epstatus = ep.status; // EP0R on input -> return this value after modifications + uint8_t reqtype = setup_packet.bmRequestType & 0x7f; + uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0; + if ((ep.rx_flag) && (ep.setup_flag)){ + switch(reqtype){ + case STANDARD_DEVICE_REQUEST_TYPE: // standard device request + if(dev2host){ + std_d2h_req(); + }else{ + std_h2d_req(); + // send ZLP + EP_WriteIRQ(0, (uint8_t *)0, 0); + } + epstatus = SET_NAK_RX(epstatus); + epstatus = SET_VALID_TX(epstatus); + break; + case STANDARD_INTERFACE_REQUEST_TYPE: + WRITEDUMP("IFACE "); + if(dev2host && setup_packet.bRequest == GET_DESCRIPTOR){ + if(setup_packet.wValue == HID_REPORT_DESCRIPTOR){ + WRITEDUMP("HID_REPORT"); + wr0(HID_ReportDescriptor, sizeof(HID_ReportDescriptor)); + } + } + epstatus = SET_NAK_RX(epstatus); + epstatus = SET_VALID_TX(epstatus); + break; + case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request + if (setup_packet.bRequest == CLEAR_FEATURE){ + //WRITEDUMP("CLEAR_FEATURE"); + // send ZLP + EP_WriteIRQ(0, (uint8_t *)0, 0); + epstatus = SET_NAK_RX(epstatus); + epstatus = SET_VALID_TX(epstatus); + }else{ + WRITEDUMP("02:WR_REQ"); + } + break; + case CONTROL_REQUEST_TYPE: + if (setup_packet.bRequest == SET_IDLE_REQUEST){ + EP_WriteIRQ(0, (uint8_t *)0, 0); + epstatus = SET_NAK_RX(epstatus); + epstatus = SET_VALID_TX(epstatus); + WRITEDUMP("SET_IDLE_REQUEST"); + } else if (setup_packet.bRequest == SET_FEAUTRE){ + WRITEDUMP("SET_FEAUTRE"); + //set_featuring = 1; + epstatus = SET_VALID_RX(epstatus); + epstatus = KEEP_STAT_TX(epstatus); + } + break; + default: + WRITEDUMP("Bad request"); + EP_WriteIRQ(0, (uint8_t *)0, 0); + epstatus = SET_NAK_RX(epstatus); + epstatus = SET_VALID_TX(epstatus); + } + }else if (ep.rx_flag){ // got data over EP0 or host acknowlegement + /*if (set_featuring){ + set_featuring = 0; + // here we can do something with ep.rx_buf - set_feature + }*/ + // Close transaction + hexdump(ep.rx_buf, ep.rx_cnt); + epstatus = CLEAR_DTOG_RX(epstatus); + epstatus = CLEAR_DTOG_TX(epstatus); + // wait for new data from host + epstatus = SET_VALID_RX(epstatus); + epstatus = SET_STALL_TX(epstatus); + } else if (ep.tx_flag){ // package transmitted + // now we can change address after enumeration + if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){ + USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; + // change state to ADRESSED + USB_Dev.USB_Status = USB_ADRESSED_STATE; + } + // end of transaction + epstatus = CLEAR_DTOG_RX(epstatus); + epstatus = CLEAR_DTOG_TX(epstatus); + epstatus = SET_VALID_RX(epstatus); + epstatus = SET_VALID_TX(epstatus); + } +#ifdef EBUG + if(_2wr){ + usart_putchar(' '); + if (ep.rx_flag) usart_putchar('r'); + else usart_putchar('t'); + printu(setup_packet.wLength); + if(ep.setup_flag) usart_putchar('s'); + usart_putchar(' '); + usart_putchar('I'); + printu(setup_packet.wIndex); + usart_putchar('V'); + printu(setup_packet.wValue); + usart_putchar('R'); + printu(setup_packet.bRequest); + usart_putchar('T'); + printu(setup_packet.bmRequestType); + usart_putchar(' '); + usart_putchar('0' + ep0dbuflen); + usart_putchar(' '); + hexdump(ep0databuf, ep0dbuflen); + usart_putchar('\n'); + _2wr = 0; + } +#endif + return epstatus; +} +#undef WRITEDUMP + +static uint16_t lastaddr = USB_EP0_BASEADDR; +/** + * Endpoint initialisation + * !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! + * @param number - EP num (0...7) + * @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT) + * @param txsz - transmission buffer size @ USB/CAN buffer + * @param rxsz - reception buffer size @ USB/CAN buffer + * @param uint16_t (*func)(ep_t *ep) - EP handler function + * @return 0 if all OK + */ +int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)){ + if(number >= ENDPOINTS_NUM) return 4; // out of configured amount + if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large + if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable + USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); + USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1; + if(rxsz & 1 || rxsz > 992) return 3; // wrong rx buffer size + uint16_t countrx = 0; + if(rxsz < 64) countrx = rxsz / 2; + else{ + if(rxsz & 0x1f) return 3; // should be multiple of 32 + countrx = 31 + rxsz / 32; + } + USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr; + endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr); + endpoints[number].txbufsz = txsz; + lastaddr += txsz; + USB_BTABLE->EP[number].USB_COUNT_TX = 0; + USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr; + endpoints[number].rx_buf = (uint8_t *)(USB_BTABLE_BASE + lastaddr); + lastaddr += rxsz; + // buffer size: Table127 of RM + USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10; + endpoints[number].func = func; + return 0; +} + +// standard IRQ handler +void usb_isr(){ + if (USB->ISTR & USB_ISTR_RESET){ + // Reinit registers + USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM; + USB->ISTR = 0; + // Endpoint 0 - CONTROL + // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! + lastaddr = USB_EP0_BASEADDR; // roll back to beginning of buffer + EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler); + // clear address, leave only enable bit + USB->DADDR = USB_DADDR_EF; + // state is default - wait for enumeration + USB_Dev.USB_Status = USB_DEFAULT_STATE; + } + if(USB->ISTR & USB_ISTR_CTR){ + // EP number + uint8_t n = USB->ISTR & USB_ISTR_EPID; + // copy status register + uint16_t epstatus = USB->EPnR[n]; + // Calculate flags + endpoints[n].rx_flag = (epstatus & USB_EPnR_CTR_RX) ? 1 : 0; + endpoints[n].setup_flag = (epstatus & USB_EPnR_SETUP) ? 1 : 0; + endpoints[n].tx_flag = (epstatus & USB_EPnR_CTR_TX) ? 1 : 0; + // copy received bytes amount + endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter + // check direction + if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit) + if(n == 0){ // control endpoint + if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack + memcpy(&setup_packet, endpoints[0].rx_buf, sizeof(setup_packet)); + ep0dbuflen = 0; + // interrupt handler will be called later + }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf + ep0dbuflen = endpoints[0].rx_cnt; + memcpy(ep0databuf, endpoints[0].rx_buf, ep0dbuflen); + } + } + }else{ // IN interrupt - transmit data, only CTR_TX == 1 + // enumeration end could be here (if EP0) + } + // prepare status field for EP handler + endpoints[n].status = epstatus; + // call EP handler (even if it will change EPnR, it should return new status) + epstatus = endpoints[n].func(endpoints[n]); + // keep DTOG state + epstatus = KEEP_DTOG_TX(epstatus); + epstatus = KEEP_DTOG_RX(epstatus); + // clear all RX/TX flags + epstatus = CLEAR_CTR_RX(epstatus); + epstatus = CLEAR_CTR_TX(epstatus); + // refresh EPnR + USB->EPnR[n] = epstatus; + } +} + +/** + * Write data to EP buffer (called from IRQ handler) + * @param number - EP number + * @param *buf - array with data + * @param size - its size + */ +void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){ + uint8_t i; + if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz; + uint16_t N2 = (size + 1) >> 1; + // the buffer is 16-bit, so we should copy data as it would be uint16_t + uint16_t *buf16 = (uint16_t *)buf; + for (i = 0; i < N2; i++){ + endpoints[number].tx_buf[i] = buf16[i]; + } + USB_BTABLE->EP[number].USB_COUNT_TX = size; +} + +/** + * Write data to EP buffer (called outside IRQ handler) + * @param number - EP number + * @param *buf - array with data + * @param size - its size + */ +void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ + uint16_t status = USB->EPnR[number]; + EP_WriteIRQ(number, buf, size); + status = SET_NAK_RX(status); + status = SET_VALID_TX(status); + status = KEEP_DTOG_TX(status); + status = KEEP_DTOG_RX(status); + USB->EPnR[number] = status; +} + +/* + * Copy data from EP buffer into user buffer area + * @param *buf - user array for data + * @return amount of data read + */ +int EP_Read(uint8_t number, uint8_t *buf){ + int n = endpoints[number].rx_cnt; + if(n){ + for(int i = 0; i < n; ++i) + buf[i] = endpoints[number].rx_buf[i]; + } + return n; +} + +// USB status +uint8_t USB_GetState(){ + return USB_Dev.USB_Status; +} diff --git a/F0-nolib/USBHID/usb_lib.h b/F0-nolib/USBHID/usb_lib.h new file mode 100644 index 0000000..2ea9cba --- /dev/null +++ b/F0-nolib/USBHID/usb_lib.h @@ -0,0 +1,208 @@ +/* + * geany_encoding=koi8-r + * usb_lib.h + * + * Copyright 2018 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#pragma once +#ifndef __USB_LIB_H__ +#define __USB_LIB_H__ + +#include +#include "usb_defs.h" + +#define EP0DATABUF_SIZE (64) + +// Max EP amount (EP0 + other used) +#define ENDPOINTS_NUM 2 +// bmRequestType & 0x7f +#define STANDARD_DEVICE_REQUEST_TYPE 0 +#define STANDARD_INTERFACE_REQUEST_TYPE 1 +#define STANDARD_ENDPOINT_REQUEST_TYPE 2 +#define VENDOR_REQUEST_TYPE 0x40 +#define CONTROL_REQUEST_TYPE 0x21 +// bRequest, standard; for bmRequestType == 0x80 +#define GET_STATUS 0x00 +#define GET_DESCRIPTOR 0x06 +#define GET_CONFIGURATION 0x08 +#define SET_FEAUTRE 0x09 +#define SET_IDLE_REQUEST 0x0a + +// for bmRequestType == 0 +#define CLEAR_FEATURE 0x01 +#define SET_FEATURE 0x03 // unused +#define SET_ADDRESS 0x05 +#define SET_DESCRIPTOR 0x07 // unused +#define SET_CONFIGURATION 0x09 +// for bmRequestType == 0x81, 1 or 0xB2 +#define GET_INTERFACE 0x0A // unused +#define SET_INTERFACE 0x0B // unused +#define SYNC_FRAME 0x0C // unused +#define VENDOR_REQUEST 0x01 // unused + +// Class-Specific Control Requests +#define SEND_ENCAPSULATED_COMMAND 0x00 // unused +#define GET_ENCAPSULATED_RESPONSE 0x01 // unused +#define SET_COMM_FEATURE 0x02 // unused +#define GET_COMM_FEATURE 0x03 // unused +#define CLEAR_COMM_FEATURE 0x04 // unused +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +// control line states +#define CONTROL_DTR 0x01 +#define CONTROL_RTS 0x02 + +// wValue +#define DEVICE_DESCRIPTOR 0x100 +#define CONFIGURATION_DESCRIPTOR 0x200 +#define STRING_LANG_DESCRIPTOR 0x300 +#define STRING_MAN_DESCRIPTOR 0x301 +#define STRING_PROD_DESCRIPTOR 0x302 +#define STRING_SN_DESCRIPTOR 0x303 +#define DEVICE_QUALIFIER_DESCRIPTOR 0x600 +#define HID_REPORT_DESCRIPTOR 0x2200 + +// EPnR bits manipulation +#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX)) +#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R +#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX) +#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX)) +#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX)) +#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R +#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX) +#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX)) +#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX)) +#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX)) +#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX)) +#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX)) +#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX)) +#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX)) +#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX)) +#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX)) +#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX)) +#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX)) +#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX))) + +// USB state: uninitialized, addressed, ready for use +#define USB_DEFAULT_STATE 0 +#define USB_ADRESSED_STATE 1 +#define USB_CONFIGURE_STATE 2 + +// EP types +#define EP_TYPE_BULK 0x00 +#define EP_TYPE_CONTROL 0x01 +#define EP_TYPE_ISO 0x02 +#define EP_TYPE_INTERRUPT 0x03 + +#define LANG_US (uint16_t)0x0409 + +#define _USB_STRING_(name, str) \ +static const struct name \ +{ \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint16_t bString[(sizeof(str) - 2) / 2]; \ + \ +} \ +name = {sizeof(name), 0x03, str} + +#define _USB_LANG_ID_(name, lng_id) \ + \ +static const struct name \ +{ \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint16_t bString; \ + \ +} \ +name = {0x04, 0x03, lng_id} +#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4) + +// EP0 configuration packet +typedef struct { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} config_pack_t; + +// endpoints state +typedef struct __ep_t{ + uint16_t *tx_buf; // transmission buffer address + uint16_t txbufsz; // transmission buffer size + uint8_t *rx_buf; // reception buffer address + uint16_t (*func)(); // endpoint action function + uint16_t status; // status flags + unsigned rx_cnt : 10; // received data counter + unsigned tx_flag : 1; // transmission flag + unsigned rx_flag : 1; // reception flag + unsigned setup_flag : 1; // this is setup packet (only for EP0) +} ep_t; + +// USB status & its address +typedef struct { + uint8_t USB_Status; + uint16_t USB_Addr; +}usb_dev_t; + +typedef struct { + uint32_t dwDTERate; + uint8_t bCharFormat; + #define USB_CDC_1_STOP_BITS 0 + #define USB_CDC_1_5_STOP_BITS 1 + #define USB_CDC_2_STOP_BITS 2 + uint8_t bParityType; + #define USB_CDC_NO_PARITY 0 + #define USB_CDC_ODD_PARITY 1 + #define USB_CDC_EVEN_PARITY 2 + #define USB_CDC_MARK_PARITY 3 + #define USB_CDC_SPACE_PARITY 4 + uint8_t bDataBits; +} __attribute__ ((packed)) usb_LineCoding; + +typedef struct { + uint8_t bmRequestType; + uint8_t bNotificationType; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} __attribute__ ((packed)) usb_cdc_notification; + +extern ep_t endpoints[]; + +void USB_Init(); +uint8_t USB_GetState(); +int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)); +void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); +void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size); +int EP_Read(uint8_t number, uint8_t *buf); +usb_LineCoding getLineCoding(); + + +void WEAK linecoding_handler(usb_LineCoding *lc); +void WEAK clstate_handler(uint16_t val); +void WEAK break_handler(); +void WEAK vendor_handler(config_pack_t *packet); + +#endif // __USB_LIB_H__ diff --git a/F0-nolib/USBHID/usbhid.bin b/F0-nolib/USBHID/usbhid.bin new file mode 100755 index 0000000000000000000000000000000000000000..9acc3b897f623d58cc48ce2f99ab342f8e4f337e GIT binary patch literal 6564 zcma(#3v?6Lm3Kyx^|8USgo7jtJkt0Ff*>$|C(T%6k1dU{jckIkNs+NlWN@&Gp>cL| zibzRfFloRFt+7Z;Ql}+AvW^mU(=Iel*!JXvw2?40fYUwdDT}t74b|CZYvbSSeX=2e zrXQX2=H2)1=iPVTz4zTGFaWb&2dZ`0oY>%R{0Pl$G=Zb^G!NnXdu_o#K=b!xysN!? zopouTGPsQ5`c`c?m9J@>>oPd?-ouQMJHa+6QhB{+P;uTn$9W>h$obg@I+fQs&wDO- zuPd^sEH%qt@c7vv6=?Lc!}yi8YFdw}<*ZJg%Jrn{d8M_6Q@Zp%?K#lW90juhcV8|^ z(s@amkU$RQa{!qA1KRNZ0d*kdaLQ@r5mk@*;P8_s<=jgRO2s7xIhG>7*12-<*y&DeeiF>Uy%0Z2?u(gpGeSW`ul zj~+k^vZ{*TKMc0fs1o=2^psN6SRo*@Xjrn}k0vOV_5F7|6D4|auf-IoM#D--o3D*P zUancQ2(D^!Ukf#7{nWS+DCTuze+UvgCw~%xMSqNro&$yw4G;Uu2tV!8d#OTwQcnYp zwP86xCs-iy-lWw4TYkubk$H&HTx}-n$q3bf(^OZTnOFwXLQdPm=j2u=aWCcO2yFo1SoK zmu4V;r?Vcvq>)oNK~6!Y;mLUzy>2;K!*A`88@(BhiHOWn?`^3-ZltF0Z0bE})+Vo> zQ`yF&gO+WsN5x0WYdo^;>Xa-xOOwjWwgMaQ$Z*fnNaqwJv{N3m@z7+`_8`FJ-k4i# z*glNV_hNpw%GDrWza4V%oVQ9NA5U!*H&*ls8^yZHV?v$SD_}e*f`TYG1e1sLo^~jP zKDV-7X<0*7z>#{jUie09s$9>ZuGB$Z&%fE2>xD$+q%+CcR};+e@WVwWeJ%ie2C+-%$0yPM zh!27tV*_)?sZ#)coaZt@wH%uq#uR4kbFfj+tkGgWig-Epwb(vE_`k3L!oG02m|l6U z>#Z)m`DF)OWzBt|gV?8XAcq@c_4fU^M(|p-k|HQv<5Qs?+Ktnx5Z2X+CIRZJfbY6|pJvFYQpyy}XzGMfoqB zzie}L6>V$2{8aQfX27q`jIWCQp=p`Fi7*(ou8CJF7svMI z_g5BnUQ-_tvN>uAMEAx3zdw)B`0bBbmOLDJ5l_rLaSZjLScjnZf%TYJ?;o_XA%9K} zW#am&TJF0pJ!j_aY=3AoM`W8PY|6^ZyAYZ?k?6uWn*21S@)E(MPdM?LHZg#+iphr& zPMPo_EKRr(h6!IM=I)7FgvZA12>)qy0ykTIyE+kJ|9!#_gk^H+g6Njj)&sJHdS%L{o(kw%H7z%KTfoJcjD8Ofy*5@ z9vnXt--c4JjX#2%**;MK+kr?&XNv8aXcxPyD@gS@AmWdI9ckVl=LL&pb9uH;8u`r> zkEbT5{b^V3y%D!YfE~)R2kQx?hBPqCt zw__^&24i4zM;y57bK|S-oWuihg{>%}wk?c2SiUI!AY#8YzT^&eZF~*R>>0P+nHj_z zdNXHdkMoP-U@Z`rmEU`gIbYJ{7HkqATIsz7*H^Z-T)%ZWTf%hNYb!Lnu=^X&Oodgvy zB)+@`j8%*;a#tV1aRs&y=VAq1;L_5;{d2$y5a!FCA87Nl##J`Ed*(M_n$pT;)b z(PkrRvuS>J@o?xEMtMp^>#cRwbk6O}qKkN$-z{$PAGy)dwcZtQ6h$mo=(WeSeG>b1zO32D>DQJ(|RxyRitd|2#HNl+R!nB(cvVv9I6AM{L_zrf8kP<|MI?C$T?B zp4=m2v&Fm_?EECwo5UWzVMgA{v6MTKjY;gLBzE78MQCqwcEsl749MA0GJwQ=)Ag1N z;X#D2<2jXJ|2g*WV=j(hZ@_T^`~Si58SL9|EH{Fx7yCunC&IrG1ffb;STPvR>v~yu z!T6tsGeW_-Go}0|`Bmw;X9Wf4q!;i{!P= zLY7hQZxVnB(!tOLzbg2t$DGW^FAIrtS5ssW8T02j&3qou&Oa+`QXeY$D2{%OHjr@7 z#J?HzYhn*#8&cCz1+%XBbFRb74&{{}Iuuvr$KeHO8W z!|B6t0KQ>R1U`7OM)(LW;^p~0@NZa+*jyKO zzaV@HO(nx!K}Fvz@nBFB#H!dOh)?ltCWkTtixp8^O|kq^1LnvD!_7unupd?!ZBN-+ z*B|c3^EVs%;Q?cRSFZU5y!kWDr$UDXYMEPmGz1GZ zkt{q+w2JMTym`T=MSN|zsWhU$ZUg@0BGRva&QuW$aamMZLZ-1$Q<}*Ey(2p4| zdulxy-laTN?~a;cnTOO+pLfn{8TFR_QC(gZ}Su0+m)CM>!!R&rs&T*hLyA&jthEGzphtk z68t57psV@`%!<8QCz?-JHwjE<13hl2t8GG_vgw^RuYl_xX=gj z_)G>hok{-97zkoG;FIn(8vRL933uUaI}pUs^7L$#Vee>o`V7>ooP%5%xZ3 z16=S}ilm}$Pe)OzM}Oya`a!D}U#Fa9wrJXp{9A9oLj6{ys8f(vCV6J3C$P5G(s zT)}E8X>0Pv#90Y&OwQvzF%iDj+LNNYoLQ0SV!Xja`{22{U?_XB=9BN#l~H@l&sA&J z4TnB6p5CCryEB2=YL;m50NY(X8mID7#rd8Cb*ZA!lPb>h@Q%7-U>T1ezFqx?I9Y?d za!+7;3mfsR+kQoSEP-#!X9u7_9ksJmuI!}D2Q0rq8p)KD1Br8xN5$^PzX^5-d(2dk z#=^iBBP1TVWna3+$AAW3q|s6JqR*~Sme!I(!VW=p@+srC5@RP-nBk+=zUjCX{TOp{ zB22Nr6chmAbby@nyj}qo+!wXSHrl0;^HW$~a_R!pRWdp|RR}DXZZk!Afpu7;)bjoi zwc^JPQ^eMpm2oAcwq5_kj&vtyxUOFzqnBp5t|PsM=?_UGy;FqidQ^_tFL91xq><;R zuEZIuLNt0c4n<@W{%=t4p{%q>&I#~rNK8zjt|Z2D#9XW$(k>c-T6@XVucDS)UH$Ni zf%<@Y_mpEinq|yJy!s+osI?bOJt}Hh5A+%6^8v?1)L3B>k0XvMnwRyOidyj+EH z>@7Qkd~+%?|0+%zv5wBJNdHRwE659|ANjB5Fy;|ZO!ox7w*jjSW37z;1$?;q-!Y?& z#*x#?tGXS#hh*w*$Ce?PrrS|6Bunjf6b#AIx*fBIB&(X%{fxl$kWQzjTOtH&9DgT=z?s}cDR~OHt zR>(mmIg)U966TYzn1qSu$dQE4<6e*+lJrTqI|-9LQbS@AE;hkMN^loz@jRtC6~?+K zkupk?{I_5v^3AxfjGXhHj;;4MF$EQcD;BI}N~@PLRU2wGXs+Ay%k4As&Pp;3eEZIA zt&i^6)xxywZ1%Oc?%dsxoWCi@dKmA&zt$o%_@93T-N~<*`##QN9y>e?#zJv7UahOep=oMju_#kJ0= z$}f}NL%SMjYiixj%CapL#rXM>(0kWjx$Fztb;WlHy-UZHE5D$tc2|}BEt#vxerDFM zxl82TdafdSn%VdI4aF5s!CC6QTku^vtRnl`P$?3Ud-t(sDdNgXYq!+Y7T0bd=)2ci zLmZ#r@3P@NG;5G%wSDbI_ZD~Q`nzz2_Em^O=iE|UQi6_o@A`#HlXm=@@(Y&|{qKms zTmA~d?-YvpQs!RW3s(@`%bg{tRdtoS_Al^Bd)t?NrQS)K5xt!y6{Tcb8%k?X!k6t@ zxH@@WNF$UMZ@{p-$99FQ$=)4}&FIqK*n?q$cm<_Sd5Kaejj;vzKX5L!hdQd-M<1p3 zsP<7u6?>>bq*2pWpeQ)8OpVnbB|}hc(NaKJEud8FlW72J932HTl5$^{Z^o;MqGdRz zNtvEQ5acqoTq~=AVyMEz=ElAT@?_=Ugc2M-2JNs1I-mvr#M*)1CtxeiG{P=uPV(Ae z(f8jv@zTrv%YXFaS6*Mac-89s`Pq!c%I4(ey;=B^`~UUrAMAhnnPy+;^To ze55Dv!qM-3ulHDA@c4^MmfC;#+6uWMMX6G2QqyM5PSbt`*7UxVA;!2$&-%qi0-*WPj%+`%FY0k?$dhSWKA28|d@ zb{D}E!3Z9WbFES066YkQ>8SC+a7IF6MznP!uxv(rV53HDe64`)`rr9TG`?=~<$s+2 zaqgf0jI9`3<^U&%wIv|bAj^@%vprp481UO?=;O9u4~>BTV)p-t`S%)S*ktyf8;zR} zpV-@Vib@+Q>uaKr+UPp#d?9r8q_3g4@;EigYdN2?7uv$Uma0g_+6QD`%eZCXSl+iE z4ut&YRt4sr+a^S*v;Og9AAJjA&RfEB>UYv=O`&!T$d0i2Mpz&^$6U{HZzR`ik7(hR z5v?HhPz#8rs?w}LMqv6d&ntv2d~WP%Y2!=zfPaJQa`|6 z<9%cyo8W7SWw6||ove!ki29ql4$UB!p&kqZ=SC*r#;tr7rnV2taF?XP$_#pohki z98;(#8KXq%rA@SELoxZ*HCa5m=Tmq|Sxuj&o9I`z3OPXHRHc&Qs60ZSSHg5N{nWZd z-a!M3X+a-GdX=$VRrMp#M_a=a(b!eyxP5eg%ogJ$Wwd)8RXW@u9O@!-2Ai3KV@(tS zRTJO2xZZfAw|iS8w{0Tghv(RP1yx-RmH2>xC`t->iqOb)|i_yA7}x2)vB3SAl}Y_V9e5(UmU4WbE!Cem#(1?!)@W}h=x|F zS6&R`vJ^}9P*UCGcqRz}Te{4oa^x)AW7#fP)&VJTruVbYEDI~#5KNU6?Muw8jb-I; zixRVoY0W>MEfYLlu6nQRQbk2ex;s7Rohm23PjhqXascawqi?JL1 z1jK$r$Gvf+;z>_Y)Rb^r9PC43{v09U7&5;|M1AT$Jt#HH1PgqZWnSycWHB4DR?tP4 zi&dK+81Dng2(wNXu9qe7gAbnM&?eI$!ILuDJX)82CX&=SksYQlV%P6+)4Bx^G8T4) z?fS0n=~t4lXqe_xuxMVoasyQ2lV3_QBIJjBs<&+kJQ^yS6dU|d3rjta+wv1E zEuRFbTJx%&-4JkP_WI|lC7iqMLKZ4N$reKSAF(%J?B^eR zslDw^p?zEXM7ur}XP0fRnhf62n2@m%#&nD+8JjWlx-VT1L~Y0bA1^r^Q8FBVFK*jYtU6}iY(7d_Q=Z#f93vBFUV zf*>C=qyTjT0{{usubc})9ny%jAst8|=JcRUAcv5HNECSv>A^D*d14L-5ky0p5ffZ8 zpGJQ@>c>zHBmHxrRES_wKk^_tqR8=bc31I2`*G~;B1$i_mt0*GxENes+bM$0 z2f1hSY-7o1TTkL`DzTX%{|=BGsooG|97Cs@Pd1Y3eAbbQhPd$q&YloI3XBVQvz(Z4hK4>70Ef9x-318CRn=;*lH bXM-)_H5*rNTHScvavN-Fpo6pKuH}9Kn?)UK delta 2286 zcma)-e{2)?6~N#5{NrqF>|lqU?Zi3zLIN>P-TW8?$T)n?H$R*vj6|@KY9!=NtN~|j$D(zRZ1S82fto-%p=z`pv00)K5l~oL%vRdE+e*R;@t$e6 zYVEep(ns(6zVChC_q})Td{d836&Zj9?k6jNIga!pJsH*@q!n2DrPt-lJ~gHtzKrkw zA3py(h6yjp`1gx+%AWHb!5d@;sUUTvuy$^ARp-x0qdCEj5oi5aMg6Qkzgnge%Ea%( z7+GDv$6Mwv3v?1f@~Za>W&Rn}x~T>GQRwm%U){xQcG5F5%EI_Abgr;zD#Xbl49Z%+cJYv2JploFqdeIWFVor8xCG>4+?h4n)M2^*De+AxwFy-X@eR_zh6nM(qp z(LrL$5(;2O$UPbDCREWjLthjMmc^{BsU{3BN}_6)_AnS&RZR$1u!dvOX;mKI5oyOc zQAzTlrbF^>MUS%AqS`Pme>fju9Ty8Z?9%%xYtUMoC0Ko&7>Zijt#f9djJw39=3h;L z!`W$NogtIY(%vFBPp2ox6m#=jGz$z4xzH%|i*j)=I>Ch~ztFxkN=>S}({6r1{A*%B zyq!=jP2Ah@d93vnEG;#eN}Z*EJDXl#NToVfMhv4J5w$cBRbry)VP-HPxL;G10>oGeA@Bj2inI49vonYJ{juo zKL8&31k`ENZatuQzWo}8IER@WzzMv>0Hb51E9$QX_br}@!rBkx3*!?cIeH`lYjR?% z>L9nY6I`-52XrJk?(k)`u7w|XOtbcS2b6)!3dtw#gDZ0u_~KBu&w3D?=6HvL^{tRu zTHi@P?jI9cSotqs5qx6q-Ruck`_Dn#P!su1Hp63{b^Je|zNw85?<5 zvxcJbB)!%}ZI;Tl_3EbAHT;Lwkw>Nc*^@uNmH?+){SNcg(9X$`tP1M$%CqMnt(*I+d|*`MG=U z$I99{(AXjAx+i^*aVzM>Y)bI5wERybM_(r}sxR=&=s+QAfrekIw!|~RQ0`Lyg1D$* z(&2@Y zKiDcSz7@34h4-$~ynNFjLzN7IMR1wb=Iu5p!2cy4=6HCcxjF04jW2la#pU?5NRBHY zZB61Ex80_II|&EeO(aJ8mWz+TuF}W3$#~1J+ttIh#w|` zpH)@3RMjw62oEe3$h63 zAEtXA(>;fS4Gxj%@*Ma*JyL4?0~LH-2h4fo4Dw^-GO}$sFl}Fg@L%i&xX*shwjA}U e-ED3A>>AkNt=v}8P|;ZamEP[number].USB_ADDR_TX = lastaddr; - endpoints[number].tx_sz = txsz; endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr); lastaddr += txsz; USB_BTABLE->EP[number].USB_COUNT_TX = 0; diff --git a/F0-nolib/pl2303/usb_lib.h b/F0-nolib/pl2303/usb_lib.h index 642e91e..0651e5f 100644 --- a/F0-nolib/pl2303/usb_lib.h +++ b/F0-nolib/pl2303/usb_lib.h @@ -1,203 +1,202 @@ -/* - * geany_encoding=koi8-r - * usb_lib.h - * - * Copyright 2018 Edward V. Emelianov - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#pragma once -#ifndef __USB_LIB_H__ -#define __USB_LIB_H__ - -#include -#include "usb_defs.h" - -#define EP0DATABUF_SIZE (64) - -// Max EP amount (EP0 + other used) -#define ENDPOINTS_NUM 4 -// bmRequestType & 0x7f -#define STANDARD_DEVICE_REQUEST_TYPE 0 -#define STANDARD_ENDPOINT_REQUEST_TYPE 2 -#define VENDOR_REQUEST_TYPE 0x40 -#define CONTROL_REQUEST_TYPE 0x21 -// bRequest, standard; for bmRequestType == 0x80 -#define GET_STATUS 0x00 -#define GET_DESCRIPTOR 0x06 -#define GET_CONFIGURATION 0x08 -// for bmRequestType == 0 -#define CLEAR_FEATURE 0x01 -#define SET_FEATURE 0x03 // unused -#define SET_ADDRESS 0x05 -#define SET_DESCRIPTOR 0x07 // unused -#define SET_CONFIGURATION 0x09 -// for bmRequestType == 0x81, 1 or 0xB2 -#define GET_INTERFACE 0x0A // unused -#define SET_INTERFACE 0x0B // unused -#define SYNC_FRAME 0x0C // unused -#define VENDOR_REQUEST 0x01 // unused - -// Class-Specific Control Requests -#define SEND_ENCAPSULATED_COMMAND 0x00 // unused -#define GET_ENCAPSULATED_RESPONSE 0x01 // unused -#define SET_COMM_FEATURE 0x02 // unused -#define GET_COMM_FEATURE 0x03 // unused -#define CLEAR_COMM_FEATURE 0x04 // unused -#define SET_LINE_CODING 0x20 -#define GET_LINE_CODING 0x21 -#define SET_CONTROL_LINE_STATE 0x22 -#define SEND_BREAK 0x23 - -// control line states -#define CONTROL_DTR 0x01 -#define CONTROL_RTS 0x02 - -// wValue -#define DEVICE_DESCRIPTOR 0x100 -#define CONFIGURATION_DESCRIPTOR 0x200 -#define STRING_LANG_DESCRIPTOR 0x300 -#define STRING_MAN_DESCRIPTOR 0x301 -#define STRING_PROD_DESCRIPTOR 0x302 -#define STRING_SN_DESCRIPTOR 0x303 -#define DEVICE_QUALIFIER_DESCRIPTOR 0x600 - -// EPnR bits manipulation -#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX)) -#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R -#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX) -#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX)) -#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX)) -#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R -#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX) -#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX)) -#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX)) -#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX)) -#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX)) -#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX)) -#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX)) -#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX)) -#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX)) -#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX)) -#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX)) -#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX)) -#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX))) - -// USB state: uninitialized, addressed, ready for use -#define USB_DEFAULT_STATE 0 -#define USB_ADRESSED_STATE 1 -#define USB_CONFIGURE_STATE 2 - -// EP types -#define EP_TYPE_BULK 0x00 -#define EP_TYPE_CONTROL 0x01 -#define EP_TYPE_ISO 0x02 -#define EP_TYPE_INTERRUPT 0x03 - -#define LANG_US (uint16_t)0x0409 - -#define _USB_STRING_(name, str) \ -static const struct name \ -{ \ - uint8_t bLength; \ - uint8_t bDescriptorType; \ - uint16_t bString[(sizeof(str) - 2) / 2]; \ - \ -} \ -name = {sizeof(name), 0x03, str} - -#define _USB_LANG_ID_(name, lng_id) \ - \ -static const struct name \ -{ \ - uint8_t bLength; \ - uint8_t bDescriptorType; \ - uint16_t bString; \ - \ -} \ -name = {0x04, 0x03, lng_id} -#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4) - -// EP0 configuration packet -typedef struct { - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; -} config_pack_t; - -// endpoints state -typedef struct __ep_t{ - uint16_t *tx_buf; // transmission buffer address - uint8_t *rx_buf; // reception buffer address - uint16_t (*func)(); // endpoint action function - uint16_t status; // status flags - unsigned tx_sz : 10; // Tx buffer size - unsigned rx_cnt : 10; // received data counter - unsigned tx_flag : 1; // transmission flag - unsigned rx_flag : 1; // reception flag - unsigned setup_flag : 1; // this is setup packet (only for EP0) -} ep_t; - -// USB status & its address -typedef struct { - uint8_t USB_Status; - uint16_t USB_Addr; -}usb_dev_t; - -typedef struct { - uint32_t dwDTERate; - uint8_t bCharFormat; - #define USB_CDC_1_STOP_BITS 0 - #define USB_CDC_1_5_STOP_BITS 1 - #define USB_CDC_2_STOP_BITS 2 - uint8_t bParityType; - #define USB_CDC_NO_PARITY 0 - #define USB_CDC_ODD_PARITY 1 - #define USB_CDC_EVEN_PARITY 2 - #define USB_CDC_MARK_PARITY 3 - #define USB_CDC_SPACE_PARITY 4 - uint8_t bDataBits; -} __attribute__ ((packed)) usb_LineCoding; - -typedef struct { - uint8_t bmRequestType; - uint8_t bNotificationType; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; -} __attribute__ ((packed)) usb_cdc_notification; - -extern ep_t endpoints[]; - -void USB_Init(); -uint8_t USB_GetState(); -int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)); -void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); -void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size); -int EP_Read(uint8_t number, uint8_t *buf); -usb_LineCoding getLineCoding(); - - -void WEAK linecoding_handler(usb_LineCoding *lc); -void WEAK clstate_handler(uint16_t val); -void WEAK break_handler(); -void WEAK vendor_handler(config_pack_t *packet); - -#endif // __USB_LIB_H__ +/* + * geany_encoding=koi8-r + * usb_lib.h + * + * Copyright 2018 Edward V. Emelianov + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#pragma once +#ifndef __USB_LIB_H__ +#define __USB_LIB_H__ + +#include +#include "usb_defs.h" + +#define EP0DATABUF_SIZE (64) + +// Max EP amount (EP0 + other used) +#define ENDPOINTS_NUM 4 +// bmRequestType & 0x7f +#define STANDARD_DEVICE_REQUEST_TYPE 0 +#define STANDARD_ENDPOINT_REQUEST_TYPE 2 +#define VENDOR_REQUEST_TYPE 0x40 +#define CONTROL_REQUEST_TYPE 0x21 +// bRequest, standard; for bmRequestType == 0x80 +#define GET_STATUS 0x00 +#define GET_DESCRIPTOR 0x06 +#define GET_CONFIGURATION 0x08 +// for bmRequestType == 0 +#define CLEAR_FEATURE 0x01 +#define SET_FEATURE 0x03 // unused +#define SET_ADDRESS 0x05 +#define SET_DESCRIPTOR 0x07 // unused +#define SET_CONFIGURATION 0x09 +// for bmRequestType == 0x81, 1 or 0xB2 +#define GET_INTERFACE 0x0A // unused +#define SET_INTERFACE 0x0B // unused +#define SYNC_FRAME 0x0C // unused +#define VENDOR_REQUEST 0x01 // unused + +// Class-Specific Control Requests +#define SEND_ENCAPSULATED_COMMAND 0x00 // unused +#define GET_ENCAPSULATED_RESPONSE 0x01 // unused +#define SET_COMM_FEATURE 0x02 // unused +#define GET_COMM_FEATURE 0x03 // unused +#define CLEAR_COMM_FEATURE 0x04 // unused +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +// control line states +#define CONTROL_DTR 0x01 +#define CONTROL_RTS 0x02 + +// wValue +#define DEVICE_DESCRIPTOR 0x100 +#define CONFIGURATION_DESCRIPTOR 0x200 +#define STRING_LANG_DESCRIPTOR 0x300 +#define STRING_MAN_DESCRIPTOR 0x301 +#define STRING_PROD_DESCRIPTOR 0x302 +#define STRING_SN_DESCRIPTOR 0x303 +#define DEVICE_QUALIFIER_DESCRIPTOR 0x600 + +// EPnR bits manipulation +#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX)) +#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R +#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX) +#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX)) +#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX)) +#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R +#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX) +#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX)) +#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX)) +#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX)) +#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX)) +#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX)) +#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX)) +#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX)) +#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX)) +#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX)) +#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX)) +#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX)) +#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX))) + +// USB state: uninitialized, addressed, ready for use +#define USB_DEFAULT_STATE 0 +#define USB_ADRESSED_STATE 1 +#define USB_CONFIGURE_STATE 2 + +// EP types +#define EP_TYPE_BULK 0x00 +#define EP_TYPE_CONTROL 0x01 +#define EP_TYPE_ISO 0x02 +#define EP_TYPE_INTERRUPT 0x03 + +#define LANG_US (uint16_t)0x0409 + +#define _USB_STRING_(name, str) \ +static const struct name \ +{ \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint16_t bString[(sizeof(str) - 2) / 2]; \ + \ +} \ +name = {sizeof(name), 0x03, str} + +#define _USB_LANG_ID_(name, lng_id) \ + \ +static const struct name \ +{ \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint16_t bString; \ + \ +} \ +name = {0x04, 0x03, lng_id} +#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4) + +// EP0 configuration packet +typedef struct { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} config_pack_t; + +// endpoints state +typedef struct __ep_t{ + uint16_t *tx_buf; // transmission buffer address + uint8_t *rx_buf; // reception buffer address + uint16_t (*func)(); // endpoint action function + uint16_t status; // status flags + unsigned rx_cnt : 10; // received data counter + unsigned tx_flag : 1; // transmission flag + unsigned rx_flag : 1; // reception flag + unsigned setup_flag : 1; // this is setup packet (only for EP0) +} ep_t; + +// USB status & its address +typedef struct { + uint8_t USB_Status; + uint16_t USB_Addr; +}usb_dev_t; + +typedef struct { + uint32_t dwDTERate; + uint8_t bCharFormat; + #define USB_CDC_1_STOP_BITS 0 + #define USB_CDC_1_5_STOP_BITS 1 + #define USB_CDC_2_STOP_BITS 2 + uint8_t bParityType; + #define USB_CDC_NO_PARITY 0 + #define USB_CDC_ODD_PARITY 1 + #define USB_CDC_EVEN_PARITY 2 + #define USB_CDC_MARK_PARITY 3 + #define USB_CDC_SPACE_PARITY 4 + uint8_t bDataBits; +} __attribute__ ((packed)) usb_LineCoding; + +typedef struct { + uint8_t bmRequestType; + uint8_t bNotificationType; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} __attribute__ ((packed)) usb_cdc_notification; + +extern ep_t endpoints[]; + +void USB_Init(); +uint8_t USB_GetState(); +int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)); +void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); +void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size); +int EP_Read(uint8_t number, uint8_t *buf); +usb_LineCoding getLineCoding(); + + +void WEAK linecoding_handler(usb_LineCoding *lc); +void WEAK clstate_handler(uint16_t val); +void WEAK break_handler(); +void WEAK vendor_handler(config_pack_t *packet); + +#endif // __USB_LIB_H__