diff --git a/.gitignore b/.gitignore
index 63ffbd5..66aead2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,6 @@ picolibc/*
# Build artifacts
obj/*
host_aprom.bin
+
+# Flashing tool
+flashtool/*
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 8236676..a71f8c4 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -2,6 +2,7 @@
"recommendations": [
"aaron-bond.better-comments",
"marus25.cortex-debug",
- "llvm-vs-code-extensions.vscode-clangd"
+ "llvm-vs-code-extensions.vscode-clangd",
+ "aaron-bond.better-comments"
]
}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 845cb15..8a870d4 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -6,13 +6,70 @@
"-I${workspaceFolder}/NUC123/inc",
"-I${workspaceFolder}/NUC123/StdDriver/inc",
"-D__GNUC__",
- "-D__XSTRING(x)=", // Workaround for string.h
+ "-D__XSTRING(x)=", // Workaround for string.h
"-Wno-pointer-to-int-cast",
- "-Wno-int-to-pointer-cast",
+ "-Wno-int-to-pointer-cast"
],
- "cortex-debug.variableUseNaturalFormat": true,
+ "cortex-debug.variableUseNaturalFormat": false,
"cortex-debug.liveWatchRefreshRate": 1000,
"cortex-debug.enableTelemetry": false,
"files.trimFinalNewlines": true,
"editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd",
+
+ "better-comments.tags": [
+ {
+ "tag": "===",
+ "color": "#00F5FF",
+ "strikethrough": false,
+ "underline": false,
+ "backgroundColor": "#00F5FF11",
+ "bold": false,
+ "italic": false
+ },
+ {
+ "tag": "!",
+ "color": "#FF2D00",
+ "strikethrough": false,
+ "underline": false,
+ "backgroundColor": "transparent",
+ "bold": false,
+ "italic": false
+ },
+ {
+ "tag": "?",
+ "color": "#3498DB",
+ "strikethrough": false,
+ "underline": false,
+ "backgroundColor": "transparent",
+ "bold": false,
+ "italic": false
+ },
+ {
+ "tag": "//",
+ "color": "#474747",
+ "strikethrough": true,
+ "underline": false,
+ "backgroundColor": "transparent",
+ "bold": false,
+ "italic": false
+ },
+ {
+ "tag": "todo",
+ "color": "#FF8C00",
+ "strikethrough": false,
+ "underline": false,
+ "backgroundColor": "transparent",
+ "bold": false,
+ "italic": false
+ },
+ {
+ "tag": "*",
+ "color": "#98C379",
+ "strikethrough": false,
+ "underline": false,
+ "backgroundColor": "transparent",
+ "bold": false,
+ "italic": false
+ }
+ ]
}
diff --git a/Development.md b/Development.md
deleted file mode 100644
index 48273c6..0000000
--- a/Development.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Development
-## Requirements
-- Windows (Strongly recommend. Compiling on anything else is not officially supported.)
-- [Make for Windows](https://gnuwin32.sourceforge.net/packages/make.htm)
- - On the path, please
-- [Arm GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) (Currently using 13.2 Rel1)
- - To make your life easier, ensure this is located at `C:\Program Files (x86)\GNU Arm Embedded Toolchain\13.2 Rel1`
-- [picolibc 1.8.6](https://github.com/picolibc/picolibc/releases/download/1.8.6/picolibc-1.8.6-13.2.Rel1.zip)
- - Place the contents of this zip file in `picolibc`
-
-VSCode is recommended for development, and all recommended extensions should be installed.
-
-## Compiling and Uploading
-Run `make -j` to compile the firmware.
-
-For rapid development, the HID bootloader is quite annoying. `flash.cmd` is provided which reprograms the chip using an ST-Link V2. This requires an OpenOCD installation in the root project folder, along with an existing compiled host bootloader binary.
-
-For debugging in VSCode, install the recommended extensions then hit F5. This requires an OpenOCD installation in the root project folder, and an ST-Link V2.
-
-## NUC123 BSP
-The `NUC123` folder is a heavily reduced form of the complete BSP provided by Nuvoton. Modifications should not be made to any files within the `inc` or `StdDriver` folder.
-
-`startup_NUC123.s` is the program entrypoint, and may require modification.
-
-`NUC123.ld` is a modified version of the GCC linker script provided by Nuvoton, and may require modification.
-
-To pull in additional BSP drivers, if required, the `Makefile` should be modified.
diff --git a/GCC.mk b/GCC.mk
index 0dcb3b8..d9b3b95 100644
--- a/GCC.mk
+++ b/GCC.mk
@@ -16,6 +16,6 @@ OPTIM ?= -flto -Os
GCCFLAGS := $(SPECS) -nolibc -nostdlib -nostartfiles -nodefaultlibs -mcpu=cortex-m0 -mthumb -Wl,--gc-sections $(OPTIM) -g
CFLAGS := $(GCCFLAGS) -c -ffunction-sections -fdata-sections -fsigned-char \
- -fmessage-length=0 -ffreestanding
+ -fmessage-length=0 -ffreestanding -fstack-usage -Wall
ASFLAGS := $(GCCFLAGS) -c -x assembler-with-cpp
LDFLAGS := $(GCCFLAGS) -Lpicolibc/arm-none-eabi/picolibc/arm-none-eabi/lib/thumb/v6-m/nofp
diff --git a/Makefile b/Makefile
index 77a4bdd..0f469de 100644
--- a/Makefile
+++ b/Makefile
@@ -3,12 +3,9 @@ OBJ_DIR := obj
BINARY_NAME := host_aprom
OPTIM := -O0
-# OPTIM := -Ofast -flto
# OPTIM := -Os -flto
include GCC.mk
LIBRARY_MODULES := clk uart timer i2c
include NUC123/NUC123.mk
-CFLAGS += -Wno-gnu-variable-sized-type-not-at-end
-
include generic.mk
diff --git a/NUC123/NUC123.ld b/NUC123/NUC123.ld
index 5c3ca27..5fa8485 100644
--- a/NUC123/NUC123.ld
+++ b/NUC123/NUC123.ld
@@ -1,6 +1,5 @@
/* Linker script to configure memory regions. */
-MEMORY
-{
+MEMORY {
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x10000 /* 64k */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x5000 /* 20k */
}
@@ -8,127 +7,45 @@ MEMORY
/* Library configurations */
GROUP(libgcc.a libc.a libm.a libnosys.a)
-/* Linker script to place sections and symbol values. Should be used together
- * with other linker script that defines memory regions FLASH and RAM.
- * It references following symbols, which must be defined in code:
- * Reset_Handler : Entry of reset handler
- *
- * It defines following symbols, which code can use without definition:
- * __exidx_start
- * __exidx_end
- * __copy_table_start__
- * __copy_table_end__
- * __zero_table_start__
- * __zero_table_end__
+/**
+ * Used for loading .data into memory:
* __etext
* __data_start__
- * __preinit_array_start
- * __preinit_array_end
- * __init_array_start
- * __init_array_end
- * __fini_array_start
- * __fini_array_end
* __data_end__
+ * Used for zeroing .bss:
* __bss_start__
* __bss_end__
- * __end__
- * end
- * __HeapLimit
- * __StackLimit
- * __StackTop
- * __stack
- * __Vectors_End
- * __Vectors_Size
+ * Used for stack setup:
+ * __StackLimit
+ * __StackTop
+ * Used for heap setup:
+ * __HeapBase
+ * __HeapLimit
*/
ENTRY(Reset_Handler)
-SECTIONS
-{
- .text :
- {
+SECTIONS {
+ .text : {
KEEP(*(.vectors))
- __Vectors_End = .;
- __Vectors_Size = __Vectors_End - __Vectors;
- __end__ = .;
-
. = . + 16;
-
+ /* KEEP(*(.init)) */
+ /* KEEP(*(.text._entry)) */
*(.text*)
-
- KEEP(*(.init))
- KEEP(*(.fini))
-
- /* .ctors */
- *crtbegin.o(.ctors)
- *crtbegin?.o(.ctors)
- *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
- *(SORT(.ctors.*))
- *(.ctors)
-
- /* .dtors */
- *crtbegin.o(.dtors)
- *crtbegin?.o(.dtors)
- *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
- *(SORT(.dtors.*))
- *(.dtors)
-
*(.rodata*)
-
- KEEP(*(.eh_frame*))
} > FLASH
- .ARM.extab :
- {
- *(.ARM.extab* .gnu.linkonce.armextab.*)
- } > FLASH
-
- __exidx_start = .;
- .ARM.exidx :
- {
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- } > FLASH
- __exidx_end = .;
-
. = ALIGN(4);
__etext = .;
- .data : AT (__etext)
- {
+ .data : AT (__etext) {
. = ALIGN(4);
__data_start__ = .;
- *(vtable)
*(.data*)
-
. = ALIGN(4);
- /* preinit data */
- PROVIDE_HIDDEN (__preinit_array_start = .);
- KEEP(*(.preinit_array))
- PROVIDE_HIDDEN (__preinit_array_end = .);
-
- . = ALIGN(4);
- /* init data */
- PROVIDE_HIDDEN (__init_array_start = .);
- KEEP(*(SORT(.init_array.*)))
- KEEP(*(.init_array))
- PROVIDE_HIDDEN (__init_array_end = .);
-
-
- . = ALIGN(4);
- /* finit data */
- PROVIDE_HIDDEN (__fini_array_start = .);
- KEEP(*(SORT(.fini_array.*)))
- KEEP(*(.fini_array))
- PROVIDE_HIDDEN (__fini_array_end = .);
-
- KEEP(*(.jcr*))
- . = ALIGN(4);
- /* All data end */
__data_end__ = .;
-
} > RAM
- .bss :
- {
+ .bss : {
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
@@ -137,11 +54,8 @@ SECTIONS
__bss_end__ = .;
} > RAM
- .heap (COPY):
- {
+ .heap (COPY): {
__HeapBase = .;
- __end__ = .;
- end = __end__;
KEEP(*(.heap*))
__HeapLimit = .;
} > RAM
@@ -149,8 +63,7 @@ SECTIONS
/* .stack_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign
* values to stack symbols later */
- .stack_dummy (COPY):
- {
+ .stack_dummy (COPY): {
KEEP(*(.stack*))
} > RAM
@@ -158,7 +71,6 @@ SECTIONS
* size of stack_dummy section */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
- PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
diff --git a/NUC123/startup_NUC123.s b/NUC123/startup_NUC123.s
index aaad46a..cc27d67 100644
--- a/NUC123/startup_NUC123.s
+++ b/NUC123/startup_NUC123.s
@@ -89,33 +89,33 @@ __Vectors:
.size __Vectors, . - __Vectors
-
- .text
+ // I really want to move this into its own section but GDB messes up mapping when I do
+ @ .section .init
+ .section .text
.thumb
.thumb_func
.align 2
.global Reset_Handler
- .type Reset_Handler, % function
-
+ .type Reset_Handler, %function
Reset_Handler:
// Unlock Register
- ldr r0, =0x50000100 // REGCTL
- movs r1, #0x59
- str r1, [r0]
- movs r1, #0x16
- str r1, [r0]
- movs r1, #0x88
- str r1, [r0]
+ ldr r0, =0x50000100 // REGCTL
+ movs r1, #0x59
+ str r1, [r0]
+ movs r1, #0x16
+ str r1, [r0]
+ movs r1, #0x88
+ str r1, [r0]
// Init POR
- ldr r2, =0x50000024 // PORCTL
- movs r1, #0x5A
+ ldr r2, =0x50000024 // PORCTL
+ movs r1, #0x5A
lsls r1,r1,8
adds r1,r1,#0xA5
- str r1, [r2]
+ str r1, [r2]
// Lock registers
- movs r1, #0
- str r1, [r0]
+ movs r1, #0
+ str r1, [r0]
/* Single section scheme.
*
@@ -160,10 +160,12 @@ Reset_Handler:
bgt .L_loop3
.L_loop3_done:
-#ifndef __ENTRY
-#define __ENTRY _entry
-#endif
- bl __ENTRY
+ // GCC doesn't realise that we're in a very strict thumb-16 mode here.
+ // GCC's linker isn't very good at locality.
+ // These two together mean that we can't perform a simple branch,
+ // because it'll end up generating a 32-bit instruction.
+ ldr r0, =_entry
+ bx r0
.pool
.size Reset_Handler, . - Reset_Handler
diff --git a/README.md b/README.md
index 816d659..1dc8b3c 100644
--- a/README.md
+++ b/README.md
@@ -39,31 +39,45 @@ If `COM1` is already in use, check what device it is assigned to in Device Manag
Pre-chusan Chunithm uses IO3. This firmware does not (and unfortunately cannot) support IO3. It is recommended to enable the HID keyboard mode, and continue to use keyboard input for IRs.
-## Configuration
-Hold FN2 for configuration. It is not the same as stock DAO.
+## Controls
+### General
+Tap FN1 to insert a coin. FN2 is currently unbound.
-- Pad 1/2 (cell 0): Left wing colour
+### Configuration
+Hold FN1 for configuration:
+
+- Pad 1/2 (cell 0): Left tower colour
- Pad 3/4 (cell 1): Ground colour
- Pad 5/6 (cell 2): Ground colour when pressed, and separator colour
-- Pad 7/8 (cell 3): Right wing colour
+- Pad 7/8 (cell 3): Right tower colour
- Pad 9/10 (cell 4): No function
- Pad 11/12 (cell 5): Toggle rainbow effect on/off
- Pad 13/14 (cell 6): Increase/decrease ground brightness
-- Pad 15/16 (cell 7): Increase/decrease wing brightness
+- Pad 15/16 (cell 7): Increase/decrease tower brightness
- Pad 17/18 (cell 8): No function
-- Pad 19/20 (cell 9): No function
-- Pad 21/22 (cell 10): No function
+- Pad 19/20 (cell 9): System volume up/down
+- Pad 21/22 (cell 10): Holds Enter for 5 seconds (insert Aime card)
- Pad 23/24 (cell 11): No function
- Pad 25/26 (cell 12): Increase/decrease sensitivity
- Pad 27/28 (cell 13): No function
-- Pad 29/30 (cell 14): Toggle HID keyboard mode
-- Pad 31/32 (cell 15): Toggle IO4 emulation mode
+- Pad 29/30 (cell 14): No function
+- Pad 31/32 (cell 15): Toggle HID keyboard mode
-## Calibration
-Make sure no hands or objects are near the slider before starting calibration.
+### Test menu
+To enter the system test menu, double-tap FN2. This will mirror the on-screen controls, and additionally adds controls for the TEST and SERVICE buttons on a real cabinet. Double-tap FN2 again to leave this mode on the controller (note that this is not synced with the game exiting the menu!).
-Hold FN1 for two seconds; the slider will flash red for a few seconds, then fill up with a blue bar.
+Cell 6 and 7 are the TEST button, and cell 8 and 9 are the SERVICE button.
-The slider will then briefly flash green. After this, begin to rub your hands across the slider as much as possible! The cells will turn increasingly green; the greener you can get them the better. Once the dividers have turned green you can save your calibration by pressing FN2.
+To access the TEST and SERVICE buttons without entering the test menu, hold FN2 instead.
-**Note:** Calibration is a separate process to adjusting the sensor sensitivity. It is recommended to re-calibrate after adjustment of sensitivity. For the best performance, run a re-calibration before every play session to account for changes in your room's temperature and humidity.
+## Keyboard Mapping
+When the HID keyboard is enabled, the following mapping (UMIGURI defaults) is used:
+
+```
+I8U7Y6T5R4E3W2Q1
+9KMJNHBGVFCDXSZA
+```
+
+with the airs mapped as `0OLP,.`.
+
+Please note that this is slightly different to stock firmware!
diff --git a/docs/Colours.md b/docs/Colours.md
new file mode 100644
index 0000000..4a06a8c
--- /dev/null
+++ b/docs/Colours.md
@@ -0,0 +1,11 @@
+| | RGB | Approx HSV |
+| ----------- | ------- | ----------- |
+| Light gates | #910c45 | 334,92 ,57 |
+| Cells: | #FEFE00 | 60 ,100,100 |
+| Dividers | #FE00FE | 300,100,100 |
+
+
+Something: FF 00 8B (FF) [Magenta]
+Something: 30 0A 60 (FF) [Purple?]
+Something: 2D 0A 5A (FF)
+Something: 2B 0A 55 (FF)
diff --git a/docs/Development.md b/docs/Development.md
new file mode 100644
index 0000000..7d1c0f2
--- /dev/null
+++ b/docs/Development.md
@@ -0,0 +1,79 @@
+# Development
+## Requirements
+- Windows (Strongly recommend. Compiling on anything else is not officially supported.)
+- [Make for Windows](https://gnuwin32.sourceforge.net/packages/make.htm)
+ - On the path, please
+- [Arm GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) (Currently using 13.2 Rel1)
+ - To make your life easier, ensure this is located at `C:\Program Files (x86)\GNU Arm Embedded Toolchain\13.2 Rel1`
+- [picolibc 1.8.6](https://github.com/picolibc/picolibc/releases/download/1.8.6/picolibc-1.8.6-13.2.Rel1.zip)
+ - Place the contents of this zip file in `picolibc`
+
+VSCode is recommended for development, and all recommended extensions should be installed.
+
+## Compiling and Uploading
+Run `make -j` to compile the firmware.
+
+For rapid development, the HID bootloader is quite annoying. `flash.cmd` is provided which reprograms the chip using an ST-Link V2. This requires an OpenOCD installation in the root project folder, along with an existing compiled host bootloader binary.
+
+For debugging in VSCode, install the recommended extensions then hit F5. This requires an OpenOCD installation in the root project folder, and an ST-Link V2.
+
+## NUC123 BSP
+The `NUC123` folder is a heavily reduced form of the complete BSP provided by Nuvoton. Modifications should not be made to any files within the `inc` or `StdDriver` folder.
+
+`startup_NUC123.s` is the program entrypoint, and may require modification.
+
+`NUC123.ld` is a modified version of the GCC linker script provided by Nuvoton, and may require modification.
+
+To pull in additional BSP drivers, if required, the `Makefile` should be modified.
+
+## CONFIG Flags
+
+Stock TASOLLERs ship with Config0=FFFFFF7D, Config1=FFFFFFFF. The breakdown of Config0 is as follows:
+
+| Bit | Function | Stock Value | Description |
+| ----- | ---------- | ----------- | ----------------------------------- |
+| 31 | `CWDTEN` | 1 | Watchdog inactive |
+| 30 | `CWDTPDEN` | 1 | N/A |
+| 29:28 | Reserved | 11 | |
+| 27 | `CGPFMFP` | 1 | PF.0/PF.1 used for external crystal |
+| 26:24 | `CFOSC` | 111 | 22.11284 MHz internal HIRC |
+| 23 | `CBODEN` | 1 | Brown-out detection disabled |
+| 22:21 | `CBOV` | 11 | Brown-out voltage is 4.5V |
+| 20 | `CBORST` | 1 | Brown-out reset disabled |
+| 19:11 | Reserved | 111111111 | |
+| 10 | `CIOINI` | 1 | GPIO defaults to quasi-directional |
+| 9:8 | Reserved | 11 | |
+| 7:6 | `CBS` | 01 | Boot from LDROM without IAP |
+| 5:3 | Reserved | 111 | |
+| 2 | `DFVSEN` | 1 | Data flash fixed at 4kB |
+| 1 | `LOCK` | 0 | Flash memory is locked |
+| 0 | `DFEN` | 1 | N/A |
+
+For debugging, `LOCK` being enabled can be problematic. Unlocking the processor involves performing a complete chip erase, at which point we must provision out bootloader. We can then set config0 to `FFFFFF7F`, allowing access to flash memory for debugging. `flash.cmd` does this.
+
+Config1 is just used for `DFBADR` and because `DFVSEN=1` this is ignored anyway.
+
+Of note, neither the watchdog nor brown-out detection is enabled. This custom firmware makes no attempt to alter this, as it would present complications when reverting to stock firmware. I would much prefer to have the watchdog enabled, trust me.
+
+## USB
+This firmware is compliant with the USB specification. The following USB3CV tests are used to verify compliance:
+
+- `Chapter 9 Tests [USB 2 devices]`
+- `Connector Type Tests`
+- `HID Tests`
+
+If you make changes to the USB code, it is recommended to re-run these tests to ensure continued compliance.
+
+Additionally, the following tests may be run for diagnostics:
+
+- `Device Summary`
+- `Current Measurement Test [USB 2 devices]`
+
+xHSETT can be used to directly control the USB device, such as sending SUSPEND signals.
+
+## Airs
+See https://www.shinkoh-elecs.jp/wp-content/uploads/2024/05/C_KB1281_1581_24A.pdf
+
+The loop of wire between the two wings is for connecting emitter pin 3 to detector pin 1.
+
+The right bottom is an emitter, and then it alternates up from there.
diff --git a/docs/USB/Chapter 9 Tests - USB 2 - Passed - 2024-07-23 19-44-26.html b/docs/USB/Chapter 9 Tests - USB 2 - Passed - 2024-07-23 19-44-26.html
new file mode 100644
index 0000000..fb23667
--- /dev/null
+++ b/docs/USB/Chapter 9 Tests - USB 2 - Passed - 2024-07-23 19-44-26.html
@@ -0,0 +1,1089 @@
+
+
+
+
+ Chapter 9 Tests - USB 2 - 2024-07-23 19-44-26
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
APPLICATION: USB 3 Gen X Command Verifier
+
TEST SUITE: Chapter 9 Tests [USB 2 devices].cvtests
+
OPERATING SYSTEM:
+
WORKSTATION:
+
DATE: Tuesday, July 23, 2024
+
TIME: 07:45:50 PM
+
OPERATOR: Emma
+
NUMBER OF TESTS: 28
+
LOG NAME: Chapter 9 Tests - USB 2 - 2024-07-23 19-44-26
+
RESULT: passed
+
+
+
+
+
+
+
INFO
Test log initialized.
+
+
INFO
User Input module initialized
+
INFO
Windows Version 22H2 (OS Build 19045)
+
INFO
GuiCV.exe ver 4.1.0.0
+
INFO
BaseUtilities.dll ver 4.1.0.0
+
INFO
GuiHelper.dll ver 4.1.0.0
+
INFO
ComplianceUtilities.dll ver 4.1.0.0
+
INFO
TestSuiteParser.dll ver 4.1.0.0
+
INFO
xhci_DevIOCTL.dll ver 2.2.7.0
+
INFO
xhci_TestServices.dll ver 2.2.7.0
+
INFO
USBUtilities.dll ver 1.4.5.1
+
INFO
StackSwitcher.dll ver 1.4.5.1
+
INFO
xhci_CVServices.dll ver 2.2.7.0
+
INFO
xhci_USB2_CVServices.dll ver 2.2.7.0
+
INFO
xhci_USB2_Chapter9.dll ver 3.1.3.0
+
INFO
XHCISpecVersion: 1.10.
+
INFO
Host 1 selected: xHCI Host: VID=0x1022, PID=0x149C (PCI bus 45, device 0, function 3)
+
INFO
User selection from list: "FS Device (HID) addr=1: VID=0CA3, PID=0021 RouteString 0x00000"
+
INFO
Please select USB 2 Device to test
+
INFO
USB 2 Device Under Test is operating at Full Speed.
+
INFO
Topology: XHCI HC -- DUT
+
+
+
+
INFO
USB Version number of device: 2.00
+
INFO
Number of configurations: 1.
+
+
+
+
INFO
Number of Other Speed configurations: 0.
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:29
+
INFO
Device descriptor length : 0x12
+
INFO
Device descriptor type : 0x1
+
+
+
INFO
Each interface specifies its own device class type
+
INFO
Device sub class : 0x0
+
INFO
Device protocol : 0x0
+
INFO
Device MaxPacketSize0 : 0x40
+
INFO
Looking for Vendor Name File: usbif.json
+
INFO
Vendor information for VendorID : 0xCA3, SEGA CORPORATION
+
INFO
Device ProductID : 0x21
+
+
INFO
Checking iManufacturer String Descriptor: index = 0x01.
+
INFO
String Descriptor : "Bottersnike". (ENGLISH_US)
+
INFO
String Descriptor : "Bottersnike". (NEUTRAL)
+
INFO
Checking iProduct String Descriptor: index = 0x02.
+
INFO
String Descriptor : "TASOLLER". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER". (NEUTRAL)
+
INFO
Checking iSerialNumber String Descriptor: index = 0x03.
+
INFO
String Descriptor : "10000000FFFF000077030000". (ENGLISH_US)
+
INFO
String Descriptor : "10000000FFFF000077030000". (NEUTRAL)
+
INFO
Number of configurations device supports : 0x1
+
INFO
+Stop time: Jul 23, 2024 - 19:44:30
+
+
INFO
Stopping Test [ TD 9.1 - Device Descriptor Test (Configuration Index 0) - default:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:30
+
INFO
Configuration descriptor contains descriptor of type : 0xB (Interface Association Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x21 (HID Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x21 (HID Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Number of interface descriptors found 0x4
+
INFO
Number of alternate interface descriptors found : 0x0
+
INFO
Number of endpoint descriptors found : 0x6
+
INFO
Configuration descriptor length : 0x9
+
INFO
Configuration descriptor type : 0x2
+
INFO
Configuration descriptor TotalLength : 0x84
+
INFO
Configuration descriptor NumInterfaces : 0x4
+
INFO
Configuration descriptor ConfigurationValue: 0x1
+
INFO
Checking iConfiguration String Descriptor: index = 0x00.
+
INFO
The device omits this string descriptor.
+
INFO
Configuration descriptor bmAttributes : 0x80
+
INFO
Device does not support remote wake up
+
INFO
MaxPower = 250 PowerMultiplier = 2
+
INFO
Maximum power device requires : 500mA
+
INFO
Device is BUS POWERED
+
INFO
+Stop time: Jul 23, 2024 - 19:44:31
+
+
INFO
Stopping Test [ TD 9.2 - Configuration Descriptor Test (Configuration Index 0) - default:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:31
+
INFO
+Device has 3 functions, of which 1 has an Interface Association descriptor.
+
INFO
+Interface Association Descriptor :
+
+
INFO
bDescriptorType = 0x0b
+
+
+
INFO
bFunctionClass = 0x02
+
INFO
bFunctionSubClass = 0x02
+
INFO
bFunctionProtocol = 0x00
+
+
INFO
Running TD 9.8 : String Descriptor Test for iFunction : 0x04.
+
INFO
Checking iFunction String Descriptor: index = 0x04.
+
INFO
String Descriptor : "TASOLLER Slider Serial (COM1)". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER Slider Serial (COM1)". (NEUTRAL)
+
INFO
Found Interface Descriptor with number : 0
+
INFO
Found Interface Descriptor with number : 1
+
INFO
Function #2 does not have an Interface Association Descriptor.
+
INFO
Function #3 does not have an Interface Association Descriptor.
+
+
INFO
+Stop time: Jul 23, 2024 - 19:44:33
+
+
INFO
Stopping Test [ TD 9.3 Interface Association Descriptor Test (Config 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:33
+
INFO
Bandwidth check passed
+
INFO
Testing Interface number : 0x0 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x1
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x02.
+
INFO
Interface class code indicates [CDC-Control] Interface.
+
INFO
Interface sub class : 2 <not defined>
+
INFO
Interface protocol : 0 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x02.
+
INFO
Device does not use a class-specific protocol on this interface.
+
INFO
Interface descriptor iInterface : 0x0
+
INFO
Testing Interface number : 0x1 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x2
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x0A.
+
INFO
Interface class code indicates [CDC-Data] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 0 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Device does not use a class-specific protocol on this interface.
+
INFO
Interface descriptor iInterface : 0x0
+
INFO
Testing Interface number : 0x2 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x1
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x03.
+
INFO
Interface class code indicates [HID] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 1 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Interface descriptor bInterfaceProtocol assigned by the USB-IF : 0x01.
+
INFO
Checking iInterface String Descriptor: index = 0x05.
+
INFO
String Descriptor : "I/O CONTROL BD;15257 ;01;90;1831;6679A;00;GOUT=14_ADIN=8,E_ROTIN=4_COININ=2_SWIN=2,E_UQ1=41,6;". (ENGLISH_US)
+
INFO
String Descriptor : "I/O CONTROL BD;15257 ;01;90;1831;6679A;00;GOUT=14_ADIN=8,E_ROTIN=4_COININ=2_SWIN=2,E_UQ1=41,6;". (NEUTRAL)
+
INFO
Testing Interface number : 0x3 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x2
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x03.
+
INFO
Interface class code indicates [HID] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 1 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Interface descriptor bInterfaceProtocol assigned by the USB-IF : 0x01.
+
INFO
Checking iInterface String Descriptor: index = 0x06.
+
INFO
String Descriptor : "TASOLLER HID". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER HID". (NEUTRAL)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:34
+
+
INFO
Stopping Test [ TD 9.4 - Interface Descriptor Test (Configuration Index 0) - default:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:34
+
INFO
+Testing Interface number : 0x0 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x3, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x10
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
+Testing Interface number : 0x1 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Bulk, Number : 0x1, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x2
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Bulk, Number : 0x2, Direction : OUT
+
INFO
Endpoint descriptor bmAttributes : 0x2
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x0
+
INFO
+Testing Interface number : 0x2 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x4, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x8
+
INFO
+Testing Interface number : 0x3 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x5, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x6, Direction : OUT
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
+Stop time: Jul 23, 2024 - 19:44:35
+
+
INFO
Stopping Test [ TD 9.5 - Endpoint Descriptor Test (Configuration Index 0) - default:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:35
+
INFO
Configuration Index 0x00 has a Configuration Value of 1
+
INFO
USB Version supported: 2.00
+
+
INFO
Devices with bcdUSB <= 0x200 must respond to a GET_DESCRIPTOR(BOS) request with a Request Error.
+
INFO
Device Under Test responded with a Request Error to a GET_DESCRIPTOR(BOS) request. (as expected)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:36
+
+
INFO
Stopping Test [ TD 9.7 - BOS Descriptor Test - Device State Default:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:36
+
INFO
Initialized the device to the Default state.
+
+
INFO
Retrieved Device Descriptor.
+
INFO
Device Under Test supports USB Version 0x2.0x00.
+
INFO
Configuration Summary Descriptors are not supported in this version. (Requires BOS descriptor)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:37
+
+
INFO
Stopping Test [ TD 9.30 Configuration Summary Descriptor Test - Device State Default:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:37
+
INFO
Device descriptor length : 0x12
+
INFO
Device descriptor type : 0x1
+
+
+
INFO
Each interface specifies its own device class type
+
INFO
Device sub class : 0x0
+
INFO
Device protocol : 0x0
+
INFO
Device MaxPacketSize0 : 0x40
+
INFO
Looking for Vendor Name File: usbif.json
+
INFO
Vendor information for VendorID : 0xCA3, SEGA CORPORATION
+
INFO
Device ProductID : 0x21
+
+
INFO
Checking iManufacturer String Descriptor: index = 0x01.
+
INFO
String Descriptor : "Bottersnike". (ENGLISH_US)
+
INFO
String Descriptor : "Bottersnike". (NEUTRAL)
+
INFO
Checking iProduct String Descriptor: index = 0x02.
+
INFO
String Descriptor : "TASOLLER". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER". (NEUTRAL)
+
INFO
Checking iSerialNumber String Descriptor: index = 0x03.
+
INFO
String Descriptor : "10000000FFFF000077030000". (ENGLISH_US)
+
INFO
String Descriptor : "10000000FFFF000077030000". (NEUTRAL)
+
INFO
Number of configurations device supports : 0x1
+
INFO
+Stop time: Jul 23, 2024 - 19:44:38
+
+
INFO
Stopping Test [ TD 9.1 - Device Descriptor Test (Configuration Index 0) - addressed:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:38
+
INFO
Configuration descriptor contains descriptor of type : 0xB (Interface Association Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x21 (HID Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x21 (HID Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Number of interface descriptors found 0x4
+
INFO
Number of alternate interface descriptors found : 0x0
+
INFO
Number of endpoint descriptors found : 0x6
+
INFO
Configuration descriptor length : 0x9
+
INFO
Configuration descriptor type : 0x2
+
INFO
Configuration descriptor TotalLength : 0x84
+
INFO
Configuration descriptor NumInterfaces : 0x4
+
INFO
Configuration descriptor ConfigurationValue: 0x1
+
INFO
Checking iConfiguration String Descriptor: index = 0x00.
+
INFO
The device omits this string descriptor.
+
INFO
Configuration descriptor bmAttributes : 0x80
+
INFO
Device does not support remote wake up
+
INFO
MaxPower = 250 PowerMultiplier = 2
+
INFO
Maximum power device requires : 500mA
+
INFO
Device is BUS POWERED
+
INFO
+Stop time: Jul 23, 2024 - 19:44:39
+
+
INFO
Stopping Test [ TD 9.2 - Configuration Descriptor Test (Configuration Index 0) - addressed:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:39
+
INFO
+Device has 3 functions, of which 1 has an Interface Association descriptor.
+
INFO
+Interface Association Descriptor :
+
+
INFO
bDescriptorType = 0x0b
+
+
+
INFO
bFunctionClass = 0x02
+
INFO
bFunctionSubClass = 0x02
+
INFO
bFunctionProtocol = 0x00
+
+
INFO
Running TD 9.8 : String Descriptor Test for iFunction : 0x04.
+
INFO
Checking iFunction String Descriptor: index = 0x04.
+
INFO
String Descriptor : "TASOLLER Slider Serial (COM1)". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER Slider Serial (COM1)". (NEUTRAL)
+
INFO
Found Interface Descriptor with number : 0
+
INFO
Found Interface Descriptor with number : 1
+
INFO
Function #2 does not have an Interface Association Descriptor.
+
INFO
Function #3 does not have an Interface Association Descriptor.
+
+
INFO
+Stop time: Jul 23, 2024 - 19:44:40
+
+
INFO
Stopping Test [ TD 9.3 Interface Association Descriptor Test (Config 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:40
+
INFO
Bandwidth check passed
+
INFO
Testing Interface number : 0x0 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x1
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x02.
+
INFO
Interface class code indicates [CDC-Control] Interface.
+
INFO
Interface sub class : 2 <not defined>
+
INFO
Interface protocol : 0 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x02.
+
INFO
Device does not use a class-specific protocol on this interface.
+
INFO
Interface descriptor iInterface : 0x0
+
INFO
Testing Interface number : 0x1 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x2
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x0A.
+
INFO
Interface class code indicates [CDC-Data] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 0 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Device does not use a class-specific protocol on this interface.
+
INFO
Interface descriptor iInterface : 0x0
+
INFO
Testing Interface number : 0x2 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x1
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x03.
+
INFO
Interface class code indicates [HID] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 1 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Interface descriptor bInterfaceProtocol assigned by the USB-IF : 0x01.
+
INFO
Checking iInterface String Descriptor: index = 0x05.
+
INFO
String Descriptor : "I/O CONTROL BD;15257 ;01;90;1831;6679A;00;GOUT=14_ADIN=8,E_ROTIN=4_COININ=2_SWIN=2,E_UQ1=41,6;". (ENGLISH_US)
+
INFO
String Descriptor : "I/O CONTROL BD;15257 ;01;90;1831;6679A;00;GOUT=14_ADIN=8,E_ROTIN=4_COININ=2_SWIN=2,E_UQ1=41,6;". (NEUTRAL)
+
INFO
Testing Interface number : 0x3 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x2
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x03.
+
INFO
Interface class code indicates [HID] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 1 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Interface descriptor bInterfaceProtocol assigned by the USB-IF : 0x01.
+
INFO
Checking iInterface String Descriptor: index = 0x06.
+
INFO
String Descriptor : "TASOLLER HID". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER HID". (NEUTRAL)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:41
+
+
INFO
Stopping Test [ TD 9.4 - Interface Descriptor Test (Configuration Index 0) - addressed:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:41
+
INFO
+Testing Interface number : 0x0 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x3, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x10
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
+Testing Interface number : 0x1 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Bulk, Number : 0x1, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x2
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Bulk, Number : 0x2, Direction : OUT
+
INFO
Endpoint descriptor bmAttributes : 0x2
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x0
+
INFO
+Testing Interface number : 0x2 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x4, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x8
+
INFO
+Testing Interface number : 0x3 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x5, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x6, Direction : OUT
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
+Stop time: Jul 23, 2024 - 19:44:42
+
+
INFO
Stopping Test [ TD 9.5 - Endpoint Descriptor Test (Configuration Index 0) - addressed:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:42
+
INFO
Configuration Index 0x00 has a Configuration Value of 1
+
INFO
USB Version supported: 2.00
+
+
INFO
Devices with bcdUSB <= 0x200 must respond to a GET_DESCRIPTOR(BOS) request with a Request Error.
+
INFO
Device Under Test responded with a Request Error to a GET_DESCRIPTOR(BOS) request. (as expected)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:43
+
+
INFO
Stopping Test [ TD 9.7 - BOS Descriptor Test - Device State Addressed:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:43
+
INFO
Initialized the device to the Addressed state.
+
+
INFO
Retrieved Device Descriptor.
+
INFO
Device Under Test supports USB Version 0x2.0x00.
+
INFO
Configuration Summary Descriptors are not supported in this version. (Requires BOS descriptor)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:44
+
+
INFO
Stopping Test [ TD 9.30 Configuration Summary Descriptor Test - Device State Addressed:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:44
+
INFO
Device descriptor length : 0x12
+
INFO
Device descriptor type : 0x1
+
+
+
INFO
Each interface specifies its own device class type
+
INFO
Device sub class : 0x0
+
INFO
Device protocol : 0x0
+
INFO
Device MaxPacketSize0 : 0x40
+
INFO
Looking for Vendor Name File: usbif.json
+
INFO
Vendor information for VendorID : 0xCA3, SEGA CORPORATION
+
INFO
Device ProductID : 0x21
+
+
INFO
Checking iManufacturer String Descriptor: index = 0x01.
+
INFO
String Descriptor : "Bottersnike". (ENGLISH_US)
+
INFO
String Descriptor : "Bottersnike". (NEUTRAL)
+
INFO
Checking iProduct String Descriptor: index = 0x02.
+
INFO
String Descriptor : "TASOLLER". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER". (NEUTRAL)
+
INFO
Checking iSerialNumber String Descriptor: index = 0x03.
+
INFO
String Descriptor : "10000000FFFF000077030000". (ENGLISH_US)
+
INFO
String Descriptor : "10000000FFFF000077030000". (NEUTRAL)
+
INFO
Number of configurations device supports : 0x1
+
INFO
+Stop time: Jul 23, 2024 - 19:44:45
+
+
INFO
Stopping Test [ TD 9.1 - Device Descriptor Test (Configuration Index 0) - configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:45
+
INFO
Configuration descriptor contains descriptor of type : 0xB (Interface Association Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x24
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x21 (HID Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x4 (Interface Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x21 (HID Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Configuration descriptor contains descriptor of type : 0x5 (Endpoint Descriptor)
+
INFO
Number of interface descriptors found 0x4
+
INFO
Number of alternate interface descriptors found : 0x0
+
INFO
Number of endpoint descriptors found : 0x6
+
INFO
Configuration descriptor length : 0x9
+
INFO
Configuration descriptor type : 0x2
+
INFO
Configuration descriptor TotalLength : 0x84
+
INFO
Configuration descriptor NumInterfaces : 0x4
+
INFO
Configuration descriptor ConfigurationValue: 0x1
+
INFO
Checking iConfiguration String Descriptor: index = 0x00.
+
INFO
The device omits this string descriptor.
+
INFO
Configuration descriptor bmAttributes : 0x80
+
INFO
Device does not support remote wake up
+
INFO
MaxPower = 250 PowerMultiplier = 2
+
INFO
Maximum power device requires : 500mA
+
INFO
Device is BUS POWERED
+
INFO
Device is currently BUS POWERED
+
INFO
Currently remote wakeup is DISABLED
+
INFO
+Stop time: Jul 23, 2024 - 19:44:46
+
+
INFO
Stopping Test [ TD 9.2 - Configuration Descriptor Test (Configuration Index 0) - configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:46
+
INFO
+Device has 3 functions, of which 1 has an Interface Association descriptor.
+
INFO
+Interface Association Descriptor :
+
+
INFO
bDescriptorType = 0x0b
+
+
+
INFO
bFunctionClass = 0x02
+
INFO
bFunctionSubClass = 0x02
+
INFO
bFunctionProtocol = 0x00
+
+
INFO
Running TD 9.8 : String Descriptor Test for iFunction : 0x04.
+
INFO
Checking iFunction String Descriptor: index = 0x04.
+
INFO
String Descriptor : "TASOLLER Slider Serial (COM1)". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER Slider Serial (COM1)". (NEUTRAL)
+
INFO
Found Interface Descriptor with number : 0
+
INFO
Found Interface Descriptor with number : 1
+
INFO
Function #2 does not have an Interface Association Descriptor.
+
INFO
Function #3 does not have an Interface Association Descriptor.
+
+
INFO
+Stop time: Jul 23, 2024 - 19:44:47
+
+
INFO
Stopping Test [ TD 9.3 Interface Association Descriptor Test (Config 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:47
+
INFO
Bandwidth check passed
+
INFO
Testing Interface number : 0x0 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x1
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x02.
+
INFO
Interface class code indicates [CDC-Control] Interface.
+
INFO
Interface sub class : 2 <not defined>
+
INFO
Interface protocol : 0 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x02.
+
INFO
Device does not use a class-specific protocol on this interface.
+
INFO
Interface descriptor iInterface : 0x0
+
INFO
Testing Interface number : 0x1 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x2
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x0A.
+
INFO
Interface class code indicates [CDC-Data] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 0 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Device does not use a class-specific protocol on this interface.
+
INFO
Interface descriptor iInterface : 0x0
+
INFO
Testing Interface number : 0x2 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x1
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x03.
+
INFO
Interface class code indicates [HID] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 1 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Interface descriptor bInterfaceProtocol assigned by the USB-IF : 0x01.
+
INFO
Checking iInterface String Descriptor: index = 0x05.
+
INFO
String Descriptor : "I/O CONTROL BD;15257 ;01;90;1831;6679A;00;GOUT=14_ADIN=8,E_ROTIN=4_COININ=2_SWIN=2,E_UQ1=41,6;". (ENGLISH_US)
+
INFO
String Descriptor : "I/O CONTROL BD;15257 ;01;90;1831;6679A;00;GOUT=14_ADIN=8,E_ROTIN=4_COININ=2_SWIN=2,E_UQ1=41,6;". (NEUTRAL)
+
INFO
Testing Interface number : 0x3 Alternate setting : 0x0
+
INFO
Interface descriptor length : 0x9
+
INFO
Interface descriptor bDescriptorType : 0x4
+
INFO
Interface descriptor bAlternateSetting : 0x0
+
INFO
Interface descriptor bNumEndPoints: 0x2
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 0x03.
+
INFO
Interface class code indicates [HID] Interface.
+
INFO
Interface sub class : 0 <not defined>
+
INFO
Interface protocol : 1 <not defined>
+
INFO
Interface descriptor bInterfaceSubClass : 0x00.
+
INFO
Interface descriptor bInterfaceProtocol assigned by the USB-IF : 0x01.
+
INFO
Checking iInterface String Descriptor: index = 0x06.
+
INFO
String Descriptor : "TASOLLER HID". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER HID". (NEUTRAL)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:49
+
+
INFO
Stopping Test [ TD 9.4 - Interface Descriptor Test (Configuration Index 0) - configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:49
+
INFO
+Testing Interface number : 0x0 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x3, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x10
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
+Testing Interface number : 0x1 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Bulk, Number : 0x1, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x2
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Bulk, Number : 0x2, Direction : OUT
+
INFO
Endpoint descriptor bmAttributes : 0x2
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x0
+
INFO
+Testing Interface number : 0x2 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x4, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x8
+
INFO
+Testing Interface number : 0x3 Alternate setting : 0x0
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x5, Direction : IN
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
Endpoint descriptor length : 0x7
+
INFO
Endpoint descriptor type : 0x5
+
INFO
Endpoint Type : Interrupt, Number : 0x6, Direction : OUT
+
INFO
Endpoint descriptor bmAttributes : 0x3
+
INFO
Endpoint descriptor raw MaxPacketSize : 0x40
+
INFO
Endpoint descriptor interval : 0x1
+
INFO
+Stop time: Jul 23, 2024 - 19:44:50
+
+
INFO
Stopping Test [ TD 9.5 - Endpoint Descriptor Test (Configuration Index 0) - configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:50
+
INFO
Configuration Index 0x00 has a Configuration Value of 1
+
INFO
Initializing the device to the Configured state with Configuration Value 1
+
+
INFO
USB Version supported: 2.00
+
+
INFO
Devices with bcdUSB <= 0x200 must respond to a GET_DESCRIPTOR(BOS) request with a Request Error.
+
INFO
Device Under Test responded with a Request Error to a GET_DESCRIPTOR(BOS) request. (as expected)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:51
+
+
INFO
Stopping Test [ TD 9.7 - BOS Descriptor Test (Configuration Index 0) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:51
+
INFO
Testing Interface number : 0x0 Alternate setting : 0x0
+
INFO
Testing EndPoint type : Interrupt, Address : 0x83
+
INFO
Endpoint is currently not halted for endpoint 0x83
+
INFO
Setting feature endpoint halt for endpoint 0x83
+
INFO
Endpoint is halted for endpoint 0x83
+
INFO
Clearing feature endpoint halt for endpoint 0x83
+
INFO
Endpoint is no longer halted for endpoint 0x83
+
INFO
Testing Interface number : 0x1 Alternate setting : 0x0
+
INFO
Testing EndPoint type : Bulk, Address : 0x81
+
INFO
Endpoint is currently not halted for endpoint 0x81
+
INFO
Setting feature endpoint halt for endpoint 0x81
+
INFO
Endpoint is halted for endpoint 0x81
+
INFO
Clearing feature endpoint halt for endpoint 0x81
+
INFO
Endpoint is no longer halted for endpoint 0x81
+
INFO
Testing EndPoint type : Bulk, Address : 0x2
+
INFO
Endpoint is currently not halted for endpoint 0x02
+
INFO
Setting feature endpoint halt for endpoint 0x02
+
INFO
Endpoint is halted for endpoint 0x02
+
INFO
Clearing feature endpoint halt for endpoint 0x02
+
INFO
Endpoint is no longer halted for endpoint 0x02
+
INFO
Testing Interface number : 0x2 Alternate setting : 0x0
+
INFO
Testing EndPoint type : Interrupt, Address : 0x84
+
INFO
Endpoint is currently not halted for endpoint 0x84
+
INFO
Setting feature endpoint halt for endpoint 0x84
+
INFO
Endpoint is halted for endpoint 0x84
+
INFO
Clearing feature endpoint halt for endpoint 0x84
+
INFO
Endpoint is no longer halted for endpoint 0x84
+
INFO
Testing Interface number : 0x3 Alternate setting : 0x0
+
INFO
Testing EndPoint type : Interrupt, Address : 0x85
+
INFO
Endpoint is currently not halted for endpoint 0x85
+
INFO
Setting feature endpoint halt for endpoint 0x85
+
INFO
Endpoint is halted for endpoint 0x85
+
INFO
Clearing feature endpoint halt for endpoint 0x85
+
INFO
Endpoint is no longer halted for endpoint 0x85
+
INFO
Testing EndPoint type : Interrupt, Address : 0x6
+
INFO
Endpoint is currently not halted for endpoint 0x06
+
INFO
Setting feature endpoint halt for endpoint 0x06
+
INFO
Endpoint is halted for endpoint 0x06
+
INFO
Clearing feature endpoint halt for endpoint 0x06
+
INFO
Endpoint is no longer halted for endpoint 0x06
+
INFO
+Stop time: Jul 23, 2024 - 19:44:52
+
+
INFO
Stopping Test [ TD 9.9 - Halt Endpoint Test (Configuration Index 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:52
+
INFO
SetConfiguration with configuration value : 0x1
+
INFO
Unconfigured the device
+
INFO
SetConfiguration with configuration value : 0x1
+
INFO
+Stop time: Jul 23, 2024 - 19:44:53
+
+
INFO
Stopping Test [ TD 9.13 - SetConfiguration Test (Configuration Index 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:53
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
Retrieved Device Descriptor.
+
INFO
Device Under Test supports USB Version 0x2.0x00.
+
INFO
Configuration Summary Descriptors are not supported in this version. (Requires BOS descriptor)
+
INFO
+Stop time: Jul 23, 2024 - 19:44:54
+
+
INFO
Stopping Test [ TD 9.30 Configuration Summary Descriptor Test (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:54
+
INFO
Suspended the parent port of the Device Under Test.
+
INFO
Resumed the parent port of the Device Under Test.
+
INFO
Got device descriptor of Device Under Test
+
INFO
+Stop time: Jul 23, 2024 - 19:44:56
+
+
INFO
Stopping Test [ TD 9.14 - Suspend/Resume Test (Configuration Index 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:56
+
INFO
The device does not support remote wakeup
+
INFO
+Stop time: Jul 23, 2024 - 19:44:57
+
+
INFO
Stopping Test [ TD 9.12 - Remote Wakeup Test (Configuration Index 0) - Enabled::
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:57
+
INFO
The device does not support remote wakeup
+
INFO
+Stop time: Jul 23, 2024 - 19:44:58
+
+
INFO
Stopping Test [ TD 9.12 - Remote Wakeup Test (Configuration Index 0) - Disabled::
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:58
+
INFO
Checking Device Under Test for LPM L1 Compatibility...
+
INFO
USB version of device is 2.00.
+
INFO
DUT is NOT compatible with LPM.
+
INFO
LPM is NOT required for DUT
+
INFO
LPM is only supported in USB version 2.01 and above.
+
INFO
+Stop time: Jul 23, 2024 - 19:44:59
+
+
INFO
Stopping Test [ L1Suspend/Resume Test (Configuration Index 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:44:59
+
INFO
Device speed is Full.
+
INFO
Beginning enumeration test with 150 enumerations. This may take several minutes to complete.
+
INFO
Enumerated 150 iterations.
+
INFO
Device tree re-enumerated.
+
INFO
Recovered Device Under Test after device tree re-enumeration.
+
INFO
Device speed of Device Under Test: Full Speed.
+
INFO
+Stop time: Jul 23, 2024 - 19:45:48
+
INFO
Duration: 49 seconds.
+
INFO
Stopping Test [ TD 9.16 - Enumeration Test(repeat 150 times):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Informed user: run Connector Type Tests on this device.
+
INFO
Informed user: run HID Tests on this device.
+
+
+
+
INFO
TEST SUITE SUMMARY:
+ [ Fails (0); Aborts (0); Warnings (0) ]
+
INFO
TEST RESULTS:
+ [ Passed (28); Failed (0) ]
+
+
+
diff --git a/docs/USB/Connector Type Tests - Passed - 2024-07-23 19-45-53.html b/docs/USB/Connector Type Tests - Passed - 2024-07-23 19-45-53.html
new file mode 100644
index 0000000..dc88312
--- /dev/null
+++ b/docs/USB/Connector Type Tests - Passed - 2024-07-23 19-45-53.html
@@ -0,0 +1,349 @@
+
+
+
+
+ Connector Type Tests - 2024-07-23 19-45-53
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
APPLICATION: USB 3 Gen X Command Verifier
+
TEST SUITE: Connector Type Tests.cvtests
+
OPERATING SYSTEM:
+
WORKSTATION:
+
DATE: Tuesday, July 23, 2024
+
TIME: 07:46:09 PM
+
OPERATOR: Emma
+
NUMBER OF TESTS: 10
+
LOG NAME: Connector Type Tests - 2024-07-23 19-45-53
+
RESULT: passed
+
+
+
+
+
+
+
INFO
Test log initialized.
+
+
INFO
User Input module initialized
+
INFO
Windows Version 22H2 (OS Build 19045)
+
INFO
GuiCV.exe ver 4.1.0.0
+
INFO
BaseUtilities.dll ver 4.1.0.0
+
INFO
GuiHelper.dll ver 4.1.0.0
+
INFO
ComplianceUtilities.dll ver 4.1.0.0
+
INFO
TestSuiteParser.dll ver 4.1.0.0
+
INFO
xhci_DevIOCTL.dll ver 2.2.7.0
+
INFO
xhci_TestServices.dll ver 2.2.7.0
+
INFO
USBUtilities.dll ver 1.4.5.1
+
INFO
StackSwitcher.dll ver 1.4.5.1
+
INFO
xhci_CVServices.dll ver 2.2.7.0
+
INFO
xhci_ConnectorType.dll ver 3.1.3.0
+
INFO
XHCISpecVersion: 1.10.
+
INFO
Host 1 selected: xHCI Host: VID=0x1022, PID=0x149C (PCI bus 45, device 0, function 3)
+
INFO
User selection from list: "FS Device (HID) addr=1: VID=0CA3, PID=0021 RouteString 0x00000"
+
INFO
Please select USB Device to test
+
INFO
USB Device Under Test is operating at Full Speed.
+
INFO
Topology: XHCI HC -- DUT
+
+
+
+
INFO
USB Version number of device: 2.00
+
INFO
Number of configurations: 1.
+
+
+
+
INFO
Number of Other Speed configurations: 0.
+
+
+
+
INFO
Device Under Test is not a Hub.
+
+
+
+
INFO
Device Under Test is not a Hub.
+
+
+
+
INFO
Acquiring power state helper.
+
INFO
User selected power state: "Standard USB Current".
+
+
+
+
INFO
Device Under Test is embedded, and cannot have a Vendor Info File (VIF) for its upstream facing port.
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:45:58
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
Device Under Test does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:45:59
+
+
INFO
Stopping Test [ TD 9.1 PD Configuration Descriptor Test (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:45:59
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:00
+
+
INFO
Stopping Test [ TD 9.2 PD Capability Descriptor Test (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:01
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:02
+
+
INFO
Stopping Test [ TD 9.3 PD Battery Info Capability Descriptor Test (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:02
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:03
+
+
INFO
Stopping Test [ TD 9.4 PD Consumer Port Capability Descriptor Test (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:03
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:04
+
+
INFO
Stopping Test [ TD 9.5 PD Provider Port Capability Descriptor Test (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:04
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:05
+
+
INFO
Stopping Test [ TD 9.6 PD Battery Status Test (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:05
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:06
+
+
INFO
Stopping Test [ TD 9.7 PD Remote Wake Test - Enabled (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:06
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:07
+
+
INFO
Stopping Test [ TD 9.7 Remote Wake Test - Disabled (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:07
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
VIF contains 0 components.
+
INFO
VIF has 0 Upstream Facing Ports.
+
INFO
Device Under Test does not have a BOS descriptor and so does not support PD.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:08
+
+
INFO
Stopping Test [ TD 9.8 PD CHARGING_POLICY Test (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:08
+
INFO
Configuration Index 0x00 has a Configuration Value of 1.
+
INFO
Initialized the device to the Configured state with Configuration Value 1.
+
+
INFO
Device Under Test is not a hub.
+
INFO
+Stop time: Jul 23, 2024 - 19:46:09
+
+
INFO
Stopping Test [ TD 9.9 PD Hub Bridge Test on single host (Configuration Index 0x00) - Device State Configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Cleaning up VIF for Upstream Facing Port
+
INFO
Cleaning up VIF for Downstream Facing Ports.
+
+
+
+
INFO
TEST SUITE SUMMARY:
+ [ Fails (0); Aborts (0); Warnings (0) ]
+
INFO
TEST RESULTS:
+ [ Passed (10); Failed (0) ]
+
+
+
diff --git a/docs/USB/Device Summary - Passed - 2024-07-23 19-46-25.html b/docs/USB/Device Summary - Passed - 2024-07-23 19-46-25.html
new file mode 100644
index 0000000..6d5d143
--- /dev/null
+++ b/docs/USB/Device Summary - Passed - 2024-07-23 19-46-25.html
@@ -0,0 +1,205 @@
+
+
+
+
+ Device Summary - 2024-07-23 19-46-25
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
APPLICATION: USB 3 Gen X Command Verifier
+
TEST SUITE: Device Summary.cvtests
+
OPERATING SYSTEM:
+
WORKSTATION:
+
DATE: Tuesday, July 23, 2024
+
TIME: 07:46:29 PM
+
OPERATOR: Emma
+
NUMBER OF TESTS: 1
+
LOG NAME: Device Summary - 2024-07-23 19-46-25
+
RESULT: passed
+
+
+
+
+
+
+
INFO
Test log initialized.
+
+
INFO
User Input module initialized
+
INFO
Windows Version 22H2 (OS Build 19045)
+
INFO
GuiCV.exe ver 4.1.0.0
+
INFO
BaseUtilities.dll ver 4.1.0.0
+
INFO
GuiHelper.dll ver 4.1.0.0
+
INFO
ComplianceUtilities.dll ver 4.1.0.0
+
INFO
TestSuiteParser.dll ver 4.1.0.0
+
INFO
xhci_DevIOCTL.dll ver 2.2.7.0
+
INFO
xhci_TestServices.dll ver 2.2.7.0
+
INFO
USBUtilities.dll ver 1.4.5.1
+
INFO
StackSwitcher.dll ver 1.4.5.1
+
INFO
xhci_CVServices.dll ver 2.2.7.0
+
INFO
XHCISpecVersion: 1.10.
+
INFO
Host 1 selected: xHCI Host: VID=0x1022, PID=0x149C (PCI bus 45, device 0, function 3)
+
INFO
User selection from list: "FS Device (HID) addr=1: VID=0CA3, PID=0021 RouteString 0x00000"
+
INFO
Please select USB Device to test
+
INFO
USB Device Under Test is operating at Full Speed.
+
INFO
Topology: XHCI HC -- DUT
+
+
+
+
INFO
USB Version number of device: 2.00
+
INFO
Number of configurations: 1.
+
+
+
+
INFO
Number of Other Speed configurations: 0.
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:28
+
INFO
Host VEN = 1022h
+Host DEV = 149ch
+Host Revision number = 0h
+Host HCI Version = 110
+
+
INFO
Device is attached to port 4
+
+
INFO
Looking for Vendor Name File: usbif.json
+
INFO
Device Vendor : 3235 (0xca3) -- SEGA CORPORATION
+
INFO
Device Product ID : 33 (0x21)
+
INFO
Device Revision (bcdDevice) : 0x0100
+
INFO
Checking iProduct String Descriptor: index = 0x02.
+
INFO
String Descriptor : "TASOLLER". (ENGLISH_US)
+
INFO
String Descriptor : "TASOLLER". (NEUTRAL)
+
+
INFO
bDeviceProtocol = 0x0
+
INFO
bDeviceSubClass = 0x0
+
+
INFO
Device Speed : Full Speed
+
INFO
Number of configurations device supports : 1
+
INFO
Got configuration descriptor for config index : 0
+
INFO
Full length of configuration descriptor is 132 bytes
+
+
+
+
INFO
Number of interfaces device supports : 4
+
INFO
Descriptor for interface 0
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 2
+
INFO
Interface class code indicates [CDC-Control] Interface
+
INFO
Descriptor for interface 1
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : a
+
INFO
Interface class code indicates [CDC-Data] Interface
+
INFO
Descriptor for interface 2
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 3
+
INFO
Interface class code indicates [HID] Interface
+
INFO
Descriptor for interface 3
+
INFO
Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 3
+
INFO
Interface class code indicates [HID] Interface
+
INFO
+Stop time: Jul 23, 2024 - 19:46:29
+
+
INFO
Stopping Test [ Device Summary:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
TEST SUITE SUMMARY:
+ [ Fails (0); Aborts (0); Warnings (0) ]
+
INFO
TEST RESULTS:
+ [ Passed (1); Failed (0) ]
+
+
+
diff --git a/docs/USB/HID Tests - Passed - 2024-07-23 19-46-13.html b/docs/USB/HID Tests - Passed - 2024-07-23 19-46-13.html
new file mode 100644
index 0000000..e4ffa3e
--- /dev/null
+++ b/docs/USB/HID Tests - Passed - 2024-07-23 19-46-13.html
@@ -0,0 +1,254 @@
+
+
+
+
+ HID Tests - 2024-07-23 19-46-13
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
APPLICATION: USB 3 Gen X Command Verifier
+
TEST SUITE: HID Tests.cvtests
+
OPERATING SYSTEM:
+
WORKSTATION:
+
DATE: Tuesday, July 23, 2024
+
TIME: 07:46:21 PM
+
OPERATOR: Emma
+
NUMBER OF TESTS: 5
+
LOG NAME: HID Tests - 2024-07-23 19-46-13
+
RESULT: passed
+
+
+
+
+
+
+
INFO
Test log initialized.
+
+
INFO
User Input module initialized
+
INFO
Windows Version 22H2 (OS Build 19045)
+
INFO
GuiCV.exe ver 4.1.0.0
+
INFO
BaseUtilities.dll ver 4.1.0.0
+
INFO
GuiHelper.dll ver 4.1.0.0
+
INFO
ComplianceUtilities.dll ver 4.1.0.0
+
INFO
TestSuiteParser.dll ver 4.1.0.0
+
INFO
xhci_DevIOCTL.dll ver 2.2.7.0
+
INFO
xhci_TestServices.dll ver 2.2.7.0
+
INFO
USBUtilities.dll ver 1.4.5.1
+
INFO
StackSwitcher.dll ver 1.4.5.1
+
INFO
xhci_CVServices.dll ver 2.2.7.0
+
INFO
HidParser.dll ver 1.4.5.0
+
INFO
xhci_HID.dll ver 3.1.3.0
+
INFO
XHCISpecVersion: 1.10.
+
INFO
Host 1 selected: xHCI Host: VID=0x1022, PID=0x149C (PCI bus 45, device 0, function 3)
+
INFO
User selection from list: "FS Device (HID) addr=1: VID=0CA3, PID=0021 RouteString 0x00000"
+
INFO
Please select HID Device to test
+
INFO
HID Device Under Test is operating at Full Speed.
+
INFO
Topology: XHCI HC -- DUT
+
+
+
+
INFO
USB Version number of device: 2.00
+
INFO
Number of configurations: 1.
+
+
+
+
INFO
Number of Other Speed configurations: 0.
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:16
+
INFO
USB Version number of device: 2.00
+
INFO
Interface 0x2 Alternate Setting 0x0 is draft 4 Compliant
+
INFO
Interface 0x3 Alternate Setting 0x0 is draft 4 Compliant
+
INFO
+Stop time: Jul 23, 2024 - 19:46:17
+
+
INFO
Stopping Test [ HID Class WhichSpecCompliant Test:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:17
+
INFO
Testing HID descriptor for Interface 0x2
+
INFO
HID descriptor total length : 0x9
+
INFO
HID descriptor type : 0x21
+
INFO
HID specification version : 0x110
+
+
INFO
Number of other descriptors present : 0x1
+
INFO
HID report descriptor length : 0x71
+
INFO
Testing HID descriptor for Interface 0x3
+
INFO
HID descriptor total length : 0x9
+
INFO
HID descriptor type : 0x21
+
INFO
HID specification version : 0x110
+
+
INFO
Number of other descriptors present : 0x1
+
INFO
HID report descriptor length : 0x97
+
INFO
+Stop time: Jul 23, 2024 - 19:46:18
+
+
INFO
Stopping Test [ HID Class Descriptor Test (Configuration Index 0) - configured:
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:18
+
INFO
Starting GET/SET protocol tests for interface : 2
+
INFO
GET/SET protocol request is optional. Skipping tests
+
INFO
Starting GET/SET protocol tests for interface : 3
+
INFO
GET/SET protocol request is optional. Skipping tests
+
INFO
+Stop time: Jul 23, 2024 - 19:46:19
+
+
INFO
Stopping Test [ HID Class Protocol Test (Configuration Index 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:19
+
INFO
GET/SETIdle test for report ID 0x1. Setting idle rate to : 0x7F
+
INFO
GET/SETIdle test for report ID 0x1. Setting idle rate to : 0xFF
+
INFO
GET/SETIdle test for report ID 0x1. Setting idle rate to : 0x0
+
INFO
GET/SETIdle test for report ID 0x2. Setting idle rate to : 0x7F
+
INFO
GET/SETIdle test for report ID 0x2. Setting idle rate to : 0xFF
+
INFO
GET/SETIdle test for report ID 0x2. Setting idle rate to : 0x0
+
INFO
GET/SETIdle test for report ID 0x3. Setting idle rate to : 0x7F
+
INFO
GET/SETIdle test for report ID 0x3. Setting idle rate to : 0xFF
+
INFO
GET/SETIdle test for report ID 0x3. Setting idle rate to : 0x0
+
INFO
GET/SETIdle test for report ID 0x4. Setting idle rate to : 0x7F
+
INFO
GET/SETIdle test for report ID 0x4. Setting idle rate to : 0xFF
+
INFO
GET/SETIdle test for report ID 0x4. Setting idle rate to : 0x0
+
INFO
+Stop time: Jul 23, 2024 - 19:46:20
+
+
INFO
Stopping Test [ HID Class GET/SET Idle Test (Configuration Index 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
Start time: Jul 23, 2024 - 19:46:20
+
INFO
Report descriptor length: 113
+
INFO
Item count in report descriptor: 54
+
INFO
Report descriptor test passed. Proceeding to next descriptor
+
INFO
Report descriptor length: 151
+
INFO
Item count in report descriptor: 71
+
INFO
Report descriptor test passed. Proceeding to next descriptor
+
INFO
+Stop time: Jul 23, 2024 - 19:46:21
+
+
INFO
Stopping Test [ HID Class Report Descriptor Test (Configuration Index 0):
+ Number of: Fails (0); Aborts (0); Warnings (0) ]
+
+
+
+
+
INFO
TEST SUITE SUMMARY:
+ [ Fails (0); Aborts (0); Warnings (0) ]
+
INFO
TEST RESULTS:
+ [ Passed (5); Failed (0) ]
+
+
+
diff --git a/flash.cmd b/flash.cmd
index eaf1458..f15476d 100644
--- a/flash.cmd
+++ b/flash.cmd
@@ -1,17 +1,31 @@
-@..\..\openocd-0.12.0-3\bin\openocd.exe -f interface/stlink-v2.cfg -f ..\..\nucxxx.cfg ^
+@ECHO off
+
+FOR /F "tokens=* USEBACKQ" %%g IN (`
+ ..\..\openocd-0.12.0-3\bin\openocd.exe -f ..\..\nucxxx.cfg ^
+ -c "init; PrintPart; exit" 2^>NUL
+`) DO (SET "PART_NUM=%%g")
+
+IF NOT "%PART_NUM%"=="NUC123SD4AN0" (
+ ECHO Invalid part number %PART_NUM%. Make sure you're connected to HOST not LED!
+ EXIT /B 1
+)
+
+REM SET LDROM_PATH=../bootloader/host_bl.bin
+SET LDROM_PATH=../../../TASOLLER_HOST_LDROM.bin
+SET APROM_PATH=host_aprom.bin
+
+..\..\openocd-0.12.0-3\bin\openocd.exe -f ..\..\nucxxx.cfg ^
-c "SysReset halt" ^
-c "flash read_bank 1 dataflash.bin" ^
-c "ChipErase" ^
- -c "exit"
-
-@..\..\openocd-0.12.0-3\bin\openocd.exe -f interface/stlink-v2.cfg -f ..\..\nucxxx.cfg ^
- -c "SysReset halt" ^
-c "WriteConfigRegs 0xFFFFFF7F 0xFFFFFFFF" ^
-c "ReadConfigRegs" ^
- -c "program ../bootloader/host_bl.bin 0x100000" ^
- -c "program host_aprom.bin 0" ^
+ -c "program %LDROM_PATH% 0x100000" ^
+ -c "program %APROM_PATH% 0" ^
-c "program dataflash.bin 0x1F000" ^
+ -c "ReadConfigRegs" ^
-c "SysReset aprom run" ^
- -c "exit"
+ -c "exit" -d0
-@del dataflash.bin
+REM Clean up after ourself
+del dataflash.bin
diff --git a/src/_compiler.h b/src/_compiler.h
new file mode 100644
index 0000000..beb2cda
--- /dev/null
+++ b/src/_compiler.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#ifndef __packed
+#if defined(__CC_ARM)
+#elif defined(__GNUC__)
+#define __packed __attribute__((packed))
+#else
+#error Unknown compiler
+#endif
+#endif
diff --git a/src/delay.s b/src/delay.s
deleted file mode 100644
index 08349a3..0000000
--- a/src/delay.s
+++ /dev/null
@@ -1,6 +0,0 @@
-.syntax unified
- .global DelayCycles
-DelayCycles:
- subs r0, r0, #1
- bcs DelayCycles
- bx lr
diff --git a/src/descriptors.c b/src/descriptors.c
index 598604d..4d5cced 100644
--- a/src/descriptors.c
+++ b/src/descriptors.c
@@ -74,7 +74,7 @@ static const uint8_t IO4_ReportDescriptor[] = {
HID_COLLECTION(APPLICATION),
HID_USAGE(UNDEFINED),
HID_LOGICAL_MINIMUM(1, 0),
- HID_LOGICAL_MAXIMUM(1, 255),
+ HID_LOGICAL_MAXIMUM(2, 255),
HID_REPORT_SIZE(8),
HID_REPORT_COUNT(63),
HID_OUTPUT(DATA, VARIABLE, ABSOLUTE, NO_WRAP, LINEAR, PREFERRED_STATE, NO_NULL_POSITION,
@@ -85,7 +85,7 @@ static const uint8_t IO4_ReportDescriptor[] = {
};
static const uint8_t Keyboard_ReportDescriptor[] = {
- // Keyboard input descriptor
+ // Keyboard input report
HID_USAGE_PAGE(GENERIC_DESKTOP),
HID_USAGE(KEYBOARD),
HID_COLLECTION(APPLICATION),
@@ -93,7 +93,7 @@ static const uint8_t Keyboard_ReportDescriptor[] = {
HID_USAGE_PAGE(KEYBOARD),
HID_LOGICAL_MINIMUM(1, 0),
- HID_LOGICAL_MAXIMUM(1, 231),
+ HID_LOGICAL_MAXIMUM(2, 231),
HID_USAGE_MINIMUM(1, 0),
HID_USAGE_MAXIMUM(1, 231),
HID_REPORT_SIZE(8),
@@ -102,130 +102,37 @@ static const uint8_t Keyboard_ReportDescriptor[] = {
HID_END_COLLECTION(APPLICATION),
- // Debugging reports descriptors (they dump the raw PSoC data)
- HID_USAGE_PAGE(GENERIC_DESKTOP),
- HID_USAGE(JOYSTICK),
+ // Consumer control report
+ HID_USAGE_PAGE(CONSUMER),
+ HID_USAGE(CONSUMER_CONTROL),
HID_COLLECTION(APPLICATION),
+ HID_REPORT_ID(HID_REPORT_ID_CONSUMER_CONTROL),
- HID_REPORT_ID(HID_REPORT_ID_DEBUG_A),
- HID_USAGE(POINTER),
- HID_COLLECTION(LOGICAL),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
+ HID_USAGE_PAGE(CONSUMER),
+ HID_USAGE_MINIMUM(1, 0),
+ HID_USAGE_MAXIMUM(2, 0x0FFF),
HID_LOGICAL_MINIMUM(1, 0),
- HID_LOGICAL_MAXIMUM(4, 0xffff),
- HID_PHYSICAL_MINIMUM(1, 0),
- HID_PHYSICAL_MAXIMUM(4, 0xffff),
- HID_REPORT_COUNT(16),
+ HID_LOGICAL_MAXIMUM(2, 0x0FFF),
HID_REPORT_SIZE(16),
- HID_INPUT(DATA, VARIABLE, ABSOLUTE),
- HID_END_COLLECTION(LOGICAL),
-
- HID_REPORT_ID(HID_REPORT_ID_DEBUG_B),
- HID_USAGE(POINTER),
- HID_COLLECTION(LOGICAL),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_LOGICAL_MINIMUM(1, 0),
- HID_LOGICAL_MAXIMUM(4, 0xffff),
- HID_PHYSICAL_MINIMUM(1, 0),
- HID_PHYSICAL_MAXIMUM(4, 0xffff),
- HID_REPORT_SIZE(16),
- HID_REPORT_COUNT(16),
- HID_INPUT(DATA, VARIABLE, ABSOLUTE),
- HID_END_COLLECTION(LOGICAL),
+ HID_REPORT_COUNT(2),
+ HID_INPUT(DATA, ARRAY, ABSOLUTE, NO_WRAP, LINEAR, PREFERRED_STATE, NO_NULL_POSITION),
HID_END_COLLECTION(APPLICATION),
-};
-static const uint8_t Debug_ReportDescriptor[] = {
+ // Report for sending the enter key
HID_USAGE_PAGE(GENERIC_DESKTOP),
- HID_USAGE(JOYSTICK),
+ HID_USAGE(KEYBOARD),
HID_COLLECTION(APPLICATION),
+ HID_REPORT_ID(HID_REPORT_ID_ENTER),
- HID_REPORT_ID(HID_REPORT_ID_DEBUG_A),
- HID_USAGE(POINTER),
- HID_COLLECTION(LOGICAL),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
+ HID_USAGE_PAGE(KEYBOARD),
HID_LOGICAL_MINIMUM(1, 0),
- HID_LOGICAL_MAXIMUM(4, 0xffff),
- HID_PHYSICAL_MINIMUM(1, 0),
- HID_PHYSICAL_MAXIMUM(4, 0xffff),
- HID_REPORT_COUNT(16),
- HID_REPORT_SIZE(16),
- HID_INPUT(DATA, VARIABLE, ABSOLUTE),
- HID_END_COLLECTION(LOGICAL),
-
- HID_REPORT_ID(HID_REPORT_ID_DEBUG_B),
- HID_USAGE(POINTER),
- HID_COLLECTION(LOGICAL),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_USAGE(X),
- HID_USAGE(Y),
- HID_LOGICAL_MINIMUM(1, 0),
- HID_LOGICAL_MAXIMUM(4, 0xffff),
- HID_PHYSICAL_MINIMUM(1, 0),
- HID_PHYSICAL_MAXIMUM(4, 0xffff),
- HID_REPORT_SIZE(16),
- HID_REPORT_COUNT(16),
- HID_INPUT(DATA, VARIABLE, ABSOLUTE),
- HID_END_COLLECTION(LOGICAL),
+ HID_LOGICAL_MAXIMUM(2, 231),
+ HID_USAGE_MINIMUM(1, 0),
+ HID_USAGE_MAXIMUM(1, 231),
+ HID_REPORT_SIZE(8),
+ HID_REPORT_COUNT(1),
+ HID_INPUT(DATA, ARRAY, ABSOLUTE),
HID_END_COLLECTION(APPLICATION),
};
@@ -291,7 +198,7 @@ static const config_desc_t gConfigDescriptor = {
_USBD_ITF_MAX,
0x01,
0x00,
- 0x80 | (USBD_SELF_POWERED << 6) | (USBD_REMOTE_WAKEUP << 5),
+ 0x80 | USBD_REMOTE_WAKEUP_Msk,
USBD_MAX_POWER,
},
@@ -313,7 +220,7 @@ static const config_desc_t gConfigDescriptor = {
DESC_INTERFACE,
USBD_ITF_CDC_CMD,
0x00,
- 0x01,
+ 1,
USB_CLASS_CDC,
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL,
CDC_COMM_PROTOCOL_NONE,
@@ -389,7 +296,7 @@ static const config_desc_t gConfigDescriptor = {
DESC_INTERFACE,
USBD_ITF_HID_IO4,
0x00,
- 0x01,
+ 1,
USB_CLASS_HID,
0,
HID_KEYBOARD,
@@ -419,7 +326,7 @@ static const config_desc_t gConfigDescriptor = {
DESC_INTERFACE,
USBD_ITF_HID_MISC,
0x00,
- 0x01,
+ 2,
USB_CLASS_HID,
0,
HID_KEYBOARD,
@@ -452,12 +359,11 @@ static const config_desc_t gConfigDescriptor = {
},
};
-const char* gszVendorInitial = "Bottersnike";
const char* gszVendor = IO4_VENDOR;
const char* gszProduct = "TASOLLER";
-const usb_device_descr_t *gpDeviceDescriptor = &gIO4DeviceDescriptor;
-const usb_desc_config_t *gpConfigDescriptor = &gConfigDescriptor.Config;
+const usb_device_descr_t* gpDeviceDescriptor = &gIO4DeviceDescriptor;
+const usb_desc_config_t* gpConfigDescriptor = &gConfigDescriptor.Config;
const uint32_t gu32HidDescIO4Offset = (offsetof(config_desc_t, HID_IO4));
const uint32_t gu32HidDescMiscOffset = (offsetof(config_desc_t, HID_Misc));
const uint32_t gu32UsbHidIO4ReportLen = sizeof IO4_ReportDescriptor;
diff --git a/src/fmc.c b/src/fmc.c
index 222fbe4..1b5b317 100644
--- a/src/fmc.c
+++ b/src/fmc.c
@@ -51,7 +51,6 @@ void FMC_EEPROM_Load(void) {
if (gConfig.u32Magic != DATAFLASH_MAGIC) {
// Zeroing flags first means GCC knows we don't care about the other bits
gConfig.u8Flags = 0;
- gConfig.bEnableIO4 = 1;
gConfig.bEnableKeyboard = 0;
gConfig.bEnableRainbow = 1;
@@ -59,6 +58,7 @@ void FMC_EEPROM_Load(void) {
gConfig.u16HueWingLeft = 330;
gConfig.u16HueWingRight = 180;
+ // TODO: These are the DJ DAO defaults, but the game looks like the hue should be 60 and 300
gConfig.u16HueGround = 45;
gConfig.u16HueGroundActive = 330;
diff --git a/src/fmc_user.h b/src/fmc_user.h
index 345351b..04cabc7 100644
--- a/src/fmc_user.h
+++ b/src/fmc_user.h
@@ -34,7 +34,7 @@ typedef struct __attribute__((aligned(4), packed)) {
// Flags
union {
struct __packed {
- uint8_t bEnableIO4 : 1;
+ uint8_t bRsv00 : 1;
uint8_t bEnableKeyboard : 1;
uint8_t bEnableRainbow : 1;
};
diff --git a/src/hid.c b/src/hid.c
index 9c2a0c4..37a9ebf 100644
--- a/src/hid.c
+++ b/src/hid.c
@@ -1,144 +1,189 @@
#include "tasoller.h"
-#define HID_IO4_BUF ((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_HID_IO4_IN)))
-#define HID_MISC_BUF ((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_HID_MISC_IN)))
+uint16_t u16RequestedConsumerControl = 0;
+uint32_t u32EnterPressStarted = 0xFFFFFFFF;
+
+#define ENTER_HOLD_TIME 5000 // 5 seconds
+
+#define HID_MISC_BUF ((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_HID_MISC_IN)))
+#define HID_IO4_BUF ((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_HID_IO4_IN)))
+
+#define HID_MISC_SEND(buf) \
+ do { \
+ USBD_SET_PAYLOAD_LEN(EP_HID_MISC_IN, sizeof *(buf)); \
+ gu8HIDMiscReady = 0; \
+ } while (0)
-static const uint8_t u8GroundThreshold = 20;
static const uint8_t u8GroundKeymap[32] = {
- KEY_I, KEY_COMMA, //
- KEY_8, KEY_K, //
- KEY_U, KEY_M, //
- KEY_7, KEY_J, //
- KEY_Y, KEY_N, //
- KEY_6, KEY_H, //
- KEY_T, KEY_B, //
- KEY_5, KEY_G, //
- KEY_R, KEY_V, //
- KEY_4, KEY_F, //
- KEY_E, KEY_C, //
- KEY_3, KEY_D, //
- KEY_W, KEY_X, //
- KEY_2, KEY_S, //
- KEY_Q, KEY_Z, //
- KEY_1, KEY_A, //
+ KEY_I, KEY_9, // Dao uses: KEY_I, KEY_COMMA
+ KEY_8, KEY_K, //
+ KEY_U, KEY_M, //
+ KEY_7, KEY_J, //
+ KEY_Y, KEY_N, //
+ KEY_6, KEY_H, //
+ KEY_T, KEY_B, //
+ KEY_5, KEY_G, //
+ KEY_R, KEY_V, //
+ KEY_4, KEY_F, //
+ KEY_E, KEY_C, //
+ KEY_3, KEY_D, //
+ KEY_W, KEY_X, //
+ KEY_2, KEY_S, //
+ KEY_Q, KEY_Z, //
+ KEY_1, KEY_A, //
};
static const uint8_t u8AirKeymap[6] = {
- HID_KEYBOARD_SLASH_AND_QUESTION_MARK, // VK_OEM_2
- HID_KEYBOARD_PERIOD_AND_GREATER_THAN, // VK_OEM_PERIOD
- HID_KEYBOARD_QUOTE_AND_DOUBLEQUOTE, // VK_OEM_7
- HID_KEYBOARD_SEMICOLON_AND_COLON, // VK_OEM_1
- HID_KEYBOARD_RIGHT_BRACKET_AND_RIGHT_CURLY_BRACE, // VK_OEM_6
- HID_KEYBOARD_LEFT_BRACKET_AND_LEFT_CURLY_BRACE, // VK_OEM_4
+ // Dao mapping:
+ // HID_KEYBOARD_SLASH_AND_QUESTION_MARK, // VK_OEM_2
+ // HID_KEYBOARD_PERIOD_AND_GREATER_THAN, // VK_OEM_PERIOD
+ // HID_KEYBOARD_QUOTE_AND_DOUBLEQUOTE, // VK_OEM_7
+ // HID_KEYBOARD_SEMICOLON_AND_COLON, // VK_OEM_1
+ // HID_KEYBOARD_RIGHT_BRACKET_AND_RIGHT_CURLY_BRACE, // VK_OEM_6
+ // HID_KEYBOARD_LEFT_BRACKET_AND_LEFT_CURLY_BRACE, // VK_OEM_4
+
+ // UMIGURI mapping:
+ KEY_0, KEY_O, KEY_L, KEY_P, KEY_COMMA, KEY_PERIOD,
};
-static inline void _HID_Keyboard_Tick(uint8_t bReal) {
- hid_report_t *buf = (hid_report_t *)HID_MISC_BUF;
+
+static uint8_t _HID_Keyboard_Tick(uint8_t bReleaseAll) {
+ hid_kbd_report_t *buf = (hid_kbd_report_t *)HID_MISC_BUF;
+
+ // Send a report of zeroes to release all keys
+ if (bReleaseAll) {
+ memset(buf, 0, sizeof *buf);
+ buf->bReportId = HID_REPORT_ID_KEYBOARD;
+
+ HID_MISC_SEND(buf);
+ return 1;
+ }
+
+ static uint8_t u8LastButtons = 0;
+ static uint32_t u32LastSlider = 0;
+
+ // If nothing changed, do nothing
+ if (gu8DigitalButtons == u8LastButtons && gu32PSoCDigital == u32LastSlider) {
+ return 0;
+ }
memset(buf, 0, sizeof *buf);
buf->bReportId = HID_REPORT_ID_KEYBOARD;
uint8_t kI = 0;
- if (bReal) {
- if (gu8DigitalButtons & 0x01) buf->bKeyboard[kI++] = HID_KEYBOARD_F1;
- if (gu8DigitalButtons & 0x02) buf->bKeyboard[kI++] = HID_KEYBOARD_F2;
- if (gu8DigitalButtons & 0x04) buf->bKeyboard[kI++] = u8AirKeymap[0];
- if (gu8DigitalButtons & 0x08) buf->bKeyboard[kI++] = u8AirKeymap[1];
- if (gu8DigitalButtons & 0x10) buf->bKeyboard[kI++] = u8AirKeymap[2];
- if (gu8DigitalButtons & 0x20) buf->bKeyboard[kI++] = u8AirKeymap[3];
- if (gu8DigitalButtons & 0x40) buf->bKeyboard[kI++] = u8AirKeymap[4];
- if (gu8DigitalButtons & 0x80) buf->bKeyboard[kI++] = u8AirKeymap[5];
+ if (gu8DigitalButtons & DIGITAL_FN2_Msk) buf->bKeyboard[kI++] = HID_KEYBOARD_F1;
+ if (gu8DigitalButtons & DIGITAL_FN1_Msk) buf->bKeyboard[kI++] = HID_KEYBOARD_F2;
+ if (gu8DigitalButtons & 0x04) buf->bKeyboard[kI++] = u8AirKeymap[0];
+ if (gu8DigitalButtons & 0x08) buf->bKeyboard[kI++] = u8AirKeymap[1];
+ if (gu8DigitalButtons & 0x10) buf->bKeyboard[kI++] = u8AirKeymap[2];
+ if (gu8DigitalButtons & 0x20) buf->bKeyboard[kI++] = u8AirKeymap[3];
+ if (gu8DigitalButtons & 0x40) buf->bKeyboard[kI++] = u8AirKeymap[4];
+ if (gu8DigitalButtons & 0x80) buf->bKeyboard[kI++] = u8AirKeymap[5];
- for (int i = 0; i < 32; i++) {
- if (gu8GroundData[i] > u8GroundThreshold) buf->bKeyboard[kI++] = u8GroundKeymap[i];
- }
+ for (int i = 0; i < 32; i++) {
+ if (gu32PSoCDigital & (1 << i)) buf->bKeyboard[kI++] = u8GroundKeymap[i];
}
- USBD_SET_PAYLOAD_LEN(EP_HID_MISC_IN, sizeof *buf);
+ HID_MISC_SEND(buf);
+ u8LastButtons = gu8DigitalButtons;
+ u32LastSlider = gu32PSoCDigital;
+ return 1;
}
+static uint8_t _HID_Consumer_Tick(void) {
+ static uint16_t u16Last = 0;
+ if (u16Last == u16RequestedConsumerControl) return 0;
+ u16Last = u16RequestedConsumerControl;
-#define IO4_BUTTON_TEST (1 << 9)
-#define IO4_BUTTON_SERVICE (1 << 6)
-
-#define IO4_CMD_SET_COMM_TIMEOUT 0x01
-#define IO4_CMD_SET_SAMPLING_COUNT 0x02
-#define IO4_CMD_CLEAR_BOARD_STATUS 0x03
-#define IO4_CMD_SET_GENERAL_OUTPUT 0x04
-#define IO4_CMD_SET_PWM_OUTPUT 0x05
-#define IO4_CMD_SET_UNIQUE_OUTPUT 0x41
-#define IO4_CMD_UPDATE_FIRMWARE 0x85
-
-volatile uint8_t u8IO4SystemStatus = 0;
-volatile uint8_t u8IO4USBStatus = 0;
-volatile uint16_t u16IO4CommTimeout = 0;
-volatile uint8_t u8IO4SamplingCount = 0;
-
-static void _HID_IO4_Prepare(volatile uint8_t *pu8EpBuf) {
- io4_hid_in_t *buf = (io4_hid_in_t *)pu8EpBuf;
+ hid_consumer_report_t *buf = (hid_consumer_report_t *)HID_MISC_BUF;
memset(buf, 0, sizeof *buf);
- buf->bReportId = HID_REPORT_ID_IO4;
-
- // System buttons
- if (gu8DigitalButtons & 0x01) buf->wButtons[0] |= IO4_BUTTON_TEST;
- if (gu8DigitalButtons & 0x02) buf->wButtons[0] |= IO4_BUTTON_SERVICE;
- // Airs
- if (!(gu8DigitalButtons & 0x04)) buf->wButtons[0] |= 1 << 13;
- if (!(gu8DigitalButtons & 0x08)) buf->wButtons[1] |= 1 << 13;
- if (!(gu8DigitalButtons & 0x10)) buf->wButtons[0] |= 1 << 12;
- if (!(gu8DigitalButtons & 0x20)) buf->wButtons[1] |= 1 << 12;
- if (!(gu8DigitalButtons & 0x40)) buf->wButtons[0] |= 1 << 11;
- if (!(gu8DigitalButtons & 0x80)) buf->wButtons[1] |= 1 << 11;
-
- buf->bUsbStatus = u8IO4USBStatus;
- buf->bSystemStatus = u8IO4SystemStatus;
+ buf->bReportId = HID_REPORT_ID_CONSUMER_CONTROL;
+ buf->u16Control[0] = u16RequestedConsumerControl;
+ HID_MISC_SEND(buf);
+ return 1;
}
-static void _HID_IO4_Tick() {
- _HID_IO4_Prepare(HID_IO4_BUF);
- // We must send data every 8ms! None of that "only sending changed keys" stuff
- // Trigger a write
- gu8HIDIO4Ready = 0;
- USBD_SET_PAYLOAD_LEN(EP_HID_IO4_IN, sizeof(io4_hid_in_t));
-}
-static void _HID_Debug_Tick() {
- debug_hid_report_t *buf = (debug_hid_report_t *)HID_MISC_BUF;
- memset(buf, 0, sizeof *buf);
+static uint8_t _HID_Enter_Tick(void) {
+ // TODO: This isn't working, so we're using su8LastState for now instead
+ if (u32EnterPressStarted == 0xFFFFFFFF) return 0;
- static uint8_t bWhich = 0;
- if ((bWhich++) & 1) {
- buf->bReportId = HID_REPORT_ID_DEBUG_A;
- for (uint8_t i = 0; i < 32; i += 2) buf->wData[i / 2] = gu8GroundData[i];
+ static uint8_t su8LastState = 0;
+ uint8_t u8State = 0;
+
+ // There's an _incredibly_ small chance the user tapped the cell at exactly the ms (49 days in!)
+ // when the timer wrapped round to 0. This is too stupid to account for.
+ if (u32EnterPressStarted && (MS_SINCE(u32EnterPressStarted) < ENTER_HOLD_TIME)) {
+ u8State = 1;
} else {
- buf->bReportId = HID_REPORT_ID_DEBUG_B;
- for (uint8_t i = 1; i < 32; i += 2) buf->wData[i / 2] = gu8GroundData[i];
+ u8State = 0;
+ u32EnterPressStarted = 0xFFFFFFFF;
}
- USBD_SET_PAYLOAD_LEN(EP_HID_MISC_IN, sizeof *buf);
+
+ if (u8State == su8LastState) return 0;
+ su8LastState = u8State;
+
+ hid_enter_report_t *buf = (hid_enter_report_t *)HID_MISC_BUF;
+ memset(buf, 0, sizeof *buf);
+ buf->bReportId = HID_REPORT_ID_ENTER;
+ if (u8State) buf->u8Keyboard[0] = KEY_ENTER;
+
+ HID_MISC_SEND(buf);
+ return 1;
}
-static void _HID_Misc_Tick() {
+typedef enum {
+ TIMESLOT_KEYBOARD = 0,
+ TIMESLOT_CONSUMER,
+ TIMESLOT_ENTER,
+ _TIMESLOT_COUNT,
+} eTimeslot_t;
+static void _HID_Misc_Tick(void) {
static uint8_t sbLastEnableKeyboard = 0;
- if (gConfig.bEnableKeyboard) {
- sbLastEnableKeyboard = 1;
- _HID_Keyboard_Tick(1);
- } else if (sbLastEnableKeyboard) {
- // If we've just disabled the keyboard, make sure to send a packet with all keys released!
- sbLastEnableKeyboard = 0;
- _HID_Keyboard_Tick(0);
- }
- // TODO: gbEnableDebug (we'll need to use a toggle to alternate)
- gu8HIDMiscReady = 0;
+ // We have multiple things we're going to be sending over this HID endpoint, so we timeshare
+ // which reports are sent. If a particular report has nothing to report in its slot, the next
+ // report gets a chance instead.
+ static eTimeslot_t eTimeslot = 0;
+
+ uint8_t u8Tries = _TIMESLOT_COUNT;
+ while (u8Tries--) {
+ switch (eTimeslot++) {
+ case TIMESLOT_KEYBOARD:
+ if (gConfig.bEnableKeyboard) {
+ sbLastEnableKeyboard = 1;
+ if (_HID_Keyboard_Tick(0)) goto timeslot_used;
+ } else if (sbLastEnableKeyboard) {
+ // If we've just disabled the keyboard, make sure to send a packet with all keys
+ // released!
+ sbLastEnableKeyboard = 0;
+ if (_HID_Keyboard_Tick(1)) goto timeslot_used;
+ }
+ break;
+
+ case TIMESLOT_CONSUMER:
+ if (_HID_Consumer_Tick()) goto timeslot_used;
+ break;
+
+ case TIMESLOT_ENTER:
+ if (_HID_Enter_Tick()) goto timeslot_used;
+ break;
+
+ default:
+ break;
+ }
+ if (eTimeslot > _TIMESLOT_COUNT) eTimeslot = 0;
+ }
+timeslot_used:;
+ ;
}
-void USBD_HID_PrepareReport() {
- if (gu8HIDIO4Ready) _HID_IO4_Tick();
+void USBD_HID_PrepareReport(void) {
+ if (gu8HIDIO4Ready) IO4_HID_Tick();
if (gu8HIDMiscReady) _HID_Misc_Tick();
}
static uint8_t sIO4InBuffer[sizeof(io4_hid_in_t)] = { 0 };
uint8_t *USBD_HID_GetReport(uint8_t u8ReportId, uint32_t *pu32Size) {
switch (u8ReportId) {
case HID_REPORT_ID_IO4:
- if (!gConfig.bEnableIO4) return NULL;
- _HID_IO4_Prepare(sIO4InBuffer);
+ IO4_HID_Prepare(sIO4InBuffer);
*pu32Size = sizeof sIO4InBuffer;
return sIO4InBuffer;
default:
@@ -148,51 +193,7 @@ uint8_t *USBD_HID_GetReport(uint8_t u8ReportId, uint32_t *pu32Size) {
void USBD_HID_SetReport(volatile uint8_t *pu8EpBuf, uint32_t u32Size) {
// TODO: is pu8EpBuf[0] the report ID?
// We need to switch on that report ID so we know what we're doing!
- if (!gConfig.bEnableIO4) return;
if (u32Size < 2) return;
- switch (pu8EpBuf[1]) {
- case IO4_CMD_SET_COMM_TIMEOUT:
- if (u32Size >= 2 + 1) {
- u16IO4CommTimeout = (uint16_t)pu8EpBuf[2] * 200;
- u8IO4SystemStatus |= 0x10;
-
- gu8HIDIO4Ready = 1;
- _HID_IO4_Tick();
- }
- break;
- case IO4_CMD_SET_SAMPLING_COUNT:
- if (u32Size >= 2 + 1) {
- u8IO4SamplingCount = pu8EpBuf[2];
- u8IO4SystemStatus |= 0x20;
-
- gu8HIDIO4Ready = 1;
- _HID_IO4_Tick();
- }
- break;
- case IO4_CMD_CLEAR_BOARD_STATUS:
- u8IO4SystemStatus &= 0x0F;
- u8IO4USBStatus &= 0x04;
-
- gu8HIDIO4Ready = 1;
- _HID_IO4_Tick();
- break;
- case IO4_CMD_SET_GENERAL_OUTPUT:
- if (u32Size >= 2 + 3) {
- // 20 bits of data for GPO (+4 of padding)
- }
- break;
- case IO4_CMD_SET_PWM_OUTPUT:
- if (u32Size >= 2 + 0) {
- // 0 bytes of data for PWM duty cycles (IO4 has no PWM!)
- }
- break;
- case IO4_CMD_SET_UNIQUE_OUTPUT:
- if (u32Size >= 2 + 62) {
- // 62 bytes of unique output data
- }
- break;
- case IO4_CMD_UPDATE_FIRMWARE:
- break;
- }
+ IO4_Control(pu8EpBuf[1], u32Size - 2, &pu8EpBuf[2]);
}
diff --git a/src/hid_def.h b/src/hid_def.h
new file mode 100644
index 0000000..0aefc4c
--- /dev/null
+++ b/src/hid_def.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include
+
+#include "_compiler.h"
+
+// Triggers to start sending data
+extern uint8_t volatile gu8HIDIO4Ready;
+extern uint8_t volatile gu8HIDMiscReady;
+
+extern uint16_t u16RequestedConsumerControl;
+extern uint32_t u32EnterPressStarted;
+
+enum {
+ HID_REPORT_ID_IO4 = 1,
+ HID_REPORT_ID_KEYBOARD,
+ HID_REPORT_ID_CONSUMER_CONTROL,
+ HID_REPORT_ID_ENTER,
+ HID_REPORT_ID_IO4_CMD = 16,
+};
+
+#define NUM_FN 2
+#define NUM_AIR 6
+#define NUM_GROUND 32
+
+typedef struct __packed {
+ uint8_t bReportId;
+ uint8_t bKeyboard[NUM_FN + NUM_AIR + NUM_GROUND];
+} hid_kbd_report_t;
+
+typedef struct __packed {
+ uint8_t bReportId;
+ uint16_t u16Control[2];
+} hid_consumer_report_t;
+
+typedef struct __packed {
+ uint8_t bReportId;
+ uint8_t u8Keyboard[1];
+} hid_enter_report_t;
+
+typedef struct __packed {
+ uint8_t bReportId;
+ uint16_t wADC[8];
+ uint16_t wRotary[4];
+ uint16_t wCoin[2];
+ uint16_t wButtons[2];
+ uint8_t bSystemStatus;
+ uint8_t bUsbStatus;
+ uint8_t bUnique[29];
+} io4_hid_in_t;
+
+typedef struct __packed {
+ uint8_t bReportId;
+ uint8_t bCmd;
+ uint8_t bData[62];
+} io4_hid_out_t;
+
+// void HID_Tick();
+void USBD_HID_PrepareReport();
+uint8_t *USBD_HID_GetReport(uint8_t u8ReportId, uint32_t *pu32Size);
+void USBD_HID_SetReport(volatile uint8_t *pu8EpBuf, uint32_t u32Size);
diff --git a/src/io4.c b/src/io4.c
new file mode 100644
index 0000000..53a68b0
--- /dev/null
+++ b/src/io4.c
@@ -0,0 +1,156 @@
+#include "tasoller.h"
+
+#define HID_IO4_BUF ((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_HID_IO4_IN)))
+
+volatile uint8_t u8IO4SystemStatus = 0;
+volatile uint8_t u8IO4USBStatus = 0;
+volatile uint16_t u16IO4CommTimeout = 0;
+volatile uint8_t u8IO4SamplingCount = 0;
+
+volatile uint16_t u16IO4Coins[2];
+
+volatile uint8_t gu8IO4PWMScale;
+volatile uint8_t gu8IO4PWMOutput[6];
+volatile uint8_t gu8IO4DigitalOutput[3]; // 20 bits
+
+uint16_t gu16IO4ForceButtons = 0;
+void IO4_HID_Prepare(volatile uint8_t *pu8EpBuf) {
+ io4_hid_in_t *buf = (io4_hid_in_t *)pu8EpBuf;
+
+ memset(buf, 0, sizeof *buf);
+ buf->bReportId = HID_REPORT_ID_IO4;
+
+ // System buttons
+ buf->wButtons[0] = gu16IO4ForceButtons;
+ // if (gu8DigitalButtons & DIGITAL_FN2_Msk) buf->wButtons[0] |= IO4_BUTTON_TEST;
+ // if (gu8DigitalButtons & DIGITAL_FN1_Msk) buf->wButtons[0] |= IO4_BUTTON_SERVICE;
+ // Airs
+ if (!(gu8DigitalButtons & 0x04)) buf->wButtons[0] |= 1 << 13;
+ if (!(gu8DigitalButtons & 0x08)) buf->wButtons[1] |= 1 << 13;
+ if (!(gu8DigitalButtons & 0x10)) buf->wButtons[0] |= 1 << 12;
+ if (!(gu8DigitalButtons & 0x20)) buf->wButtons[1] |= 1 << 12;
+ if (!(gu8DigitalButtons & 0x40)) buf->wButtons[0] |= 1 << 11;
+ if (!(gu8DigitalButtons & 0x80)) buf->wButtons[1] |= 1 << 11;
+
+ buf->bUsbStatus = u8IO4USBStatus;
+ buf->bSystemStatus = u8IO4SystemStatus;
+
+ // Pos-edge trigger
+ static uint8_t su8LastDigitalButtons = 0;
+ if ((gu8DigitalButtons & ~su8LastDigitalButtons) & DIGITAL_FN1_Msk) {
+ if (!IO4_GetCoinBlocker()) {
+ u16IO4Coins[0]++;
+ }
+ }
+ su8LastDigitalButtons = gu8DigitalButtons;
+
+ buf->wCoin[0] = BYTESWAP_U16(u16IO4Coins[0]);
+ buf->wCoin[1] = BYTESWAP_U16(u16IO4Coins[1]);
+}
+
+void IO4_HID_Tick(void) {
+ IO4_HID_Prepare(HID_IO4_BUF);
+
+ // We must send data every 8ms! None of that "only sending changed keys" stuff
+ // Trigger a write
+ gu8HIDIO4Ready = 0;
+ USBD_SET_PAYLOAD_LEN(EP_HID_IO4_IN, sizeof(io4_hid_in_t));
+}
+
+void IO4_Control(uint8_t u8Cmd, uint32_t u32Size, volatile uint8_t *pu8Buffer) {
+ /**
+ * Setup sequence:
+ *
+ * - IO4_CMD_CLEAR_BOARD_STATUS
+ * - IO4_CMD_SET_COMM_TIMEOUT (00)
+ * - IO4_CMD_SET_SAMPLING_COUNT (06)
+ * - IO4_CMD_SET_GENERAL_OUTPUT (00 00 00)
+ * - IO4_CMD_SET_UNIQUE_OUTPUT (38 00 00 00 ..)
+ */
+
+ switch (u8Cmd) {
+ case IO4_CMD_SET_COMM_TIMEOUT:
+ if (u32Size >= 1) {
+ u16IO4CommTimeout = (uint16_t)pu8Buffer[0] * 200;
+ u8IO4SystemStatus |= 0x10;
+
+ gu8HIDIO4Ready = 1;
+ IO4_HID_Tick();
+ }
+ break;
+ case IO4_CMD_SET_SAMPLING_COUNT:
+ if (u32Size >= 1) {
+ u8IO4SamplingCount = pu8Buffer[0];
+ u8IO4SystemStatus |= 0x20;
+
+ gu8HIDIO4Ready = 1;
+ IO4_HID_Tick();
+ }
+ break;
+ case IO4_CMD_CLEAR_BOARD_STATUS:
+ u8IO4SystemStatus &= 0x0F;
+ u8IO4USBStatus &= 0x04;
+
+ gu8HIDIO4Ready = 1;
+ IO4_HID_Tick();
+ break;
+ case IO4_CMD_SET_GENERAL_OUTPUT:
+ // 20 bits of data for GPO (+4 bits of padding)
+ if (u32Size >= 3) {
+ gu8IO4DigitalOutput[0] = pu8Buffer[0];
+ gu8IO4DigitalOutput[1] = pu8Buffer[1];
+ gu8IO4DigitalOutput[2] = pu8Buffer[2];
+ }
+ break;
+ case IO4_CMD_SET_PWM_OUTPUT:
+ if (u32Size >= 0) {
+ // 0 bytes of data for PWM duty cycles (IO4 has no PWM!)
+ }
+ break;
+ case IO4_CMD_SET_UNIQUE_OUTPUT:
+ // 62 bytes of unique output data
+ if (u32Size >= 62) {
+ // [0]: Enable mask (bit 7=PWM1, 2=PWM6, 0~1 unused)
+ // [1]: Brightness scaler (1~256, with 0=256)
+ // [2]: PWM1 brightness (pin CN3.55)
+ // [3]: PWM2 brightness (pin CN3.56)
+ // [4]: PWM3 brightness (pin CN9.5 )
+ // [5]: PWM4 brightness (pin CN9.6 )
+ // [6]: PWM5 brightness (pin CN9.9 )
+ // [7]: PWM6 brightness (pin CN9.10)
+
+ // For maimai DX:
+ // [0]: 11111100 (Enable PWM1~6)
+ // [1]: 00
+ // [2]: 1P Billboard Red
+ // [3]: 2P Billboard Red
+ // [4]: 1P Billboard Green
+ // [5]: 2P Billboard Green
+ // [6]: 1P Billboard Blue
+ // [7]: 2P Billboard Blue
+ //
+ // For chunithm:
+ // [0]: 00111000 (Enable PWM3~5)
+ // [1]: 00
+ // [2]: Unused
+ // [3]: Unused
+ // [4]: Light gate Blue
+ // [5]: Light gate Red
+ // [6]: Light gate Green
+ // [7]: Unused
+
+ uint8_t u8Mask = pu8Buffer[0];
+ if (pu8Buffer[1] == 0)
+ gu8IO4PWMScale = 255;
+ else
+ gu8IO4PWMScale = pu8Buffer[1] - 1;
+
+ for (uint8_t i = 0; i < 6; i++) {
+ gu8IO4PWMOutput[i] = (u8Mask & (1 << (7 - i))) ? pu8Buffer[2 + i] : 0;
+ }
+ }
+ break;
+ case IO4_CMD_UPDATE_FIRMWARE:
+ break;
+ }
+}
diff --git a/src/io4.h b/src/io4.h
new file mode 100644
index 0000000..26a3e25
--- /dev/null
+++ b/src/io4.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include
+
+#define IO4_BUTTON_TEST (1 << 9)
+#define IO4_BUTTON_SERVICE (1 << 6)
+
+#define IO4_CMD_SET_COMM_TIMEOUT 0x01
+#define IO4_CMD_SET_SAMPLING_COUNT 0x02
+#define IO4_CMD_CLEAR_BOARD_STATUS 0x03
+#define IO4_CMD_SET_GENERAL_OUTPUT 0x04
+#define IO4_CMD_SET_PWM_OUTPUT 0x05
+#define IO4_CMD_SET_UNIQUE_OUTPUT 0x41
+#define IO4_CMD_84 0x84
+#define IO4_CMD_UPDATE_FIRMWARE 0x85
+#define IO4_CMD_88 0x88 // data[0] = D9
+
+extern volatile uint8_t gu8IO4PWMScale;
+extern volatile uint8_t gu8IO4PWMOutput[6];
+extern volatile uint8_t gu8IO4DigitalOutput[3];
+
+extern uint16_t gu16IO4ForceButtons;
+
+static inline uint8_t IO4_GetCoinBlocker(void) {
+ // Chunithm's coin blocker is wired to OUT1
+ return (gu8IO4DigitalOutput[0] & 0x80) ? 0 : 1;
+}
+
+void IO4_HID_Prepare(volatile uint8_t *pu8EpBuf);
+void IO4_HID_Tick(void);
+void IO4_Control(uint8_t u8Cmd, uint32_t u32Size, volatile uint8_t *pu8Buffer);
diff --git a/src/led.c b/src/led.c
index 7e119a0..cab5f8a 100644
--- a/src/led.c
+++ b/src/led.c
@@ -1,61 +1,137 @@
#include "tasoller.h"
-hsv_t gaControlledIntLedData[LED_NUM_GROUND] = { 0 };
+hsv_t gaControlledIntLedData[LED_NUM_GROUND_LOGICAL] = { 0 };
uint8_t gbLedDataIsControlledInt = 0;
-uint8_t gu8aControlledExtLedData[32 * 3];
+rgb_t gaControlledExtLedData[32];
uint8_t gbLedDataIsControlledExt = 0;
+uint8_t gbLedIsCustom = 0;
-volatile uint8_t gu8LEDTx[LED_Tx_BUFFER];
-static void (*s_I2C1HandlerFn)(uint32_t u32Status) = NULL;
+volatile uint8_t gu8LEDTx[LED_PACKET_MAX_SIZE];
-volatile static uint8_t su8LedTxDataLock = 0;
+typedef enum : uint8_t {
+ I2C_SLAVE_TX_REPEAT_START_STOP = 0xA0,
+ I2C_SLAVE_TX_ADDR_ACK = 0xA8,
+ I2C_SLAVE_TX_ARBITRATION_LOST = 0xB0,
+ I2C_SLAVE_TX_DATA_ACK = 0xB8,
+ I2C_SLAVE_TX_DATA_NACK = 0xC0,
+ I2C_SLAVE_TX_LAST_DATA_ACK = 0xC8,
+ I2C_SLAVE_RX_ADDR_ACK = 0x60,
+ I2C_SLAVE_RX_ARBITRATION_LOST = 0x68,
+ I2C_SLAVE_RX_DATA_ACK = 0x80,
+ I2C_SLAVE_RX_DATA_NACK = 0x88,
+} I2C_Status_Slave;
-// Helper definitions
-#define SLAVE_RX_ADDR_ACK 0x60
-#define SLAVE_RX_ACK 0x80
-#define I2C_SLAVE_RX_NACK 0x88
-#define I2C_SLAVE_TX_REPEAT_START_STOP 0xA0
-#define SLAVE_TX_ACK 0xA8
-#define I2C_SLAVE_TX_NACK 0xC0
+volatile uint8_t* gpu8I2CRx = NULL;
+volatile uint16_t u16I2CRxIndex = 0;
+void I2C1_SlaveTx(I2C_Status_Slave eStatus) {
+ if (!eStatus) {
+ // Something went very wrong; restart the I2C controller
+ I2C_Close(I2C1);
+ LED_I2C1_Init();
+ return;
+ }
+ static uint8_t u8Cmd = 0;
+ static uint16_t su16I2CReadAddr = 0;
+
+ /**
+ * Bulk data receive request:
+ * (B0)Rx: START+SLA+W
+ * (B1)Tx: ACK
+ * (B2)Rx: [u8Cmd]
+ * (B3)Tx: ACK
+ * (B4)Rx: (Repeat START)+SLA+R
+ * (B5)Tx: ACK
+ * (B6)Rx: ACK
+ * (B7)Tx: [u8Data[i]] |
+ * (B8)Rx: ACK | Looped until Rx:NACK
+ * Rx: STOP
+ *
+ * Single data receive request:
+ * (S0)Rx: START+SLA+W
+ * (S1)Tx: ACK
+ * (S2)Rx: [u8Cmd]
+ * (S3)Tx: ACK
+ * Rx: STOP
+ * ---
+ * (S4)Rx: START+SLA+R
+ * (S5)Tx: ACK
+ */
+ switch (eStatus) {
+ // === Receive address and command ===
+ case I2C_SLAVE_RX_ADDR_ACK: // (B0,S0)
+ I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA); // (B1,S1)
+ break;
+ case I2C_SLAVE_RX_DATA_ACK: // (B2,S2)
+ uint8_t u8Data = I2C_GET_DATA(I2C1);
+ if (u16I2CRxIndex == 0) {
+ u8Cmd = u8Data;
+ switch (u8Cmd) {
+ case LED_I2C_REG_PACKET:
+ // The master is requesting a read-out of all the data we have in our
+ // buffer.
+ su16I2CReadAddr = 0;
+ break;
+ default:
+ // If we don't recognise this command, treat it as a register read.
+ // (Back-compat with stock LED firmware)
+ su16I2CReadAddr = u8Cmd;
+ break;
+ }
+ u16I2CRxIndex++;
+ } else {
+ // TODO: Currently we don't expose u8Cmd anywhere
+ if (gpu8I2CRx != NULL) {
+ gpu8I2CRx[u16I2CRxIndex - 1] = u8Data;
+ // TODO: Have some bounds checking, and NACK an out of bounds write
+ }
+ u16I2CRxIndex++;
+ }
+
+ I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA); // (B3,S3)
+ break;
+ case I2C_SLAVE_RX_DATA_NACK:
+ I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
+ u16I2CRxIndex = 0;
+ break;
+ case I2C_SLAVE_TX_REPEAT_START_STOP: // (B4)
+ I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA); // (B5)
+ u16I2CRxIndex = 0;
+ break;
+
+ // === Transmit our data ===
+ case I2C_SLAVE_TX_ADDR_ACK: // (B6)
+ case I2C_SLAVE_TX_DATA_ACK: // We got an ACK, and need to continue
+ I2C_SET_DATA(I2C1, gu8LEDTx[su16I2CReadAddr++]); // (B7)
+ I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
+ break;
+ case I2C_SLAVE_TX_LAST_DATA_ACK: // We got an ACK, but it's time to stop
+ I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI);
+ u16I2CRxIndex = 0;
+ break;
+ case I2C_SLAVE_TX_DATA_NACK: // We got a NACK; master has read enough data
+ I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
+ u16I2CRxIndex = 0;
+ break;
+
+ // === Error cases ===
+ case I2C_SLAVE_RX_ARBITRATION_LOST: // SLA+W
+ case I2C_SLAVE_TX_ARBITRATION_LOST: // SLA+R
+ I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
+ u16I2CRxIndex = 0;
+ break;
+ }
+}
void I2C1_IRQHandler(void) {
if (I2C_GET_TIMEOUT_FLAG(I2C1)) {
I2C_ClearTimeoutFlag(I2C1);
} else {
- if (s_I2C1HandlerFn != NULL) (s_I2C1HandlerFn)(I2C1->I2CSTATUS);
- }
-}
-
-void I2C1_SlaveTx(uint32_t u32Status) {
- static uint8_t su8I2CReadAddr = 0;
-
- switch (u32Status) {
- case SLAVE_RX_ACK:
- su8I2CReadAddr = I2C1->I2CDAT;
- su8LedTxDataLock = 1;
- I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
- break;
- case SLAVE_TX_ACK:
- I2C_SET_DATA(I2C1, gu8LEDTx[su8I2CReadAddr]);
- I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
- break;
-
- case SLAVE_RX_ADDR_ACK:
- case I2C_SLAVE_TX_NACK:
- case I2C_SLAVE_RX_NACK:
- case I2C_SLAVE_TX_REPEAT_START_STOP:
- I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
- break;
-
- default:
- // Hmm?
- I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
- break;
+ I2C1_SlaveTx(I2C1->I2CSTATUS);
}
}
void LED_I2C1_Init(void) {
- I2C_Open(I2C1, 100000);
+ I2C_Open(I2C1, 400 kHz);
I2C_SetSlaveAddr(I2C1, 0, 0x18, 0);
I2C_SetSlaveAddr(I2C1, 1, 0x30, 0);
I2C_SetSlaveAddr(I2C1, 2, 0x55, 0);
@@ -69,344 +145,118 @@ void LED_I2C1_Init(void) {
// I2C1 enter no address SLV mode
I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
-
- s_I2C1HandlerFn = I2C1_SlaveTx;
}
-// static inline void LEDTxLock(void) {
-// gu8LEDTx[0] = 0;
-// }
-// static inline void LEDTxCommit(uint8_t u8Command, uint8_t u8NExpected) {
-// gu8LEDTx[0] = u8Command;
-// }
+static const uint8_t _LED_GroundBrightness(void) {
+ if (gbLedDataIsControlledInt) return gConfig.u8LedGroundBrightness;
+ if (g_u8UsbState == USB_STATE_SUSPEND && gu32NowMs > 5000) return 0;
+ if (gbLedDataIsControlledExt) {
+ // The game is going to tell us how bright it wants the LEDs
+ // For chunithm, that's 40/63 = 63.5% brightness.
+ // TODO: Do we actually want to do this? Chunithm has no way for operators to change it
+ // TODO: This won't be reflected in gu8LEDTx[1] with our custom firmware
-/**
- * @brief Convert from RGB to HSV
- *
- * @param pu8aRGB Destination 3-tuple to receive RGB values
- * @param u16H Hue, ranging 0~LED_HUE_MAX
- * @param u8S Saturation, ranging 0~255
- * @param u8V Value, ranging 0~255
- */
-void HsvToRgb(uint8_t* pu8aRGB, uint16_t u16H, uint8_t u8S, uint8_t u8V) {
- if (u8S == 0) {
- pu8aRGB[0] = u8V;
- pu8aRGB[1] = u8V;
- pu8aRGB[2] = u8V;
- return;
+ // The real range for this value is 0~63
+ // Chunithm will always be sending a constant value of 40 though, as far as I'm aware.
+ // Because of that, if we performed the scaling we'd be getting 40/63 = 63.5% brightness.
+ // Instead, we're only going to scale on the off-chance that the brightness is actually
+ // changed and it goes below 40.
+ // During startup the brightness is set to 0, but all LEDs are zeroed too so... :D
+ if (gu8GameBrightness < 40)
+ return ((uint16_t)gConfig.u8LedGroundBrightness * (uint16_t)gu8GameBrightness) / 63;
+ return gConfig.u8LedGroundBrightness;
}
-
- uint8_t region = u16H / (LED_HUE_MAX / 6);
- uint8_t remainder = (u16H - (region * (LED_HUE_MAX / 6))) * (255 / (LED_HUE_MAX / 6));
-
- uint8_t p = (u8V * (255 - u8S)) >> 8;
- uint8_t q = (u8V * (255 - ((u8S * remainder) >> 8))) >> 8;
- uint8_t t = (u8V * (255 - ((u8S * (255 - remainder)) >> 8))) >> 8;
-
- switch (region) {
- case 0:
- pu8aRGB[0] = u8V;
- pu8aRGB[1] = t;
- pu8aRGB[2] = p;
- break;
- case 1:
- pu8aRGB[0] = q;
- pu8aRGB[1] = u8V;
- pu8aRGB[2] = p;
- break;
- case 2:
- pu8aRGB[0] = p;
- pu8aRGB[1] = u8V;
- pu8aRGB[2] = t;
- break;
- case 3:
- pu8aRGB[0] = p;
- pu8aRGB[1] = q;
- pu8aRGB[2] = u8V;
- break;
- case 4:
- pu8aRGB[0] = t;
- pu8aRGB[1] = p;
- pu8aRGB[2] = u8V;
- break;
- default:
- pu8aRGB[0] = u8V;
- pu8aRGB[1] = p;
- pu8aRGB[2] = q;
- break;
- }
-
- return;
+ return gConfig.u8LedGroundBrightness;
+}
+static const uint8_t _LED_WingBrightness(void) {
+ if (gbLedDataIsControlledInt) return gConfig.u8LedWingBrightness;
+ if (g_u8UsbState == USB_STATE_SUSPEND && gu32NowMs > 5000) return 0;
+ if (gbLedDataIsControlledExt)
+ return ((uint16_t)gConfig.u8LedGroundBrightness * (uint16_t)gu8IO4PWMScale) / 255;
+ return gConfig.u8LedWingBrightness;
}
-// 0x00: Normal operation (all other values ignore ground data)
-// 0x01: [Stock] Uses colours. Bar 1 full (from right)
-// 0x02: [Stock] Uses colours. Bar 2 full (from right)
-// 0x03: [Stock] Uses colours. Bar 3 full (from right)
-// 0x04: [Stock] Uses colours. Bar 4 full (from right)
-// 0x1X: [Stock] All white with black gaps. X bars black (from right)
-// 0x1X: [CFW] Rainbow with black gaps. X bars black (from right)
-// 0x20: [CFW] Flashes three times
-// 0x80: [Stock] Flashes three times
-static uint8_t su8LedSpecial = 0x05;
-
-// 0: Separator bar every 4 (4 sections)
-// 1: Separator bar every 2 (8 sections)
-// 2: Separator bar every 1 (16 sections)
-// 3: No separator bars
-// 4~7: LEDs off
-// For some reason this value can be |8, even though firmware suggests otherwise
-static uint8_t su8LedSeparators = 1;
-
-// 0: Invalid, but functions as 1
-// 1: 32-key mode
-// 2: 16-key mode (same as 32key mode)
-// 3: 8-key mode (bars light in pairs)
-// 4: 4-key mode (bars light in quads)
-static uint8_t su8LedNKey = 1;
-
-// 0x40: Turns off ground LEDs
-// 0x80: Turns off wing LEDs
-static uint8_t su8LedOff = 0;
-
-// 0x8X: Separator 1~(X+1) lit (ie X ranges from 0~E; F is the same as E)
-static uint8_t su8LedCfwRainbow = 0x8F;
-
-void LED_WriteBasicGrounds(void) {
- gu8LEDTx[0] = LED_CMD_BASIC;
-
- // 32 bits of grounds
- // (01,02)=key1, (04,08)=key2 (10,20)=key3, (40,80)=key4
- gu8LEDTx[1] = 0;
- gu8LEDTx[2] = 0;
- gu8LEDTx[3] = 0;
- gu8LEDTx[4] = 0;
- for (uint8_t i = 0; i < 4; i++) {
- for (uint8_t j = 0; j < 8; j++) {
- if (gu8GroundData[i * 8 + j] > PSoC_INTERNAL_DIGITAL_TH) gu8LEDTx[i + 1] |= (1 << j);
- }
- }
-
-#ifdef LED_FIRMWARE_CFW
- gu8LEDTx[5] = 0; // Wing fill
- for (uint8_t i = 0; i < 6; i++)
- if (gu8DigitalButtons & (1 << (i + 2))) gu8LEDTx[5] |= 1 << i;
- gu8LEDTx[6] = su8LedCfwRainbow;
- gu8LEDTx[7] = 0; // Unused
-#else
- // Wings
- gu8LEDTx[5] = 0; // Wing fill
- for (uint8_t i = 0; i < 6; i++)
- if (gu8DigitalButtons & (1 << (i + 2))) gu8LEDTx[5] |= 1 << i;
- gu8LEDTx[6] = gConfig.u16HueWingLeft / LED_HUE_SCALE; // Hue left (default 330)
- gu8LEDTx[7] = gConfig.u16HueWingRight / LED_HUE_SCALE; // Hue right (default 180)
-#endif
-
- // Unused in CFW
- gu8LEDTx[8] = gConfig.u16HueGround / LED_HUE_SCALE; // Hue ground inactive (default 45)
- gu8LEDTx[9] = gConfig.u16HueGroundActive / LED_HUE_SCALE; // Hue ground active (default 330)
-
- // In CFW only su8LedOff is respected
- gu8LEDTx[10] = (su8LedSeparators << 4) | su8LedOff | su8LedNKey;
- gu8LEDTx[11] = su8LedSpecial;
+static inline void _LED_SetPower(void) {
+ PIN_LED_GROUND_PWR = _LED_GroundBrightness() ? 1 : 0;
+ PIN_LED_WING_PWR = _LED_WingBrightness() ? 1 : 0;
}
-static const uint8_t su8aWingSensors[LED_NUM_LEFT] = {
- DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, //
- DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, //
- DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, //
- DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, //
- DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, //
- DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, //
-};
+void LED_Write(void) {
+ Pled_rx_custom_rgb pTxRGB = (Pled_rx_custom_rgb)gu8LEDTx;
+ Pled_rx_custom_hsv pTxHSV = (Pled_rx_custom_hsv)gu8LEDTx;
+ Pled_rx_custom_mixed pTxMix = (Pled_rx_custom_mixed)gu8LEDTx;
+ // We might not use all of these (we aren't using RGB at the moment!) but they're just
+ // convenience aliases.
+ (void)pTxRGB;
+ (void)pTxHSV;
+ (void)pTxMix;
-#define SATURATION_ACTIVE 255
-#define SATURATION_INACTIVE 240
-#define VALUE_ACTIVE (gConfig.u8LedWingBrightness)
-#define VALUE_INACTIVE (gConfig.u8LedWingBrightness / 2)
-
-static void LED_OffGround(void) {
- memset((uint8_t*)&gu8LEDTx[LED_DATA_OFFSET], 0, LED_NUM_GROUND * 3);
-}
-static void LED_OffWings(void) {
- memset((uint8_t*)&gu8LEDTx[LED_DATA_OFFSET + LED_NUM_GROUND * 3], 0,
- (LED_NUM_LEFT + LED_NUM_RIGHT) * 3);
-}
-static void LED_AirWings(void) {
- uint8_t u8aRgbActive[3];
- uint8_t u8aRgbInactive[3];
-
- uint8_t j, i = LED_NUM_GROUND;
-
- // Left wing
- HsvToRgb(u8aRgbActive, gConfig.u16HueWingLeft, SATURATION_ACTIVE, VALUE_ACTIVE);
- HsvToRgb(u8aRgbInactive, gConfig.u16HueWingLeft, SATURATION_INACTIVE, VALUE_INACTIVE);
- for (j = 0; i < LED_NUM_GROUND + LED_NUM_LEFT; i++, j++) {
- // GRB
- if (gu8DigitalButtons & su8aWingSensors[LED_NUM_LEFT - j - 1]) {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRgbActive[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRgbActive[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRgbActive[2];
- } else {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRgbInactive[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRgbInactive[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRgbInactive[2];
- }
- }
-
- // Right wing
- HsvToRgb(u8aRgbActive, gConfig.u16HueWingRight, SATURATION_ACTIVE, VALUE_ACTIVE);
- HsvToRgb(u8aRgbInactive, gConfig.u16HueWingRight, SATURATION_INACTIVE, VALUE_INACTIVE);
- for (j = 0; i < LED_NUM_GROUND + LED_NUM_LEFT + LED_NUM_RIGHT; i++, j++) {
- // GRB
- if (gu8DigitalButtons & su8aWingSensors[j]) {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRgbActive[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRgbActive[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRgbActive[2];
- } else {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRgbInactive[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRgbInactive[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRgbInactive[2];
- }
- }
-}
-
-static uint8_t LED_ScaleU8(uint8_t u8V, uint8_t u8Scale) {
- return ((uint16_t)u8V * (uint16_t)u8Scale) / 255;
-}
-
-static void LED_GroundRainbow(void) {
- uint8_t u8aRGB[3];
-
- // 5 ticks * 360 hue = 1800 calls for one cycle (1.8s)
- static uint16_t u16Hue = 0;
- static uint8_t u8Ticker = 0;
- if (++u8Ticker == 5) {
- u8Ticker = 0;
- u16Hue++;
- if (u16Hue == LED_HUE_MAX) u16Hue = 0;
- }
-
- /**
- * There are 48 LEDs for ground, but we only send 31 values
- * They're mapped to the LEDs as follows:
- * 00a11b22c33d44f55g66h77i...
- *
- * That is, we can't split-colour a key :P
- */
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- uint8_t v = 190;
- uint8_t h = 0;
- uint8_t nCell = i >> 1;
- if (i % 2 == 0) {
- if (gu16PSoCDigital & (1 << nCell)) {
- v = 255;
- h = LED_HUE_MAX / 2;
- }
- } else if (nCell % 4 == 3) {
- h = LED_HUE_MAX / 2;
- }
-
- // GRB
- HsvToRgb(u8aRGB, (u16Hue + h + (i * (LED_HUE_MAX / LED_NUM_GROUND))) % LED_HUE_MAX, v,
- LED_ScaleU8(v - 63, gConfig.u8LedGroundBrightness));
-
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRGB[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRGB[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRGB[2];
- }
-}
-static void LED_GroundStatic(void) {
- uint8_t u8aGround[3];
- uint8_t u8aGroundActive[3];
-
- HsvToRgb(u8aGround, gConfig.u16HueGround, 255, gConfig.u8LedGroundBrightness);
- HsvToRgb(u8aGroundActive, gConfig.u16HueGroundActive, 255, gConfig.u8LedGroundBrightness);
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- const uint8_t nCell = i >> 1;
- if (i % 2 == 0) {
- // This is a cell. Light it according to the touch input
- if (gu16PSoCDigital & (1 << nCell)) {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGroundActive[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGroundActive[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGroundActive[2];
- } else {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGround[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGround[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGround[2];
- }
- } else if (nCell % 4 == 3) {
- // This is a separating divider. Light it with the active colour
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGroundActive[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGroundActive[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGroundActive[2];
- } else {
- // This is a non-separating divider. Light it based on the two cells either side
- if (gu16PSoCDigital & (1 << nCell) && gu16PSoCDigital & (1 << (nCell + 1))) {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGroundActive[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGroundActive[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGroundActive[2];
- } else {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGround[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGround[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGround[2];
- }
- }
- }
-}
-
-void LED_WriteRGB(void) {
- gu8LEDTx[0] = LED_CMD_RGB_FULL;
-
-#ifdef LED_FIRMWARE_CFW
- // "CFW" added this byte
- gu8LEDTx[1] = su8LedSpecial | su8LedOff;
-#endif
-
- // Even when grounds are disabled, internal control overrides that
+ // If we're internally controlled, data will be HSV
if (gbLedDataIsControlledInt) {
- PIN_LED_GROUND_PWR = 1;
+ pTxHSV->u8Cmd = LED_CMD_CUSTOM_HSV;
+ pTxHSV->u8GroundBrightness = _LED_GroundBrightness();
+ pTxHSV->u8WingBrightness = _LED_WingBrightness();
+ _LED_SetPower();
- uint8_t u8aRGB[3];
- // Convert from HSV to GRB
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- HsvToRgb(u8aRGB, gaControlledIntLedData[LED_NUM_GROUND - i - 1].u16H,
- gaControlledIntLedData[LED_NUM_GROUND - i - 1].u8S,
- gaControlledIntLedData[LED_NUM_GROUND - i - 1].u8V);
+ LED_Ground_Internal_HSV(pTxHSV->aGround);
+ LED_Wings_Reactive_HSV(&pTxHSV->Wings);
+ } else if (gbLedDataIsControlledExt) {
+ // RGB control from the game
+ pTxRGB->u8Cmd = LED_CMD_CUSTOM_RGB;
+ pTxRGB->u8GroundBrightness = _LED_GroundBrightness();
+ pTxRGB->u8WingBrightness = _LED_WingBrightness();
+ _LED_SetPower();
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRGB[1];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRGB[0];
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRGB[2];
- }
- } else if (gConfig.u8LedGroundBrightness) {
- PIN_LED_GROUND_PWR = 1;
+ LED_Ground_Controlled_RGB(pTxRGB->aGround);
+ LED_Wings_Controlled_RGB(&pTxRGB->Wings);
+ } else {
+ // User-set coloring scheme
+ pTxHSV->u8Cmd = LED_CMD_CUSTOM_HSV;
+ pTxHSV->u8GroundBrightness = _LED_GroundBrightness();
+ pTxHSV->u8WingBrightness = _LED_WingBrightness();
+ _LED_SetPower();
- if (gbLedDataIsControlledExt) {
- // Swap from BRG to GRB
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] =
- LED_ScaleU8(gu8aControlledExtLedData[i * 3 + 2], gConfig.u8LedGroundBrightness);
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] =
- LED_ScaleU8(gu8aControlledExtLedData[i * 3 + 1], gConfig.u8LedGroundBrightness);
- gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] =
- LED_ScaleU8(gu8aControlledExtLedData[i * 3 + 0], gConfig.u8LedGroundBrightness);
- }
- } else if (gConfig.bEnableRainbow) {
- LED_GroundRainbow();
+ if (gConfig.bEnableRainbow) {
+ LED_Ground_Rainbow_HSV(pTxHSV->aGround);
} else {
- LED_GroundStatic();
+ LED_Ground_Static_HSV(pTxHSV->aGround);
}
- } else {
- PIN_LED_GROUND_PWR = 0;
- LED_OffGround();
- }
-
- if (gConfig.u8LedWingBrightness) {
- PIN_LED_WING_PWR = 1;
- // TODO: Get data from game when gbLedDataIsControlledExt (HID, probably)
- LED_AirWings();
- } else {
- PIN_LED_WING_PWR = 0;
- LED_OffWings();
+ LED_Wings_Reactive_HSV(&pTxHSV->Wings);
}
}
+
+#define I2C_WaitTimeout (SystemCoreClock / 5);
+#define WAIT_INDEX(cond) \
+ do { \
+ u32TimeOutCnt = I2C_WaitTimeout; \
+ while (u16I2CRxIndex cond) { \
+ if (--u32TimeOutCnt == 0) return 0; \
+ } \
+ } while (0)
+
+uint8_t LED_FMC_Read(uint32_t u32Offset, uint32_t* pu32Data) {
+ static volatile uint32_t u32Data;
+ u32Data = 0xFFFFFFFF;
+ uint32_t u32TimeOutCnt;
+
+ // Wait for anything in the buffer to be read
+ WAIT_INDEX(!= 0);
+ WAIT_INDEX(== 0);
+ // Request a 4-byte read from the LED board
+ gpu8I2CRx = (volatile uint8_t*)&u32Data;
+ gu8LEDTx[0] = 0;
+ gu8LEDTx[1] = u32Offset & 0xff;
+ gu8LEDTx[2] = (u32Offset >> 8) & 0xff;
+ gu8LEDTx[3] = (u32Offset >> 16) & 0xff;
+ gu8LEDTx[4] = (u32Offset >> 24) & 0xff;
+ gu8LEDTx[0] = LED_CMD_FMC_READ;
+
+ // Wait for our packet to be sent
+ WAIT_INDEX(!= 0);
+ WAIT_INDEX(== 0);
+ // Wait for the LED board to send its response
+ WAIT_INDEX(!= 5);
+
+ if (pu32Data) *pu32Data = u32Data;
+ return 1;
+}
diff --git a/src/led.h b/src/led.h
index 63cdd6e..7c460d4 100644
--- a/src/led.h
+++ b/src/led.h
@@ -1,73 +1,49 @@
#pragma once
-#include
+#include "led_shared.h"
-#define LED_FIRMWARE_CFW
-#ifndef LED_FIRMWARE_CFW
-#define LED_DATA_OFFSET 1
-#else
-#define LED_DATA_OFFSET 2
-#endif
+// Defined as volatile due to the I2C interrupt reading at random times!
+extern volatile uint8_t gu8LEDTx[LED_PACKET_MAX_SIZE];
-// LED count definitions
-#define LED_NUM_GROUND 31
-#define LED_NUM_LEFT 24
-#define LED_NUM_RIGHT 24
-
-// HSV definitions
-#define LED_HUE_SCALE 5 // For transmission to LED board in basic mode
-#define LED_HUE_MAX 360
-
-// Host->LED MCU commands
-#define LED_CMD_BASIC 0xA5
-#define LED_CMD_RGB_FULL 0x5A
-
-// LED index names
-#define LED_CELL_0 0
-#define LED_CELL_1 2
-#define LED_CELL_2 4
-#define LED_CELL_3 6
-#define LED_CELL_4 8
-#define LED_CELL_5 10
-#define LED_CELL_6 12
-#define LED_CELL_7 14
-#define LED_CELL_8 16
-#define LED_CELL_9 18
-#define LED_CELL_10 20
-#define LED_CELL_11 22
-#define LED_CELL_12 24
-#define LED_CELL_13 26
-#define LED_CELL_14 28
-#define LED_CELL_15 30
-
-#define LED_DIVIDER_0_1 1
-#define LED_DIVIDER_1_2 3
-#define LED_DIVIDER_2_3 5
-#define LED_DIVIDER_3_4 7
-#define LED_DIVIDER_4_5 9
-#define LED_DIVIDER_5_6 11
-#define LED_DIVIDER_6_7 13
-#define LED_DIVIDER_7_8 15
-#define LED_DIVIDER_8_9 17
-#define LED_DIVIDER_9_10 19
-#define LED_DIVIDER_10_11 21
-#define LED_DIVIDER_11_12 23
-#define LED_DIVIDER_12_13 25
-#define LED_DIVIDER_13_14 27
-#define LED_DIVIDER_14_15 29
-
-typedef struct {
- uint16_t u16H;
- uint8_t u8S;
- uint8_t u8V;
-} hsv_t;
// Internal LED control, from the settings UI (gets priority)
-extern hsv_t gaControlledIntLedData[LED_NUM_GROUND];
+extern hsv_t gaControlledIntLedData[LED_NUM_GROUND_LOGICAL];
extern uint8_t gbLedDataIsControlledInt;
// External LED control, from the game
-extern uint8_t gu8aControlledExtLedData[32 * 3];
+extern rgb_t gaControlledExtLedData[32];
extern uint8_t gbLedDataIsControlledExt;
+// For reception of data from I2C
+extern volatile uint8_t* gpu8I2CRx;
+extern volatile uint16_t u16I2CRxIndex;
+
+extern uint8_t gbLedIsCustom;
+
+// === Assigners (led_impl.c) ===
+void LED_Wings_Reactive_HSV(_led_wings_hsv* pWings);
+void LED_Ground_Rainbow_HSV(hsv_t* aGround);
+void LED_Ground_Static_HSV(hsv_t* aGround);
+void LED_Ground_Internal_HSV(hsv_t* aGround);
+/** All "controlled" data is in RGB format, so these aren't a thing
+ * void LED_Wings_Controlled_HSV(_led_wings_hsv* pWings);
+ * void LED_Ground_Controlled_HSV(hsv_t* aGround);
+ */
+
+// Unimplemented nonsense stuff
+void LED_Wings_Reactive_RGB(_led_wings_rgb* pWings);
+void LED_Ground_Rainbow_RGB(rgb_t* pWings);
+void LED_Ground_Internal_RGB(rgb_t* aGround);
+void LED_Ground_Static_RGB(rgb_t* aGround);
+// Actual RGBs that're used
+void LED_Wings_Controlled_RGB(_led_wings_rgb* pWings);
+void LED_Ground_Controlled_RGB(rgb_t* aGround);
+
+// === Exported functions ===
+void HsvToHost(rgb_t* pRGB, uint16_t u16H, uint8_t u8S, uint8_t u8V);
void LED_I2C1_Init(void);
-void LED_WriteBasicGrounds(void);
-void LED_WriteRGB(void);
+
+/**
+ * Write data out to the LEDs
+ */
+void LED_Write(void);
+
+uint8_t LED_FMC_Read(uint32_t u32Offset, uint32_t* pu32Data);
diff --git a/src/led_impl.c b/src/led_impl.c
new file mode 100644
index 0000000..edb0324
--- /dev/null
+++ b/src/led_impl.c
@@ -0,0 +1,273 @@
+#include "tasoller.h"
+
+static inline uint8_t LED_ScaleU8(uint8_t u8V, uint8_t u8Scale) {
+ // When using our custom firmware, don't perform scaling here because it'll be performed on the
+ // LED processor for us instead
+#if LED_FIRMWARE_TYPE == LED_FW_OURS
+ return u8V;
+#else
+ return ((uint16_t)u8V * (uint16_t)u8Scale) / 255;
+#endif
+}
+
+static const uint8_t su8aWingSensors[LED_NUM_WING] = {
+ DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, //
+ DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, //
+ DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, //
+ DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, //
+ DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, //
+ DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, //
+};
+
+#define SATURATION_ACTIVE 255
+#define SATURATION_INACTIVE 240
+#define VALUE_ACTIVE (gConfig.u8LedWingBrightness)
+#define VALUE_INACTIVE (gConfig.u8LedWingBrightness / 2)
+
+void LED_Wings_Reactive_HSV(_led_wings_hsv* pWings) {
+ for (uint8_t i = 0; i < LED_NUM_WING; i++) {
+ // Left wing
+ if (gu8DigitalButtons & su8aWingSensors[LED_NUM_WING - i - 1]) {
+ pWings->aWingL[i].h = gConfig.u16HueWingLeft;
+ pWings->aWingL[i].s = SATURATION_ACTIVE;
+ pWings->aWingL[i].v = VALUE_ACTIVE;
+ } else {
+ pWings->aWingL[i].h = gConfig.u16HueWingLeft;
+ pWings->aWingL[i].s = SATURATION_INACTIVE;
+ pWings->aWingL[i].v = VALUE_INACTIVE;
+ }
+
+ // Right wing
+ if (gu8DigitalButtons & su8aWingSensors[i]) {
+ pWings->aWingR[i].h = gConfig.u16HueWingRight;
+ pWings->aWingR[i].s = SATURATION_ACTIVE;
+ pWings->aWingR[i].v = VALUE_ACTIVE;
+ } else {
+ pWings->aWingR[i].h = gConfig.u16HueWingRight;
+ pWings->aWingR[i].s = SATURATION_INACTIVE;
+ pWings->aWingR[i].v = VALUE_INACTIVE;
+ }
+ }
+}
+void LED_Ground_Rainbow_HSV(hsv_t* aGround) {
+ // 5 ticks * 360 hue = 1800 calls for one cycle (1.8s)
+ static uint16_t u16Hue = 0;
+ static uint8_t u8Ticker = 0;
+ if (++u8Ticker == 5) {
+ u8Ticker = 0;
+ u16Hue++;
+ if (u16Hue == LED_HUE_MAX) u16Hue = 0;
+ }
+
+ for (uint8_t i = 0; i < LED_NUM_GROUND_LOGICAL; i++) {
+ uint16_t h = 0;
+ uint8_t v = 190;
+ uint8_t nCell = i >> 1;
+ if (i % 2 == 0) {
+ if (gu16PSoCDigital & (1 << nCell)) {
+ v = 255;
+ h = LED_HUE_MAX / 2;
+ }
+ } else if (nCell % 4 == 3) {
+ h = LED_HUE_MAX / 2;
+ }
+
+ aGround[i].h = (u16Hue + h + (i * (LED_HUE_MAX / LED_NUM_GROUND_LOGICAL))) % LED_HUE_MAX;
+ aGround[i].s = v;
+ aGround[i].v = v - 63;
+ }
+}
+void LED_Ground_Static_HSV(hsv_t* aGround) {
+ for (uint8_t i = 0; i < LED_NUM_GROUND_LOGICAL; i++) {
+ const uint8_t nCell = i >> 1;
+ if (i % 2 == 0) {
+ // This is a cell. Light it according to the touch input
+ if (gu16PSoCDigital & (1 << nCell)) {
+ aGround[i].h = gConfig.u16HueGroundActive;
+ aGround[i].s = 255;
+ aGround[i].v = 255;
+ } else {
+ aGround[i].h = gConfig.u16HueGround;
+ aGround[i].s = 255;
+ aGround[i].v = 255;
+ }
+ } else if (nCell % 4 == 3) {
+ // This is a separating divider. Light it with the active colour
+ aGround[i].h = gConfig.u16HueGroundActive;
+ aGround[i].s = 255;
+ aGround[i].v = 255;
+ } else {
+ // This is a non-separating divider. Light it based on the two cells either side
+ if (gu16PSoCDigital & (1 << nCell) && gu16PSoCDigital & (1 << (nCell + 1))) {
+ aGround[i].h = gConfig.u16HueGroundActive;
+ aGround[i].s = 255;
+ aGround[i].v = 255;
+ } else {
+ aGround[i].h = gConfig.u16HueGround;
+ aGround[i].s = 255;
+ aGround[i].v = 255;
+ }
+ }
+ }
+}
+void LED_Ground_Internal_HSV(hsv_t* aGround) {
+ for (uint8_t i = 0; i < LED_NUM_GROUND_LOGICAL; i++) {
+ aGround[i].h = gaControlledIntLedData[LED_NUM_GROUND_LOGICAL - i - 1].h;
+ aGround[i].s = gaControlledIntLedData[LED_NUM_GROUND_LOGICAL - i - 1].s;
+ aGround[i].v = gaControlledIntLedData[LED_NUM_GROUND_LOGICAL - i - 1].v;
+ }
+}
+
+void HsvToHost(rgb_t* pRGB, uint16_t u16H, uint8_t u8S, uint8_t u8V) {
+ if (u8S == 0) {
+ pRGB->host.r = u8V;
+ pRGB->host.g = u8V;
+ pRGB->host.b = u8V;
+ return;
+ }
+
+ uint8_t region = u16H / (LED_HUE_MAX / 6);
+ uint8_t remainder = (u16H - (region * (LED_HUE_MAX / 6))) * (255 / (LED_HUE_MAX / 6));
+
+ uint8_t p = (u8V * (255 - u8S)) >> 8;
+ uint8_t q = (u8V * (255 - ((u8S * remainder) >> 8))) >> 8;
+ uint8_t t = (u8V * (255 - ((u8S * (255 - remainder)) >> 8))) >> 8;
+
+ switch (region) {
+ case 0:
+ pRGB->host.r = u8V;
+ pRGB->host.g = t;
+ pRGB->host.b = p;
+ break;
+ case 1:
+ pRGB->host.r = q;
+ pRGB->host.g = u8V;
+ pRGB->host.b = p;
+ break;
+ case 2:
+ pRGB->host.r = p;
+ pRGB->host.g = u8V;
+ pRGB->host.b = t;
+ break;
+ case 3:
+ pRGB->host.r = p;
+ pRGB->host.g = q;
+ pRGB->host.b = u8V;
+ break;
+ case 4:
+ pRGB->host.r = t;
+ pRGB->host.g = p;
+ pRGB->host.b = u8V;
+ break;
+ default:
+ pRGB->host.r = u8V;
+ pRGB->host.g = p;
+ pRGB->host.b = q;
+ break;
+ }
+
+ return;
+}
+
+void LED_Wings_Reactive_RGB(_led_wings_rgb* pWings) {
+ rgb_t u8aRgbActive;
+ rgb_t u8aRgbInactive;
+
+ uint8_t i;
+
+ // Left wing
+ HsvToHost(&u8aRgbActive, gConfig.u16HueWingLeft, SATURATION_ACTIVE, VALUE_ACTIVE);
+ HsvToHost(&u8aRgbInactive, gConfig.u16HueWingLeft, SATURATION_INACTIVE, VALUE_INACTIVE);
+ for (i = 0; i < LED_NUM_WING; i++) {
+ // GRB
+ if (gu8DigitalButtons & su8aWingSensors[LED_NUM_WING - i - 1]) {
+ pWings->aWingL[i].host.r = u8aRgbActive.host.r;
+ pWings->aWingL[i].host.g = u8aRgbActive.host.g;
+ pWings->aWingL[i].host.b = u8aRgbActive.host.b;
+ } else {
+ pWings->aWingL[i].host.r = u8aRgbInactive.host.r;
+ pWings->aWingL[i].host.g = u8aRgbInactive.host.g;
+ pWings->aWingL[i].host.b = u8aRgbInactive.host.b;
+ }
+ }
+
+ // Right wing
+ HsvToHost(&u8aRgbActive, gConfig.u16HueWingRight, SATURATION_ACTIVE, VALUE_ACTIVE);
+ HsvToHost(&u8aRgbInactive, gConfig.u16HueWingRight, SATURATION_INACTIVE, VALUE_INACTIVE);
+ for (i = 0; i < LED_NUM_WING; i++) {
+ // GRB
+ if (gu8DigitalButtons & su8aWingSensors[i]) {
+ pWings->aWingR[i].host.r = u8aRgbActive.host.r;
+ pWings->aWingR[i].host.g = u8aRgbActive.host.g;
+ pWings->aWingR[i].host.b = u8aRgbActive.host.b;
+ } else {
+ pWings->aWingR[i].host.r = u8aRgbInactive.host.r;
+ pWings->aWingR[i].host.g = u8aRgbInactive.host.g;
+ pWings->aWingR[i].host.b = u8aRgbInactive.host.b;
+ }
+ }
+}
+void LED_Ground_Rainbow_RGB(rgb_t* aGround) {
+ // TODO: Even bother?
+ return;
+}
+void LED_Ground_Static_RGB(rgb_t* aGround) {
+ // TODO: Even bother?
+ rgb_t rgbGround;
+ rgb_t rgbGroundActive;
+ HsvToHost(&rgbGround, gConfig.u16HueGround, 255, gConfig.u8LedGroundBrightness);
+ HsvToHost(&rgbGroundActive, gConfig.u16HueGroundActive, 255, gConfig.u8LedGroundBrightness);
+ for (uint8_t i = 0; i < LED_NUM_GROUND_LOGICAL; i++) {
+ const uint8_t nCell = i >> 1;
+ if (i % 2 == 0) {
+ // This is a cell. Light it according to the touch input
+ if (gu16PSoCDigital & (1 << nCell)) {
+ aGround[i].host.r = rgbGroundActive.host.r;
+ aGround[i].host.g = rgbGroundActive.host.g;
+ aGround[i].host.b = rgbGroundActive.host.b;
+ } else {
+ aGround[i].host.r = rgbGround.host.r;
+ aGround[i].host.g = rgbGround.host.g;
+ aGround[i].host.b = rgbGround.host.b;
+ }
+ } else if (nCell % 4 == 3) {
+ // This is a separating divider. Light it with the active colour
+ aGround[i].host.r = rgbGroundActive.host.r;
+ aGround[i].host.g = rgbGroundActive.host.g;
+ aGround[i].host.b = rgbGroundActive.host.b;
+ } else {
+ // This is a non-separating divider. Light it based on the two cells either side
+ if (gu16PSoCDigital & (1 << nCell) && gu16PSoCDigital & (1 << (nCell + 1))) {
+ aGround[i].host.r = rgbGroundActive.host.r;
+ aGround[i].host.g = rgbGroundActive.host.g;
+ aGround[i].host.b = rgbGroundActive.host.b;
+ } else {
+ aGround[i].host.r = rgbGround.host.r;
+ aGround[i].host.g = rgbGround.host.g;
+ aGround[i].host.b = rgbGround.host.b;
+ }
+ }
+ }
+}
+
+void LED_Wings_Controlled_RGB(_led_wings_rgb* pWings) {
+ // TODO: Get data from game when gbLedDataIsControlledExt (HID, probably)
+
+ for (uint8_t i = 0; i < LED_NUM_WING; i++) {
+ // The PWM output is wired as BGR on PWM3~5
+ pWings->aWingL[i].host.b = gu8IO4PWMOutput[2];
+ pWings->aWingR[i].host.b = gu8IO4PWMOutput[2];
+ pWings->aWingL[i].host.r = gu8IO4PWMOutput[3];
+ pWings->aWingR[i].host.r = gu8IO4PWMOutput[3];
+ pWings->aWingL[i].host.g = gu8IO4PWMOutput[4];
+ pWings->aWingR[i].host.g = gu8IO4PWMOutput[4];
+ }
+}
+void LED_Ground_Controlled_RGB(rgb_t* aGround) {
+ // Swap from BRG(game) to GRB(host)
+ for (uint8_t i = 0; i < LED_NUM_GROUND_LOGICAL; i++) {
+ aGround[i].host.r = LED_ScaleU8(gaControlledExtLedData[i].game.r, 255);
+ aGround[i].host.g = LED_ScaleU8(gaControlledExtLedData[i].game.g, 255);
+ aGround[i].host.b = LED_ScaleU8(gaControlledExtLedData[i].game.b, 255);
+ }
+}
diff --git a/src/led_shared.h b/src/led_shared.h
new file mode 100644
index 0000000..c821439
--- /dev/null
+++ b/src/led_shared.h
@@ -0,0 +1,213 @@
+/**
+ * !!WARNING!!
+ * This file is included into the LED APROM firmware too.
+ * Don't place anything in here that would be inappropriate there.
+ * !!WARNING!!
+ */
+
+#pragma once
+
+#include
+
+#include "_compiler.h"
+
+// === LED Firmware Type Configuration ===
+// (Only applicable on the host)
+#define LED_FW_STOCK 0
+#define LED_FW_MAINLAND 1
+#define LED_FW_OURS 2
+
+// #define LED_FIRMWARE_TYPE LED_FW_STOCK
+// #define LED_FIRMWARE_TYPE LED_FW_MAINLAND
+#define LED_FIRMWARE_TYPE LED_FW_OURS
+
+// === LED Count Definitions ===
+/**
+ * There are 48 LEDs for ground, but we only send 31 values
+ * They're mapped to the LEDs as follows:
+ * 00a11b22c33d44f55g66h77i...
+ *
+ * That is, we can't split-colour a key :P
+ */
+#define LED_NUM_GROUND_LOGICAL 31
+// Ground: [0] = Obscured, [1] = Right, [47] = Left
+#define LED_NUM_GROUND_PHYSICAL 48
+// Right wing: [0] = Bottom, [23] = Top
+// Left wing: [23] = Bottom, [0] = Top
+#define LED_NUM_WING 24
+
+// === Colour Byte Order Definitions ===
+// What we know and love
+#define RGB_R 0
+#define RGB_G 1
+#define RGB_B 2
+// What WS2813 uses, and what we receive from the host in stock mode
+#define GRB_R 1
+#define GRB_G 0
+#define GRB_B 2
+// Our internal reversed WS2813 format
+#define BRG_R 1
+#define BRG_G 2
+#define BRG_B 0
+
+#define HOST_FORMAT GRB
+#define _CHANNEL(fmt, c) fmt##_##c
+#define CHANNEL(fmt, c) _CHANNEL(fmt, c)
+
+#define HOST_R CHANNEL(HOST_FORMAT, R)
+#define HOST_G CHANNEL(HOST_FORMAT, G)
+#define HOST_B CHANNEL(HOST_FORMAT, B)
+
+typedef union {
+ struct __packed {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ } rgb;
+ // Data received from the game is in BRG format
+ struct __packed {
+ uint8_t b;
+ uint8_t r;
+ uint8_t g;
+ } game;
+ // WS2813 uses GRB, and that's what we received from the host
+ struct __packed {
+ uint8_t g;
+ uint8_t r;
+ uint8_t b;
+ } host;
+ // Internally we use a reversed WS2813 format (BRG)
+ struct __packed {
+ uint8_t b;
+ uint8_t r;
+ uint8_t g;
+ } internal;
+ uint8_t aRaw[3];
+} rgb_t;
+typedef struct __packed {
+ uint16_t h;
+ uint8_t s;
+ uint8_t v;
+} hsv_t;
+
+// === Host->LED MCU Commands ===
+#define LED_I2C_REG_PACKET 0xFF
+
+#define LED_CMD_BASIC 0xA5
+#define LED_CMD_RGB_FULL 0x5A
+#define LED_CMD_CUSTOM_RGB 0x5B
+#define LED_CMD_CUSTOM_HSV 0x5C
+#define LED_CMD_CUSTOM_MIXED 0x5D
+#define LED_CMD_FMC_READ 0x5E
+#define LED_CMD_FMC_ENTER_LDROM 0x5F
+
+// === HOST->LED MCU Packets ===
+typedef struct __packed {
+ rgb_t aWingL[LED_NUM_WING];
+ rgb_t aWingR[LED_NUM_WING];
+} _led_wings_rgb;
+typedef struct __packed {
+ hsv_t aWingL[LED_NUM_WING];
+ hsv_t aWingR[LED_NUM_WING];
+} _led_wings_hsv;
+
+typedef struct __packed {
+ uint8_t u8Cmd;
+ uint32_t u32Ground;
+
+ uint8_t u8WingFill;
+#if LED_FIRMWARE_TYPE == LED_FW_MAINLAND
+ uint8_t u8Rainbow;
+ uint8_t u8Rsv07;
+ uint8_t u8Rsv08;
+ uint8_t u8Rsv09;
+#else
+ uint8_t u8HueLeft;
+ uint8_t u8HueRight;
+ uint8_t u8HueGround;
+ uint8_t u8HueGroundActive;
+#endif
+ uint8_t u8Flags0;
+ uint8_t u8Flags1;
+} led_rx_basic, *Pled_rx_basic;
+
+typedef struct __packed {
+ uint8_t u8Cmd;
+#if LED_FIRMWARE_TYPE == LED_FW_MAINLAND
+ uint8_t u8Config;
+#endif
+ rgb_t aGround[LED_NUM_GROUND_LOGICAL];
+ _led_wings_rgb Wings;
+} led_rx_full, *Pled_rx_full;
+
+typedef struct __packed {
+ uint8_t u8Cmd;
+ uint8_t u8GroundBrightness;
+ uint8_t u8WingBrightness;
+ rgb_t aGround[LED_NUM_GROUND_LOGICAL];
+ _led_wings_rgb Wings;
+} led_rx_custom_rgb, *Pled_rx_custom_rgb;
+
+typedef struct __packed {
+ uint8_t u8Cmd;
+ uint8_t u8GroundBrightness;
+ uint8_t u8WingBrightness;
+ rgb_t aGround[LED_NUM_GROUND_LOGICAL];
+ _led_wings_hsv Wings;
+} led_rx_custom_mixed, *Pled_rx_custom_mixed;
+
+typedef struct __packed {
+ uint8_t u8Cmd;
+ uint8_t u8GroundBrightness;
+ uint8_t u8WingBrightness;
+ hsv_t aGround[LED_NUM_GROUND_LOGICAL];
+ _led_wings_hsv Wings;
+} led_rx_custom_hsv, *Pled_rx_custom_hsv;
+
+typedef struct __packed {
+ uint8_t u8Cmd;
+ uint32_t u32Offset;
+} led_rx_fmc_read, *Pled_rx_fmc_read;
+
+#define LED_PACKET_MAX_SIZE \
+ Maximum(Maximum(Maximum(sizeof(led_rx_basic), sizeof(led_rx_full)), \
+ Maximum(sizeof(led_rx_custom_rgb), sizeof(led_rx_custom_hsv))), \
+ sizeof(led_rx_custom_mixed))
+
+// === LED index names ===
+#define LED_CELL_0 0
+#define LED_CELL_1 2
+#define LED_CELL_2 4
+#define LED_CELL_3 6
+#define LED_CELL_4 8
+#define LED_CELL_5 10
+#define LED_CELL_6 12
+#define LED_CELL_7 14
+#define LED_CELL_8 16
+#define LED_CELL_9 18
+#define LED_CELL_10 20
+#define LED_CELL_11 22
+#define LED_CELL_12 24
+#define LED_CELL_13 26
+#define LED_CELL_14 28
+#define LED_CELL_15 30
+
+#define LED_DIVIDER_0_1 1
+#define LED_DIVIDER_1_2 3
+#define LED_DIVIDER_2_3 5
+#define LED_DIVIDER_3_4 7
+#define LED_DIVIDER_4_5 9
+#define LED_DIVIDER_5_6 11
+#define LED_DIVIDER_6_7 13
+#define LED_DIVIDER_7_8 15
+#define LED_DIVIDER_8_9 17
+#define LED_DIVIDER_9_10 19
+#define LED_DIVIDER_10_11 21
+#define LED_DIVIDER_11_12 23
+#define LED_DIVIDER_12_13 25
+#define LED_DIVIDER_13_14 27
+#define LED_DIVIDER_14_15 29
+
+// === HSV Definitions ===
+#define LED_HUE_SCALE 5 // For transmission to LED board in basic mode
+#define LED_HUE_MAX 360
diff --git a/src/main.c b/src/main.c
index 083381c..752099c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,69 +2,70 @@
uint8_t volatile gu8HIDIO4Ready = 0;
uint8_t volatile gu8HIDMiscReady = 0;
+uint32_t gu32NowMs = 0;
-#define DEBOUNCE_COUNT 8
+#define NUM_BUTTONS 8
+#define DEBOUNCE_ON (2 * 4) // We need a digital high for 2ms to latch on
+#define DEBOUNCE_OFF (8 * 4) // Then a digital low for 8ms to latch off
uint8_t TickDebouncer(uint8_t u8Buttons) {
- static uint8_t u8Counters[8] = { 0 };
- uint8_t debounced = 0;
- for (uint8_t i = 0; i < 8; i++) {
- if (u8Buttons & (1 << i))
- u8Counters[i] = 0;
- else if (u8Counters[i] < DEBOUNCE_COUNT)
- u8Counters[i]++;
+ static uint8_t u8CountUp[NUM_BUTTONS] = { 0 };
+ static uint8_t u8CountDown[NUM_BUTTONS] = { 0 };
- if (u8Counters[i] < DEBOUNCE_COUNT) debounced |= (1 << i);
+ uint8_t debounced = 0;
+ for (uint8_t i = 0; i < NUM_BUTTONS; i++) {
+ if (u8Buttons & (1 << i)) {
+ if (u8CountUp[i] < DEBOUNCE_ON)
+ u8CountUp[i]++;
+ else
+ u8CountDown[i] = DEBOUNCE_OFF;
+ } else {
+ if (u8CountDown[i])
+ u8CountDown[i]--;
+ else
+ u8CountUp[i] = 0;
+ }
+
+ if (u8CountDown[i]) debounced |= (1 << i);
}
return debounced;
}
+/**
+ * @brief Perform a sensor read using Quasi-bidirectional Mode
+ *
+ * See TRM section 6.5.5.4 for details
+ */
+static inline uint8_t DigitalRead(volatile uint32_t* pData, GPIO_T* pGpio, uint32_t u32Pin) {
+ GPIO_SetMode(pGpio, u32Pin, GPIO_PMD_INPUT);
+ *pData = 1;
+ DELAY_CYCLES_2;
+ DELAY_CYCLES_2;
+ DELAY_CYCLES_2;
+ GPIO_SetMode(pGpio, u32Pin, GPIO_PMD_QUASI);
+ DELAY_CYCLES_2;
+ DELAY_CYCLES_2;
+ DELAY_CYCLES_2;
+ return *pData;
+}
+
uint8_t gu8DigitalButtons;
-#define DELAY_FN 2
-#define DELAY_AIR 2
void Digital_TickInputs() {
uint8_t u8Buttons = 0;
- GPIO_SetMode(_PIN_FN1, GPIO_PMD_INPUT);
- DelayCycles_Small(DELAY_FN);
- GPIO_SetMode(_PIN_FN1, GPIO_PMD_QUASI);
- u8Buttons |= PIN_FN1 ? 0 : DIGITAL_FN1_Msk;
+ // The two FN buttons need a quasi read cycle
+ u8Buttons |= DigitalRead(&PIN_FN1, _PIN_FN1) ? 0 : DIGITAL_FN2_Msk;
+ u8Buttons |= DigitalRead(&PIN_FN2, _PIN_FN1) ? 0 : DIGITAL_FN1_Msk;
- GPIO_SetMode(_PIN_FN2, GPIO_PMD_INPUT);
- DelayCycles_Small(DELAY_FN);
- GPIO_SetMode(_PIN_FN2, GPIO_PMD_QUASI);
- u8Buttons |= PIN_FN2 ? 0 : DIGITAL_FN2_Msk;
+ // The 6 AIR sensors drive a ~4.5V signal on the pin, so are just in INPUT mode
+ u8Buttons |= DigitalRead(&PIN_AIR1, _PIN_AIR1) ? DIGITAL_AIR1_Msk : 0;
+ u8Buttons |= DigitalRead(&PIN_AIR2, _PIN_AIR2) ? DIGITAL_AIR2_Msk : 0;
+ u8Buttons |= DigitalRead(&PIN_AIR3, _PIN_AIR3) ? DIGITAL_AIR3_Msk : 0;
+ u8Buttons |= DigitalRead(&PIN_AIR4, _PIN_AIR4) ? DIGITAL_AIR4_Msk : 0;
+ u8Buttons |= DigitalRead(&PIN_AIR5, _PIN_AIR5) ? DIGITAL_AIR5_Msk : 0;
+ u8Buttons |= DigitalRead(&PIN_AIR6, _PIN_AIR6) ? DIGITAL_AIR6_Msk : 0;
- GPIO_SetMode(_PIN_AIR1, GPIO_PMD_INPUT);
- DelayCycles_Small(DELAY_AIR);
- GPIO_SetMode(_PIN_AIR1, GPIO_PMD_QUASI);
- u8Buttons |= PIN_AIR1 ? DIGITAL_AIR1_Msk : 0;
-
- GPIO_SetMode(_PIN_AIR2, GPIO_PMD_INPUT);
- DelayCycles_Small(DELAY_AIR);
- GPIO_SetMode(_PIN_AIR2, GPIO_PMD_QUASI);
- u8Buttons |= PIN_AIR2 ? DIGITAL_AIR2_Msk : 0;
-
- GPIO_SetMode(_PIN_AIR3, GPIO_PMD_INPUT);
- DelayCycles_Small(DELAY_AIR);
- GPIO_SetMode(_PIN_AIR3, GPIO_PMD_QUASI);
- u8Buttons |= PIN_AIR3 ? DIGITAL_AIR3_Msk : 0;
-
- GPIO_SetMode(_PIN_AIR4, GPIO_PMD_INPUT);
- DelayCycles_Small(DELAY_AIR);
- GPIO_SetMode(_PIN_AIR4, GPIO_PMD_QUASI);
- u8Buttons |= PIN_AIR4 ? DIGITAL_AIR4_Msk : 0;
-
- GPIO_SetMode(_PIN_AIR5, GPIO_PMD_INPUT);
- DelayCycles_Small(DELAY_AIR);
- GPIO_SetMode(_PIN_AIR5, GPIO_PMD_QUASI);
- u8Buttons |= PIN_AIR5 ? DIGITAL_AIR5_Msk : 0;
-
- GPIO_SetMode(_PIN_AIR6, GPIO_PMD_INPUT);
- DelayCycles_Small(DELAY_AIR);
- GPIO_SetMode(_PIN_AIR6, GPIO_PMD_QUASI);
- u8Buttons |= PIN_AIR6 ? DIGITAL_AIR6_Msk : 0;
-
- gu8DigitalButtons = TickDebouncer(u8Buttons);
+ u8Buttons = TickDebouncer(u8Buttons);
+ gu8DigitalButtons = u8Buttons;
}
int _entry(void) {
@@ -78,7 +79,7 @@ int _entry(void) {
FMC_EEPROM_Load();
- gu8VcomReady = 1;
+ gu8VComReady = 1;
gu8HIDIO4Ready = 1;
gu8HIDMiscReady = 1;
@@ -88,20 +89,30 @@ int _entry(void) {
* delay added first.
* To make matters worse, if we ever actually call PSoCSetFingerCapacitance it ends up with
* huge asymmetry between the two PSoCs, which is just unworkable.
+ *
+ * Instead, see the non-blocking logic in the 1ms tick block.
*/
// uint16_t u16InitialFingerCap = PSoCGetFingerCapacitance();
// if (u16InitialFingerCap != gu16PSoCFingerCap) {
- // PSoCSetFingerCapacitance(gu16PSoCFingerCap);
+ // PSoCSetFingerCapacitance(gu16PSoCFingerCap, 1);
// }
- static uint32_t su32NowMs = 0;
- su32NowMs++;
+ gbLedIsCustom = LED_FMC_Read(0, NULL);
+
+ gu32NowMs = 0;
+ uint8_t bPSoCHasTalked = 0;
+
while (1) {
USB_VCOM_Tick();
- if (bPSoCDirty) {
- bPSoCDirty = 0;
+ if (bPSoCDirtyVolatile) {
+ bPSoCDirtyVolatile = 0;
PSoC_PostProcessing();
+
+ if (!bPSoCHasTalked) {
+ PSoC_SetFingerCapacitanceFromConfig(1);
+ bPSoCHasTalked = 1;
+ }
}
Slider_TickSerial();
@@ -114,24 +125,17 @@ int _entry(void) {
}
if (gu8Do1msTick) {
- su32NowMs++;
+ // Update timer
+ gu32NowMs++;
gu8Do1msTick = 0;
Slider_Tick1ms();
+ USB_VCOM_Tick();
PSoC_DigitalCalc();
UI_Tick();
- // LED_WriteBasicGrounds();
- LED_WriteRGB();
- } /* else {
- DelayCycles(45);
- }*/
-
- // Wait until we know both PSoC are awake and talking before we attempt configure them
- if (gu8PSoCSeenData == 0b011) {
- PSoC_SetFingerCapacitanceFromConfig();
- gu8PSoCSeenData |= 0b100;
+ LED_Write();
}
FMC_EEPROM_Store();
diff --git a/src/pins.h b/src/pins.h
index b4d4b6a..33507a3 100644
--- a/src/pins.h
+++ b/src/pins.h
@@ -46,16 +46,16 @@
#define USB_MUX_HOST 0
#define USB_MUX_LEDS 1
-#define DIGITAL_FN1_Pos 0
-#define DIGITAL_FN2_Pos 1
+#define DIGITAL_FN2_Pos 0
+#define DIGITAL_FN1_Pos 1
#define DIGITAL_AIR1_Pos 2
#define DIGITAL_AIR2_Pos 3
#define DIGITAL_AIR3_Pos 4
#define DIGITAL_AIR4_Pos 5
#define DIGITAL_AIR5_Pos 6
#define DIGITAL_AIR6_Pos 7
-#define DIGITAL_FN1_Msk (1 << DIGITAL_FN1_Pos)
#define DIGITAL_FN2_Msk (1 << DIGITAL_FN2_Pos)
+#define DIGITAL_FN1_Msk (1 << DIGITAL_FN1_Pos)
#define DIGITAL_AIR1_Msk (1 << DIGITAL_AIR1_Pos)
#define DIGITAL_AIR2_Msk (1 << DIGITAL_AIR2_Pos)
#define DIGITAL_AIR3_Msk (1 << DIGITAL_AIR3_Pos)
diff --git a/src/psoc.c b/src/psoc.c
index c3cebef..8afb4c2 100644
--- a/src/psoc.c
+++ b/src/psoc.c
@@ -1,6 +1,18 @@
#include "tasoller.h"
+// For some reason, any level of optimisation
+// #pragma GCC diagnostic push
+// #pragma GCC diagnostic warning "-Wpedantic"
+// #pragma GCC push_options
+// #pragma GCC optimize ("O0")
+
uint16_t gu16PSoCDiff[32] = { 0 };
+// Touch threshold as calculated by SmartSense. Has hysteresis built in.
+// 0 is an insane default, so instead we default to 100 which is far less likely to break things :)
+uint16_t gu16PSoCThreshold[32] = {
+ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+};
uint32_t gu32PSoCDigital = 0;
uint32_t gu32PSoCDigitalPos = 0;
@@ -11,13 +23,16 @@ uint16_t gu16PSoCDigitalPos = 0;
uint16_t gu16PSoCDigitalNeg = 0;
uint16_t gu16PSoCDigitalTrig = 0;
-uint8_t gu8PSoCSeenData = 0;
+uint32_t gu32LastCapSenseStart = 0;
+uint32_t gu32LastCapSenseEnd = 0;
-volatile uint8_t bPSoCDirty = 0;
+volatile uint8_t bPSoCDirtyVolatile = 0;
+volatile uint8_t bForceSliderSend = 0;
static void* pu8PsocRxDestination = NULL;
static uint8_t pu8PsocRxDestinationLen = 0;
-static volatile uint8_t* pu8PsocGotData = NULL;
+static volatile uint8_t* volatile pu8PsocGotData = NULL;
+static volatile PSoC_CMD_RX eBlockingCommand = _PSoC_CMD_RX_NONE;
static void PSoC_HandleRx(PSoC_CMD_RX eCmd, uint8_t u8Len, uint8_t* u8Data) {
if (eCmd != PSoC_CMD_RX_SLAVE_DIFF && eCmd != PSoC_CMD_RX_MASTER_DIFF &&
eCmd != PSoC_CMD_RX_CS_START) {
@@ -25,40 +40,76 @@ static void PSoC_HandleRx(PSoC_CMD_RX eCmd, uint8_t u8Len, uint8_t* u8Data) {
debug++;
}
- uint8_t u8PsocDataOffset = 0;
switch (eCmd) {
case PSoC_CMD_RX_REQUEST_FINGER_CAP:
- PSoC_SetFingerCapacitanceFromConfig();
+ // We're in the IRQ here, so don't block on this!
+ PSoC_SetFingerCapacitanceFromConfig(0);
return;
- // We don't care about these
+ // Debug traces
case PSoC_CMD_RX_CS_START:
+ gu32LastCapSenseStart = gu32NowMs;
+ return;
case PSoC_CMD_RX_CS_END:
+ gu32LastCapSenseEnd = gu32NowMs;
return;
case PSoC_CMD_RX_SLAVE_DIFF:
- u8PsocDataOffset = 16;
- gu8PSoCSeenData |= 1;
- // Falls through
- case PSoC_CMD_RX_MASTER_DIFF:
- if (eCmd == PSoC_CMD_RX_MASTER_DIFF) gu8PSoCSeenData |= 2;
+ // Request a refresh of our touch thresholds
+ PSoC_GetDebug(PSoC_CMD_DEBUG_SLAVE_TOUCH_TH, NULL);
+
if (u8Len != 32) return;
for (uint8_t i = 0; i < 16; i++) {
- gu16PSoCDiff[u8PsocDataOffset + i] = u8Data[(i * 2)] << 8;
- gu16PSoCDiff[u8PsocDataOffset + i] |= u8Data[(i * 2) + 1];
+ gu16PSoCDiff[16 + i] = u8Data[(i * 2)] << 8;
+ gu16PSoCDiff[16 + i] |= u8Data[(i * 2) + 1];
}
- bPSoCDirty = 1;
+ bPSoCDirtyVolatile = 1;
+ return;
+
+ case PSoC_CMD_RX_MASTER_DIFF:
+ // Request a refresh of our touch thresholds
+ PSoC_GetDebug(PSoC_CMD_DEBUG_MASTER_TOUCH_TH, NULL);
+
+ if (u8Len != 32) return;
+ for (uint8_t i = 0; i < 16; i++) {
+ gu16PSoCDiff[i] = u8Data[(i * 2)] << 8;
+ gu16PSoCDiff[i] |= u8Data[(i * 2) + 1];
+ }
+ bPSoCDirtyVolatile = 1;
return;
// Arbitrary data reception
case PSoC_CMD_RX_MASTER_TOUCH_TH:
+ if (u8Len == 32) {
+ for (uint8_t i = 0; i < 16; i++) {
+ gu16PSoCThreshold[i] = u8Data[(i * 2)] << 8;
+ gu16PSoCThreshold[i] |= u8Data[(i * 2) + 1];
+ }
+ }
+ goto arbitrary_data_reception;
case PSoC_CMD_RX_SLAVE_TOUCH_TH:
+ if (u8Len == 32) {
+ for (uint8_t i = 0; i < 16; i++) {
+ gu16PSoCThreshold[16 + i] = u8Data[(i * 2)] << 8;
+ gu16PSoCThreshold[16 + i] |= u8Data[(i * 2) + 1];
+ }
+ }
+ goto arbitrary_data_reception;
+
case PSoC_CMD_RX_MASTER_FINGER_TH:
case PSoC_CMD_RX_MASTER_HYSTERESIS:
case PSoC_CMD_RX_SLAVE_FINGER_TH:
case PSoC_CMD_RX_SLAVE_HYSTERESIS:
case PSoC_CMD_RX_GET_FINGER_CAP:
case PSoC_CMD_RX_SET_FINGER_CAP:
+ case PSoC_CMD_RX_ENABLE_DEBUG:
+ arbitrary_data_reception:
+ // Only handle the command if it's what we were actually blocking on
+ if (eCmd != eBlockingCommand) {
+ // This was a rogue command! (breakpoint here for PSoC diagnosis stuff)
+ return;
+ }
+
if (pu8PsocRxDestination) {
if (u8Len > pu8PsocRxDestinationLen) u8Len = pu8PsocRxDestinationLen;
memcpy(pu8PsocRxDestination, u8Data, u8Len);
@@ -71,8 +122,84 @@ static void PSoC_HandleRx(PSoC_CMD_RX eCmd, uint8_t u8Len, uint8_t* u8Data) {
pu8PsocGotData = NULL;
}
return;
+
+ // Nonsense, but just to satisfy the switch condition validation :)
+ case _PSoC_CMD_RX_NONE:
+ return;
}
}
+
+/**
+ * @brief Returns 1 on successful reception of a command, 0 otherwise
+ *
+ * @param eCommand
+ * @return uint8_t
+ */
+static volatile uint8_t su8Ready = 0;
+static uint8_t PSoC_Await_Command(PSoC_CMD_RX eCommand) {
+ su8Ready = 0;
+ pu8PsocGotData = &su8Ready;
+
+ // TODO: What timeout does this actually work out to be?
+ // With O0, it looks like /33 = 1 second (ie the loop is 33 clocks)
+ // Haven't tested Os which is what we'd want for prod
+ uint32_t u32Timeout = (SystemCoreClock / 33) / 16; // 62.5ms
+
+ eBlockingCommand = eCommand;
+ // Block on reception of the command
+ while (!su8Ready) {
+ // Timeout condition
+ if (--u32Timeout == 0) {
+ eBlockingCommand = _PSoC_CMD_RX_NONE;
+ return 0;
+ }
+ }
+ eBlockingCommand = _PSoC_CMD_RX_NONE;
+ return 1;
+}
+static uint8_t PSoC_Valid_Len(PSoC_CMD_RX eCmd, uint8_t u8Len) {
+ switch (eCmd) {
+ case PSoC_CMD_RX_CS_START:
+ case PSoC_CMD_RX_CS_END:
+ // We should never be seeing a length for these!
+ return 0;
+
+ // Commands that have a payload we need to receive
+ case PSoC_CMD_RX_SET_FINGER_CAP:
+ case PSoC_CMD_RX_REQUEST_FINGER_CAP:
+ case PSoC_CMD_RX_ENABLE_DEBUG:
+ return u8Len == 2;
+ case PSoC_CMD_RX_MASTER_DIFF:
+ case PSoC_CMD_RX_SLAVE_DIFF:
+ case PSoC_CMD_RX_MASTER_TOUCH_TH:
+ case PSoC_CMD_RX_SLAVE_TOUCH_TH:
+ case PSoC_CMD_RX_MASTER_FINGER_TH:
+ case PSoC_CMD_RX_MASTER_HYSTERESIS:
+ case PSoC_CMD_RX_SLAVE_FINGER_TH:
+ case PSoC_CMD_RX_SLAVE_HYSTERESIS:
+ case PSoC_CMD_RX_GET_FINGER_CAP:
+ return u8Len == 0x20;
+
+ // Nonsense
+ case _PSoC_CMD_RX_NONE:
+ return 0;
+ }
+ return 0;
+}
+
+static inline uint8_t PSoC_Validate_Sum(PSoC_CMD_RX eCmd, uint8_t u8Observed, uint8_t u8Received) {
+ switch (eCmd) {
+ // These four commands are broken, and their checksum is always zero
+ case PSoC_CMD_RX_MASTER_FINGER_TH:
+ case PSoC_CMD_RX_MASTER_HYSTERESIS:
+ case PSoC_CMD_RX_SLAVE_FINGER_TH:
+ case PSoC_CMD_RX_SLAVE_HYSTERESIS:
+ return u8Received == 0;
+ default:
+ return u8Received == u8Observed;
+ }
+}
+
void UART1_IRQHandler(void) {
static uint8_t su8RxData[32] = { 0 };
static uint8_t su8State = 0;
@@ -88,18 +215,15 @@ void UART1_IRQHandler(void) {
switch (su8State) {
case 0:
- eCmd = u8Data; // For debugging
switch (u8Data) {
- // Just go away
+ // Commands with no payload
case PSoC_CMD_RX_CS_START:
case PSoC_CMD_RX_CS_END:
- return;
- // Commands with no payload
- case PSoC_CMD_RX_SET_FINGER_CAP:
- PSoC_HandleRx(u8Data, 0, NULL);
+ // PSoC_HandleRx(u8Data, 0, NULL);
return;
// Commands that have a payload we need to receive
+ case PSoC_CMD_RX_SET_FINGER_CAP:
case PSoC_CMD_RX_REQUEST_FINGER_CAP:
case PSoC_CMD_RX_MASTER_DIFF:
case PSoC_CMD_RX_SLAVE_DIFF:
@@ -114,6 +238,11 @@ void UART1_IRQHandler(void) {
su8Sum = u8Data;
su8State++;
return;
+
+ // Unknown command
+ default:
+ su8State = 0;
+ return;
}
return;
case 1:
@@ -125,16 +254,28 @@ void UART1_IRQHandler(void) {
if (!su8Len) su8State++;
// Packets too large for reception need dropped
if (su8Len > sizeof su8RxData) su8State = 0;
+
+ if (!PSoC_Valid_Len(eCmd, su8Len)) {
+ // This isn't the right length for this command, so we know we're out of sync
+ su8State = 0;
+ }
return;
case 2:
su8Sum += u8Data;
su8RxData[su8Index++] = u8Data;
- if (su8Index == su8Len) su8State++;
+ if (su8Index == su8Len) {
+ su8State++;
+ }
return;
case 3:
// Only process packets with a valid checksum
- if (su8Sum == u8Data) PSoC_HandleRx(eCmd, su8Len, su8RxData);
- su8State = 0;
+ if (PSoC_Validate_Sum(eCmd, su8Sum, u8Data)) {
+ PSoC_HandleRx(eCmd, su8Len, su8RxData);
+ su8State = 0;
+ } else {
+ // For breakpoints
+ su8State = 0;
+ }
return;
// If we somehow land in an invalid state (should be impossible), make sure we can recover
@@ -144,29 +285,43 @@ void UART1_IRQHandler(void) {
}
}
-static inline void PSoC_Cmd(PSoC_CMD_TX eCmd, uint8_t u8D0, uint8_t u8D1, uint8_t u8Blocking) {
- static uint8_t su8Ready = 0;
- if (u8Blocking) {
- su8Ready = 0;
- pu8PsocGotData = &su8Ready;
- }
+static inline void _UART_Write(uint8_t u8Data) {
+ while (UART_IS_TX_FULL(UART1))
+ ;
+ UART_WRITE(UART1, u8Data);
+}
+static inline void PSoC_Cmd(PSoC_CMD_TX eCmd, uint8_t u8D0, uint8_t u8D1, PSoC_CMD_RX eBlocking) {
+ // The protocol for the PSoCs has no sync byte
+ // This means it's quite likely we're going to sometimes be parsing in the middle of a packets,
+ // causing us to potentially lose future packets that we wanted to receive.
+ //
+ // To avoid this situation, we're going to repeatedly send the packet on a timeout.
+ //
+ // If the PSoC is totally non-responsive this will deadlock. For now that's probably fine. We
+ // can add a retry counter down the line if it causes problems.
+ do {
+ _UART_Write(eCmd);
+ _UART_Write(2);
+ _UART_Write(u8D0);
+ _UART_Write(u8D1);
+ _UART_Write(eCmd + 2 + u8D0 + u8D1);
- static uint8_t u8Packet[5];
- u8Packet[0] = eCmd;
- u8Packet[1] = 2;
- u8Packet[2] = u8D0;
- u8Packet[3] = u8D1;
- u8Packet[4] = eCmd + 2 + u8D0 + u8D1;
- for (uint8_t i = 0; i < 5; i++) {
- while (UART_IS_TX_FULL(UART1))
- ;
- UART_WRITE(UART1, u8Packet[i]);
- }
+ if (eBlocking == _PSoC_CMD_RX_NONE) break;
+ if (PSoC_Await_Command(eBlocking)) break;
- if (u8Blocking) {
- while (!su8Ready)
- ;
- }
+ // The issue with sync bytes goes both ways. Our packets are 5 bytes long, and the PSoC will
+ // error out if the second byte isn't a 2 (and stop reading), so by ensuring we send an
+ // odd-length stream we'll be back in sync eventually
+ //
+ // It can take quite a few failed packets to bring the PSoC back into sync. Once we have the
+ // PSoC in sync, it should stay in sync for the duration of the program execution. We
+ // perform a blocking sensitivity assignment at the start of the program, which is hopefully
+ // where this resync should ocur if required.
+ //
+ //
+ // ...that's all in theory though.
+ // In practice it seems if we ever break sync the PSoC will need a hard reset.
+ } while (1);
}
uint16_t PSoC_GetFingerCapacitance(void) {
@@ -174,27 +329,50 @@ uint16_t PSoC_GetFingerCapacitance(void) {
pu8PsocRxDestination = &u16FingerCap;
pu8PsocRxDestinationLen = sizeof u16FingerCap;
- PSoC_Cmd(PSoC_CMD_TX_GET_FINGER_CAP, 0, 0, 1);
+ PSoC_Cmd(PSoC_CMD_TX_GET_FINGER_CAP, 0, 0, PSoC_CMD_RX_GET_FINGER_CAP);
- return u16FingerCap;
+ return BYTESWAP_U16(u16FingerCap);
}
-void PSoC_GetDebug(PSoC_CMD_DEBUG u8Cmd, uint8_t* pu8Data, volatile uint8_t* pu8Ready) {
- pu8PsocGotData = pu8Ready;
+void PSoC_GetDebug(PSoC_CMD_DEBUG u8Cmd, uint8_t* pu8Data) {
pu8PsocRxDestination = pu8Data;
- pu8PsocRxDestinationLen = 32;
- PSoC_Cmd(PSoC_CMD_TX_GET_DEBUG, 0, u8Cmd, 0);
+ pu8PsocRxDestinationLen = pu8Data ? 32 : 0;
+
+ PSoC_CMD_RX eRet = _PSoC_CMD_RX_NONE;
+ if (pu8Data != NULL) {
+ switch (u8Cmd) {
+ case PSoC_CMD_DEBUG_MASTER_TOUCH_TH:
+ eRet = PSoC_CMD_RX_MASTER_TOUCH_TH;
+ break;
+ case PSoC_CMD_DEBUG_SLAVE_TOUCH_TH:
+ eRet = PSoC_CMD_RX_SLAVE_TOUCH_TH;
+ break;
+ case PSoC_CMD_DEBUG_MASTER_FINGER_TH:
+ eRet = PSoC_CMD_RX_MASTER_FINGER_TH;
+ break;
+ case PSoC_CMD_DEBUG_SLAVE_FINGER_TH:
+ eRet = PSoC_CMD_RX_SLAVE_FINGER_TH;
+ break;
+ case PSoC_CMD_DEBUG_MASTER_HYSTERESIS:
+ eRet = PSoC_CMD_RX_MASTER_HYSTERESIS;
+ break;
+ case PSoC_CMD_DEBUG_SLAVE_HYSTERESIS:
+ eRet = PSoC_CMD_RX_SLAVE_HYSTERESIS;
+ break;
+ }
+ }
+ PSoC_Cmd(PSoC_CMD_TX_GET_DEBUG, 0, u8Cmd, eRet);
}
-void PSoC_SetFingerCapacitance(uint16_t u16FingerCap) {
+void PSoC_SetFingerCapacitance(uint16_t u16FingerCap, uint8_t u8Blocking) {
if (u16FingerCap > 1023) u16FingerCap = 1023;
- // PSoC_Cmd(PSoC_CMD_TX_SET_FINGER_CAP, u16FingerCap >> 8, u16FingerCap & 0xff, 1);
- PSoC_Cmd(PSoC_CMD_TX_SET_FINGER_CAP, u16FingerCap >> 8, u16FingerCap & 0xff, 1);
+ PSoC_Cmd(PSoC_CMD_TX_SET_FINGER_CAP, u16FingerCap >> 8, u16FingerCap & 0xff,
+ u8Blocking ? PSoC_CMD_RX_SET_FINGER_CAP : _PSoC_CMD_RX_NONE);
}
-void PSoC_SetFingerCapacitanceFromConfig(void) {
- PSoC_SetFingerCapacitance(PSoC_FINGER_CAP_MIN + (16 - gConfig.u8Sens) * PSoC_FINGER_CAP_STEP);
+void PSoC_SetFingerCapacitanceFromConfig(uint8_t u8Blocking) {
+ PSoC_SetFingerCapacitance(PSoC_FINGER_CAP_MIN + (16 - gConfig.u8Sens) * PSoC_FINGER_CAP_STEP,
+ u8Blocking);
}
-void PSoC_EnableDebug(uint8_t u8D1, uint8_t u8D2) {
- // TODO: Finish figuring out what values these two bytes need
- PSoC_Cmd(PSoC_CMD_TX_ENABLE_DEBUG, u8D1, u8D2, 1);
+void PSoC_SetDebug(PSoC_DebugFlag eFlag, uint8_t bEnable) {
+ PSoC_Cmd(PSoC_CMD_TX_ENABLE_DEBUG, eFlag, bEnable, PSoC_CMD_RX_ENABLE_DEBUG);
}
uint8_t gu8GroundData[32];
@@ -205,20 +383,33 @@ void PSoC_PostProcessing(void) {
uint8_t j = (15 - (i / 2)) * 2 + (i & 1);
const uint16_t u16Pad = gu16PSoCDiff[i];
+ const uint16_t u16TouchTh = gu16PSoCThreshold[i];
- const uint16_t u16Min = gConfig.u16PSoCScaleMin[i];
- const uint16_t u16Max = gConfig.u16PSoCScaleMax[i];
-
- if (u16Pad < u16Min) {
- gu8GroundData[j] = 0;
- } else if (u16Pad > u16Max) {
+ // Chunithm defaults to a threshold of 20
+ // As such, we need to scale u16Pad such that (0,u16TouchTh)=(0,20)
+ //
+ // This can go over 255, so make sure to clamp it
+ uint16_t u16Val = (u16Pad * 20) / u16TouchTh;
+ if (u16Val > 255)
gu8GroundData[j] = 255;
- } else {
- // Multiply by 255 first to retain precision
- // This can overflow u16, hence the u32 cast pre-mult
- gu8GroundData[j] = ((uint32_t)(u16Pad - u16Min) * 255) / (u16Max - u16Min);
- }
+ else
+ gu8GroundData[j] = u16Val;
+
+ // const uint16_t u16Min = gConfig.u16PSoCScaleMin[i];
+ // const uint16_t u16Max = gConfig.u16PSoCScaleMax[i];
+
+ // if (u16Pad < u16Min) {
+ // gu8GroundData[j] = 0;
+ // } else if (u16Pad > u16Max) {
+ // gu8GroundData[j] = 255;
+ // } else {
+ // // Multiply by 255 first to retain precision
+ // // This can overflow u16, hence the u32 cast pre-mult
+ // gu8GroundData[j] = ((uint32_t)(u16Pad - u16Min) * 255) / (u16Max - u16Min);
+ // }
}
+
+ bForceSliderSend = 1;
}
/**
* @brief Calculate digital input data from PSoC values
@@ -283,3 +474,6 @@ void PSoC_DigitalCalc(void) {
}
}
}
+
+// #pragma GCC diagnostic pop
+// #pragma GCC pop_options
diff --git a/src/psoc.h b/src/psoc.h
index d40ac06..515aae4 100644
--- a/src/psoc.h
+++ b/src/psoc.h
@@ -5,22 +5,26 @@
#define PSoC_DATA_SIZE 32
#define PSoC_PACKET_SIZE (2 + PSoC_DATA_SIZE)
-// Used for calculation of PSoC_FINGER_CAP_MIN
// The difference between CAP and MIN must be divisible by 8
-#define PSoC_FINGER_CAP_MIN 20 // 0.2pF
-#define PSoC_DEFAULT_CAP 340 // 3.2pF
-// Maximum is CAP*2-MIN*2 ie 6.0pF
+// The stupidly high gain kicks in around 0.7pF. It's not directly based on fingerCap though
+// so 1.0pF gives us a bit of a margin to ensure we avoid it
+#define PSoC_FINGER_CAP_MIN 100 // 1.0pF
+#define PSoC_DEFAULT_CAP 500 // 5.0pF
+// Maximum is CAP*2-MIN*2 ie 8.0pF
#define PSoC_FINGER_CAP_STEP ((PSoC_DEFAULT_CAP - PSoC_FINGER_CAP_MIN) / 8)
-typedef enum {
+typedef enum : uint8_t {
// Host -> PSoC
PSoC_CMD_TX_GET_FINGER_CAP = 0xB5,
PSoC_CMD_TX_GET_DEBUG = 0xB6,
PSoC_CMD_TX_SET_FINGER_CAP = 0xBD,
PSoC_CMD_TX_ENABLE_DEBUG = 0xDE,
} PSoC_CMD_TX;
-typedef enum {
+typedef enum : uint8_t {
+ // We'd use 0x00, but that's used, so 0x01 it is
+ _PSoC_CMD_RX_NONE = 0x01,
+
// PSoC -> Host
PSoC_CMD_RX_MASTER_DIFF = 0xAD,
PSoC_CMD_RX_SLAVE_DIFF = 0xAF,
@@ -39,24 +43,28 @@ typedef enum {
// Packets that get a direct response
PSoC_CMD_RX_GET_FINGER_CAP = PSoC_CMD_TX_GET_FINGER_CAP,
PSoC_CMD_RX_SET_FINGER_CAP = PSoC_CMD_TX_SET_FINGER_CAP,
+ PSoC_CMD_RX_ENABLE_DEBUG = PSoC_CMD_TX_ENABLE_DEBUG,
} PSoC_CMD_RX;
-typedef enum {
+typedef enum : uint8_t {
PSoC_CMD_DEBUG_MASTER_TOUCH_TH = 0,
PSoC_CMD_DEBUG_SLAVE_TOUCH_TH,
PSoC_CMD_DEBUG_MASTER_FINGER_TH,
- PSoC_CMD_DEBUG_SLAVE_FINGER_TH,
+ PSoC_CMD_DEBUG_SLAVE_FINGER_TH, // Broken!
PSoC_CMD_DEBUG_MASTER_HYSTERESIS,
- PSoC_CMD_DEBUG_SLAVE_HYSTERESIS,
+ PSoC_CMD_DEBUG_SLAVE_HYSTERESIS, // Broken!
} PSoC_CMD_DEBUG;
// Difference between the raw count value and the baseline, from SmartSense
extern uint16_t gu16PSoCDiff[32];
-// Has the difference data changed?
-extern volatile uint8_t bPSoCDirty;
+// Has the difference data changed in the interrupt handler?
+extern volatile uint8_t bPSoCDirtyVolatile;
+// Has the post-processed difference data changed?
+extern volatile uint8_t bForceSliderSend;
// Used for producing gu32PSoCDigital and gu16PSoCDigital
-#define PSoC_INTERNAL_DIGITAL_TH 0
+// (Same threshold as default in Chunithm)
+#define PSoC_INTERNAL_DIGITAL_TH 20
// PSoC data, re-interpreted as digital inputs
extern uint32_t gu32PSoCDigital;
@@ -68,27 +76,16 @@ extern uint16_t gu16PSoCDigitalPos;
extern uint16_t gu16PSoCDigitalNeg;
extern uint16_t gu16PSoCDigitalTrig;
-extern uint8_t gu8PSoCSeenData;
-
-#define PSoC_RAW_T0 34
-#define PSoC_RAW_T1 91
-#define PSoC_RAW_T2 121
-#define PSoC_RAW_MIN 199
-#define PSoC_SCALE 5 // ie to scale from [0~4ff] to [0~ff]
-
-#define PSoC_OUT_MIN 20
-#define PSoC_OUT_MAX 255
-
-#define PSoC_SCALE_MIN (0 + 128)
-#define PSoC_SCALE_MAX (0x4ff - 128 - 256)
-#define PSoC_SCALE_RANGE (3) // ie to scale from [min~max] to [0~ff]
+//
+extern uint32_t gu32LastCapSenseStart;
+extern uint32_t gu32LastCapSenseEnd;
void PSoC_PostProcessing(void);
void PSoC_DigitalCalc(void);
-// General usage PSoC commands; return instantly
-void PSoC_SetFingerCapacitance(uint16_t u16FingerCap);
-void PSoC_SetFingerCapacitanceFromConfig(void);
+// General usage PSoC commands
+void PSoC_SetFingerCapacitance(uint16_t u16FingerCap, uint8_t u8Blocking);
+void PSoC_SetFingerCapacitanceFromConfig(uint8_t u8Blocking);
/**
* @brief Get the finger capacitance value currently configured on the Master PSoC
*
@@ -98,13 +95,24 @@ uint16_t PSoC_GetFingerCapacitance(void);
/**
* @brief Request a debug array from the PSoC pair
*
- * This call is asynchronous. Use pu8Ready to ensure pu8Data is ready.
- * Only one call can be in-flight at once.
- * **DO NOT** call PSoCGetFingerCapacitance while waiting on this function.
- *
* @param u8Cmd The specific debug array to request
* @param pu8Data Pointer to array that will receive the data. Must be 32 bytes.
- * @param pu8Ready Optional uint8_t to signal the data is ready
*/
-void PSoC_GetDebug(PSoC_CMD_DEBUG u8Cmd, uint8_t* pu8Data, volatile uint8_t* pu8Ready);
-void PSoC_EnableDebug(uint8_t u8D1, uint8_t u8D2);
+void PSoC_GetDebug(PSoC_CMD_DEBUG u8Cmd, uint8_t* pu8Data);
+
+typedef enum : uint8_t {
+ // Flag 0 doesn't appear to be used anywhere, nor does it appear to have any effect
+ PSoC_DebugFlag_0 = 0,
+ PSoC_DebugFlag_TraceReset = 1,
+} PSoC_DebugFlag;
+/**
+ * @brief Enable or disable a debug tracing flag
+ *
+ * The reception of debug traces will be recorded in:
+ * - gu32LastCapSenseStart
+ * - gu32LastCapSenseEnd
+ *
+ * @param eFlag Which flag to set
+ * @param bEnable Should the flag be enabled or disabled
+ */
+void PSoC_SetDebug(PSoC_DebugFlag eFlag, uint8_t bEnable);
diff --git a/src/slider.c b/src/slider.c
index 149e78f..490f095 100644
--- a/src/slider.c
+++ b/src/slider.c
@@ -10,7 +10,7 @@ static uint8_t su8AutoEnabledRaw = 0;
static uint8_t su8AutoEnabledByte = 0;
static uint32_t su32SinceLastControlled = 0;
-uint8_t gu8GameBrightness = 40; // TODO: Actually make use of this
+uint8_t gu8GameBrightness = 40;
static uint16_t su16ByteRawSliderOffset = 0;
static uint8_t su8ByteRawSliderShift = 0;
@@ -23,9 +23,11 @@ typedef enum {
SLIDER_PARSE_CHECKSUM,
} slider_parse_state;
+// Hardware information for a Chunithm slider
static const slider_cmd_Tx_hw_info sSliderHwInfo = {
"15330 ", 0xA0, "06712", 0xFF, 0x90, 0, 0,
};
+void Slider_Exception(uint8_t u8SliderCmd, slider_exception u8Exc);
static inline void Slider_Write(uint8_t u8Byte) {
if (u8Byte == SLIDER_SYNC || u8Byte == SLIDER_MARK) {
@@ -47,11 +49,36 @@ static void Slider_Respond(slider_cmd_Tx u8SliderCmd, const uint8_t* pu8Packet,
Slider_Write(-u8Sum);
}
+uint8_t u8Null64[64] = { 0 };
+static void Slider_Send_Report(void) {
+ if (gbUIOpen) {
+ Slider_Respond(SLIDER_CMD_Tx_REPORT, u8Null64, sizeof gu8GroundData);
+ } else {
+ Slider_Respond(SLIDER_CMD_Tx_REPORT, gu8GroundData, sizeof gu8GroundData);
+ }
+}
+static void Slider_Send_Report_Raw(void) {
+ if (gbUIOpen) {
+ Slider_Respond(SLIDER_CMD_Tx_RAW, u8Null64, sizeof gu16PSoCDiff);
+ } else {
+ Slider_Respond(SLIDER_CMD_Tx_RAW, (void*)gu16PSoCDiff, sizeof gu16PSoCDiff);
+ }
+}
+static void Slider_Send_Report_Byte(void) {
+ slider_cmd_Tx_raw buffer;
+ for (uint8_t i = 0; i < 32; i++) {
+ if (gbUIOpen) {
+ buffer.u16Raw[i] = 0;
+ } else {
+ buffer.u16Raw[i] = (gu16PSoCDiff[i] >> su8ByteRawSliderShift) - su16ByteRawSliderOffset;
+ }
+ }
+ Slider_Respond(SLIDER_CMD_Tx_RAW, (void*)&buffer, sizeof buffer);
+}
static void Slider_Process(slider_cmd_Rx u8SliderCmd, uint8_t* pu8Packet, uint8_t u8NPacket) {
switch (u8SliderCmd) {
case SLIDER_CMD_Rx_RESET:
// These three weren't present previously, but PSoC firmware suggests they should be
- // TODO: Validate this against the game!
su8AutoEnabled = 0;
su8AutoEnabledRaw = 0;
su8AutoEnabledByte = 0;
@@ -92,7 +119,7 @@ static void Slider_Process(slider_cmd_Rx u8SliderCmd, uint8_t* pu8Packet, uint8_
gbLedDataIsControlledExt = 1;
su32SinceLastControlled = 0;
- memcpy(gu8aControlledExtLedData, &((slider_cmd_Rx_led*)pu8Packet)->aBRG, 3 * 32);
+ memcpy(gaControlledExtLedData, &((slider_cmd_Rx_led*)pu8Packet)->aBRG, 3 * 32);
}
// Reprocess this packet as a report request where applicable
if (u8SliderCmd == SLIDER_CMD_Rx_REPORT_PING_PONG) {
@@ -105,13 +132,13 @@ static void Slider_Process(slider_cmd_Rx u8SliderCmd, uint8_t* pu8Packet, uint8_
return;
case SLIDER_CMD_Rx_REPORT:
- Slider_Respond(SLIDER_CMD_Tx_REPORT, gu8GroundData, sizeof gu8GroundData);
+ Slider_Send_Report();
return;
case SLIDER_CMD_Rx_RAW:
- // TODO:
+ Slider_Send_Report_Raw();
return;
case SLIDER_CMD_Rx_BRAW:
- // TODO:
+ Slider_Send_Report_Byte();
return;
case SLIDER_CMD_Rx_REPORT_ENABLE:
@@ -143,6 +170,92 @@ static void Slider_Process(slider_cmd_Rx u8SliderCmd, uint8_t* pu8Packet, uint8_
su8ByteRawSliderShift = ((slider_cmd_Rx_braw_set_shift*)pu8Packet)->u8Shift;
Slider_Respond(SLIDER_CMD_Tx_BRAW_SET_SHIFT, NULL, 0);
return;
+
+ case SLIDER_CMD_Rx_DEBUG:
+ uint8_t u8aData[32];
+
+ switch ((slider_debug_cmd_Rx)pu8Packet[0]) {
+ case SLIDER_DEBUG_CMD_Rx_GET_FINGER_CAP:
+ uint16_t u16FingerCap = PSoC_GetFingerCapacitance();
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, (uint8_t*)&u16FingerCap,
+ sizeof u16FingerCap);
+ break;
+ case SLIDER_DEBUG_CMD_Rx_TRACE_RESET:
+ // TODO: Broken. Blocks forever.
+ PSoC_SetDebug(PSoC_DebugFlag_TraceReset, 1);
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, NULL, 0);
+ break;
+ case SLIDER_DEBUG_CMD_Rx_GET_LAST_CS_START:
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, (uint8_t*)&gu32LastCapSenseStart,
+ sizeof gu32LastCapSenseStart);
+ break;
+ case SLIDER_DEBUG_CMD_Rx_GET_LAST_CS_END:
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, (uint8_t*)&gu32LastCapSenseEnd,
+ sizeof gu32LastCapSenseEnd);
+ break;
+
+ case SLIDER_DEBUG_CMD_Rx_PSoC_REQUEST_DEBUG:
+ if (u8NPacket == 2) {
+ PSoC_GetDebug(pu8Packet[1], u8aData);
+ }
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, u8aData, sizeof u8aData);
+ break;
+
+ case SLIDER_DEBUG_CMD_Rx_HOST_FMC_READ:
+ if (u8NPacket == 5) {
+ // We can't use a cast to uint32_t* because of unaligned reads!
+ uint32_t u32Base = pu8Packet[1];
+ u32Base |= pu8Packet[2] << 8;
+ u32Base |= pu8Packet[3] << 16;
+ u32Base |= pu8Packet[4] << 24;
+ memset(u8aData, 0xFF, sizeof u8aData);
+ FMC_Open();
+ FMC_ReadData(u32Base, u32Base + sizeof u8aData, (void*)u8aData);
+ FMC_Close();
+ }
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, u8aData, sizeof u8aData);
+ break;
+ case SLIDER_DEBUG_CMD_Rx_LED_FMC_READ:
+ uint32_t u32Data = 0xFFFFFFFF;
+ if (u8NPacket == 5) {
+ uint32_t u32Offset = pu8Packet[1];
+ u32Offset |= pu8Packet[2] << 8;
+ u32Offset |= pu8Packet[3] << 16;
+ u32Offset |= pu8Packet[4] << 24;
+
+ LED_FMC_Read(u32Offset, &u32Data);
+ }
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, (uint8_t*)&u32Data, sizeof u32Data);
+ break;
+
+ case SLIDER_DEBUG_CMD_Rx_HOST_ENTER_LDROM:
+ SYS_EnterLDROM();
+ break;
+ case SLIDER_DEBUG_CMD_Rx_LED_ENTER_LDROM:
+ gu8LEDTx[0] = LED_CMD_FMC_ENTER_LDROM;
+ // The LED firmware checks every 10ms or so
+ CLK_SysTickLongDelay(15 ms);
+ SYS_WaitBootloaderLED();
+ break;
+ case SLIDER_DEBUG_CMD_Rx_LED_CHECK:
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, (uint8_t*)&gbLedIsCustom,
+ sizeof gbLedIsCustom);
+ break;
+
+ case SLIDER_DEBUG_CMD_Rx_LED_GET_DIGITAL:
+ Slider_Respond(SLIDER_CMD_Tx_DEBUG, &gu8DigitalButtons,
+ sizeof gu8DigitalButtons);
+ break;
+
+ default:
+ Slider_Exception(u8SliderCmd, SLIDER_EXCEPTION_BUS_ERROR);
+ break;
+ }
+ return;
+
+ default:
+ Slider_Exception(u8SliderCmd, SLIDER_EXCEPTION_BUS_ERROR);
+ break;
}
}
void Slider_Exception(uint8_t u8SliderCmd, slider_exception u8Exc) {
@@ -233,13 +346,37 @@ void Slider_Tick1ms() {
if (++su32SinceLastControlled == 5 * 1000) gbLedDataIsControlledExt = 0;
}
- if (su8AutoEnabled) {
- static uint8_t u8Counter = 0;
- // Only actually send an update every 8ms
- if (++u8Counter != 8) return;
+ static uint16_t u16Counter = 0;
+ /**
+ * I haven't totally tracked down the source of the interval timer on a real slider.
+ * That said, from measurement it's 15.365ms or so. The exact time will be based on
+ * a counter from one of the low speed clocks.
+ *
+ * The game makes calls to ReadFile on an 8ms interval, but this isn't the most stable.
+ * I took a short capture, and my intervals were:
+ *
+ * 0% | 3.6ms
+ * 10% | 7.0ms
+ * 50% | 8.0ms
+ * 90% | 9.0ms
+ * 100% | 14.0ms
+ *
+ * This +-1ms appears to be caused by the use of Sleep() to regulate the interval, which
+ * has an argument precision of 1ms (and an overall precision far worse!).
+ *
+ * Chunithm will retry a read four times, at which point it considers the slider to have
+ * timed out (error 3100).
+ *
+ * Based on this, we should be safe to indeed run at a 15ms interval here.
+ *
+ * I received one report of a user getting a 3100 when they started the game. I am current
+ * working on the basis that this is a one-off, however this will need re-addressed if this
+ * issue becomes widespread.
+ */
+ if (++u16Counter != 15) return;
+ u16Counter = 0;
- u8Counter = 0;
-
- Slider_Respond(SLIDER_CMD_Tx_REPORT, gu8GroundData, sizeof gu8GroundData);
- }
+ if (su8AutoEnabled) Slider_Send_Report();
+ if (su8AutoEnabledRaw) Slider_Send_Report_Raw();
+ if (su8AutoEnabledByte) Slider_Send_Report_Byte();
}
diff --git a/src/slider.h b/src/slider.h
index 11bb6b9..f849b2b 100644
--- a/src/slider.h
+++ b/src/slider.h
@@ -52,7 +52,7 @@
#define PAD_31_Msk BIT0
#define PAD_32_Msk BIT1
-typedef enum {
+typedef enum : uint8_t {
// =========================
// Actually used by Chunithm
// =========================
@@ -69,9 +69,14 @@ typedef enum {
/* Retrieve hardware information (model number, etc.) */
SLIDER_CMD_Rx_HW_INFO = 0xF0,
- // ======
- // Autism
- // ======
+ // ==========================================
+ // Custom additions, used for debugging, etc.
+ // ==========================================
+ SLIDER_CMD_Rx_DEBUG = 0xF1,
+
+ // =====================================================================
+ // Required for a complete slider implementation, but unused by the game
+ // =====================================================================
/* Request a single standard report */
SLIDER_CMD_Rx_REPORT = 0x01,
/* Set LED brightness and BRG values, with a report as the response */
@@ -98,7 +103,27 @@ typedef enum {
/* Request the CPU status registers */
SLIDER_CMD_Rx_CPU_STATUS = 0xE0,
} slider_cmd_Rx;
-typedef enum {
+typedef enum : uint8_t {
+ // Actual debugging stuff
+ SLIDER_DEBUG_CMD_Rx_GET_FINGER_CAP = 0x00,
+ SLIDER_DEBUG_CMD_Rx_TRACE_RESET = 0x01,
+ SLIDER_DEBUG_CMD_Rx_GET_LAST_CS_START = 0x02,
+ SLIDER_DEBUG_CMD_Rx_GET_LAST_CS_END = 0x03,
+ SLIDER_DEBUG_CMD_Rx_PSoC_REQUEST_DEBUG = 0x04,
+
+ // Flash access
+ SLIDER_DEBUG_CMD_Rx_HOST_FMC_READ = 0x10,
+ SLIDER_DEBUG_CMD_Rx_LED_FMC_READ = 0x12,
+
+ // Chip reset
+ SLIDER_DEBUG_CMD_Rx_HOST_ENTER_LDROM = 0x20,
+ SLIDER_DEBUG_CMD_Rx_LED_ENTER_LDROM = 0x21,
+ SLIDER_DEBUG_CMD_Rx_LED_CHECK = 0x22,
+
+ // IO Access
+ SLIDER_DEBUG_CMD_Rx_LED_GET_DIGITAL = 0x30,
+} slider_debug_cmd_Rx;
+typedef enum : uint8_t {
SLIDER_CMD_Tx_REPORT = 0x01,
SLIDER_CMD_Tx_REPORT_DISABLE = 0x04,
@@ -112,8 +137,10 @@ typedef enum {
SLIDER_CMD_Tx_CPU_STATUS = 0xE0,
SLIDER_CMD_Tx_EXCEPTION = 0xEE,
SLIDER_CMD_Tx_HW_INFO = 0xF0,
+
+ SLIDER_CMD_Tx_DEBUG = 0xF1,
} slider_cmd_Tx;
-typedef enum {
+typedef enum : uint8_t {
SLIDER_EXCEPTION_CHECKSUM = 1,
SLIDER_EXCEPTION_BUS_ERROR = 2,
} slider_exception;
@@ -126,7 +153,7 @@ typedef enum {
#define SLIDER_EXCEPTION_CTX_GENERIC 0xED
typedef struct __packed {
- uint8_t u8Brightness;
+ uint8_t u8Brightness; // Range: 0~63
struct __packed {
uint8_t u8B;
uint8_t u8R;
@@ -184,6 +211,6 @@ typedef struct __packed {
};
} slider_cmd_Tx_cpu_status;
-extern uint8_t gu8GameBrightness; // 0~63
+extern uint8_t gu8GameBrightness; // Range: 0~63
void Slider_TickSerial(void);
void Slider_Tick1ms(void);
diff --git a/src/sys.c b/src/sys.c
index 2b0bff1..612b6ae 100644
--- a/src/sys.c
+++ b/src/sys.c
@@ -17,10 +17,16 @@ void SYS_ResetModule(uint32_t u32ModuleIndex) {
~(1 << (u32ModuleIndex & 0x00ffffff));
}
+// Even though we have an external 12MHz crystal, it's never actually used.
+// This define toggles if we will even bother configuring it or not.
+#define EXT_CLK
+
void SYS_Init(void) {
+#ifdef EXT_CLK
// Enable XT1_OUT (PF.0) and XT1_IN (PF.1)
SYS->GPF_MFP &= ~(SYS_GPF_MFP_PF0_Msk | SYS_GPF_MFP_PF1_Msk);
SYS->GPF_MFP |= SYS_GPF_MFP_PF0_XT1_OUT | SYS_GPF_MFP_PF1_XT1_IN;
+#endif
// Enable Internal RC 22.1184 MHz clock
CLK_EnableXtalRC(CLK_PWRCON_OSC22M_EN_Msk);
@@ -29,12 +35,14 @@ void SYS_Init(void) {
// Switch HCLK clock source to Internal RC and HCLK source divide 1
CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1));
+#ifdef EXT_CLK
// Enable external XTAL 12 MHz clock
CLK_EnableXtalRC(CLK_PWRCON_XTL12M_EN_Msk);
CLK_WaitClockReady(CLK_CLKSTATUS_XTL12M_STB_Msk);
+#endif
// Set core clock
- CLK_SetCoreClock(72000000);
+ CLK_SetCoreClock(72 MHz);
// Enable module clocks
CLK_EnableModuleClock(UART1_MODULE);
@@ -57,6 +65,8 @@ void SYS_Init(void) {
PIN_SCL = 1;
// Configure our GPIO pins
+ GPIO_SetMode(_PIN_FN1, GPIO_PMD_QUASI);
+ GPIO_SetMode(_PIN_FN2, GPIO_PMD_QUASI);
GPIO_SetMode(_PIN_EC1, GPIO_PMD_INPUT);
GPIO_SetMode(_PIN_RX2, GPIO_PMD_INPUT);
GPIO_SetMode(_PIN_RX3, GPIO_PMD_INPUT);
@@ -71,26 +81,30 @@ void SYS_Init(void) {
PIN_LED_WING_PWR = 1;
PIN_LED_GROUND_PWR = 1;
- GPIO_SetMode(_PIN_FN2, GPIO_PMD_INPUT);
- // TODO:
+ // If FN2 is depressed, trigger the LED bootloader to enter bootloading mode by pulling both
+ // PA10 and PA11 low rather than configuring them for I2C (pulling high).
+ //
+ // We have 145us to get to this point, because that's how long the LED bootloader is willing to
+ // wait!
if (PIN_FN2 == 0) {
PIN_USB_MUX_SEL = USB_MUX_LEDS;
PIN_USB_MUX_EN = USB_MUX_ENABLE;
+
+ // Trigger the bootloader
GPIO_SetMode(_PIN_SDA, GPIO_PMD_OUTPUT);
GPIO_SetMode(_PIN_SCL, GPIO_PMD_OUTPUT);
PIN_SDA = 0;
PIN_SCL = 0;
- return;
+ } else {
+ // Set GPA multi-function pins for I2C1 SDA and SCL
+ SYS->GPA_MFP &= ~(SYS_GPA_MFP_PA10_Msk | SYS_GPA_MFP_PA11_Msk);
+ SYS->GPA_MFP |= (SYS_GPA_MFP_PA10_I2C1_SDA | SYS_GPA_MFP_PA11_I2C1_SCL);
+ SYS->ALT_MFP &= ~(SYS_ALT_MFP_PA10_Msk | SYS_ALT_MFP_PA11_Msk);
+ SYS->ALT_MFP |= (SYS_ALT_MFP_PA10_I2C1_SDA | SYS_ALT_MFP_PA11_I2C1_SCL);
+
+ PIN_USB_MUX_SEL = USB_MUX_HOST;
+ PIN_USB_MUX_EN = USB_MUX_ENABLE;
}
-
- // Set GPA multi-function pins for I2C1 SDA and SCL
- SYS->GPA_MFP &= ~(SYS_GPA_MFP_PA10_Msk | SYS_GPA_MFP_PA11_Msk);
- SYS->GPA_MFP |= (SYS_GPA_MFP_PA10_I2C1_SDA | SYS_GPA_MFP_PA11_I2C1_SCL);
- SYS->ALT_MFP &= ~(SYS_ALT_MFP_PA10_Msk | SYS_ALT_MFP_PA11_Msk);
- SYS->ALT_MFP |= (SYS_ALT_MFP_PA10_I2C1_SDA | SYS_ALT_MFP_PA11_I2C1_SCL);
-
- PIN_USB_MUX_EN = USB_MUX_ENABLE;
- PIN_USB_MUX_SEL = USB_MUX_HOST;
}
void SYS_ModuleInit(void) {
@@ -130,13 +144,46 @@ void SYS_ModuleInit(void) {
NVIC_EnableIRQ(USBD_IRQn);
}
-// Define a dedicated symbol for this, so we can easily trap it with a debugger!
-void HardFault_Handler() {
+void HardFault_Handler(uint32_t *stack) {
+ // Extract r0-3, r12, lr, pc, psr, and place them into "stack"
+ asm("MOVS r0, #4 \n"
+ "MOV r1, lr \n"
+ "TST r0, r1 \n" // check LR bit 2
+ "BEQ 1f \n" // stack use MSP
+ "MRS r0, psp \n" // stack use PSP, read PSP
+ "MOV r1, lr \n" // LR current value
+ "B 2f \n"
+ "1: \n"
+ "MRS r0, msp \n" // LR current value
+ "2: \n");
+
+ // Extract out into locals for easy debugging
+ uint32_t r0 = stack[0];
+ uint32_t r1 = stack[1];
+ uint32_t r2 = stack[2];
+ uint32_t r3 = stack[3];
+ uint32_t r12 = stack[4];
+ uint32_t lr = stack[5];
+ uint32_t pc = stack[6];
+ uint32_t psr = stack[7];
+
+ // Silence unused warnings
+ (void)r0;
+ (void)r1;
+ (void)r2;
+ (void)r3;
+ (void)r12;
+ (void)lr;
+ (void)pc;
+ (void)psr;
+
+ // Force a chip reset
+ SYS->IPRSTC1 = SYS_IPRSTC1_CHIP_RST_Msk;
while (1)
;
}
-void SYS_Bootloader_Check() {
+void SYS_Bootloader_Check(void) {
FMC_Open();
while (FMC_Read(BOOTLOADER_MAGIC_ADDR) != BOOTLOADER_MAGIC)
;
@@ -156,3 +203,88 @@ void TMR0_IRQHandler(void) {
}
}
}
+
+#define V6M_AIRCR_VECTKEY_DATA 0x05FA0000UL
+void __attribute__((noreturn)) SYS_EnterLDROM(void) {
+ SYS_UnlockReg();
+
+ // If we use a CPU reset, I2C is left setup and so the LED board will be timing out rather than
+ // early-NACKS.
+ // If we use a CHIP reset we aren't guaranteed to land in LDROM because it's based on the CONFIG
+ // flags, though realistically we are.
+ // An MCU reset guarantees we end up in LDROM regardless of configuration.
+
+ // Reset to LDROM using a CPU reset
+ // FMC->ISPCON |= FMC_ISPCON_BS_Msk | FMC_ISPCON_ISPEN_Msk;
+ // SYS->IPRSTC1 |= SYS_IPRSTC1_CPU_RST_Msk;
+
+ // Reset to LDROM using a CHIP reset
+ // SYS->IPRSTC1 |= SYS_IPRSTC1_CHIP_RST_Msk;
+
+ // Reset to LDROM using a MCU reset
+ SYS->RSTSRC = SYS_RSTSRC_RSTS_POR_Msk | SYS_RSTSRC_RSTS_RESET_Msk;
+ FMC->ISPCON |= FMC_ISPCON_BS_Msk | FMC_ISPCON_ISPEN_Msk;
+ NVIC_SystemReset();
+
+ // Trap the processor
+ while (1)
+ ;
+ __builtin_unreachable();
+}
+
+void SYS_WaitBootloaderLED(void) {
+ SYS_UnlockReg();
+
+ // Switch PA10 and PA11 to GPIO so we can pull them low
+ SYS->GPA_MFP &= ~(SYS_GPA_MFP_PA10_Msk | SYS_GPA_MFP_PA11_Msk);
+ SYS->GPA_MFP |= (SYS_GPA_MFP_PA10_GPIO | SYS_GPA_MFP_PA11_GPIO);
+ SYS->ALT_MFP &= ~(SYS_ALT_MFP_PA10_Msk | SYS_ALT_MFP_PA11_Msk);
+ SYS->ALT_MFP |= (SYS_ALT_MFP_PA10_GPIO | SYS_ALT_MFP_PA11_GPIO);
+
+ // Trigger the bootloader
+ GPIO_SetMode(_PIN_SDA, GPIO_PMD_OUTPUT);
+ GPIO_SetMode(_PIN_SCL, GPIO_PMD_OUTPUT);
+ PIN_SDA = 0;
+ PIN_SCL = 0;
+
+ // Shutdown I2C
+ I2C_Close(I2C1);
+
+ // Turn off our USB PHY
+ USBD->ATTR = 0x650;
+ NVIC_DisableIRQ(USBD_IRQn);
+ SYS_ResetModule(USBD_RST);
+ // Give Windows a moment to notice the disconnection
+ CLK_SysTickLongDelay(1000 ms);
+ // Switch the USB connection over the LED microcontroller
+ PIN_USB_MUX_SEL = USB_MUX_LEDS;
+ PIN_USB_MUX_EN = USB_MUX_ENABLE;
+
+ u16I2CRxIndex = 0;
+ // Wait 5 seconds, which is long enough for the LED bootloader to take over
+ CLK_SysTickLongDelay(5000 ms);
+
+ // Switch PA10 and PA11 back to I2C
+ SYS->GPA_MFP &= ~(SYS_GPA_MFP_PA10_Msk | SYS_GPA_MFP_PA11_Msk);
+ SYS->GPA_MFP |= (SYS_GPA_MFP_PA10_I2C1_SDA | SYS_GPA_MFP_PA11_I2C1_SCL);
+ SYS->ALT_MFP &= ~(SYS_ALT_MFP_PA10_Msk | SYS_ALT_MFP_PA11_Msk);
+ SYS->ALT_MFP |= (SYS_ALT_MFP_PA10_I2C1_SDA | SYS_ALT_MFP_PA11_I2C1_SCL);
+
+ // Restart the I2C controller
+ LED_I2C1_Init();
+
+ // Wait until we start getting data from the LED firmware
+ while (u16I2CRxIndex == 0)
+ ;
+
+ // Take back control of USB
+ PIN_USB_MUX_SEL = USB_MUX_HOST;
+ PIN_USB_MUX_EN = USB_MUX_ENABLE;
+
+ // Bring our USB PHY back online, along with a delay sufficient for a device reconnect to be
+ // detected
+ Tas_USBD_Open();
+ Tas_USBD_Init();
+ Tas_USBD_Start();
+ NVIC_EnableIRQ(USBD_IRQn);
+}
\ No newline at end of file
diff --git a/src/tasoller.h b/src/tasoller.h
index 0e0049e..470b933 100644
--- a/src/tasoller.h
+++ b/src/tasoller.h
@@ -3,39 +3,33 @@
#include
#include
-#if defined(__CC_ARM)
-#elif defined(__GNUC__)
-#define __packed __attribute__((packed))
-#else
-#error Unknown compiler
-#endif
+#include "_compiler.h"
#define ms *1000
#define kHz *1000
+#define MHz *1000000
-/* === LEDs === */
-#define LED_Tx_BUFFER 254
-// Defined as volatile due to the I2C interrupt reading at random times!
-extern volatile uint8_t gu8LEDTx[LED_Tx_BUFFER];
+extern uint32_t gu32NowMs;
+extern uint8_t gbUIOpen;
-/* === DAO-DRM === */
+#define BYTESWAP_U16(x) ((((x) & 0xFF) << 8) | ((x) >> 8))
+
+// === DAO-DRM ===
// * For now the bootloader check is being left enabled.
// * It'll help catch if I break that in my bootloader :P
#define ENABLE_BOOTLOADER_CHECK
#define BOOTLOADER_MAGIC 0x5555A320
#define BOOTLOADER_MAGIC_ADDR 0x100FF8
-/* === USB definitions === */
-#include "usb_inc/hid.h"
-#include "usb_inc/keymap.h"
-#include "usb_inc/usb.h"
-
-/* === Local files === */
+// === Local files ===
#include "fmc_user.h"
#include "led.h"
#include "pins.h"
#include "psoc.h"
#include "slider.h"
+#include "usb_def.h"
+#include "vcom.h"
+#include "io4.h"
#define IO4_VENDOR "SEGA INTERACTIVE"
// Product description
@@ -48,102 +42,26 @@ extern volatile uint8_t gu8LEDTx[LED_Tx_BUFFER];
"6679A;" /* Chip number */ \
"00;" /* Config */
// Functional description
-#define _IO4_FUNCTION \
- "GOUT=14_" /* General purpose output (20) */ \
- "ADIN=8,E_" /* ADC input (8) */ \
- "ROTIN=4_" /* Rotary input (4) */ \
- "COININ=2_" /* Coin input (2) */ \
- "SWIN=2,E_" /* Switch inputs (2) */ \
- "UQ1=41,6;" /* Unique function 1 (?) */
+#define _IO4_FUNCTION \
+ "GOUT=14_" /* General purpose output (20) */ \
+ "ADIN=8,E_" /* ADC input (8) */ \
+ "ROTIN=4_" /* Rotary input (4) */ \
+ "COININ=2_" /* Coin input (2) */ \
+ "SWIN=2,E_" /* Switch inputs (2) */ \
+ "UQ1=41,6;" /* Unique 1 (Command: 41h, bytes 6) */
#define IO4_PRODUCT _IO4_PRODUCT _IO4_FUNCTION
#define IO4_VID 0x0CA3
#define IO4_PID 0x0021
-#define INCR(x, y) ((x) = (x) < (y) ? (x) + 1 : (y))
-#define DECR(x, y) ((x) = (x) > (y) ? (x)-1 : (y))
-#define MOD_INCR(x, y) ((x) = (x) == ((y)-1) ? 0 : ((x) + 1))
-#define MOD_DECR(x, y) ((x) = (x) == 0 ? ((y)-1) : ((x)-1))
-#define INV(x) ((x) = 1 - (x))
-
-extern volatile uint8_t gu8VcomReady;
/**
* WARNING: This is both used internally and sent verbatim over serial
* It **MUST** be 32 bytes of ground data
*/
extern uint8_t gu8GroundData[32];
-/* === For HID === */
-enum {
- HID_REPORT_ID_IO4 = 1,
- HID_REPORT_ID_KEYBOARD,
- HID_REPORT_ID_DEBUG_A,
- HID_REPORT_ID_DEBUG_B,
- HID_REPORT_ID_IO4_CMD = 16,
-};
-
-#define NUM_FN 2
-#define NUM_AIR 6
-#define NUM_GROUND 32
-
-typedef struct __packed {
- uint8_t bReportId;
- uint8_t bKeyboard[NUM_FN + NUM_AIR + NUM_GROUND];
-} hid_report_t;
-typedef struct __packed {
- uint8_t bReportId;
- uint16_t wADC[8];
- uint16_t wRotary[4];
- uint16_t wCoin[2];
- uint16_t wButtons[2];
- uint8_t bSystemStatus;
- uint8_t bUsbStatus;
- uint8_t bUnique[29];
-} io4_hid_in_t;
-typedef struct __packed {
- uint8_t bReportId;
- uint8_t bCmd;
- uint8_t bData[62];
-} io4_hid_out_t;
-typedef struct __packed {
- uint8_t bReportId;
- uint16_t wData[16];
-} debug_hid_report_t;
-
extern uint8_t gu8DigitalButtons;
-// void HID_Tick();
-void USBD_HID_PrepareReport();
-uint8_t *USBD_HID_GetReport(uint8_t u8ReportId, uint32_t *pu32Size);
-void USBD_HID_SetReport(volatile uint8_t *pu8EpBuf, uint32_t u32Size);
-
-// For CDC
-typedef struct __packed {
- uint32_t u32DTERate; // Baud rate
- uint8_t u8CharFormat; // Stop bit
- uint8_t u8ParityType; // Parity
- uint8_t u8DataBits; // Data bits
-} STR_VCOM_LINE_CODING;
-extern volatile int8_t gi8BulkOutReady;
-extern STR_VCOM_LINE_CODING gLineCoding;
-extern uint16_t gCtrlSignal;
-extern volatile uint16_t comRbytes;
-extern volatile uint16_t comRhead;
-extern volatile uint16_t comRtail;
-extern volatile uint16_t comTbytes;
-extern volatile uint16_t comThead;
-extern volatile uint16_t comTtail;
-extern volatile uint8_t *gpu8RxBuf;
-extern volatile uint32_t gu32RxSize;
-extern volatile uint32_t gu32TxSize;
-// For HID
-extern uint8_t volatile gu8HIDIO4Ready;
-extern uint8_t volatile gu8HIDMiscReady;
-// General USB control
-extern uint8_t volatile g_u8Suspend;
-extern uint8_t g_u8Idle;
-extern uint8_t g_u8Protocol;
-
-extern const char *gszVendorInitial;
+// === descriptors.c, used in usbd_driver.c ===
extern const char *gszVendor;
extern const char *gszProduct;
extern const usb_device_descr_t *gpDeviceDescriptor;
@@ -155,128 +73,28 @@ extern const uint32_t gu32UsbHidMiscReportLen;
extern const uint8_t *gpu8UsbHidIO4Report;
extern const uint8_t *gpu8UsbHidMiscReport;
-/*-------------------------------------------------------------*/
-
-// Interfaces
-enum {
- USBD_ITF_CDC_CMD,
- USBD_ITF_CDC_DAT,
- USBD_ITF_HID_IO4,
- USBD_ITF_HID_MISC,
- _USBD_ITF_MAX,
-};
-
-// Endpoint number mapping
-#define EP_CTRL_IN EP0
-#define EP_CTRL_OUT EP1
-#define EP_CDC_IN EP2
-#define EP_CDC_OUT EP3
-#define EP_CDC_CMD EP4
-#define EP_HID_IO4_IN EP5
-#define EP_HID_MISC_IN EP6
-#define EP_HID_MISC_OUT EP7
-
-#define _USBD_INTSTS(x) USBD_INTSTS_EP##x
-#define USBD_INTSTS(x) _USBD_INTSTS(x)
-
-// Must match the above!!
-#define USBD_INTSTS_CTRL_IN USBD_INTSTS(EP_CTRL_IN)
-#define USBD_INTSTS_CTRL_OUT USBD_INTSTS(EP_CTRL_OUT)
-#define USBD_INTSTS_CDC_IN USBD_INTSTS(EP_CDC_IN)
-#define USBD_INTSTS_CDC_OUT USBD_INTSTS(EP_CDC_OUT)
-#define USBD_INTSTS_CDC_CMD USBD_INTSTS(EP_CDC_CMD)
-#define USBD_INTSTS_HID_IO4_IN USBD_INTSTS(EP_HID_IO4_IN)
-#define USBD_INTSTS_HID_MISC_IN USBD_INTSTS(EP_HID_MISC_IN)
-#define USBD_INTSTS_HID_MISC_OUT USBD_INTSTS(EP_HID_MISC_OUT)
-
-#define USBD_CDC_EP_IN (1 | EP_INPUT)
-#define USBD_CDC_EP_OUT (2 | EP_OUTPUT)
-#define USBD_CDC_EP_CMD (3 | EP_INPUT)
-#define USBD_HID_IO4_EP_IN (4 | EP_INPUT)
-#define USBD_HID_MISC_EP_IN (5 | EP_INPUT)
-#define USBD_HID_MISC_EP_OUT (6 | EP_OUTPUT)
-
-#define USBD_SETUP_BUF_LEN (8)
-#define USBD_CDC_CMD_MAX_SIZE (16)
-#define USBD_CDC_IN_MAX_SIZE (64) // Device -> Host
-#define USBD_CDC_OUT_MAX_SIZE (64) // Host -> Device
-#define USBD_HID_BUF_LEN (64)
-
-// Endpoint packet max size (cannot total more than 512!)
-#define EP0_MAX_PKT_SIZE 64
-#define EP1_MAX_PKT_SIZE 64
-#define EP2_MAX_PKT_SIZE USBD_CDC_IN_MAX_SIZE
-#define EP3_MAX_PKT_SIZE USBD_CDC_OUT_MAX_SIZE
-#define EP4_MAX_PKT_SIZE USBD_CDC_CMD_MAX_SIZE
-#define EP5_MAX_PKT_SIZE USBD_HID_BUF_LEN
-#define EP6_MAX_PKT_SIZE USBD_HID_BUF_LEN
-#define EP7_MAX_PKT_SIZE USBD_HID_BUF_LEN
-
-#define SETUP_BUF_BASE 0
-#define SETUP_BUF_LEN 8
-
-#if (SETUP_BUF_LEN + EP0_MAX_PKT_SIZE + EP1_MAX_PKT_SIZE + EP2_MAX_PKT_SIZE + EP3_MAX_PKT_SIZE + \
- EP4_MAX_PKT_SIZE + EP5_MAX_PKT_SIZE + EP6_MAX_PKT_SIZE + EP7_MAX_PKT_SIZE) > 512
-#error USB endpoint packet sizes exceeds 512-byte maximum
-#endif
-
-#define EP0_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
-#define EP1_BUF_BASE (EP0_BUF_BASE + EP0_MAX_PKT_SIZE)
-#define EP2_BUF_BASE (EP1_BUF_BASE + EP1_MAX_PKT_SIZE)
-#define EP3_BUF_BASE (EP2_BUF_BASE + EP2_MAX_PKT_SIZE)
-#define EP4_BUF_BASE (EP3_BUF_BASE + EP3_MAX_PKT_SIZE)
-#define EP5_BUF_BASE (EP4_BUF_BASE + EP4_MAX_PKT_SIZE)
-#define EP6_BUF_BASE (EP5_BUF_BASE + EP5_MAX_PKT_SIZE)
-#define EP7_BUF_BASE (EP5_BUF_BASE + EP6_MAX_PKT_SIZE)
-
-// Define Descriptor information
-#define HID_IO4_INT_IN_INTERVAL 8
-#define HID_DEFAULT_INT_IN_INTERVAL 1
-#define HID_DEFAULT_INT_OUT_INTERVAL 1
-#define USBD_SELF_POWERED 0
-#define USBD_REMOTE_WAKEUP 0
-#define USBD_MAX_POWER (500 / 2)
-
-/*-------------------------------------------------------------*/
-#define HEX_NIBBLE(x) ("0123456789ABCDEF"[(x)&0xf])
-
+// === sys.c ===
void SYS_Init(void);
void SYS_Bootloader_Check(void);
void SYS_ModuleInit(void);
+void SYS_EnterLDROM(void);
+void SYS_WaitBootloaderLED(void);
extern volatile uint8_t gu8Do250usTick;
extern volatile uint8_t gu8Do1msTick;
-void EP_CDC_CMD_Handler(void);
-void EP_CDC_OUT_Handler(void);
-void EP_CDC_IN_Handler(void);
-void EP_HID_IO4_IN_Handler(void);
-void EP_HID_MISC_IN_Handler(void);
-void EP_HID_MISC_OUT_Handler(void);
-
-void USB_VCOM_Write(uint8_t u8Char);
-uint16_t USB_VCOM_Available(void);
-uint8_t USB_VCOM_Read(void);
-void USB_VCOM_Tick(void);
-void USB_VCOM_PurgeTx(void);
-
+// === ui.c ===
void UI_Tick(void);
-void DelayCycles(uint32_t u32Cycles);
-#define DelayCycles_Small(x) \
- for (int i = 0; i < (x); i++) __asm__ volatile("" : "+g"(i) : :);
+// === Misc ===
+#define HEX_NIBBLE(x) ("0123456789ABCDEF"[(x)&0xf])
+#define DELAY_CYCLES_2 __asm__ volatile("NOP\nNOP\n");
-// Custom USBD implementation
-void Tas_USBD_Open(void);
-void Tas_USBD_Init(void);
-void Tas_USBD_Start(void);
-void Tas_USBD_ClassRequest(void);
-void Tas_USBD_GetSetupPacket(usb_setup_t *buf);
-void Tas_USBD_ProcessSetupPacket(void);
-void Tas_USBD_PrepareCtrlIn(void *pu8Buf, uint32_t u32Size);
-void Tas_USBD_CtrlIn(void);
-void Tas_USBD_PrepareCtrlOut(void *pu8Buf, uint32_t u32Size,
- void (*pCallback)(volatile uint8_t *, uint32_t));
-void Tas_USBD_CtrlOut(void);
-void Tas_USBD_SwReset(void);
-extern volatile uint8_t *g_usbd_CtrlInPointer;
-extern volatile uint32_t g_usbd_CtrlInSize;
+#define INCR(x, y) ((x) = (x) < (y) ? (x) + 1 : (y))
+#define DECR(x, y) ((x) = (x) > (y) ? (x)-1 : (y))
+#define MOD_INCR(x, y) ((x) = (x) == ((y)-1) ? 0 : ((x) + 1))
+#define MOD_DECR(x, y) ((x) = (x) == 0 ? ((y)-1) : ((x)-1))
+#define INV(x) ((x) = 1 - (x))
+
+#define MS_SINCE(x) \
+ ((gu32NowMs >= (x)) ? /* We haven't wrapped yet */ (gu32NowMs - (x)) \
+ : /* We've wrapped over (50 days!) */ (gu32NowMs + (0xFFFFFFFF - (x))))
diff --git a/src/ui.c b/src/ui.c
index 53fb765..c16e902 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -1,7 +1,8 @@
#include "tasoller.h"
-#define FN2_HOLD_TIME 250 // ms of FN2 to enter config
-#define FN1_HOLD_TIME 2000 // ms of FN1 to enter calibration
+#define FN1_HOLD_TIME 250 // ms of FN1 to enter config
+#define FN2_TAP_TIME 250 // ms of FN2 to enter service/test
+#define FN2_HOLD_TIME 500 // ms of FN2 to enter service/test
// All three of these are scaled based on gConfig.u8Sens
#define CALIB_HANDS_MIN 100 // If we read less than this, ignore it
@@ -12,14 +13,17 @@
#define GREEN 120
#define BLUE 240
+uint8_t gbUIOpen = 0;
+static uint8_t u8TestIsActive = 0;
+
static void UI_TickSensitivity(void) {
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- gaControlledIntLedData[i].u16H = 0;
- gaControlledIntLedData[i].u8S = (gConfig.u8Sens - 1) * 16;
- gaControlledIntLedData[i].u8V = 0;
+ for (uint8_t i = 0; i < LED_NUM_GROUND_LOGICAL; i++) {
+ gaControlledIntLedData[i].h = 0;
+ gaControlledIntLedData[i].s = (gConfig.u8Sens - 1) * 16;
+ gaControlledIntLedData[i].v = 0;
}
- for (uint8_t i = 0; i < gConfig.u8Sens; i++) gaControlledIntLedData[i * 2].u8V = 255;
+ for (uint8_t i = 0; i < gConfig.u8Sens; i++) gaControlledIntLedData[i * 2].v = 255;
// Preferentially allow decreasing of sensitivity, in case it's been taken up too high
if (gu32PSoCDigitalPos & PAD_26_Msk && gConfig.u8Sens > 1) {
@@ -29,9 +33,9 @@ static void UI_TickSensitivity(void) {
}
}
+static uint8_t su8SensTimeout = 0;
static void UI_TickSettings(void) {
// If either of the sensitivity settings are being changed, just render that
- static uint8_t su8SensTimeout = 0;
if (gu16PSoCDigital & CELL_12_Msk) {
su8SensTimeout = 150;
UI_TickSensitivity();
@@ -41,27 +45,35 @@ static void UI_TickSettings(void) {
UI_TickSensitivity();
// Save the sensitivity on exit
- if (su8SensTimeout == 0) PSoC_SetFingerCapacitanceFromConfig();
+ if (su8SensTimeout == 0) PSoC_SetFingerCapacitanceFromConfig(1);
return;
}
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- gaControlledIntLedData[i].u16H = 0;
- gaControlledIntLedData[i].u8S = 255;
- gaControlledIntLedData[i].u8V = 0;
+ static uint8_t u8Pulser = 0;
+ static uint8_t u8PulserDir = 0;
+ if (u8PulserDir) {
+ if (--u8Pulser == 0) u8PulserDir = 0;
+ } else {
+ if (++u8Pulser == 255) u8PulserDir = 1;
+ }
+
+ for (uint8_t i = 0; i < LED_NUM_GROUND_LOGICAL; i++) {
+ gaControlledIntLedData[i].h = 0;
+ gaControlledIntLedData[i].s = 255;
+ gaControlledIntLedData[i].v = 0;
}
{ // LED colour control
- gaControlledIntLedData[LED_CELL_0].u16H = gConfig.u16HueWingLeft;
- gaControlledIntLedData[LED_CELL_0].u8V = 255;
- gaControlledIntLedData[LED_CELL_1].u16H = gConfig.u16HueGround;
- gaControlledIntLedData[LED_CELL_1].u8V = 255;
- gaControlledIntLedData[LED_DIVIDER_1_2].u16H = gConfig.u16HueGroundActive;
- gaControlledIntLedData[LED_DIVIDER_1_2].u8V = 255;
- gaControlledIntLedData[LED_CELL_2].u16H = gConfig.u16HueGround;
- gaControlledIntLedData[LED_CELL_2].u8V = 255;
- gaControlledIntLedData[LED_CELL_3].u16H = gConfig.u16HueWingRight;
- gaControlledIntLedData[LED_CELL_3].u8V = 255;
+ gaControlledIntLedData[LED_CELL_0].h = gConfig.u16HueWingLeft;
+ gaControlledIntLedData[LED_CELL_0].v = 255;
+ gaControlledIntLedData[LED_CELL_1].h = gConfig.u16HueGround;
+ gaControlledIntLedData[LED_CELL_1].v = 255;
+ gaControlledIntLedData[LED_DIVIDER_1_2].h = gConfig.u16HueGroundActive;
+ gaControlledIntLedData[LED_DIVIDER_1_2].v = 255;
+ gaControlledIntLedData[LED_CELL_2].h = gConfig.u16HueGround;
+ gaControlledIntLedData[LED_CELL_2].v = 255;
+ gaControlledIntLedData[LED_CELL_3].h = gConfig.u16HueWingRight;
+ gaControlledIntLedData[LED_CELL_3].v = 255;
if (gu32PSoCDigitalTrig & PAD_1_Msk) MOD_INCR(gConfig.u16HueWingLeft, LED_HUE_MAX);
if (gu32PSoCDigitalTrig & PAD_2_Msk) MOD_DECR(gConfig.u16HueWingLeft, LED_HUE_MAX);
@@ -77,27 +89,27 @@ static void UI_TickSettings(void) {
static uint16_t su16Hue = 0;
MOD_INCR(su16Hue, LED_HUE_MAX * 5);
if (gConfig.bEnableRainbow) {
- gaControlledIntLedData[LED_CELL_5].u16H = su16Hue / 5;
- gaControlledIntLedData[LED_CELL_5].u8V = 255;
+ gaControlledIntLedData[LED_CELL_5].h = su16Hue / 5;
+ gaControlledIntLedData[LED_CELL_5].v = 255;
} else {
- gaControlledIntLedData[LED_CELL_5].u8S = 0;
- gaControlledIntLedData[LED_CELL_5].u8V = 255;
+ gaControlledIntLedData[LED_CELL_5].s = 0;
+ gaControlledIntLedData[LED_CELL_5].v = 255;
}
if (gu16PSoCDigitalPos & CELL_5_Msk) INV(gConfig.bEnableRainbow);
}
{ // Brightness
if (gConfig.u8LedGroundBrightness) {
- gaControlledIntLedData[LED_CELL_6].u8S = 0;
- gaControlledIntLedData[LED_CELL_6].u8V = gConfig.u8LedGroundBrightness;
+ gaControlledIntLedData[LED_CELL_6].s = 0;
+ gaControlledIntLedData[LED_CELL_6].v = gConfig.u8LedGroundBrightness;
} else {
- gaControlledIntLedData[LED_CELL_6].u8V = 255;
+ gaControlledIntLedData[LED_CELL_6].v = 255;
}
if (gConfig.u8LedWingBrightness) {
- gaControlledIntLedData[LED_CELL_7].u8S = 0;
- gaControlledIntLedData[LED_CELL_7].u8V = gConfig.u8LedWingBrightness;
+ gaControlledIntLedData[LED_CELL_7].s = 0;
+ gaControlledIntLedData[LED_CELL_7].v = gConfig.u8LedWingBrightness;
} else {
- gaControlledIntLedData[LED_CELL_7].u8V = 255;
+ gaControlledIntLedData[LED_CELL_7].v = 255;
}
if (gu32PSoCDigitalTrig & PAD_13_Msk) INCR(gConfig.u8LedGroundBrightness, 255);
@@ -105,145 +117,201 @@ static void UI_TickSettings(void) {
if (gu32PSoCDigitalTrig & PAD_15_Msk) INCR(gConfig.u8LedWingBrightness, 255);
if (gu32PSoCDigitalTrig & PAD_16_Msk) DECR(gConfig.u8LedWingBrightness, 0);
}
- // [Cell 8,9,10,11 no function]
+ // [Cell 8 no function]
+
+ { // Consumer control
+ gaControlledIntLedData[LED_CELL_9].s = 0;
+ gaControlledIntLedData[LED_CELL_9].v = 255;
+ if (u32EnterPressStarted != 0xFFFFFFFF) {
+ gaControlledIntLedData[LED_CELL_10].s = 0;
+ gaControlledIntLedData[LED_CELL_10].v = u8Pulser;
+ } else {
+ gaControlledIntLedData[LED_CELL_10].s = 0;
+ gaControlledIntLedData[LED_CELL_10].v = 255;
+ }
+
+ if (gu32PSoCDigital & PAD_20_Msk) {
+ u16RequestedConsumerControl = MEDIA_VOLUME_DOWN;
+ } else if (gu32PSoCDigital & PAD_19_Msk) {
+ u16RequestedConsumerControl = MEDIA_VOLUME_UP;
+ } else {
+ u16RequestedConsumerControl = 0;
+ }
+
+ if (gu16PSoCDigitalPos & CELL_10_Msk) {
+ if (u32EnterPressStarted == 0xFFFFFFFF) u32EnterPressStarted = gu32NowMs;
+ }
+ }
+
+ // [Cell 11 no function]
+
{ // Sensitivity control (handled in dedicated function)
- gaControlledIntLedData[LED_CELL_12].u8S = (gConfig.u8Sens - 1) * 16;
- gaControlledIntLedData[LED_CELL_12].u8V = 255;
+ gaControlledIntLedData[LED_CELL_12].s = (gConfig.u8Sens - 1) * 16;
+ gaControlledIntLedData[LED_CELL_12].v = 255;
}
- // [Cell 13 no function]
+ // [Cell 13,14 no function]
{ // Mode switching
- gaControlledIntLedData[LED_CELL_14].u16H = gConfig.bEnableKeyboard ? GREEN : RED;
- gaControlledIntLedData[LED_CELL_14].u8V = 255;
- gaControlledIntLedData[LED_CELL_15].u16H = gConfig.bEnableIO4 ? GREEN : RED;
- gaControlledIntLedData[LED_CELL_15].u8V = 255;
+ gaControlledIntLedData[LED_CELL_15].h = gConfig.bEnableKeyboard ? GREEN : RED;
+ gaControlledIntLedData[LED_CELL_15].v = 255;
- if (gu16PSoCDigitalPos & CELL_14_Msk) INV(gConfig.bEnableKeyboard);
- if (gu16PSoCDigitalPos & CELL_15_Msk) INV(gConfig.bEnableIO4);
+ if (gu16PSoCDigitalPos & CELL_15_Msk) INV(gConfig.bEnableKeyboard);
}
}
-static inline void _FillControlled(uint16_t u16H, uint8_t u8Fill) {
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- gaControlledIntLedData[i].u16H = u16H;
- gaControlledIntLedData[i].u8S = 255;
- gaControlledIntLedData[i].u8V = i < u8Fill ? 255 : 0;
+static uint32_t su32EnteredTestMenuAt = 0;
+static void UI_TickServiceTest(void) {
+ uint8_t u8V = 0;
+ // Zero out the LED data
+ for (uint8_t i = 0; i < LED_NUM_GROUND_LOGICAL; i++) {
+ gaControlledIntLedData[i].h = 0;
+ gaControlledIntLedData[i].s = 0;
+ gaControlledIntLedData[i].v = 0;
}
-}
-static uint8_t bCalibrationActive = 0;
-static void UI_TickCalibration(void) {
- static uint16_t u16Timer = 0;
- static uint16_t su16MaxNoHands[32] = { 0 };
- static uint16_t su16MaxHands[32] = { 0 };
-
- if (!bCalibrationActive) {
- // Calibration start
- u16Timer = 0;
- bCalibrationActive = 1;
- memset(su16MaxNoHands, 0, sizeof su16MaxNoHands);
- memset(su16MaxHands, 0, sizeof su16MaxHands);
- }
- // Only tick the timer when we're using it, to avoid overflow
- if (u16Timer < 5000) u16Timer++;
-
- if (u16Timer < 3000) {
- // Flash red for the first 3 seconds
- _FillControlled(RED, ((u16Timer / 250) & 1) ? 0 : LED_NUM_GROUND);
- } else if (u16Timer < 4000) {
- // Fill up the cells with blue
- _FillControlled(BLUE, (u16Timer - 3000) / (1000 / LED_NUM_GROUND));
- for (uint8_t i; i < 32; i++) {
- su16MaxNoHands[i] = Maximum(su16MaxNoHands[i], gu16PSoCDiff[i]);
- }
- } else if (u16Timer < 5000) {
- // Flash green for the next second
- _FillControlled(GREEN, ((u16Timer / 250) & 1) ? 0 : LED_NUM_GROUND);
- } else {
- for (uint8_t i = 0; i < 32; i++) {
- // As well as the raw minimum, force a small constant threshold minimum too
- su16MaxHands[i] = Maximum(su16MaxHands[i], gu16PSoCDiff[i] + (gConfig.u8Sens * 5));
+ uint8_t u8ForceTest = 0;
+ if (u8TestIsActive) {
+ // Send a test button, to trigger entry to the test menu
+ if (MS_SINCE(su32EnteredTestMenuAt) < 100) {
+ gu16IO4ForceButtons |= IO4_BUTTON_TEST;
+ u8ForceTest = 1;
}
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- gaControlledIntLedData[i].u8S = 255;
- gaControlledIntLedData[i].u8V = 255;
- }
-
- uint16_t u16CalibMin = CALIB_HANDS_MIN + (gConfig.u8Sens * 50);
- uint16_t u16CalibReq = CALIB_HANDS_REQ + (gConfig.u8Sens * 50);
- uint16_t u16CalibMax = CALIB_HANDS_MAX + (gConfig.u8Sens * 50);
-
- uint8_t bOk = 1;
- // Iterate over the cells
- for (uint8_t i = 0; i < 16; i++) {
- if (su16MaxHands[i * 2] < u16CalibMin || su16MaxHands[i * 2 + 1] < u16CalibMin ||
- su16MaxHands[i * 2] < su16MaxNoHands[i * 2] ||
- su16MaxHands[i * 2 + 1] < su16MaxNoHands[i * 2 + 1]) {
- // Not enough data
- gaControlledIntLedData[i * 2].u8V = 0;
- bOk = 0;
- } else if (su16MaxHands[i * 2] < u16CalibReq || su16MaxHands[i * 2 + 1] < u16CalibReq) {
- // Data is too low
- gaControlledIntLedData[i * 2].u16H = RED;
- bOk = 0;
- } else if (su16MaxHands[i * 2] < u16CalibMax || su16MaxHands[i * 2 + 1] < u16CalibMax) {
- // We've got enough, but it could be better
- uint16_t u16Min = Minimum(su16MaxHands[i * 2], su16MaxHands[i * 2 + 1]);
- gaControlledIntLedData[i * 2].u16H =
- ((u16Min - u16CalibReq) * GREEN) / (u16CalibMax - u16CalibReq);
+ // Implement the on-screen buttons
+ { // Down
+ if (gu16PSoCDigital & (CELL_0_Msk | CELL_1_Msk | CELL_2_Msk)) {
+ u8V = 200;
} else {
- // More than enough data
- gaControlledIntLedData[i * 2].u16H = GREEN;
+ u8V = 50;
}
+ gaControlledIntLedData[LED_CELL_0].v = u8V;
+ gaControlledIntLedData[LED_DIVIDER_0_1].v = u8V;
+ gaControlledIntLedData[LED_CELL_1].v = u8V;
+ gaControlledIntLedData[LED_DIVIDER_1_2].v = u8V;
+ gaControlledIntLedData[LED_CELL_2].v = u8V;
}
-
- for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
- if (i % 2 == 1) {
- gaControlledIntLedData[i].u16H = bOk ? GREEN : RED;
+ gaControlledIntLedData[LED_DIVIDER_2_3].v = 255;
+ { // Up
+ if (gu16PSoCDigital & (CELL_3_Msk | CELL_4_Msk | CELL_5_Msk)) {
+ u8V = 200;
+ } else {
+ u8V = 50;
}
+ gaControlledIntLedData[LED_CELL_3].v = u8V;
+ gaControlledIntLedData[LED_DIVIDER_3_4].v = u8V;
+ gaControlledIntLedData[LED_CELL_4].v = u8V;
+ gaControlledIntLedData[LED_DIVIDER_4_5].v = u8V;
+ gaControlledIntLedData[LED_CELL_5].v = u8V;
}
+ gaControlledIntLedData[LED_DIVIDER_5_6].v = 255;
- // Calibration complete
- if (gu8DigitalButtons & DIGITAL_FN1_Msk) {
- bCalibrationActive = 0;
-
- if (bOk) {
- memcpy(gConfig.u16PSoCScaleMin, su16MaxNoHands, sizeof su16MaxNoHands);
- memcpy(gConfig.u16PSoCScaleMax, su16MaxHands, sizeof su16MaxHands);
- bConfigDirty = 1;
+ gaControlledIntLedData[LED_DIVIDER_12_13].v = 255;
+ { // OK
+ if (gu16PSoCDigital & (CELL_13_Msk | CELL_14_Msk | CELL_15_Msk)) {
+ u8V = 200;
+ } else {
+ u8V = 50;
}
+ gaControlledIntLedData[LED_CELL_13].v = u8V;
+ gaControlledIntLedData[LED_DIVIDER_13_14].v = u8V;
+ gaControlledIntLedData[LED_CELL_14].v = u8V;
+ gaControlledIntLedData[LED_DIVIDER_14_15].v = u8V;
+ gaControlledIntLedData[LED_CELL_15].v = u8V;
}
}
+
+ // Implement our custom buttons for test and service
+ gaControlledIntLedData[LED_DIVIDER_5_6].v = 255;
+ { // Test
+ if (gu16PSoCDigital & (CELL_6_Msk | CELL_7_Msk)) {
+ u8V = 200;
+ gu16IO4ForceButtons |= IO4_BUTTON_TEST;
+ } else {
+ u8V = 50;
+ // Don't un-press the test button if we're forcing it on
+ if (!u8ForceTest) gu16IO4ForceButtons &= ~IO4_BUTTON_TEST;
+ }
+ gaControlledIntLedData[LED_CELL_6].v = u8V;
+ gaControlledIntLedData[LED_DIVIDER_6_7].v = u8V;
+ gaControlledIntLedData[LED_CELL_7].v = u8V;
+ }
+ gaControlledIntLedData[LED_DIVIDER_7_8].v = 255;
+ { // Service
+ if (gu16PSoCDigital & (CELL_8_Msk | CELL_9_Msk)) {
+ u8V = 200;
+ gu16IO4ForceButtons |= IO4_BUTTON_SERVICE;
+ } else {
+ u8V = 50;
+ gu16IO4ForceButtons &= ~IO4_BUTTON_SERVICE;
+ }
+ gaControlledIntLedData[LED_CELL_8].v = u8V;
+ gaControlledIntLedData[LED_DIVIDER_8_9].v = u8V;
+ gaControlledIntLedData[LED_CELL_9].v = u8V;
+ }
+ gaControlledIntLedData[LED_DIVIDER_9_10].v = 255;
}
void UI_Tick(void) {
- static uint8_t u8Fn2Held = 0;
- if (gu8DigitalButtons & DIGITAL_FN2_Msk) {
- if (u8Fn2Held < FN2_HOLD_TIME) u8Fn2Held++;
+ // Handle hold trigger on FN1
+ static uint8_t u8Fn1Held = 0;
+ if (gu8DigitalButtons & DIGITAL_FN1_Msk) {
+ if (u8Fn1Held < FN1_HOLD_TIME) u8Fn1Held++;
} else {
// We released the button after holding it for long enough to be in the configuration UI, so
// assume something changed
- if (u8Fn2Held >= FN2_HOLD_TIME) {
+ if (u8Fn1Held >= FN1_HOLD_TIME) {
+ // If FN2 was released while still in sensitivity adjustment, make sure the changes save
+ if (su8SensTimeout) {
+ PSoC_SetFingerCapacitanceFromConfig(1);
+ su8SensTimeout = 0;
+ }
+
bConfigDirty = 1;
}
- u8Fn2Held = 0;
+ u16RequestedConsumerControl = 0;
+ u32EnterPressStarted = 0;
+ u8Fn1Held = 0;
}
- static uint16_t u16Fn1Held = 0;
- if (gu8DigitalButtons & DIGITAL_FN1_Msk) {
- if (u16Fn1Held < FN1_HOLD_TIME) u16Fn1Held++;
+ // Handle double tap trigger on FN2
+ static uint32_t u32LastFn2 = 0;
+ static uint8_t u8LastDB = 0;
+ const uint8_t u8PostDb = gu8DigitalButtons & (~u8LastDB);
+ if (u8PostDb & DIGITAL_FN2_Msk) {
+ if (u32LastFn2 && MS_SINCE(u32LastFn2) < FN2_TAP_TIME) {
+ u8TestIsActive = !u8TestIsActive;
+
+ if (u8TestIsActive) {
+ su32EnteredTestMenuAt = gu32NowMs;
+ gu16IO4ForceButtons = IO4_BUTTON_TEST;
+ } else {
+ su32EnteredTestMenuAt = 0;
+ gu16IO4ForceButtons = 0;
+ }
+ }
+ u32LastFn2 = gu32NowMs;
+ }
+ u8LastDB = gu8DigitalButtons;
+
+ // Handle hold trigger on FN2
+ static uint16_t u16Fn2Held = 0;
+ if (gu8DigitalButtons & DIGITAL_FN2_Msk) {
+ if (u16Fn2Held < FN2_HOLD_TIME) u16Fn2Held++;
} else {
- u16Fn1Held = 0;
+ u16Fn2Held = 0;
}
- if (bCalibrationActive || u16Fn1Held >= FN1_HOLD_TIME) {
- gbLedDataIsControlledInt = 1;
- UI_TickCalibration();
- } else if (u8Fn2Held >= FN2_HOLD_TIME) {
+ // Render the appropriate UI based on what's being done
+ if (u8Fn1Held >= FN1_HOLD_TIME) {
gbLedDataIsControlledInt = 1;
+ gbUIOpen = 1;
UI_TickSettings();
+ } else if (u16Fn2Held >= FN2_HOLD_TIME || u8TestIsActive) {
+ gbLedDataIsControlledInt = 1;
+ gbUIOpen = 0;
+ UI_TickServiceTest();
} else {
gbLedDataIsControlledInt = 0;
+ gbUIOpen = 0;
}
}
diff --git a/src/usb_def.h b/src/usb_def.h
new file mode 100644
index 0000000..2442029
--- /dev/null
+++ b/src/usb_def.h
@@ -0,0 +1,129 @@
+#pragma once
+#pragma once
+
+#include
+
+#define USB_STATE_FLOATING 2
+#define USB_STATE_SUSPEND 1
+
+// USB definition files
+#include "hid_def.h"
+#include "usb_inc/hid.h"
+#include "usb_inc/keymap.h"
+#include "usb_inc/usb.h"
+
+// Interfaces
+enum : uint8_t {
+ USBD_ITF_CDC_CMD,
+ USBD_ITF_CDC_DAT,
+ USBD_ITF_HID_IO4,
+ USBD_ITF_HID_MISC,
+ _USBD_ITF_MAX,
+};
+
+// Endpoint number mapping
+#define EP_CTRL_IN EP0
+#define EP_CTRL_OUT EP1
+#define EP_CDC_IN EP2
+#define EP_CDC_OUT EP3
+#define EP_CDC_CMD EP4
+#define EP_HID_IO4_IN EP5
+#define EP_HID_MISC_IN EP6
+#define EP_HID_MISC_OUT EP7
+
+#define _USBD_INTSTS(x) USBD_INTSTS_EP##x
+#define USBD_INTSTS(x) _USBD_INTSTS(x)
+
+// Must match the above!!
+#define USBD_INTSTS_CTRL_IN USBD_INTSTS(EP_CTRL_IN)
+#define USBD_INTSTS_CTRL_OUT USBD_INTSTS(EP_CTRL_OUT)
+#define USBD_INTSTS_CDC_IN USBD_INTSTS(EP_CDC_IN)
+#define USBD_INTSTS_CDC_OUT USBD_INTSTS(EP_CDC_OUT)
+#define USBD_INTSTS_CDC_CMD USBD_INTSTS(EP_CDC_CMD)
+#define USBD_INTSTS_HID_IO4_IN USBD_INTSTS(EP_HID_IO4_IN)
+#define USBD_INTSTS_HID_MISC_IN USBD_INTSTS(EP_HID_MISC_IN)
+#define USBD_INTSTS_HID_MISC_OUT USBD_INTSTS(EP_HID_MISC_OUT)
+
+#define USBD_CDC_EP_IN (1 | EP_INPUT)
+#define USBD_CDC_EP_OUT (2 | EP_OUTPUT)
+#define USBD_CDC_EP_CMD (3 | EP_INPUT)
+#define USBD_HID_IO4_EP_IN (4 | EP_INPUT)
+#define USBD_HID_MISC_EP_IN (5 | EP_INPUT)
+#define USBD_HID_MISC_EP_OUT (6 | EP_OUTPUT)
+
+#define USBD_SETUP_BUF_LEN (8)
+#define USBD_CDC_CMD_MAX_SIZE (16)
+#define USBD_CDC_IN_MAX_SIZE (64) // Device -> Host
+#define USBD_CDC_OUT_MAX_SIZE (64) // Host -> Device
+#define USBD_HID_BUF_LEN (64)
+
+_Static_assert(USBD_HID_BUF_LEN >= sizeof(hid_kbd_report_t) &&
+ USBD_HID_BUF_LEN >= sizeof(hid_consumer_report_t) &&
+ USBD_HID_BUF_LEN >= sizeof(io4_hid_in_t) &&
+ USBD_HID_BUF_LEN >= sizeof(io4_hid_out_t),
+ "HID USB buffer insufficient size for possible reports");
+
+// Endpoint packet max size (cannot total more than 512!)
+#define EP0_MAX_PKT_SIZE 64
+#define EP1_MAX_PKT_SIZE 64
+#define EP2_MAX_PKT_SIZE USBD_CDC_IN_MAX_SIZE
+#define EP3_MAX_PKT_SIZE USBD_CDC_OUT_MAX_SIZE
+#define EP4_MAX_PKT_SIZE USBD_CDC_CMD_MAX_SIZE
+#define EP5_MAX_PKT_SIZE USBD_HID_BUF_LEN
+#define EP6_MAX_PKT_SIZE USBD_HID_BUF_LEN
+#define EP7_MAX_PKT_SIZE USBD_HID_BUF_LEN
+
+#define SETUP_BUF_BASE 0
+#define SETUP_BUF_LEN 8
+
+_Static_assert((SETUP_BUF_LEN + EP0_MAX_PKT_SIZE + EP1_MAX_PKT_SIZE + EP2_MAX_PKT_SIZE +
+ EP3_MAX_PKT_SIZE + EP4_MAX_PKT_SIZE + EP5_MAX_PKT_SIZE + EP6_MAX_PKT_SIZE +
+ EP7_MAX_PKT_SIZE) <= 512,
+ "USB endpoint packet sizes exceeds 512-byte maximum");
+
+#define EP0_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
+#define EP1_BUF_BASE (EP0_BUF_BASE + EP0_MAX_PKT_SIZE)
+#define EP2_BUF_BASE (EP1_BUF_BASE + EP1_MAX_PKT_SIZE)
+#define EP3_BUF_BASE (EP2_BUF_BASE + EP2_MAX_PKT_SIZE)
+#define EP4_BUF_BASE (EP3_BUF_BASE + EP3_MAX_PKT_SIZE)
+#define EP5_BUF_BASE (EP4_BUF_BASE + EP4_MAX_PKT_SIZE)
+#define EP6_BUF_BASE (EP5_BUF_BASE + EP5_MAX_PKT_SIZE)
+#define EP7_BUF_BASE (EP5_BUF_BASE + EP6_MAX_PKT_SIZE)
+
+// Define Descriptor information
+#define HID_IO4_INT_IN_INTERVAL 8
+#define HID_DEFAULT_INT_IN_INTERVAL 1
+#define HID_DEFAULT_INT_OUT_INTERVAL 1
+#define USBD_SELF_POWERED_Pos 6
+#define USBD_SELF_POWERED_Msk (1 << USBD_SELF_POWERED_Pos)
+#define USBD_REMOTE_WAKEUP_Pos 5
+#define USBD_REMOTE_WAKEUP_Msk (1 << USBD_REMOTE_WAKEUP_Pos)
+#define USBD_MAX_POWER (500 / 2)
+
+// Endpoint handler functions (usbd_user.c)
+void EP_CDC_OUT_Handler(void);
+void EP_CDC_IN_Handler(void);
+void EP_HID_IO4_IN_Handler(void);
+void EP_HID_MISC_IN_Handler(void);
+void EP_HID_MISC_OUT_Handler(void);
+
+// Custom USBD implementation (usbd_driver.c)
+void Tas_USBD_Open(void);
+void Tas_USBD_Init(void);
+void Tas_USBD_Start(void);
+void Tas_USBD_ClassRequest(void);
+void Tas_USBD_GetSetupPacket(usb_setup_t *buf);
+void Tas_USBD_ProcessSetupPacket(void);
+void Tas_USBD_PrepareCtrlIn(void *pu8Buf, uint32_t u32Size);
+void Tas_USBD_CtrlIn(void);
+void Tas_USBD_PrepareCtrlOut(void *pu8Buf, uint32_t u32Size,
+ void (*pCallback)(volatile uint8_t *, uint32_t));
+void Tas_USBD_CtrlOut(void);
+void Tas_USBD_SwReset(void);
+extern volatile uint8_t *g_usbd_CtrlInPointer;
+extern volatile uint32_t g_usbd_CtrlInSize;
+
+// General USB control
+extern volatile uint8_t g_u8UsbState;
+extern uint8_t g_u8Idle;
+extern uint8_t g_u8Protocol;
diff --git a/src/usb_inc/keymap.h b/src/usb_inc/keymap.h
index 6a1dd88..651559c 100644
--- a/src/usb_inc/keymap.h
+++ b/src/usb_inc/keymap.h
@@ -622,22 +622,8 @@ static const uint16_t _asciimap[] = {
// The following characters belong to ISO-8859-15
// ! The first 16 values here are used for the numpad
- KEYPAD_0,
- KEYPAD_1,
- KEYPAD_2,
- KEYPAD_3,
- KEYPAD_4,
- KEYPAD_5,
- KEYPAD_6,
- KEYPAD_7,
- KEYPAD_8,
- KEYPAD_9,
- KEYPAD_ADD,
- KEYPAD_SUBTRACT,
- KEYPAD_MULTIPLY,
- KEYPAD_DIVIDE,
- KEYPAD_ENTER,
- KEYPAD_DOT,
+ KEYPAD_0, KEYPAD_1, KEYPAD_2, KEYPAD_3, KEYPAD_4, KEYPAD_5, KEYPAD_6, KEYPAD_7, KEYPAD_8,
+ KEYPAD_9, KEYPAD_ADD, KEYPAD_SUBTRACT, KEYPAD_MULTIPLY, KEYPAD_DIVIDE, KEYPAD_ENTER, KEYPAD_DOT,
// KEY_RESERVED, // 128 - Unused
// KEY_RESERVED, // 129 - Unused
// KEY_RESERVED, // 130 - Unused
@@ -767,3 +753,425 @@ static const uint16_t _asciimap[] = {
KEY_RESERVED, // 254 - Thorn
KEY_RESERVED, // 255 - 'y' Umlaut
};
+
+enum ConsumerKeycode : uint16_t {
+ // Some keys might only work with linux
+ CONSUMER_POWER = 0x30,
+ CONSUMER_SLEEP = 0x32,
+
+ MEDIA_RECORD = 0xB2,
+ MEDIA_FAST_FORWARD = 0xB3,
+ MEDIA_REWIND = 0xB4,
+ MEDIA_NEXT = 0xB5,
+ MEDIA_PREVIOUS = 0xB6,
+ MEDIA_PREV = 0xB6, // Alias
+ MEDIA_STOP = 0xB7,
+ MEDIA_PLAY_PAUSE = 0xCD,
+ MEDIA_PAUSE = 0xB0,
+
+ MEDIA_VOLUME_MUTE = 0xE2,
+ MEDIA_VOL_MUTE = 0xE2, // Alias
+ MEDIA_VOLUME_UP = 0xE9,
+ MEDIA_VOL_UP = 0xE9, // Alias
+ MEDIA_VOLUME_DOWN = 0xEA,
+ MEDIA_VOL_DOWN = 0xEA, // Alias
+
+ CONSUMER_BRIGHTNESS_UP = 0x006F,
+ CONSUMER_BRIGHTNESS_DOWN = 0x0070,
+
+ CONSUMER_SCREENSAVER = 0x19e,
+
+ CONSUMER_PROGRAMMABLE_BUTTON_CONFIGURATION = 0x182,
+ CONSUMER_CONTROL_CONFIGURATION = 0x183,
+ CONSUMER_EMAIL_READER = 0x18A,
+ CONSUMER_CALCULATOR = 0x192,
+ CONSUMER_EXPLORER = 0x194,
+
+ CONSUMER_BROWSER_HOME = 0x223,
+ CONSUMER_BROWSER_BACK = 0x224,
+ CONSUMER_BROWSER_FORWARD = 0x225,
+ CONSUMER_BROWSER_REFRESH = 0x227,
+ CONSUMER_BROWSER_BOOKMARKS = 0x22A,
+
+ // Consumer_Page_(0x0C) 0x15
+ HID_CONSUMER_UNASSIGNED = 0x00,
+ HID_CONSUMER_NUMERIC_KEY_PAD = 0x02, // HID type NARY
+ HID_CONSUMER_PROGRAMMABLE_BUTTONS = 0x03, // HID type NARY
+ HID_CONSUMER_MICROPHONE_CA = 0x04,
+ HID_CONSUMER_HEADPHONE_CA = 0x05,
+ HID_CONSUMER_GRAPHIC_EQUALIZER_CA = 0x06,
+ // Reserved = 0x07-1F
+ HID_CONSUMER_PLUS_10 = 0x20, // HID type OSC
+ HID_CONSUMER_PLUS_100 = 0x21, // HID type OSC
+ HID_CONSUMER_AM_SLASH_PM = 0x22, // HID type OSC
+ // Reserved = 0x23-3F
+ HID_CONSUMER_POWER = 0x30, // HID type OOC
+ HID_CONSUMER_RESET = 0x31, // HID type OSC
+ HID_CONSUMER_SLEEP = 0x32, // HID type OSC
+ HID_CONSUMER_SLEEP_AFTER = 0x33, // HID type OSC
+ HID_CONSUMER_SLEEP_MODE = 0x34, // HID type RTC
+ HID_CONSUMER_ILLUMINATION = 0x35, // HID type OOC
+ HID_CONSUMER_FUNCTION_BUTTONS = 0x36, // HID type NARY
+ // Reserved = 0x37-3F
+ HID_CONSUMER_MENU = 0x40, // HID type OOC
+ HID_CONSUMER_MENU_PICK = 0x41, // HID type OSC
+ HID_CONSUMER_MENU_UP = 0x42, // HID type OSC
+ HID_CONSUMER_MENU_DOWN = 0x43, // HID type OSC
+ HID_CONSUMER_MENU_LEFT = 0x44, // HID type OSC
+ HID_CONSUMER_MENU_RIGHT = 0x45, // HID type OSC
+ HID_CONSUMER_MENU_ESCAPE = 0x46, // HID type OSC
+ HID_CONSUMER_MENU_VALUE_INCREASE = 0x47, // HID type OSC
+ HID_CONSUMER_MENU_VALUE_DECREASE = 0x48, // HID type OSC
+ // Reserved 0x49-5F
+ HID_CONSUMER_DATA_ON_SCREEN = 0x60, // HID type OOC
+ HID_CONSUMER_CLOSED_CAPTION = 0x61, // HID type OOC
+ HID_CONSUMER_CLOSED_CAPTION_SELECT = 0x62, // HID type OSC
+ HID_CONSUMER_VCR_SLASH_TV = 0x63, // HID type OOC
+ HID_CONSUMER_BROADCAST_MODE = 0x64, // HID type OSC
+ HID_CONSUMER_SNAPSHOT = 0x65, // HID type OSC
+ HID_CONSUMER_STILL = 0x66, // HID type OSC
+ // Reserved 0x67-7F
+ HID_CONSUMER_SELECTION = 0x80, // HID type NARY
+ HID_CONSUMER_ASSIGN_SELECTION = 0x81, // HID type OSC
+ HID_CONSUMER_MODE_STEP = 0x82, // HID type OSC
+ HID_CONSUMER_RECALL_LAST = 0x83, // HID type OSC
+ HID_CONSUMER_ENTER_CHANNEL = 0x84, // HID type OSC
+ HID_CONSUMER_ORDER_MOVIE = 0x85, // HID type OSC
+ HID_CONSUMER_CHANNEL = 0x86, // HID type LC
+ HID_CONSUMER_MEDIA_SELECTION = 0x87, // HID type NARY
+ HID_CONSUMER_MEDIA_SELECT_COMPUTER = 0x88, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_TV = 0x89, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_WWW = 0x8A, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_DVD = 0x8B, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_TELEPHONE = 0x8C, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_PROGRAM_GUIDE = 0x8D, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_VIDEO_PHONE = 0x8E, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_GAMES = 0x8F, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_MESSAGES = 0x90, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_CD = 0x91, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_VCR = 0x92, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_TUNER = 0x93, // HID type SEL
+ HID_CONSUMER_QUIT = 0x94, // HID type OSC
+ HID_CONSUMER_HELP = 0x95, // HID type OOC
+ HID_CONSUMER_MEDIA_SELECT_TAPE = 0x96, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_CABLE = 0x97, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_SATELLITE = 0x98, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_SECURITY = 0x99, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_HOME = 0x9A, // HID type SEL
+ HID_CONSUMER_MEDIA_SELECT_CALL = 0x9B, // HID type SEL
+ HID_CONSUMER_CHANNEL_INCREMENT = 0x9C, // HID type OSC
+ HID_CONSUMER_CHANNEL_DECREMENT = 0x9D, // HID type OSC
+ HID_CONSUMER_MEDIA_SELECT_SAP = 0x9E, // HID type SEL
+ // Reserved 0x9F
+ HID_CONSUMER_VCR_PLUS = 0xA0, // HID type OSC
+ HID_CONSUMER_ONCE = 0xA1, // HID type OSC
+ HID_CONSUMER_DAILY = 0xA2, // HID type OSC
+ HID_CONSUMER_WEEKLY = 0xA3, // HID type OSC
+ HID_CONSUMER_MONTHLY = 0xA4, // HID type OSC
+ // Reserved 0xA5-AF
+ HID_CONSUMER_PLAY = 0xB0, // HID type OOC
+ HID_CONSUMER_PAUSE = 0xB1, // HID type OOC
+ HID_CONSUMER_RECORD = 0xB2, // HID type OOC
+ HID_CONSUMER_FAST_FORWARD = 0xB3, // HID type OOC
+ HID_CONSUMER_REWIND = 0xB4, // HID type OOC
+ HID_CONSUMER_SCAN_NEXT_TRACK = 0xB5, // HID type OSC
+ HID_CONSUMER_SCAN_PREVIOUS_TRACK = 0xB6, // HID type OSC
+ HID_CONSUMER_STOP = 0xB7, // HID type OSC
+ HID_CONSUMER_EJECT = 0xB8, // HID type OSC
+ HID_CONSUMER_RANDOM_PLAY = 0xB9, // HID type OOC
+ HID_CONSUMER_SELECT_DISC = 0xBA, // HID type NARY
+ HID_CONSUMER_ENTER_DISC_MC = 0xBB,
+ HID_CONSUMER_REPEAT = 0xBC, // HID type OSC
+ HID_CONSUMER_TRACKING = 0xBD, // HID type LC
+ HID_CONSUMER_TRACK_NORMAL = 0xBE, // HID type OSC
+ HID_CONSUMER_SLOW_TRACKING = 0xBF, // HID type LC
+ HID_CONSUMER_FRAME_FORWARD = 0xC0, // HID type RTC
+ HID_CONSUMER_FRAME_BACK = 0xC1, // HID type RTC
+ HID_CONSUMER_MARK = 0xC2, // HID type OSC
+ HID_CONSUMER_CLEAR_MARK = 0xC3, // HID type OSC
+ HID_CONSUMER_REPEAT_FROM_MARK = 0xC4, // HID type OOC
+ HID_CONSUMER_RETURN_TO_MARK = 0xC5, // HID type OSC
+ HID_CONSUMER_SEARCH_MARK_FORWARD = 0xC6, // HID type OSC
+ HID_CONSUMER_SEARCH_MARK_BACKWARDS = 0xC7, // HID type OSC
+ HID_CONSUMER_COUNTER_RESET = 0xC8, // HID type OSC
+ HID_CONSUMER_SHOW_COUNTER = 0xC9, // HID type OSC
+ HID_CONSUMER_TRACKING_INCREMENT = 0xCA, // HID type RTC
+ HID_CONSUMER_TRACKING_DECREMENT = 0xCB, // HID type RTC
+ HID_CONSUMER_STOP_SLASH_EJECT = 0xCC, // HID type OSC
+ HID_CONSUMER_PLAY_SLASH_PAUSE = 0xCD, // HID type OSC
+ HID_CONSUMER_PLAY_SLASH_SKIP = 0xCE, // HID type OSC
+ // Reserved 0xCF-DF
+ HID_CONSUMER_VOLUME = 0xE0, // HID type LC
+ HID_CONSUMER_BALANCE = 0xE1, // HID type LC
+ HID_CONSUMER_MUTE = 0xE2, // HID type OOC
+ HID_CONSUMER_BASS = 0xE3, // HID type LC
+ HID_CONSUMER_TREBLE = 0xE4, // HID type LC
+ HID_CONSUMER_BASS_BOOST = 0xE5, // HID type OOC
+ HID_CONSUMER_SURROUND_MODE = 0xE6, // HID type OSC
+ HID_CONSUMER_LOUDNESS = 0xE7, // HID type OOC
+ HID_CONSUMER_MPX = 0xE8, // HID type OOC
+ HID_CONSUMER_VOLUME_INCREMENT = 0xE9, // HID type RTC
+ HID_CONSUMER_VOLUME_DECREMENT = 0xEA, // HID type RTC
+ // Reserved 0xEB-EF
+ HID_CONSUMER_SPEED_SELECT = 0xF0, // HID type OSC
+ HID_CONSUMER_PLAYBACK_SPEED = 0xF1, // HID type NARY
+ HID_CONSUMER_STANDARD_PLAY = 0xF2, // HID type SEL
+ HID_CONSUMER_LONG_PLAY = 0xF3, // HID type SEL
+ HID_CONSUMER_EXTENDED_PLAY = 0xF4, // HID type SEL
+ HID_CONSUMER_SLOW = 0xF5, // HID type OSC
+ // Reserved 0xF6-FF
+ HID_CONSUMER_FAN_ENABLE = 0x100, // HID type OOC
+ HID_CONSUMER_FAN_SPEED = 0x101, // HID type LC
+ HID_CONSUMER_LIGHT_ENABLE = 0x102, // HID type OOC
+ HID_CONSUMER_LIGHT_ILLUMINATION_LEVEL = 0x103, // HID type LC
+ HID_CONSUMER_CLIMATE_CONTROL_ENABLE = 0x104, // HID type OOC
+ HID_CONSUMER_ROOM_TEMPERATURE = 0x105, // HID type LC
+ HID_CONSUMER_SECURITY_ENABLE = 0x106, // HID type OOC
+ HID_CONSUMER_FIRE_ALARM = 0x107, // HID type OSC
+ HID_CONSUMER_POLICE_ALARM = 0x108, // HID type OSC
+ HID_CONSUMER_PROXIMITY = 0x109, // HID type LC
+ HID_CONSUMER_MOTION = 0x10A, // HID type OSC
+ HID_CONSUMER_DURESS_ALARM = 0x10B, // HID type OSC
+ HID_CONSUMER_HOLDUP_ALARM = 0x10C, // HID type OSC
+ HID_CONSUMER_MEDICAL_ALARM = 0x10D, // HID type OSC
+ // Reserved 0x10E-14F
+ HID_CONSUMER_BALANCE_RIGHT = 0x150, // HID type RTC
+ HID_CONSUMER_BALANCE_LEFT = 0x151, // HID type RTC
+ HID_CONSUMER_BASS_INCREMENT = 0x152, // HID type RTC
+ HID_CONSUMER_BASS_DECREMENT = 0x153, // HID type RTC
+ HID_CONSUMER_TREBLE_INCREMENT = 0x154, // HID type RTC
+ HID_CONSUMER_TREBLE_DECREMENT = 0x155, // HID type RTC
+ // Reserved 0x156-15F
+ HID_CONSUMER_SPEAKER_SYSTEM = 0x160, // HID type CL
+ HID_CONSUMER_CHANNEL_LEFT = 0x161, // HID type CL
+ HID_CONSUMER_CHANNEL_RIGHT = 0x162, // HID type CL
+ HID_CONSUMER_CHANNEL_CENTER = 0x163, // HID type CL
+ HID_CONSUMER_CHANNEL_FRONT = 0x164, // HID type CL
+ HID_CONSUMER_CHANNEL_CENTER_FRONT = 0x165, // HID type CL
+ HID_CONSUMER_CHANNEL_SIDE = 0x166, // HID type CL
+ HID_CONSUMER_CHANNEL_SURROUND = 0x167, // HID type CL
+ HID_CONSUMER_CHANNEL_LOW_FREQUENCY_ENHANCEMENT = 0x168, // HID type CL
+ HID_CONSUMER_CHANNEL_TOP = 0x169, // HID type CL
+ HID_CONSUMER_CHANNEL_UNKNOWN = 0x16A, // HID type CL
+ // Reserved 0x16B-16F
+ HID_CONSUMER_SUB_CHANNEL = 0x170, // HID type LC
+ HID_CONSUMER_SUB_CHANNEL_INCREMENT = 0x171, // HID type OSC
+ HID_CONSUMER_SUB_CHANNEL_DECREMENT = 0x172, // HID type OSC
+ HID_CONSUMER_ALTERNATE_AUDIO_INCREMENT = 0x173, // HID type OSC
+ HID_CONSUMER_ALTERNATE_AUDIO_DECREMENT = 0x174, // HID type OSC
+ // Reserved 0x175-17F
+ HID_CONSUMER_APPLICATION_LAUNCH_BUTTONS = 0x180, // HID type NARY
+ HID_CONSUMER_AL_LAUNCH_BUTTON_CONFIGURATION_TOOL = 0x181, // HID type SEL
+ HID_CONSUMER_AL_PROGRAMMABLE_BUTTON_CONFIGURATION = 0x182, // HID type SEL
+ HID_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x183, // HID type SEL
+ HID_CONSUMER_AL_WORD_PROCESSOR = 0x184, // HID type SEL
+ HID_CONSUMER_AL_TEXT_EDITOR = 0x185, // HID type SEL
+ HID_CONSUMER_AL_SPREADSHEET = 0x186, // HID type SEL
+ HID_CONSUMER_AL_GRAPHICS_EDITOR = 0x187, // HID type SEL
+ HID_CONSUMER_AL_PRESENTATION_APP = 0x188, // HID type SEL
+ HID_CONSUMER_AL_DATABASE_APP = 0x189, // HID type SEL
+ HID_CONSUMER_AL_EMAIL_READER = 0x18A, // HID type SEL
+ HID_CONSUMER_AL_NEWSREADER = 0x18B, // HID type SEL
+ HID_CONSUMER_AL_VOICEMAIL = 0x18C, // HID type SEL
+ HID_CONSUMER_AL_CONTACTS_SLASH_ADDRESS_BOOK = 0x18D, // HID type SEL
+ HID_CONSUMER_AL_CALENDAR_SLASH_SCHEDULE = 0x18E, // HID type SEL
+ HID_CONSUMER_AL_TASK_SLASH_PROJECT_MANAGER = 0x18F, // HID type SEL
+ HID_CONSUMER_AL_LOG_SLASH_JOURNAL_SLASH_TIMECARD = 0x190, // HID type SEL
+ HID_CONSUMER_AL_CHECKBOOK_SLASH_FINANCE = 0x191, // HID type SEL
+ HID_CONSUMER_AL_CALCULATOR = 0x192, // HID type SEL
+ HID_CONSUMER_AL_A_SLASH_V_CAPTURE_SLASH_PLAYBACK = 0x193, // HID type SEL
+ HID_CONSUMER_AL_LOCAL_MACHINE_BROWSER = 0x194, // HID type SEL
+ HID_CONSUMER_AL_LAN_SLASH_WAN_BROWSER = 0x195, // HID type SEL
+ HID_CONSUMER_AL_INTERNET_BROWSER = 0x196, // HID type SEL
+ HID_CONSUMER_AL_REMOTE_NETWORKING_SLASH_ISP_CONNECT = 0x197, // HID type SEL
+ HID_CONSUMER_AL_NETWORK_CONFERENCE = 0x198, // HID type SEL
+ HID_CONSUMER_AL_NETWORK_CHAT = 0x199, // HID type SEL
+ HID_CONSUMER_AL_TELEPHONY_SLASH_DIALER = 0x19A, // HID type SEL
+ HID_CONSUMER_AL_LOGON = 0x19B, // HID type SEL
+ HID_CONSUMER_AL_LOGOFF = 0x19C, // HID type SEL
+ HID_CONSUMER_AL_LOGON_SLASH_LOGOFF = 0x19D, // HID type SEL
+ HID_CONSUMER_AL_TERMINAL_LOCK_SLASH_SCREENSAVER = 0x19E, // HID type SEL
+ HID_CONSUMER_AL_CONTROL_PANEL = 0x19F, // HID type SEL
+ HID_CONSUMER_AL_COMMAND_LINE_PROCESSOR_SLASH_RUN = 0x1A0, // HID type SEL
+ HID_CONSUMER_AL_PROCESS_SLASH_TASK_MANAGER = 0x1A1, // HID type SEL
+ HID_CONSUMER_AL_SELECT_TASK_SLASH_APPLICATION = 0x1A2, // HID type SEL
+ HID_CONSUMER_AL_NEXT_TASK_SLASH_APPLICATION = 0x1A3, // HID type SEL
+ HID_CONSUMER_AL_PREVIOUS_TASK_SLASH_APPLICATION = 0x1A4, // HID type SEL
+ HID_CONSUMER_AL_PREEMPTIVE_HALT_TASK_SLASH_APPLICATION = 0x1A5, // HID type SEL
+ HID_CONSUMER_AL_INTEGRATED_HELP_CENTER = 0x1A6, // HID type SEL
+ HID_CONSUMER_AL_DOCUMENTS = 0x1A7, // HID type SEL
+ HID_CONSUMER_AL_THESAURUS = 0x1A8, // HID type SEL
+ HID_CONSUMER_AL_DICTIONARY = 0x1A9, // HID type SEL
+ HID_CONSUMER_AL_DESKTOP = 0x1AA, // HID type SEL
+ HID_CONSUMER_AL_SPELL_CHECK = 0x1AB, // HID type SEL
+ HID_CONSUMER_AL_GRAMMAR_CHECK = 0x1AC, // HID type SEL
+ HID_CONSUMER_AL_WIRELESS_STATUS = 0x1AD, // HID type SEL
+ HID_CONSUMER_AL_KEYBOARD_LAYOUT = 0x1AE, // HID type SEL
+ HID_CONSUMER_AL_VIRUS_PROTECTION = 0x1AF, // HID type SEL
+ HID_CONSUMER_AL_ENCRYPTION = 0x1B0, // HID type SEL
+ HID_CONSUMER_AL_SCREEN_SAVER = 0x1B1, // HID type SEL
+ HID_CONSUMER_AL_ALARMS = 0x1B2, // HID type SEL
+ HID_CONSUMER_AL_CLOCK = 0x1B3, // HID type SEL
+ HID_CONSUMER_AL_FILE_BROWSER = 0x1B4, // HID type SEL
+ HID_CONSUMER_AL_POWER_STATUS = 0x1B5, // HID type SEL
+ HID_CONSUMER_AL_IMAGE_BROWSER = 0x1B6, // HID type SEL
+ HID_CONSUMER_AL_AUDIO_BROWSER = 0x1B7, // HID type SEL
+ HID_CONSUMER_AL_MOVIE_BROWSER = 0x1B8, // HID type SEL
+ HID_CONSUMER_AL_DIGITAL_RIGHTS_MANAGER = 0x1B9, // HID type SEL
+ HID_CONSUMER_AL_DIGITAL_WALLET = 0x1BA, // HID type SEL
+ // _Reserved 0x1BB
+ HID_CONSUMER_AL_INSTANT_MESSAGING = 0x1BC, // HID type SEL
+ HID_CONSUMER_AL_OEM_FEATURES_SLASH__TIPS_SLASH_TUTORIAL_BROWSER = 0x1BD, // HID type SEL
+ HID_CONSUMER_AL_OEM_HELP = 0x1BE, // HID type SEL
+ HID_CONSUMER_AL_ONLINE_COMMUNITY = 0x1BF, // HID type SEL
+ HID_CONSUMER_AL_ENTERTAINMENT_CONTENT_BROWSER = 0x1C0, // HID type SEL
+ HID_CONSUMER_AL_ONLINE_SHOPPING_BROWSER = 0x1C1, // HID type SEL
+ HID_CONSUMER_AL_SMARTCARD_INFORMATION_SLASH_HELP = 0x1C2, // HID type SEL
+ HID_CONSUMER_AL_MARKET_MONITOR_SLASH_FINANCE_BROWSER = 0x1C3, // HID type SEL
+ HID_CONSUMER_AL_CUSTOMIZED_CORPORATE_NEWS_BROWSER = 0x1C4, // HID type SEL
+ HID_CONSUMER_AL_ONLINE_ACTIVITY_BROWSER = 0x1C5, // HID type SEL
+ HID_CONSUMER_AL_RESEARCH_SLASH_SEARCH_BROWSER = 0x1C6, // HID type SEL
+ HID_CONSUMER_AL_AUDIO_PLAYER = 0x1C7, // HID type SEL
+ // Reserved 0x1C8-1FF
+ HID_CONSUMER_GENERIC_GUI_APPLICATION_CONTROLS = 0x200, // HID type NARY
+ HID_CONSUMER_AC_NEW = 0x201, // HID type SEL
+ HID_CONSUMER_AC_OPEN = 0x202, // HID type SEL
+ HID_CONSUMER_AC_CLOSE = 0x203, // HID type SEL
+ HID_CONSUMER_AC_EXIT = 0x204, // HID type SEL
+ HID_CONSUMER_AC_MAXIMIZE = 0x205, // HID type SEL
+ HID_CONSUMER_AC_MINIMIZE = 0x206, // HID type SEL
+ HID_CONSUMER_AC_SAVE = 0x207, // HID type SEL
+ HID_CONSUMER_AC_PRINT = 0x208, // HID type SEL
+ HID_CONSUMER_AC_PROPERTIES = 0x209, // HID type SEL
+ HID_CONSUMER_AC_UNDO = 0x21A, // HID type SEL
+ HID_CONSUMER_AC_COPY = 0x21B, // HID type SEL
+ HID_CONSUMER_AC_CUT = 0x21C, // HID type SEL
+ HID_CONSUMER_AC_PASTE = 0x21D, // HID type SEL
+ HID_CONSUMER_AC_SELECT_ALL = 0x21E, // HID type SEL
+ HID_CONSUMER_AC_FIND = 0x21F, // HID type SEL
+ HID_CONSUMER_AC_FIND_AND_REPLACE = 0x220, // HID type SEL
+ HID_CONSUMER_AC_SEARCH = 0x221, // HID type SEL
+ HID_CONSUMER_AC_GO_TO = 0x222, // HID type SEL
+ HID_CONSUMER_AC_HOME = 0x223, // HID type SEL
+ HID_CONSUMER_AC_BACK = 0x224, // HID type SEL
+ HID_CONSUMER_AC_FORWARD = 0x225, // HID type SEL
+ HID_CONSUMER_AC_STOP = 0x226, // HID type SEL
+ HID_CONSUMER_AC_REFRESH = 0x227, // HID type SEL
+ HID_CONSUMER_AC_PREVIOUS_LINK = 0x228, // HID type SEL
+ HID_CONSUMER_AC_NEXT_LINK = 0x229, // HID type SEL
+ HID_CONSUMER_AC_BOOKMARKS = 0x22A, // HID type SEL
+ HID_CONSUMER_AC_HISTORY = 0x22B, // HID type SEL
+ HID_CONSUMER_AC_SUBSCRIPTIONS = 0x22C, // HID type SEL
+ HID_CONSUMER_AC_ZOOM_IN = 0x22D, // HID type SEL
+ HID_CONSUMER_AC_ZOOM_OUT = 0x22E, // HID type SEL
+ HID_CONSUMER_AC_ZOOM = 0x22F, // HID type LC
+ HID_CONSUMER_AC_FULL_SCREEN_VIEW = 0x230, // HID type SEL
+ HID_CONSUMER_AC_NORMAL_VIEW = 0x231, // HID type SEL
+ HID_CONSUMER_AC_VIEW_TOGGLE = 0x232, // HID type SEL
+ HID_CONSUMER_AC_SCROLL_UP = 0x233, // HID type SEL
+ HID_CONSUMER_AC_SCROLL_DOWN = 0x234, // HID type SEL
+ HID_CONSUMER_AC_SCROLL = 0x235, // HID type LC
+ HID_CONSUMER_AC_PAN_LEFT = 0x236, // HID type SEL
+ HID_CONSUMER_AC_PAN_RIGHT = 0x237, // HID type SEL
+ HID_CONSUMER_AC_PAN = 0x238, // HID type LC
+ HID_CONSUMER_AC_NEW_WINDOW = 0x239, // HID type SEL
+ HID_CONSUMER_AC_TILE_HORIZONTALLY = 0x23A, // HID type SEL
+ HID_CONSUMER_AC_TILE_VERTICALLY = 0x23B, // HID type SEL
+ HID_CONSUMER_AC_FORMAT = 0x23C, // HID type SEL
+ HID_CONSUMER_AC_EDIT = 0x23D, // HID type SEL
+ HID_CONSUMER_AC_BOLD = 0x23E, // HID type SEL
+ HID_CONSUMER_AC_ITALICS = 0x23F, // HID type SEL
+ HID_CONSUMER_AC_UNDERLINE = 0x240, // HID type SEL
+ HID_CONSUMER_AC_STRIKETHROUGH = 0x241, // HID type SEL
+ HID_CONSUMER_AC_SUBSCRIPT = 0x242, // HID type SEL
+ HID_CONSUMER_AC_SUPERSCRIPT = 0x243, // HID type SEL
+ HID_CONSUMER_AC_ALL_CAPS = 0x244, // HID type SEL
+ HID_CONSUMER_AC_ROTATE = 0x245, // HID type SEL
+ HID_CONSUMER_AC_RESIZE = 0x246, // HID type SEL
+ HID_CONSUMER_AC_FLIP_HORIZONTAL = 0x247, // HID type SEL
+ HID_CONSUMER_AC_FLIP_VERTICAL = 0x248, // HID type SEL
+ HID_CONSUMER_AC_MIRROR_HORIZONTAL = 0x249, // HID type SEL
+ HID_CONSUMER_AC_MIRROR_VERTICAL = 0x24A, // HID type SEL
+ HID_CONSUMER_AC_FONT_SELECT = 0x24B, // HID type SEL
+ HID_CONSUMER_AC_FONT_COLOR = 0x24C, // HID type SEL
+ HID_CONSUMER_AC_FONT_SIZE = 0x24D, // HID type SEL
+ HID_CONSUMER_AC_JUSTIFY_LEFT = 0x24E, // HID type SEL
+ HID_CONSUMER_AC_JUSTIFY_CENTER_H = 0x24F, // HID type SEL
+ HID_CONSUMER_AC_JUSTIFY_RIGHT = 0x250, // HID type SEL
+ HID_CONSUMER_AC_JUSTIFY_BLOCK_H = 0x251, // HID type SEL
+ HID_CONSUMER_AC_JUSTIFY_TOP = 0x252, // HID type SEL
+ HID_CONSUMER_AC_JUSTIFY_CENTER_V = 0x253, // HID type SEL
+ HID_CONSUMER_AC_JUSTIFY_BOTTOM = 0x254, // HID type SEL
+ HID_CONSUMER_AC_JUSTIFY_BLOCK_V = 0x255, // HID type SEL
+ HID_CONSUMER_AC_INDENT_DECREASE = 0x256, // HID type SEL
+ HID_CONSUMER_AC_INDENT_INCREASE = 0x257, // HID type SEL
+ HID_CONSUMER_AC_NUMBERED_LIST = 0x258, // HID type SEL
+ HID_CONSUMER_AC_RESTART_NUMBERING = 0x259, // HID type SEL
+ HID_CONSUMER_AC_BULLETED_LIST = 0x25A, // HID type SEL
+ HID_CONSUMER_AC_PROMOTE = 0x25B, // HID type SEL
+ HID_CONSUMER_AC_DEMOTE = 0x25C, // HID type SEL
+ HID_CONSUMER_AC_YES = 0x25D, // HID type SEL
+ HID_CONSUMER_AC_NO = 0x25E, // HID type SEL
+ HID_CONSUMER_AC_CANCEL = 0x25F, // HID type SEL
+ HID_CONSUMER_AC_CATALOG = 0x260, // HID type SEL
+ HID_CONSUMER_AC_BUY_SLASH_CHECKOUT = 0x261, // HID type SEL
+ HID_CONSUMER_AC_ADD_TO_CART = 0x262, // HID type SEL
+ HID_CONSUMER_AC_EXPAND = 0x263, // HID type SEL
+ HID_CONSUMER_AC_EXPAND_ALL = 0x264, // HID type SEL
+ HID_CONSUMER_AC_COLLAPSE = 0x265, // HID type SEL
+ HID_CONSUMER_AC_COLLAPSE_ALL = 0x266, // HID type SEL
+ HID_CONSUMER_AC_PRINT_PREVIEW = 0x267, // HID type SEL
+ HID_CONSUMER_AC_PASTE_SPECIAL = 0x268, // HID type SEL
+ HID_CONSUMER_AC_INSERT_MODE = 0x269, // HID type SEL
+ HID_CONSUMER_AC_DELETE = 0x26A, // HID type SEL
+ HID_CONSUMER_AC_LOCK = 0x26B, // HID type SEL
+ HID_CONSUMER_AC_UNLOCK = 0x26C, // HID type SEL
+ HID_CONSUMER_AC_PROTECT = 0x26D, // HID type SEL
+ HID_CONSUMER_AC_UNPROTECT = 0x26E, // HID type SEL
+ HID_CONSUMER_AC_ATTACH_COMMENT = 0x26F, // HID type SEL
+ HID_CONSUMER_AC_DELETE_COMMENT = 0x270, // HID type SEL
+ HID_CONSUMER_AC_VIEW_COMMENT = 0x271, // HID type SEL
+ HID_CONSUMER_AC_SELECT_WORD = 0x272, // HID type SEL
+ HID_CONSUMER_AC_SELECT_SENTENCE = 0x273, // HID type SEL
+ HID_CONSUMER_AC_SELECT_PARAGRAPH = 0x274, // HID type SEL
+ HID_CONSUMER_AC_SELECT_COLUMN = 0x275, // HID type SEL
+ HID_CONSUMER_AC_SELECT_ROW = 0x276, // HID type SEL
+ HID_CONSUMER_AC_SELECT_TABLE = 0x277, // HID type SEL
+ HID_CONSUMER_AC_SELECT_OBJECT = 0x278, // HID type SEL
+ HID_CONSUMER_AC_REDO_SLASH_REPEAT = 0x279, // HID type SEL
+ HID_CONSUMER_AC_SORT = 0x27A, // HID type SEL
+ HID_CONSUMER_AC_SORT_ASCENDING = 0x27B, // HID type SEL
+ HID_CONSUMER_AC_SORT_DESCENDING = 0x27C, // HID type SEL
+ HID_CONSUMER_AC_FILTER = 0x27D, // HID type SEL
+ HID_CONSUMER_AC_SET_CLOCK = 0x27E, // HID type SEL
+ HID_CONSUMER_AC_VIEW_CLOCK = 0x27F, // HID type SEL
+ HID_CONSUMER_AC_SELECT_TIME_ZONE = 0x280, // HID type SEL
+ HID_CONSUMER_AC_EDIT_TIME_ZONES = 0x281, // HID type SEL
+ HID_CONSUMER_AC_SET_ALARM = 0x282, // HID type SEL
+ HID_CONSUMER_AC_CLEAR_ALARM = 0x283, // HID type SEL
+ HID_CONSUMER_AC_SNOOZE_ALARM = 0x284, // HID type SEL
+ HID_CONSUMER_AC_RESET_ALARM = 0x285, // HID type SEL
+ HID_CONSUMER_AC_SYNCHRONIZE = 0x286, // HID type SEL
+ HID_CONSUMER_AC_SEND_SLASH_RECEIVE = 0x287, // HID type SEL
+ HID_CONSUMER_AC_SEND_TO = 0x288, // HID type SEL
+ HID_CONSUMER_AC_REPLY = 0x289, // HID type SEL
+ HID_CONSUMER_AC_REPLY_ALL = 0x28A, // HID type SEL
+ HID_CONSUMER_AC_FORWARD_MSG = 0x28B, // HID type SEL
+ HID_CONSUMER_AC_SEND = 0x28C, // HID type SEL
+ HID_CONSUMER_AC_ATTACH_FILE = 0x28D, // HID type SEL
+ HID_CONSUMER_AC_UPLOAD = 0x28E, // HID type SEL
+ HID_CONSUMER_AC_DOWNLOAD_SAVE_TARGET_AS = 0x28F, // HID type SEL
+ HID_CONSUMER_AC_SET_BORDERS = 0x290, // HID type SEL
+ HID_CONSUMER_AC_INSERT_ROW = 0x291, // HID type SEL
+ HID_CONSUMER_AC_INSERT_COLUMN = 0x292, // HID type SEL
+ HID_CONSUMER_AC_INSERT_FILE = 0x293, // HID type SEL
+ HID_CONSUMER_AC_INSERT_PICTURE = 0x294, // HID type SEL
+ HID_CONSUMER_AC_INSERT_OBJECT = 0x295, // HID type SEL
+ HID_CONSUMER_AC_INSERT_SYMBOL = 0x296, // HID type SEL
+ HID_CONSUMER_AC_SAVE_AND_CLOSE = 0x297, // HID type SEL
+ HID_CONSUMER_AC_RENAME = 0x298, // HID type SEL
+ HID_CONSUMER_AC_MERGE = 0x299, // HID type SEL
+ HID_CONSUMER_AC_SPLIT = 0x29A, // HID type SEL
+ HID_CONSUMER_AC_DISRIBUTE_HORIZONTALLY = 0x29B, // HID type SEL
+ HID_CONSUMER_AC_DISTRIBUTE_VERTICALLY = 0x29C, // HID type SEL
+};
diff --git a/src/usb_inc/usb.h b/src/usb_inc/usb.h
index 19d90a5..3d39fd3 100644
--- a/src/usb_inc/usb.h
+++ b/src/usb_inc/usb.h
@@ -1,6 +1,8 @@
#pragma once
#include
+#include "../_compiler.h"
+
// USB U16 helpers
#define U16(_high, _low) ((uint16_t)(((_high) << 8) | (_low)))
#define U16_HIGH(_u16) ((uint8_t)(((_u16) >> 8) & 0x00ff))
diff --git a/src/usbd_driver.c b/src/usbd_driver.c
index 8e85458..9fa0943 100644
--- a/src/usbd_driver.c
+++ b/src/usbd_driver.c
@@ -26,7 +26,7 @@ static uint8_t su8VendorCount = 0;
void Tas_USBD_Open(void) {
g_usbd_CtrlMaxPktSize = gpDeviceDescriptor->bMaxPacketSize0;
USBD->ATTR = 0x650; // Disable D+ and USB controller
- CLK_SysTickLongDelay(3000 ms);
+ CLK_SysTickLongDelay(1000 ms);
USBD->ATTR = 0x7D0;
USBD_SET_SE0();
}
@@ -189,18 +189,10 @@ static inline void Tas_USBD_GetDescriptor(void) {
break;
case USB_STRING_VENDOR: {
- const char *szVendor;
- if (su8VendorCount < 2) {
- szVendor = gszVendorInitial;
- su8VendorCount++;
- } else {
- szVendor = gszVendor;
- }
-
- uint8_t u8Len = strlen(szVendor);
+ uint8_t u8Len = strlen(gszVendor);
u8Str[0] = 2 + u8Len * 2;
for (uint8_t i = 0; i < u8Len; i++) {
- u8Str[2 + i * 2] = szVendor[i];
+ u8Str[2 + i * 2] = gszVendor[i];
u8Str[2 + i * 2 + 1] = 0;
}
break;
@@ -215,8 +207,10 @@ static inline void Tas_USBD_GetDescriptor(void) {
break;
}
case USB_STRING_SERIAL: {
- // TODO: I think it might be a u16 then two u8s?
- // Need to check the TRM
+ // The unique ID is technically 3 words, but I'm pretty sure only the last one
+ // really changes. The TRM has no details regarding this.
+ // There's no harm using all three as our serial, so to stay on the safe side
+ // that's what we do.
uint32_t u32serial;
FMC_Open();
diff --git a/src/usbd_user.c b/src/usbd_user.c
index f557f6b..e8bed35 100644
--- a/src/usbd_user.c
+++ b/src/usbd_user.c
@@ -1,16 +1,27 @@
#include "tasoller.h"
-uint8_t volatile g_u8Suspend = 0;
+uint8_t volatile g_u8UsbState = 0;
+uint8_t volatile gu8VComDTEPresent = 0;
uint8_t g_u8Idle = 0;
uint8_t g_u8Protocol = 0;
uint8_t gHidSetReport[64];
STR_VCOM_LINE_CODING gLineCoding = { 0, 0, 0, 0 };
-uint16_t gCtrlSignal;
uint32_t volatile g_u32OutToggle = 0;
+#define STALL_CONTROL \
+ do { \
+ USBD_SetStall(EP_CTRL_IN); \
+ USBD_SetStall(EP_CTRL_OUT); \
+ } while (0)
+#define CONTROL_IN_DONE \
+ do { \
+ USBD_SET_DATA1(EP_CTRL_IN); \
+ USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0); \
+ } while (0)
+
void USBD_IRQHandler(void) {
uint32_t u32IntSts = USBD_GET_INT_FLAG();
uint32_t u32State = USBD_GET_BUS_STATE();
@@ -21,8 +32,10 @@ void USBD_IRQHandler(void) {
if (USBD_IS_ATTACHED()) {
USBD_ENABLE_USB();
+ g_u8UsbState &= ~USB_STATE_FLOATING;
} else {
USBD_DISABLE_USB();
+ g_u8UsbState |= USB_STATE_FLOATING;
}
}
@@ -38,17 +51,15 @@ void USBD_IRQHandler(void) {
USBD_ENABLE_USB();
Tas_USBD_SwReset();
g_u32OutToggle = 0;
- g_u8Suspend = 0;
+ g_u8UsbState &= ~USB_STATE_SUSPEND;
}
if (u32State & USBD_STATE_SUSPEND) {
- // Enter power down to wait USB attached; enable USB but disable PHY
- g_u8Suspend = 1;
USBD_DISABLE_PHY();
+ g_u8UsbState |= USB_STATE_SUSPEND;
}
if (u32State & USBD_STATE_RESUME) {
- // Enable USB and enable PHY
USBD_ENABLE_USB();
- g_u8Suspend = 0;
+ g_u8UsbState &= ~USB_STATE_SUSPEND;
}
}
@@ -173,30 +184,28 @@ void Tas_USBD_ClassRequest(void) {
default:
// Setup error, stall the device
- USBD_SetStall(EP_CTRL_IN);
- USBD_SetStall(EP_CTRL_OUT);
+ STALL_CONTROL;
break;
}
} else {
// Host to device
switch (setup.bRequest) {
case SET_CONTROL_LINE_STATE:
- // TODO: Use bit[0] (DTR) to identify connection state
- // Is RTS worth using?
- if (setup.wIndex == USBD_ITF_CDC_CMD) gCtrlSignal = setup.wValue;
-
- // Status stage
- USBD_SET_DATA1(EP_CTRL_IN);
- USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
+ if (setup.wIndex == USBD_ITF_CDC_CMD) {
+ gu8VComDTEPresent = setup.wValue & 1;
+ CONTROL_IN_DONE;
+ } else {
+ STALL_CONTROL;
+ }
break;
case SET_LINE_CODING:
- if (setup.setLineCoding.wInterface == USBD_ITF_CDC_CMD)
+ if (setup.setLineCoding.wInterface == USBD_ITF_CDC_CMD) {
Tas_USBD_PrepareCtrlOut(&gLineCoding, sizeof gLineCoding, NULL);
-
- // Status stage
- USBD_SET_DATA1(EP_CTRL_IN);
- USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
+ CONTROL_IN_DONE;
+ } else {
+ STALL_CONTROL;
+ }
break;
case SET_REPORT:
@@ -216,22 +225,17 @@ void Tas_USBD_ClassRequest(void) {
// // Status stage
// Tas_USBD_PrepareCtrlIn(NULL, 0);
}
- USBD_SET_DATA1(EP_CTRL_IN);
- USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
+ CONTROL_IN_DONE;
break;
case SET_IDLE:
g_u8Idle = setup.hidSetIdle.bDuration;
- // Status stage
- USBD_SET_DATA1(EP_CTRL_IN);
- USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
+ CONTROL_IN_DONE;
break;
case SET_PROTOCOL:
g_u8Protocol = setup.hidSetProtocol.wProtocol;
- // Status stage
- USBD_SET_DATA1(EP_CTRL_IN);
- USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
+ CONTROL_IN_DONE;
break;
default:
diff --git a/src/vcom.c b/src/vcom.c
index 1decb3a..7cbb9f8 100644
--- a/src/vcom.c
+++ b/src/vcom.c
@@ -3,7 +3,8 @@
#define BUF_SIZE_RX 512
#define BUF_SIZE_TX 512
-volatile uint8_t gu8VcomReady = 0;
+volatile uint8_t gu8VcomDTEPresent = 0;
+volatile uint8_t gu8VComReady = 0;
static volatile uint8_t gau8ComRbuf[BUF_SIZE_RX];
static volatile uint16_t gu16ComRbytes = 0;
@@ -26,10 +27,10 @@ void _USB_VCOM_Tick_Tx(void) {
uint32_t u32Len;
if (gu32TxSize != 0) return;
- // Check wether we have new COM Rx data to send to USB or not
+ // Check whether we have new COM Rx data to send to USB or not
if (!gu16ComRbytes) {
- // Prepare a zero packet if previous packet size is USBD_CDC_IN_MAX_SIZE and
- // no more data to send at this moment to note Host the transfer has been done
+ // Prepare a zero packet if previous packet size is USBD_CDC_IN_MAX_SIZE and no more data to
+ // send at this moment to notify to the Host that the transfer has been done
u32Len = USBD_GET_PAYLOAD_LEN(EP_CDC_IN);
if (u32Len == USBD_CDC_IN_MAX_SIZE) USBD_SET_PAYLOAD_LEN(EP_CDC_IN, 0);
return;
diff --git a/src/vcom.h b/src/vcom.h
new file mode 100644
index 0000000..42da425
--- /dev/null
+++ b/src/vcom.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include
+
+typedef struct __packed {
+ uint32_t u32DTERate; // Baud rate
+ uint8_t u8CharFormat; // Stop bit
+ uint8_t u8ParityType; // Parity
+ uint8_t u8DataBits; // Data bits
+} STR_VCOM_LINE_CODING;
+extern STR_VCOM_LINE_CODING gLineCoding;
+extern volatile int8_t gi8BulkOutReady;
+
+extern volatile uint8_t *gpu8RxBuf;
+extern volatile uint32_t gu32RxSize;
+extern volatile uint32_t gu32TxSize;
+
+extern volatile uint8_t gu8VComDTEPresent;
+extern volatile uint8_t gu8VComReady;
+
+void USB_VCOM_Write(uint8_t u8Char);
+uint16_t USB_VCOM_Available(void);
+uint8_t USB_VCOM_Read(void);
+void USB_VCOM_Tick(void);
+void USB_VCOM_PurgeTx(void);