mirror of
https://gitea.tendokyu.moe/tasoller/host-aprom.git
synced 2024-11-23 22:50:57 +01:00
Damn thats a lot
This commit is contained in:
parent
923886efde
commit
8718c10f03
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@ picolibc/*
|
||||
# Build artifacts
|
||||
obj/*
|
||||
host_aprom.bin
|
||||
|
||||
# Flashing tool
|
||||
flashtool/*
|
||||
|
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -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"
|
||||
]
|
||||
}
|
63
.vscode/settings.json
vendored
63
.vscode/settings.json
vendored
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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.
|
2
GCC.mk
2
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
|
||||
|
3
Makefile
3
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
|
||||
|
124
NUC123/NUC123.ld
124
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")
|
||||
|
@ -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
|
||||
|
42
README.md
42
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!
|
||||
|
11
docs/Colours.md
Normal file
11
docs/Colours.md
Normal file
@ -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)
|
79
docs/Development.md
Normal file
79
docs/Development.md
Normal file
@ -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.
|
1089
docs/USB/Chapter 9 Tests - USB 2 - Passed - 2024-07-23 19-44-26.html
Normal file
1089
docs/USB/Chapter 9 Tests - USB 2 - Passed - 2024-07-23 19-44-26.html
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,349 @@
|
||||
<HTML><HEAD>
|
||||
<META http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<META charset="UTF-8" />
|
||||
<STYLE type='text/css'>
|
||||
BODY { background-color: #DFDFDF; }
|
||||
.dm_display
|
||||
{
|
||||
color: Navy;
|
||||
font-family: monospace;
|
||||
background-color: White;
|
||||
border-width: 3px;
|
||||
border-style: outset;
|
||||
}
|
||||
|
||||
#suite-output
|
||||
{
|
||||
background-color: #FFFFDD;
|
||||
border: ridge 3px #FFFFDD;
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
empty-cells: hide
|
||||
}
|
||||
|
||||
#test-header
|
||||
{
|
||||
font-weight: bold;
|
||||
font-size: large;
|
||||
border-top: ridge 2px #FFFFDD;
|
||||
border-bottom: ridge 2px #FFFFDD;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.test-pass, .test-fail
|
||||
{
|
||||
float: right;
|
||||
border-left: ridge 2px #FFFDD;
|
||||
min-width: 6em;
|
||||
}
|
||||
|
||||
.test-pass { background-color: #00FF00; }
|
||||
.test-fail { background-color: #FF8888; }
|
||||
|
||||
.test-details
|
||||
{
|
||||
clear: both;
|
||||
font-family: monospace;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
empty-cells: hide;
|
||||
}
|
||||
|
||||
.label
|
||||
{
|
||||
float: left;
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.content
|
||||
{
|
||||
white-space: pre-wrap;
|
||||
margin-left: 7em;
|
||||
}
|
||||
|
||||
.err_log, .warn_log
|
||||
{
|
||||
color: Red;
|
||||
}
|
||||
|
||||
.err_log { font-weight: bold; }
|
||||
|
||||
.unexpected_log
|
||||
{
|
||||
color: Red;
|
||||
background-color: Yellow;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
</STYLE>
|
||||
<TITLE>Connector Type Tests - 2024-07-23 19-45-53</TITLE>
|
||||
<META name='Suite-Name' content='Connector Type Tests.cvtests' />
|
||||
<META name='Test-Version' content='GuiCV.exe ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='BaseUtilities.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='GuiHelper.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='ComplianceUtilities.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='TestSuiteParser.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='xhci_DevIOCTL.dll ver 2.2.7.0' />
|
||||
<META name='Test-Version' content='xhci_TestServices.dll ver 2.2.7.0' />
|
||||
<META name='Test-Version' content='USBUtilities.dll ver 1.4.5.1' />
|
||||
<META name='Test-Version' content='StackSwitcher.dll ver 1.4.5.1' />
|
||||
<META name='Test-Version' content='xhci_CVServices.dll ver 2.2.7.0' />
|
||||
<META name='Test-Version' content='xhci_ConnectorType.dll ver 3.1.3.0' />
|
||||
<META name='Host-Controller' content='VID=1022,PID=149C' />
|
||||
<META name='Device-Under-Test' content='VID=0CA3, PID=0021' />
|
||||
<META name='Device-Speed' content='Full Speed' />
|
||||
<META name='Topology' content='XHCI HC -- DUT' />
|
||||
<META name='Test-Pass' content='TD 9.1 PD Configuration Descriptor Test (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.2 PD Capability Descriptor Test (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.3 PD Battery Info Capability Descriptor Test (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.4 PD Consumer Port Capability Descriptor Test (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.5 PD Provider Port Capability Descriptor Test (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.6 PD Battery Status Test (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.7 PD Remote Wake Test - Enabled (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.7 Remote Wake Test - Disabled (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.8 PD CHARGING_POLICY Test (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='TD 9.9 PD Hub Bridge Test on single host (Configuration Index 0x00) - Device State Configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Suite-Result' content='PASS' />
|
||||
<META name='Log-Name' content='Connector Type Tests - 2024-07-23 19-45-53.html' />
|
||||
<META name='Test-Count' content='10' />
|
||||
</HEAD>
|
||||
<BODY><DIV id='suite-summary'>
|
||||
<DIV><STRONG>APPLICATION</STRONG>: USB 3 Gen X Command Verifier<BR></DIV>
|
||||
<DIV><STRONG>TEST SUITE</STRONG>: Connector Type Tests.cvtests<BR></DIV>
|
||||
<DIV><STRONG>OPERATING SYSTEM</STRONG>: <BR></DIV>
|
||||
<DIV><STRONG>WORKSTATION</STRONG>: <BR></DIV>
|
||||
<DIV><STRONG>DATE</STRONG>: Tuesday, July 23, 2024<BR></DIV>
|
||||
<DIV><STRONG>TIME</STRONG>: 07:46:09 PM<BR></DIV>
|
||||
<DIV><STRONG>OPERATOR</STRONG>: Emma<BR></DIV>
|
||||
<DIV><STRONG>NUMBER OF TESTS</STRONG>: 10<BR></DIV>
|
||||
<DIV><STRONG>LOG NAME</STRONG>: Connector Type Tests - 2024-07-23 19-45-53<BR></DIV>
|
||||
<DIV><STRONG>RESULT</STRONG>: passed<BR></DIV>
|
||||
<HR>
|
||||
</DIV>
|
||||
<BR><BR>
|
||||
<DIV id='suite-output'>
|
||||
<DIV id='test-header'>InitializeTestSuite</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Test log initialized.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Log Level: Normal</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>User Input module initialized</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Windows Version 22H2 (OS Build 19045)</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>GuiCV.exe ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>BaseUtilities.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>GuiHelper.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>ComplianceUtilities.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>TestSuiteParser.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_DevIOCTL.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_TestServices.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>USBUtilities.dll ver 1.4.5.1</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>StackSwitcher.dll ver 1.4.5.1</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_CVServices.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_ConnectorType.dll ver 3.1.3.0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>XHCISpecVersion: 1.10.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#00007F'><DIV class='label'>INFO</DIV><DIV class='content'>Host 1 selected: xHCI Host: VID=0x1022, PID=0x149C (PCI bus 45, device 0, function 3)</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>User selection from list: "FS Device (HID) addr=1: VID=0CA3, PID=0021 RouteString 0x00000"</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#00007F'><DIV class='label'>INFO</DIV><DIV class='content'>Please select USB Device to test</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>USB Device Under Test is operating at Full Speed.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Topology: XHCI HC -- DUT</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Get Number Of Configurations</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>USB Version number of device: 2.00</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Number of configurations: 1.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Get Number Of Other Speed Configurations</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Number of Other Speed configurations: 0.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Get Number Of Ports</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test is not a Hub.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Find Out Which Downstream Facing Ports Are Physically Inaccessible</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test is not a Hub.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Get Active Power State</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Acquiring power state helper.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>User selected power state: "Standard USB Current".</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Read VIF from file</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test is embedded, and cannot have a Vendor Info File (VIF) for its upstream facing port.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_8'>TD 9.1 PD Configuration Descriptor Test (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:45:58</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:45:59</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ TD 9.1 PD Configuration Descriptor Test (Configuration Index 0x00) - Device State Configured:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_9'>TD 9.2 PD Capability Descriptor Test (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:45:59</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:00</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ TD 9.2 PD Capability Descriptor Test (Configuration Index 0x00) - Device State Configured:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_10'>TD 9.3 PD Battery Info Capability Descriptor Test (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:01</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:02</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>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) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_11'>TD 9.4 PD Consumer Port Capability Descriptor Test (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:02</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:03</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>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) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_12'>TD 9.5 PD Provider Port Capability Descriptor Test (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:03</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:04</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>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) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_13'>TD 9.6 PD Battery Status Test (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:04</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:05</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ TD 9.6 PD Battery Status Test (Configuration Index 0x00) - Device State Configured:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_14'>TD 9.7 PD Remote Wake Test - Enabled (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:05</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:06</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ TD 9.7 PD Remote Wake Test - Enabled (Configuration Index 0x00) - Device State Configured:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_15'>TD 9.7 Remote Wake Test - Disabled (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:06</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:07</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ TD 9.7 Remote Wake Test - Disabled (Configuration Index 0x00) - Device State Configured:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_16'>TD 9.8 PD CHARGING_POLICY Test (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:07</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF contains 0 components.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>VIF has 0 Upstream Facing Ports.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test does not have a BOS descriptor and so does not support PD.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:08</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ TD 9.8 PD CHARGING_POLICY Test (Configuration Index 0x00) - Device State Configured:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_17'>TD 9.9 PD Hub Bridge Test on single host (Configuration Index 0x00) - Device State Configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:08</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Configuration Index 0x00 has a Configuration Value of 1.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Initialized the device to the Configured state with Configuration Value 1.
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device Under Test is not a hub.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:09</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>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) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>PDCommon_CleanupVIFs</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Cleaning up VIF for Upstream Facing Port</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Cleaning up VIF for Downstream Facing Ports.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Cleanup</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>TEST SUITE SUMMARY:
|
||||
[ Fails (0); Aborts (0); Warnings (0) ]</DIV></DIV>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>TEST RESULTS:
|
||||
[ Passed (10); Failed (0) ]</DIV></DIV>
|
||||
</DIV>
|
||||
</DIV>
|
||||
</BODY></HTML>
|
205
docs/USB/Device Summary - Passed - 2024-07-23 19-46-25.html
Normal file
205
docs/USB/Device Summary - Passed - 2024-07-23 19-46-25.html
Normal file
@ -0,0 +1,205 @@
|
||||
<HTML><HEAD>
|
||||
<META http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<META charset="UTF-8" />
|
||||
<STYLE type='text/css'>
|
||||
BODY { background-color: #DFDFDF; }
|
||||
.dm_display
|
||||
{
|
||||
color: Navy;
|
||||
font-family: monospace;
|
||||
background-color: White;
|
||||
border-width: 3px;
|
||||
border-style: outset;
|
||||
}
|
||||
|
||||
#suite-output
|
||||
{
|
||||
background-color: #FFFFDD;
|
||||
border: ridge 3px #FFFFDD;
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
empty-cells: hide
|
||||
}
|
||||
|
||||
#test-header
|
||||
{
|
||||
font-weight: bold;
|
||||
font-size: large;
|
||||
border-top: ridge 2px #FFFFDD;
|
||||
border-bottom: ridge 2px #FFFFDD;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.test-pass, .test-fail
|
||||
{
|
||||
float: right;
|
||||
border-left: ridge 2px #FFFDD;
|
||||
min-width: 6em;
|
||||
}
|
||||
|
||||
.test-pass { background-color: #00FF00; }
|
||||
.test-fail { background-color: #FF8888; }
|
||||
|
||||
.test-details
|
||||
{
|
||||
clear: both;
|
||||
font-family: monospace;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
empty-cells: hide;
|
||||
}
|
||||
|
||||
.label
|
||||
{
|
||||
float: left;
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.content
|
||||
{
|
||||
white-space: pre-wrap;
|
||||
margin-left: 7em;
|
||||
}
|
||||
|
||||
.err_log, .warn_log
|
||||
{
|
||||
color: Red;
|
||||
}
|
||||
|
||||
.err_log { font-weight: bold; }
|
||||
|
||||
.unexpected_log
|
||||
{
|
||||
color: Red;
|
||||
background-color: Yellow;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
</STYLE>
|
||||
<TITLE>Device Summary - 2024-07-23 19-46-25</TITLE>
|
||||
<META name='Suite-Name' content='Device Summary.cvtests' />
|
||||
<META name='Test-Version' content='GuiCV.exe ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='BaseUtilities.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='GuiHelper.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='ComplianceUtilities.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='TestSuiteParser.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='xhci_DevIOCTL.dll ver 2.2.7.0' />
|
||||
<META name='Test-Version' content='xhci_TestServices.dll ver 2.2.7.0' />
|
||||
<META name='Test-Version' content='USBUtilities.dll ver 1.4.5.1' />
|
||||
<META name='Test-Version' content='StackSwitcher.dll ver 1.4.5.1' />
|
||||
<META name='Test-Version' content='xhci_CVServices.dll ver 2.2.7.0' />
|
||||
<META name='Host-Controller' content='VID=1022,PID=149C' />
|
||||
<META name='Device-Under-Test' content='VID=0CA3, PID=0021' />
|
||||
<META name='Device-Speed' content='Full Speed' />
|
||||
<META name='Topology' content='XHCI HC -- DUT' />
|
||||
<META name='Test-Pass' content='Device Summary [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Suite-Result' content='PASS' />
|
||||
<META name='Log-Name' content='Device Summary - 2024-07-23 19-46-25.html' />
|
||||
<META name='Test-Count' content='1' />
|
||||
</HEAD>
|
||||
<BODY><DIV id='suite-summary'>
|
||||
<DIV><STRONG>APPLICATION</STRONG>: USB 3 Gen X Command Verifier<BR></DIV>
|
||||
<DIV><STRONG>TEST SUITE</STRONG>: Device Summary.cvtests<BR></DIV>
|
||||
<DIV><STRONG>OPERATING SYSTEM</STRONG>: <BR></DIV>
|
||||
<DIV><STRONG>WORKSTATION</STRONG>: <BR></DIV>
|
||||
<DIV><STRONG>DATE</STRONG>: Tuesday, July 23, 2024<BR></DIV>
|
||||
<DIV><STRONG>TIME</STRONG>: 07:46:29 PM<BR></DIV>
|
||||
<DIV><STRONG>OPERATOR</STRONG>: Emma<BR></DIV>
|
||||
<DIV><STRONG>NUMBER OF TESTS</STRONG>: 1<BR></DIV>
|
||||
<DIV><STRONG>LOG NAME</STRONG>: Device Summary - 2024-07-23 19-46-25<BR></DIV>
|
||||
<DIV><STRONG>RESULT</STRONG>: passed<BR></DIV>
|
||||
<HR>
|
||||
</DIV>
|
||||
<BR><BR>
|
||||
<DIV id='suite-output'>
|
||||
<DIV id='test-header'>Initialize Test Suite</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Test log initialized.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Log Level: Normal</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>User Input module initialized</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Windows Version 22H2 (OS Build 19045)</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>GuiCV.exe ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>BaseUtilities.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>GuiHelper.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>ComplianceUtilities.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>TestSuiteParser.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_DevIOCTL.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_TestServices.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>USBUtilities.dll ver 1.4.5.1</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>StackSwitcher.dll ver 1.4.5.1</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_CVServices.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>XHCISpecVersion: 1.10.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#00007F'><DIV class='label'>INFO</DIV><DIV class='content'>Host 1 selected: xHCI Host: VID=0x1022, PID=0x149C (PCI bus 45, device 0, function 3)</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>User selection from list: "FS Device (HID) addr=1: VID=0CA3, PID=0021 RouteString 0x00000"</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#00007F'><DIV class='label'>INFO</DIV><DIV class='content'>Please select USB Device to test</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>USB Device Under Test is operating at Full Speed.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Topology: XHCI HC -- DUT</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Get Number Of Configurations</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>USB Version number of device: 2.00</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Number of configurations: 1.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Get Number Of Other Speed Configurations</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Number of Other Speed configurations: 0.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_4'>Device Summary</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:28</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Host VEN = 1022h
|
||||
Host DEV = 149ch
|
||||
Host Revision number = 0h
|
||||
Host HCI Version = 110
|
||||
</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Device is attached to port 4</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> USB Version: 2.00</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Looking for Vendor Name File: usbif.json</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Device Vendor : 3235 (0xca3) -- SEGA CORPORATION</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Device Product ID : 33 (0x21)</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Device Revision (bcdDevice) : 0x0100</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Checking iProduct String Descriptor: index = 0x02.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>String Descriptor : "TASOLLER". (ENGLISH_US)</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>String Descriptor : "TASOLLER". (NEUTRAL)</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> bDeviceClass = 0x0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> bDeviceProtocol = 0x0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> bDeviceSubClass = 0x0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Device Type : HID</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Device Speed : Full Speed</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Number of configurations device supports : 1</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Got configuration descriptor for config index : 0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Full length of configuration descriptor is 132 bytes</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Max Power : 500mA</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Self-powered : No</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Remote Wakeup : No</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Number of interfaces device supports : 4</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Descriptor for interface 0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 2</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Interface class code indicates [CDC-Control] Interface</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Descriptor for interface 1</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : a</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Interface class code indicates [CDC-Data] Interface</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Descriptor for interface 2</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 3</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Interface class code indicates [HID] Interface</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Descriptor for interface 3</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Interface descriptor bInterfaceClass reserved for assignment by the USB-IF : 3</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'> Interface class code indicates [HID] Interface</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:29</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ Device Summary:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Summary</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>TEST SUITE SUMMARY:
|
||||
[ Fails (0); Aborts (0); Warnings (0) ]</DIV></DIV>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>TEST RESULTS:
|
||||
[ Passed (1); Failed (0) ]</DIV></DIV>
|
||||
</DIV>
|
||||
</DIV>
|
||||
</BODY></HTML>
|
254
docs/USB/HID Tests - Passed - 2024-07-23 19-46-13.html
Normal file
254
docs/USB/HID Tests - Passed - 2024-07-23 19-46-13.html
Normal file
@ -0,0 +1,254 @@
|
||||
<HTML><HEAD>
|
||||
<META http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<META charset="UTF-8" />
|
||||
<STYLE type='text/css'>
|
||||
BODY { background-color: #DFDFDF; }
|
||||
.dm_display
|
||||
{
|
||||
color: Navy;
|
||||
font-family: monospace;
|
||||
background-color: White;
|
||||
border-width: 3px;
|
||||
border-style: outset;
|
||||
}
|
||||
|
||||
#suite-output
|
||||
{
|
||||
background-color: #FFFFDD;
|
||||
border: ridge 3px #FFFFDD;
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
empty-cells: hide
|
||||
}
|
||||
|
||||
#test-header
|
||||
{
|
||||
font-weight: bold;
|
||||
font-size: large;
|
||||
border-top: ridge 2px #FFFFDD;
|
||||
border-bottom: ridge 2px #FFFFDD;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.test-pass, .test-fail
|
||||
{
|
||||
float: right;
|
||||
border-left: ridge 2px #FFFDD;
|
||||
min-width: 6em;
|
||||
}
|
||||
|
||||
.test-pass { background-color: #00FF00; }
|
||||
.test-fail { background-color: #FF8888; }
|
||||
|
||||
.test-details
|
||||
{
|
||||
clear: both;
|
||||
font-family: monospace;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
empty-cells: hide;
|
||||
}
|
||||
|
||||
.label
|
||||
{
|
||||
float: left;
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.content
|
||||
{
|
||||
white-space: pre-wrap;
|
||||
margin-left: 7em;
|
||||
}
|
||||
|
||||
.err_log, .warn_log
|
||||
{
|
||||
color: Red;
|
||||
}
|
||||
|
||||
.err_log { font-weight: bold; }
|
||||
|
||||
.unexpected_log
|
||||
{
|
||||
color: Red;
|
||||
background-color: Yellow;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
</STYLE>
|
||||
<TITLE>HID Tests - 2024-07-23 19-46-13</TITLE>
|
||||
<META name='Suite-Name' content='HID Tests.cvtests' />
|
||||
<META name='Test-Version' content='GuiCV.exe ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='BaseUtilities.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='GuiHelper.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='ComplianceUtilities.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='TestSuiteParser.dll ver 4.1.0.0' />
|
||||
<META name='Test-Version' content='xhci_DevIOCTL.dll ver 2.2.7.0' />
|
||||
<META name='Test-Version' content='xhci_TestServices.dll ver 2.2.7.0' />
|
||||
<META name='Test-Version' content='USBUtilities.dll ver 1.4.5.1' />
|
||||
<META name='Test-Version' content='StackSwitcher.dll ver 1.4.5.1' />
|
||||
<META name='Test-Version' content='xhci_CVServices.dll ver 2.2.7.0' />
|
||||
<META name='Test-Version' content='HidParser.dll ver 1.4.5.0' />
|
||||
<META name='Test-Version' content='xhci_HID.dll ver 3.1.3.0' />
|
||||
<META name='Host-Controller' content='VID=1022,PID=149C' />
|
||||
<META name='Device-Under-Test' content='VID=0CA3, PID=0021' />
|
||||
<META name='Device-Speed' content='Full Speed' />
|
||||
<META name='Topology' content='XHCI HC -- DUT' />
|
||||
<META name='Test-Pass' content='HID Class WhichSpecCompliant Test [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='HID Class Descriptor Test (Configuration Index 0) - configured [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='HID Class Protocol Test (Configuration Index 0) [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='HID Class GET/SET Idle Test (Configuration Index 0) [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Test-Pass' content='HID Class Report Descriptor Test (Configuration Index 0) [Fails (0); Aborts (0); Warnings (0)]' />
|
||||
<META name='Suite-Result' content='PASS' />
|
||||
<META name='Log-Name' content='HID Tests - 2024-07-23 19-46-13.html' />
|
||||
<META name='Test-Count' content='5' />
|
||||
</HEAD>
|
||||
<BODY><DIV id='suite-summary'>
|
||||
<DIV><STRONG>APPLICATION</STRONG>: USB 3 Gen X Command Verifier<BR></DIV>
|
||||
<DIV><STRONG>TEST SUITE</STRONG>: HID Tests.cvtests<BR></DIV>
|
||||
<DIV><STRONG>OPERATING SYSTEM</STRONG>: <BR></DIV>
|
||||
<DIV><STRONG>WORKSTATION</STRONG>: <BR></DIV>
|
||||
<DIV><STRONG>DATE</STRONG>: Tuesday, July 23, 2024<BR></DIV>
|
||||
<DIV><STRONG>TIME</STRONG>: 07:46:21 PM<BR></DIV>
|
||||
<DIV><STRONG>OPERATOR</STRONG>: Emma<BR></DIV>
|
||||
<DIV><STRONG>NUMBER OF TESTS</STRONG>: 5<BR></DIV>
|
||||
<DIV><STRONG>LOG NAME</STRONG>: HID Tests - 2024-07-23 19-46-13<BR></DIV>
|
||||
<DIV><STRONG>RESULT</STRONG>: passed<BR></DIV>
|
||||
<HR>
|
||||
</DIV>
|
||||
<BR><BR>
|
||||
<DIV id='suite-output'>
|
||||
<DIV id='test-header'>Initialize Test Suite</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Test log initialized.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Log Level: Normal</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>User Input module initialized</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Windows Version 22H2 (OS Build 19045)</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>GuiCV.exe ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>BaseUtilities.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>GuiHelper.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>ComplianceUtilities.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>TestSuiteParser.dll ver 4.1.0.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_DevIOCTL.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_TestServices.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>USBUtilities.dll ver 1.4.5.1</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>StackSwitcher.dll ver 1.4.5.1</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_CVServices.dll ver 2.2.7.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>HidParser.dll ver 1.4.5.0</DIV></DIV>
|
||||
<DIV style='color:#00005F'><DIV class='label'>INFO</DIV><DIV class='content'>xhci_HID.dll ver 3.1.3.0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>XHCISpecVersion: 1.10.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#00007F'><DIV class='label'>INFO</DIV><DIV class='content'>Host 1 selected: xHCI Host: VID=0x1022, PID=0x149C (PCI bus 45, device 0, function 3)</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>User selection from list: "FS Device (HID) addr=1: VID=0CA3, PID=0021 RouteString 0x00000"</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#00007F'><DIV class='label'>INFO</DIV><DIV class='content'>Please select HID Device to test</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID Device Under Test is operating at Full Speed.</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Topology: XHCI HC -- DUT</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Get Number Of Configurations</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>USB Version number of device: 2.00</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Number of configurations: 1.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Get Number Of Configurations - Other Speed</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Number of Other Speed configurations: 0.</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_4'>HID Class WhichSpecCompliant Test</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:16</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>USB Version number of device: 2.00</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Interface 0x2 Alternate Setting 0x0 is draft 4 Compliant</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Interface 0x3 Alternate Setting 0x0 is draft 4 Compliant</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:17</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ HID Class WhichSpecCompliant Test:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_5'>HID Class Descriptor Test (Configuration Index 0) - configured</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:17</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Testing HID descriptor for Interface 0x2</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID descriptor total length : 0x9</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID descriptor type : 0x21</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID specification version : 0x110</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>CountryCode : 0x0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Number of other descriptors present : 0x1</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID report descriptor length : 0x71</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Testing HID descriptor for Interface 0x3</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID descriptor total length : 0x9</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID descriptor type : 0x21</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID specification version : 0x110</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>CountryCode : 0x0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Number of other descriptors present : 0x1</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>HID report descriptor length : 0x97</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:18</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ HID Class Descriptor Test (Configuration Index 0) - configured:
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_6'>HID Class Protocol Test (Configuration Index 0)</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:18</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Starting GET/SET protocol tests for interface : 2</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SET protocol request is optional. Skipping tests</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Starting GET/SET protocol tests for interface : 3</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SET protocol request is optional. Skipping tests</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:19</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ HID Class Protocol Test (Configuration Index 0):
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_7'>HID Class GET/SET Idle Test (Configuration Index 0)</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:19</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x1. Setting idle rate to : 0x7F</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x1. Setting idle rate to : 0xFF</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x1. Setting idle rate to : 0x0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x2. Setting idle rate to : 0x7F</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x2. Setting idle rate to : 0xFF</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x2. Setting idle rate to : 0x0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x3. Setting idle rate to : 0x7F</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x3. Setting idle rate to : 0xFF</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x3. Setting idle rate to : 0x0</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x4. Setting idle rate to : 0x7F</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x4. Setting idle rate to : 0xFF</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>GET/SETIdle test for report ID 0x4. Setting idle rate to : 0x0</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:20</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ HID Class GET/SET Idle Test (Configuration Index 0):
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'><A name='anchor_8'>HID Class Report Descriptor Test (Configuration Index 0)</A><DIV class='test-pass'>Passed</DIV></DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#0000AA'><DIV class='label'>INFO</DIV><DIV class='content'>Start time: Jul 23, 2024 - 19:46:20</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Report descriptor length: 113</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Item count in report descriptor: 54</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Report descriptor test passed. Proceeding to next descriptor</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Report descriptor length: 151</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Item count in report descriptor: 71</DIV></DIV>
|
||||
<DIV><DIV class='label'>INFO</DIV><DIV class='content'>Report descriptor test passed. Proceeding to next descriptor</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>
|
||||
Stop time: Jul 23, 2024 - 19:46:21</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Duration: 1 second.</DIV></DIV>
|
||||
<DIV style='font-weight: 700;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>Stopping Test [ HID Class Report Descriptor Test (Configuration Index 0):
|
||||
Number of: Fails (0); Aborts (0); Warnings (0) ]
|
||||
</DIV></DIV>
|
||||
</DIV>
|
||||
<DIV id='test-header'>Summary</DIV>
|
||||
<DIV class='test-details'>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>TEST SUITE SUMMARY:
|
||||
[ Fails (0); Aborts (0); Warnings (0) ]</DIV></DIV>
|
||||
<DIV style='font-weight: 700;font-style:italic;color:#007F00'><DIV class='label'>INFO</DIV><DIV class='content'>TEST RESULTS:
|
||||
[ Passed (5); Failed (0) ]</DIV></DIV>
|
||||
</DIV>
|
||||
</DIV>
|
||||
</BODY></HTML>
|
32
flash.cmd
32
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
|
||||
|
10
src/_compiler.h
Normal file
10
src/_compiler.h
Normal file
@ -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
|
@ -1,6 +0,0 @@
|
||||
.syntax unified
|
||||
.global DelayCycles
|
||||
DelayCycles:
|
||||
subs r0, r0, #1
|
||||
bcs DelayCycles
|
||||
bx lr
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
301
src/hid.c
301
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]);
|
||||
}
|
||||
|
61
src/hid_def.h
Normal file
61
src/hid_def.h
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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);
|
156
src/io4.c
Normal file
156
src/io4.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
31
src/io4.h
Normal file
31
src/io4.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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);
|
582
src/led.c
582
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;
|
||||
}
|
||||
|
102
src/led.h
102
src/led.h
@ -1,73 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#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);
|
||||
|
273
src/led_impl.c
Normal file
273
src/led_impl.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
213
src/led_shared.h
Normal file
213
src/led_shared.h
Normal file
@ -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 <stdint.h>
|
||||
|
||||
#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
|
138
src/main.c
138
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();
|
||||
|
@ -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)
|
||||
|
332
src/psoc.c
332
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
|
||||
|
80
src/psoc.h
80
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);
|
||||
|
165
src/slider.c
165
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();
|
||||
}
|
||||
|
43
src/slider.h
43
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);
|
||||
|
164
src/sys.c
164
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);
|
||||
}
|
252
src/tasoller.h
252
src/tasoller.h
@ -3,39 +3,33 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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))))
|
||||
|
338
src/ui.c
338
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;
|
||||
}
|
||||
}
|
||||
|
129
src/usb_def.h
Normal file
129
src/usb_def.h
Normal file
@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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;
|
@ -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
|
||||
};
|
||||
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../_compiler.h"
|
||||
|
||||
// USB U16 helpers
|
||||
#define U16(_high, _low) ((uint16_t)(((_high) << 8) | (_low)))
|
||||
#define U16_HIGH(_u16) ((uint8_t)(((_u16) >> 8) & 0x00ff))
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
25
src/vcom.h
Normal file
25
src/vcom.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
Loading…
Reference in New Issue
Block a user