Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
Go
Haskell
HLSL
Hook
Hylo
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Objective-C
Objective-C++
OCaml
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Snowball
Scala
Solidity
Spice
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
Zig
Javascript
GIMPLE
c++ source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502-c++ 11.1.0
ARM GCC 10.2.0
ARM GCC 10.3.0
ARM GCC 10.4.0
ARM GCC 10.5.0
ARM GCC 11.1.0
ARM GCC 11.2.0
ARM GCC 11.3.0
ARM GCC 11.4.0
ARM GCC 12.1.0
ARM GCC 12.2.0
ARM GCC 12.3.0
ARM GCC 13.1.0
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 14.1.0
ARM GCC 4.5.4
ARM GCC 4.6.4
ARM GCC 5.4
ARM GCC 6.3.0
ARM GCC 6.4.0
ARM GCC 7.3.0
ARM GCC 7.5.0
ARM GCC 8.2.0
ARM GCC 8.5.0
ARM GCC 9.3.0
ARM GCC 9.4.0
ARM GCC 9.5.0
ARM GCC trunk
ARM gcc 10.2.1 (none)
ARM gcc 10.3.1 (2021.07 none)
ARM gcc 10.3.1 (2021.10 none)
ARM gcc 11.2.1 (none)
ARM gcc 5.4.1 (none)
ARM gcc 7.2.1 (none)
ARM gcc 8.2 (WinCE)
ARM gcc 8.3.1 (none)
ARM gcc 9.2.1 (none)
ARM msvc v19.0 (WINE)
ARM msvc v19.10 (WINE)
ARM msvc v19.14 (WINE)
ARM64 Morello gcc 10.1 Alpha 2
ARM64 gcc 10.2
ARM64 gcc 10.3
ARM64 gcc 10.4
ARM64 gcc 10.5.0
ARM64 gcc 11.1
ARM64 gcc 11.2
ARM64 gcc 11.3
ARM64 gcc 11.4.0
ARM64 gcc 12.1
ARM64 gcc 12.2.0
ARM64 gcc 12.3.0
ARM64 gcc 13.1.0
ARM64 gcc 13.2.0
ARM64 gcc 14.1.0
ARM64 gcc 5.4
ARM64 gcc 6.3
ARM64 gcc 6.4
ARM64 gcc 7.3
ARM64 gcc 7.5
ARM64 gcc 8.2
ARM64 gcc 8.5
ARM64 gcc 9.3
ARM64 gcc 9.4
ARM64 gcc 9.5
ARM64 gcc trunk
ARM64 msvc v19.14 (WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 14.1.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF gcc 13.1.0
BPF gcc 13.2.0
BPF gcc 14.1.0
BPF gcc trunk
EDG (experimental reflection)
EDG 6.5
EDG 6.5 (GNU mode gcc 13)
EDG 6.6
EDG 6.6 (GNU mode gcc 13)
FRC 2019
FRC 2020
FRC 2023
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
M68K gcc 13.1.0
M68K gcc 13.2.0
M68K gcc 14.1.0
M68k clang (trunk)
MRISC32 gcc (trunk)
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 14.1.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 14.1.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC gcc 14.1.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
SPARC64 gcc 14.1.0
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI C6x gcc 14.1.0
TI CL430 21.6.1
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30
arm64 msvc v19.31
arm64 msvc v19.32
arm64 msvc v19.33
arm64 msvc v19.34
arm64 msvc v19.35
arm64 msvc v19.36
arm64 msvc v19.37
arm64 msvc v19.38
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 12.0.0
armv7-a clang 12.0.1
armv7-a clang 13.0.0
armv7-a clang 13.0.1
armv7-a clang 14.0.0
armv7-a clang 15.0.0
armv7-a clang 16.0.0
armv7-a clang 17.0.1
armv7-a clang 18.1.0
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 13.0.0
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
ellcc 0.1.33
ellcc 0.1.34
ellcc 2017-07-16
hexagon-clang 16.0.5
llvm-mos atari2600-3e
llvm-mos atari2600-4k
llvm-mos atari2600-common
llvm-mos atari5200-supercart
llvm-mos atari8-cart-megacart
llvm-mos atari8-cart-std
llvm-mos atari8-cart-xegs
llvm-mos atari8-common
llvm-mos atari8-dos
llvm-mos c128
llvm-mos c64
llvm-mos commodore
llvm-mos cpm65
llvm-mos cx16
llvm-mos dodo
llvm-mos eater
llvm-mos mega65
llvm-mos nes
llvm-mos nes-action53
llvm-mos nes-cnrom
llvm-mos nes-gtrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos nes-unrom
llvm-mos nes-unrom-512
llvm-mos osi-c1p
llvm-mos pce
llvm-mos pce-cd
llvm-mos pce-common
llvm-mos pet
llvm-mos rp6502
llvm-mos rpc8e
llvm-mos supervision
llvm-mos vic20
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
loongarch64 gcc 14.1.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 14.1.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 14.1.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 14.1.0
mips64 gcc 4.9.4
mips64 gcc 5.4.0
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel gcc 12.1.0
mipsel gcc 12.2.0
mipsel gcc 12.3.0
mipsel gcc 13.1.0
mipsel gcc 13.2.0
mipsel gcc 14.1.0
mipsel gcc 4.9.4
mipsel gcc 5.4.0
mipsel gcc 5.5.0
mipsel gcc 9.5.0
nanoMIPS gcc 6.3.0 (mtk)
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 14.1.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64 gcc 11.2.0
power64 gcc 12.1.0
power64 gcc 12.2.0
power64 gcc 12.3.0
power64 gcc 13.1.0
power64 gcc 13.2.0
power64 gcc 14.1.0
power64 gcc trunk
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 14.1.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 13.1.0
s390x gcc 13.2.0
s390x gcc 14.1.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 14.1.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (WINE)
x64 msvc v19.10 (WINE)
x64 msvc v19.14
x64 msvc v19.14 (WINE)
x64 msvc v19.15
x64 msvc v19.16
x64 msvc v19.20
x64 msvc v19.21
x64 msvc v19.22
x64 msvc v19.23
x64 msvc v19.24
x64 msvc v19.25
x64 msvc v19.26
x64 msvc v19.27
x64 msvc v19.28
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30
x64 msvc v19.31
x64 msvc v19.32
x64 msvc v19.33
x64 msvc v19.34
x64 msvc v19.35
x64 msvc v19.36
x64 msvc v19.37
x64 msvc v19.38
x64 msvc v19.latest
x86 djgpp 4.9.4
x86 djgpp 5.5.0
x86 djgpp 6.4.0
x86 djgpp 7.2.0
x86 msvc v19.0 (WINE)
x86 msvc v19.10 (WINE)
x86 msvc v19.14
x86 msvc v19.14 (WINE)
x86 msvc v19.15
x86 msvc v19.16
x86 msvc v19.20
x86 msvc v19.21
x86 msvc v19.22
x86 msvc v19.23
x86 msvc v19.24
x86 msvc v19.25
x86 msvc v19.26
x86 msvc v19.27
x86 msvc v19.28
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30
x86 msvc v19.31
x86 msvc v19.32
x86 msvc v19.33
x86 msvc v19.34
x86 msvc v19.35
x86 msvc v19.36
x86 msvc v19.37
x86 msvc v19.38
x86 msvc v19.latest
x86 nvc++ 22.11
x86 nvc++ 22.7
x86 nvc++ 22.9
x86 nvc++ 23.1
x86 nvc++ 23.11
x86 nvc++ 23.3
x86 nvc++ 23.5
x86 nvc++ 23.7
x86 nvc++ 23.9
x86 nvc++ 24.1
x86 nvc++ 24.3
x86-64 Zapcc 190308
x86-64 clang (amd-stg-open)
x86-64 clang (assertions trunk)
x86-64 clang (clangir)
x86-64 clang (experimental -Wlifetime)
x86-64 clang (experimental P1061)
x86-64 clang (experimental P1144)
x86-64 clang (experimental P1221)
x86-64 clang (experimental P2996)
x86-64 clang (experimental metaprogramming - P2632)
x86-64 clang (experimental pattern matching)
x86-64 clang (old concepts branch)
x86-64 clang (reflection)
x86-64 clang (resugar)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (variadic friends - P2893)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.0 (assertions)
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.0 (assertions)
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.0 (assertions)
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.0 (assertions)
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 14.0.0 (assertions)
x86-64 clang 15.0.0
x86-64 clang 15.0.0 (assertions)
x86-64 clang 16.0.0
x86-64 clang 16.0.0 (assertions)
x86-64 clang 17.0.1
x86-64 clang 17.0.1 (assertions)
x86-64 clang 18.1.0
x86-64 clang 18.1.0 (assertions)
x86-64 clang 2.6.0 (assertions)
x86-64 clang 2.7.0 (assertions)
x86-64 clang 2.8.0 (assertions)
x86-64 clang 2.9.0 (assertions)
x86-64 clang 3.0.0
x86-64 clang 3.0.0 (assertions)
x86-64 clang 3.1
x86-64 clang 3.1 (assertions)
x86-64 clang 3.2
x86-64 clang 3.2 (assertions)
x86-64 clang 3.3
x86-64 clang 3.3 (assertions)
x86-64 clang 3.4 (assertions)
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5 (assertions)
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.6 (assertions)
x86-64 clang 3.7
x86-64 clang 3.7 (assertions)
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8 (assertions)
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.0 (assertions)
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.0 (assertions)
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.0 (assertions)
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.0 (assertions)
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.0 (assertions)
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.0 (assertions)
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.0 (assertions)
x86-64 clang 9.0.1
x86-64 clang rocm-4.5.2
x86-64 clang rocm-5.0.2
x86-64 clang rocm-5.1.3
x86-64 clang rocm-5.2.3
x86-64 clang rocm-5.3.3
x86-64 clang rocm-5.7.0
x86-64 gcc (contract labels)
x86-64 gcc (contracts natural syntax)
x86-64 gcc (contracts)
x86-64 gcc (coroutines)
x86-64 gcc (modules)
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.4
x86-64 gcc 10.5
x86-64 gcc 11.1
x86-64 gcc 11.2
x86-64 gcc 11.3
x86-64 gcc 11.4
x86-64 gcc 12.1
x86-64 gcc 12.2
x86-64 gcc 12.3
x86-64 gcc 13.1
x86-64 gcc 13.2
x86-64 gcc 14.1
x86-64 gcc 3.4.6
x86-64 gcc 4.0.4
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 5.5
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.4
x86-64 gcc 6.5
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx (latest)
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2023.2.1
x86-64 icx 2024.0.0
zig c++ 0.10.0
zig c++ 0.11.0
zig c++ 0.12.0
zig c++ 0.6.0
zig c++ 0.7.0
zig c++ 0.7.1
zig c++ 0.8.0
zig c++ 0.9.0
zig c++ trunk
Options
Source code
#include <stdio.h> #include <cstdint> #include <type_traits> #include <utility> // --------------------------------------------------------------- // Библиотечная часть, кусочек класса для работы со списками типов // --------------------------------------------------------------- template<class T> struct TypeBox { using type = T; }; template<typename T> using type_unbox = typename T::type; template<auto Value> struct ValueBox { static constexpr auto value = Value; }; template<typename T> constexpr auto value_unbox() { return T::type::value; } template<typename... Ts> struct TypeList { static constexpr auto size() { return sizeof...(Ts); } static constexpr bool is_empty() { return (sizeof...(Ts) == 0); } static constexpr auto head() { return head_<Ts...>(); } static constexpr auto tail() { return tail_<Ts...>(); } static constexpr auto back() { return (TypeBox<Ts>{}, ...); } template<typename T> static constexpr auto push_front() { return TypeList<T, Ts...>{}; } template<typename T> static constexpr auto push_front(TypeBox<T>) { return push_front<T>(); } template<typename T> static constexpr auto push_back() { return TypeList<Ts..., T>{}; } template<typename T> static constexpr auto push_back(TypeBox<T>) { return push_back<T>(); } template<typename T> static constexpr bool contains() { return (... || std::is_same_v<T, Ts>); } template<typename T> static constexpr bool contains(TypeBox<T>) { return contains<T>(); } template<typename F> static constexpr bool is_unique(F func) { return is_unique_<F, Ts...>(func); } static constexpr bool is_unique() { return is_unique([](auto v1, auto v2) { return std::is_same_v<type_unbox<decltype(v1)>, type_unbox<decltype(v2)>>; }); } template<typename F> static constexpr auto accumulate(F func) { return (TypeList<>{} + ... + func(TypeBox<Ts>{})); } template<typename F> static inline void foreach(F func) { (func(TypeBox<Ts> {}), ...); } template<auto I, typename T> static constexpr auto generate() { return generate_<T>(std::make_index_sequence<I>{}); } template<typename F> static constexpr auto transform(F func) { return TypeList<type_unbox<decltype(func(TypeBox<Ts>{}))>...>{}; } template<typename T> static constexpr auto filter(T pred) { return (TypeList<>{} + ... + std::conditional_t<pred(TypeBox<Ts>{}), TypeList<Ts>, TypeList<>>{}); } private: template<typename T, typename... Us> static constexpr auto head_() { return TypeBox<T>{}; } template<typename T, typename... Us> static constexpr auto tail_() { return TypeList<Us...>{}; } template<typename T, auto... Is> static constexpr auto generate_(std::index_sequence<Is...>) { return TypeList<type_unbox<decltype((Is, TypeBox<T>{}))>...>{}; } template<typename F> static constexpr bool is_unique_(F func) { return true; } template <typename F, typename T, typename... Us> static constexpr bool is_unique_(F &func) { return !(func(TypeBox<T>{}, TypeBox<Us>{}) || ...) && is_unique_<F, Us...>(func); } }; template<typename... Ts, typename... Us> constexpr auto operator+(TypeList<Ts...>, TypeList<Us...>) { return TypeList<Ts..., Us...> {}; } // ======================================================================================== // Собстывенно, то что касается дескрипторов // ======================================================================================== enum class DescriptorType : uint8_t { DEVICE=1, CONFIGURATION=2, STRING=3, INTERFACE=4, ENDPOINT=5, DEVICE_QUALIFIER=6, OTHER_SPEED_CONFIGURATION=7, INTERFACE_POWER=8, INTERFACE_ASSOCIATION=0xB, HID=0x21, REPORT=0x22, PHYSICAL=0x23, // HID v1.11 spec. Chapter 7.1 CS_INTERFACE=0x24, CS_ENDPOINT=0x25 // Class Specified }; enum class HID_Localization : uint8_t { Not_Localized=0, Arabic=1, Belgian=2, Canadian_Bilingual=3, Canadian_French=4, Czech_Republic=5, Danish=6, Finnish=7, French=8, German=9, Greek=10, Hebrew=11, Hungary=12, International=13, Italian=14, Japan=15, Korean=16, Latin_American=17, Netherlands_Dutch=18, Norwegian=19, Persian=20, Poland=21, Portuguese=22, Russia=23, Slovakia=24, Spanish=25, Swedish=26, Swiss_French=27, Swiss_German=28, Switzerland=29, Taiwan=30, Turkish_Q=31, UK=32, US=33, Yugoslavia=34, Turkish_F=35 }; namespace USB_DESCRIPTORS { // Типизация полей дескрипторов enum class REC_TYPE { // DEVICE_DESCRIPTOR bLength, bDescriptorType, bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0, idVendor, idProduct, bcdDevice, iManufacturer, iProduct, iSerialNumber, bNumConfigurations, bReserved, // CONFIGURATION_DESCRIPTOR_ wTotalLength, bNumInterfaces, bConfigurationValue, iConfiguration, bmAttributes, bMaxPower, // INTERFACE_DESCRIPTOR bInterfaceNumber, bAlternateSetting, bNumEndpoints, bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface, // ENDPOINT_DESCRIPTOR bEndpointAddress, wMaxPacketSize, bInterval, // INTERFACE_ASSOCIATION_DESCRIPTOR bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol, iFunction, // CDC_HEADER_FUNCTIONAL_DESCRIPTOR bDescriptorSubType, bcdCDC, // CDC_ACM_FUNCTIONAL_DESCRIPTOR bmCapabilities, // CDC_UNION_FUNCTIONAL_DESCRIPTOR bControlInterface, bSubordinateInterface0, // CDC_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR bDataInterface, // CUSTOM_HID_DESCRIPTOR_BASE bcdHID, bCountryCode, bNumDescriptors, bDescriptorType_0, wDescriptorLength_0 }; // Базовые классы для дескрипторов class DESCRIPTOR_BASE {}; class DESCRIPTOR_LIST_BASE {}; class INTERFACE_BASE {}; class INTERFACE_ASSOCIATION_BASE {}; class CONFIGURATION_DESCRIPTOR_BASE {}; class INTERFACE_DESCRIPTOR_BASE {}; class ENDPOINT_DESCRIPTOR_BASE {}; class INTERFACE_ASSOCIATION_DESCRIPTOR_BASE {}; class CDC_HEADER_FUNCTIONAL_DESCRIPTOR_BASE {}; class CDC_ACM_FUNCTIONAL_DESCRIPTOR_BASE {}; class CDC_UNION_FUNCTIONAL_DESCRIPTOR_BASE {}; class CDC_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR_BASE {}; class CUSTOM_HID_DESCRIPTOR_BASE {}; class BMATTRIBUTES_BASE {}; class ENDPOINT_ADDRES_BASE {}; //============================================================================== // Определение полей дескрипторов //============================================================================== template<typename T, REC_TYPE rt> constexpr bool IsRecType() { return value_unbox<T>()==rt; } #define REC_U8(X) template<typename U> constexpr bool is_##X() { return IsRecType<U,REC_TYPE::X>(); } \ template<uint8_t x> using X = HOLDER<REC_TYPE::X,(uint8_t)x> #define REC_U16(X) template<typename T> constexpr bool is_##X() { return IsRecType<T,REC_TYPE::X>(); } \ template<uint16_t x> using X = HOLDER<REC_TYPE::X,uint8_t(x),uint8_t(x>>8)> #define REC_8(T,X) template<typename U> constexpr bool is_##X() { return IsRecType<U,REC_TYPE::X>(); } \ template<T x> using X = HOLDER<REC_TYPE::X,(uint8_t)x> // Контейнер для полей дескрипторов template <REC_TYPE rt, uint8_t... data> struct HOLDER { using type = ValueBox<rt>; constexpr auto value() { if constexpr (sizeof...(data)==1) return buf[0]; else if constexpr (sizeof...(data)==2) return (uint16_t)buf[0]+((uint16_t)buf[1]<<8); else return; } uint8_t buf[sizeof...(data)]{ data... }; }; // Device Descriptor records REC_U8(bLength); REC_U8(bDescriptorType); REC_U16(bcdUSB); REC_U8(bDeviceClass); REC_U8(bDeviceSubClass); REC_U8(bDeviceProtocol); REC_U8(bMaxPacketSize0); REC_U16(idVendor); REC_U16(idProduct); REC_U16(bcdDevice); REC_U8(iManufacturer); REC_U8(iProduct); REC_U8(iSerialNumber); REC_U8(bNumConfigurations); REC_U8(bReserved); // Configuration Descriptor records REC_U16(wTotalLength); REC_U8(bNumInterfaces); REC_U8(bConfigurationValue); REC_U8(iConfiguration); REC_U8(bMaxPower); // bmAttributes enum class cfg_Attr : uint8_t { SelfPowered = 0xC0, RemoteWakeup = 0xA0 }; enum class epTYPE : uint8_t { Control = 0, Isochronous = 1, Bulk = 2, Interrupt = 3 }; enum class epSYNC : uint8_t { NoSynchronization = 0, Asynchronous = 4, Adaptive = 6, Synchronous = 7 }; enum class epUSAGE : uint8_t { Data = 0, Feedback = 0x10, ImplicitFeedbackData = 0x20 }; // Interface Descriptor records REC_U8(bInterfaceNumber); REC_U8(bAlternateSetting); REC_U8(bNumEndpoints); REC_U8(bInterfaceClass); REC_U8(bInterfaceSubClass); REC_U8(bInterfaceProtocol); REC_U8(iInterface); // Endpoint Descriptor records REC_U16(wMaxPacketSize); REC_U8(bInterval); // bEndpointAddress enum class epDIR : uint8_t { OUT = 0, IN = 0x80 }; // Interface Association Descriptor REC_U8(bFirstInterface); REC_U8(bInterfaceCount); REC_U8(bFunctionClass); REC_U8(bFunctionSubClass); REC_U8(bFunctionProtocol); REC_U8(iFunction); // CDC Header Functional Descriptor records REC_U8(bDescriptorSubType); REC_U16(bcdCDC); // CDC ACM Functional Descriptor records REC_U8(bmCapabilities); // CDC Union Functional Descriptor records REC_U8(bControlInterface); REC_U8(bSubordinateInterface0); // CDC Call Management Functional Descriptor records REC_U8(bDataInterface); // CUSTOM_HID Descriptor records REC_U16(bcdHID); REC_8(HID_Localization, bCountryCode); REC_U8(bNumDescriptors); REC_8(DescriptorType, bDescriptorType_0); REC_U16(wDescriptorLength_0); // "Концепты" типов дескрипторов template<typename T> constexpr bool is_Descriptor() { return std::is_base_of_v<DESCRIPTOR_BASE, T>; } template<typename T> constexpr bool is_DescriptorList() { return std::is_base_of_v<DESCRIPTOR_LIST_BASE, T>; } template<typename T> constexpr bool is_DescriptorListElement() { return is_Descriptor<T>() || is_DescriptorList<T>(); } template<typename T> constexpr bool is_ConfigurationDescriptor() { return std::is_base_of_v<CONFIGURATION_DESCRIPTOR_BASE,T>; } template<typename T> constexpr bool is_InterfaceDescriptor() { return std::is_base_of_v<INTERFACE_DESCRIPTOR_BASE,T>; } template<typename T> constexpr bool is_EndpointDescriptor() { return std::is_base_of_v<ENDPOINT_DESCRIPTOR_BASE,T>; } template<typename T> constexpr bool is_Interface() { return std::is_base_of_v<INTERFACE_BASE, T>; } // "Концепты" для полей дескрипторов template<typename T> constexpr bool is_bmAttributes() { return std::is_base_of_v<BMATTRIBUTES_BASE,T>; } template<typename T> constexpr bool is_bmAttributes_EP() { return is_bmAttributes<T>() && std::is_same_v<typename T::sub_type, epTYPE>; } template<typename T> constexpr bool is_bmAttributes_CONFIG() { return is_bmAttributes<T>() && std::is_same_v<typename T::sub_type, cfg_Attr>; } template<typename RCRD> constexpr auto copy_buf(RCRD rcrd, uint8_t **p) { for(auto &x : rcrd.buf) *(*p)++ = x; } template<typename T> constexpr bool is_Interface_Association() { return std::is_base_of_v<INTERFACE_ASSOCIATION_DESCRIPTOR_BASE,T>; } //============================================================================== // Контейнер для дескриптора //============================================================================== template<DescriptorType dt, typename... RCRDS> class DESCRIPTOR : public DESCRIPTOR_BASE { static constexpr auto sz = (sizeof(RCRDS::buf)+...)+2; public: constexpr DESCRIPTOR() { buf[0] = sz; buf[1] = (uint8_t)dt; uint8_t *p = buf+2; (copy_buf(RCRDS{}, &p),...); } uint8_t buf[sz]{}; }; //============================================================================== // Контейнер для списка дескрипторов //============================================================================== template <typename... DSCS> class DESCRIPTOR_LIST : public DESCRIPTOR_LIST_BASE { static_assert((is_DescriptorListElement<DSCS>()&&...), "DSCS is't Descriptor List Element"); static constexpr auto ExpandDL = [](auto x) { using T = type_unbox<decltype(x)>; if constexpr (is_DescriptorList<T>()) return T::GetDescriptors(); else return TypeList<T>{}; // is_Descriptor<T> }; static constexpr auto dscs_ = TypeList<DSCS...>::accumulate(ExpandDL); public: constexpr DESCRIPTOR_LIST() { uint8_t *p = buf; (copy_buf(DSCS{}, &p),...); } static constexpr auto GetDescriptors() { return dscs_; } static constexpr auto GetEndpoints() { return dscs_.filter([](auto x) { return is_EndpointDescriptor<type_unbox<decltype(x)>>(); }); } static constexpr auto GetInterfaces() { return dscs_.filter([](auto x) { return is_InterfaceDescriptor<type_unbox<decltype(x)>>(); }); } static constexpr uint8_t EndpointsCount() { return GetEndpoints().size(); } static constexpr uint8_t InterfacesCount() { return GetInterfaces().size(); } uint8_t buf[(sizeof(DSCS::buf)+...)]{}; }; //============================================================================== // Device Descriptor Type //============================================================================== template<typename TbcdUSB, typename TbDeviceClass, typename TbDeviceSubClass, typename TbDeviceProtocol, typename TbMaxPacketSize0, typename TidVendor, typename TidProduct, typename TbcdDevice, typename TiManufacturer, typename TiProduct, typename TiSerialNumber, typename TbNumConfigurations> class DEVICE_DESCRIPTOR : public DESCRIPTOR<DescriptorType::DEVICE, TbcdUSB, TbDeviceClass, TbDeviceSubClass, TbDeviceProtocol, TbMaxPacketSize0, TidVendor, TidProduct, TbcdDevice, TiManufacturer, TiProduct, TiSerialNumber, TbNumConfigurations> { static_assert(is_bcdUSB<TbcdUSB>(), "Not bcdUSB record"); static_assert(is_bDeviceClass<TbDeviceClass>(), "Not bDeviceClass record"); static_assert(is_bDeviceSubClass<TbDeviceSubClass>(), "Not bDeviceSubClass record"); static_assert(is_bDeviceProtocol<TbDeviceProtocol>(), "Not bDeviceProtocol record"); static_assert(is_bMaxPacketSize0<TbMaxPacketSize0>(), "Not bMaxPacketSize0 record"); static_assert(is_idVendor<TidVendor>(), "Not idVendor record"); static_assert(is_idProduct<TidProduct>(), "Not idProduct record"); static_assert(is_bcdDevice<TbcdDevice>(), "Not bcdDevice record"); static_assert(is_iManufacturer<TiManufacturer>(), "Not iManufacturer record"); static_assert(is_iProduct<TiProduct>(), "Not iProduct record"); static_assert(is_iSerialNumber<TiSerialNumber>(), "Not iSerialNumber record"); static_assert(is_bNumConfigurations<TbNumConfigurations>(), "Not bNumConfigurations record"); static constexpr auto ep0sz = TbMaxPacketSize0{}.value(); static_assert( (ep0sz==8)||(ep0sz==16)||(ep0sz==32)||(ep0sz==64),"Wrong TbMaxPacketSize0 size"); }; //============================================================================== // Device Qualifier Descriptor Type //============================================================================== template<typename TbcdUSB, typename TbDeviceClass, typename TbDeviceSubClass, typename TbDeviceProtocol, typename TbMaxPacketSize0, typename TbNumConfigurations> struct DEVICE_QUALIFIER_DESCRIPTOR : public DESCRIPTOR<DescriptorType::DEVICE_QUALIFIER, TbcdUSB, TbDeviceClass, TbDeviceSubClass, TbDeviceProtocol, TbMaxPacketSize0, TbNumConfigurations, bReserved<0>> { static_assert(is_bcdUSB<TbcdUSB>(), "Not bcdUSB record"); static_assert(is_bDeviceClass<TbDeviceClass>(), "Not bDeviceClass record"); static_assert(is_bDeviceSubClass<TbDeviceSubClass>(), "Not bDeviceSubClass record"); static_assert(is_bDeviceProtocol<TbDeviceProtocol>(), "Not bDeviceProtocol record"); static_assert(is_bMaxPacketSize0<TbMaxPacketSize0>(), "Not bMaxPacketSize0 record"); static_assert(is_bNumConfigurations<TbNumConfigurations>(), "Not bNumConfigurations record"); }; //============================================================================== // Configuration Descriptor Types //============================================================================== template<auto... args> class bmAttributes : public BMATTRIBUTES_BASE { static_assert((sizeof...(args)>0)&&(sizeof...(args)<4),"Wrong bmAttributes arguments"); template<auto arg1> static constexpr auto Chek1Args() { static_assert(std::is_same_v<decltype(arg1),cfg_Attr> || std::is_same_v<decltype(arg1),epTYPE>, "Wrong bmAttributes arguments"); return arg1; } template<auto arg1, auto arg2> static constexpr auto Chek2Args() { static_assert( std::is_same_v<decltype(arg1),epTYPE>, "Wrong bmAttributes arguments"); static_assert( std::is_same_v<decltype(arg2),epSYNC> || std::is_same_v<decltype(arg2),epUSAGE>, "Wrong bmAttributes arguments"); return arg1; } template<auto arg1, auto arg2, auto arg3> static constexpr auto Chek3Args() { static_assert( std::is_same_v<decltype(arg1),epTYPE>, "Wrong bmAttributes arguments"); static_assert( (std::is_same_v<decltype(arg2),epSYNC> && std::is_same_v<decltype(arg3),epUSAGE>) || (std::is_same_v<decltype(arg3),epSYNC> && std::is_same_v<decltype(arg2),epUSAGE>), "Wrong bmAttributes arguments"); return arg1; } static constexpr auto CheckArgs() { if constexpr (sizeof...(args)==1) return Chek1Args<args...>(); else if constexpr (sizeof...(args)==2) return Chek2Args<args...>(); else if constexpr (sizeof...(args)==3) return Chek3Args<args...>(); else return; } public: using type = ValueBox<REC_TYPE::bmAttributes>; using sub_type = decltype(CheckArgs()); constexpr bmAttributes() { buf[0] = (uint8_t(args) | ...); } uint8_t buf[1]{}; }; template<typename TwTotalLength, typename TbNumInterfaces, typename TbConfigurationValue, typename TiConfiguration, typename TbmAttributes, typename TbMaxPower> struct CONFIGURATION_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CONFIGURATION, TwTotalLength, TbNumInterfaces, TbConfigurationValue, TiConfiguration, TbmAttributes, TbMaxPower>, CONFIGURATION_DESCRIPTOR_BASE { using bNumInterfaces = TbNumInterfaces; using bConfigurationValue = TbConfigurationValue; using iConfiguration = TiConfiguration; using bmAttributes = TbmAttributes; using bMaxPower = TbMaxPower; static_assert(is_wTotalLength<TwTotalLength>(), "Not wTotalLength record"); static_assert(is_bNumInterfaces<TbNumInterfaces>(), "Not bNumInterfaces record"); static_assert(is_bConfigurationValue<TbConfigurationValue>(), "Not bConfigurationValue record"); static_assert(is_iConfiguration<TiConfiguration>(), "Not iConfiguration record"); static_assert(is_bmAttributes_CONFIG<TbmAttributes>(), "Not Configuration bmAttributes record"); static_assert(is_bMaxPower<TbMaxPower>(), "Not bMaxPower record"); }; //============================================================================== // Device Configuration Descriptor Type //============================================================================== template<typename TbConfigurationValue, typename TiConfiguration, typename TbmAttributes, typename TbMaxPower, typename...DSCS> class DEVICE_CONFIGURATION_DESCRIPTOR { static_assert(is_bConfigurationValue<TbConfigurationValue>(), "Not bConfigurationValue record"); static_assert(is_iConfiguration<TiConfiguration>(), "Not iConfiguration record"); static_assert(is_bmAttributes_CONFIG<TbmAttributes>(), "Not Configuration bmAttributes record"); static_assert(is_bMaxPower<TbMaxPower>(), "Not bMaxPower record"); static_assert((is_DescriptorListElement<DSCS>()&&...), "DSCS not Descriptor List Element"); static constexpr auto sz = (sizeof(DSCS::buf)+...+9); using CFG_DESCR = CONFIGURATION_DESCRIPTOR<wTotalLength<sz>, bNumInterfaces<DESCRIPTOR_LIST<DSCS...>::InterfacesCount()>, TbConfigurationValue, TiConfiguration, TbmAttributes, TbMaxPower>; static_assert(DESCRIPTOR_LIST<DSCS...>::GetEndpoints().transform( [](auto eps) { return TypeBox<typename type_unbox<decltype(eps)>::bEndpointAddress>{}; }).is_unique(), "Duplicate Endpoints!"); static_assert(DESCRIPTOR_LIST<DSCS...>::GetInterfaces().transform( [](auto eps) { return TypeBox<typename type_unbox<decltype(eps)>::bInterfaceNumber>{}; }).is_unique(), "Duplicate Interfaces!"); public: static constexpr auto GetDescriptorList() { return DESCRIPTOR_LIST<CFG_DESCR, DSCS...>{}; } constexpr DEVICE_CONFIGURATION_DESCRIPTOR() { uint8_t* p = buf; copy_buf(CFG_DESCR{}, &p); (copy_buf(DSCS{}, &p), ...); } uint8_t buf[sz]{}; }; //============================================================================== // Interface Descriptor Type //============================================================================== template<typename TbInterfaceNumber, typename TbAlternateSetting, typename TbNumEndpoints, typename TbInterfaceClass, typename TbInterfaceSubClass, typename TbInterfaceProtocol, typename TiInterface> struct INTERFACE_DESCRIPTOR : public DESCRIPTOR<DescriptorType::INTERFACE, TbInterfaceNumber, TbAlternateSetting, TbNumEndpoints, TbInterfaceClass, TbInterfaceSubClass, TbInterfaceProtocol, TiInterface>, INTERFACE_DESCRIPTOR_BASE { static_assert(is_bInterfaceNumber<TbInterfaceNumber>(), "Not bInterfaceNumber record"); static_assert(is_bAlternateSetting<TbAlternateSetting>(), "Not bAlternateSetting record"); static_assert(is_bNumEndpoints<TbNumEndpoints>(), "Not bNumEndpoints record"); static_assert(is_bInterfaceClass<TbInterfaceClass>(), "Not bInterfaceClass record"); static_assert(is_bInterfaceSubClass<TbInterfaceSubClass>(),"Not bInterfaceSubClass record"); static_assert(is_bInterfaceProtocol<TbInterfaceProtocol>(),"Not bInterfaceProtocol record"); static_assert(is_iInterface<TiInterface>(), "Not iInterface record"); using bInterfaceNumber = TbInterfaceNumber; }; //============================================================================== // Interface Type //============================================================================== template<typename TbInterfaceNumber, typename TbAlternateSetting, typename TbInterfaceClass, typename TbInterfaceSubClass, typename TbInterfaceProtocol, typename TiInterface, typename...DSCS> class INTERFACE : public DESCRIPTOR_LIST< INTERFACE_DESCRIPTOR<TbInterfaceNumber, TbAlternateSetting, bNumEndpoints<0>, TbInterfaceClass, TbInterfaceSubClass, TbInterfaceProtocol, TiInterface>, DSCS...>, INTERFACE_BASE { static_assert((is_DescriptorListElement<DSCS>()&&...), "DSCS not Descriptor List Element"); static constexpr auto sz = (sizeof(DSCS::buf)+...+9); using IF_DESCR = INTERFACE_DESCRIPTOR<TbInterfaceNumber, TbAlternateSetting, bNumEndpoints<DESCRIPTOR_LIST<DSCS...>::EndpointsCount()>, TbInterfaceClass, TbInterfaceSubClass, TbInterfaceProtocol, TiInterface>; public: constexpr INTERFACE() { uint8_t *p = buf; copy_buf(IF_DESCR{}, &p); (copy_buf(DSCS{}, &p),...); } uint8_t buf[sz]{}; }; //============================================================================== // Endpoint Descriptor Type //============================================================================== template <uint8_t number, epDIR dir> class bEndpointAddress : public ENDPOINT_ADDRES_BASE { static_assert(number<16, "Endpoint number: Bit 3...0"); static constexpr uint8_t value = (uint8_t)dir + number; public: static constexpr auto GetEpAddress() { return value; } using type = ValueBox<REC_TYPE::bEndpointAddress>; uint8_t buf[1]{value}; }; template<typename T> constexpr bool is_bEndpointAddress() { return std::is_base_of_v<ENDPOINT_ADDRES_BASE,T>; } template<typename TbEndpointAddress, typename TbmAttributes, typename TwMaxPacketSize, typename TbInterval> struct ENDPOINT_DESCRIPTOR : public DESCRIPTOR<DescriptorType::ENDPOINT, TbEndpointAddress, TbmAttributes, TwMaxPacketSize, TbInterval>, ENDPOINT_DESCRIPTOR_BASE { static_assert(is_bEndpointAddress<TbEndpointAddress>(), "Not bInterfaceNumber record"); static_assert(is_bmAttributes_EP<TbmAttributes>(), "Not Endpoint bInterfaceNumber record"); static_assert(is_wMaxPacketSize<TwMaxPacketSize>(), "Not bInterfaceNumber record"); static_assert(is_bInterval<TbInterval>(), "Not bInterfaceNumber record"); using bEndpointAddress = TbEndpointAddress; static constexpr auto GetEpAddress() { return bEndpointAddress::GetEpAddress(); } }; //============================================================================== // Interface Association Descriptor Type //============================================================================== template<typename TbFirstInterface, typename TbInterfaceCount, typename TbFunctionClass, typename TbFunctionSubClass, typename TbFunctionProtocol, typename TiFunction> struct INTERFACE_ASSOCIATION_DESCRIPTOR : public DESCRIPTOR<DescriptorType::INTERFACE_ASSOCIATION, TbFirstInterface, TbInterfaceCount, TbFunctionClass, TbFunctionSubClass, TbFunctionProtocol, TiFunction> { static_assert(is_bFirstInterface<TbFirstInterface>(), "Not bFirstInterface record"); static_assert(is_bInterfaceCount<TbInterfaceCount>(), "Not bInterfaceCount record"); static_assert(is_bFunctionClass<TbFunctionClass>(), "Not bFunctionClass record"); static_assert(is_bFunctionSubClass<TbFunctionSubClass>(), "Not bFunctionSubClass record"); static_assert(is_bFunctionProtocol<TbFunctionProtocol>(), "Not bFunctionProtocol record"); static_assert(is_iFunction<TiFunction>(), "Not iFunction record"); }; //============================================================================== // Interface Association Type //============================================================================== template<typename TbFunctionClass, typename TbFunctionSubClass, typename TbFunctionProtocol, typename TiFunction, typename... DSCS> class INTERFACE_ASSOCIATION : public DESCRIPTOR_LIST< INTERFACE_ASSOCIATION_DESCRIPTOR<bFirstInterface<0>, bInterfaceCount<0>, TbFunctionClass, TbFunctionSubClass, TbFunctionProtocol, TiFunction>, DSCS...>, INTERFACE_ASSOCIATION_BASE { static constexpr auto sz = (sizeof(DSCS::buf)+...+8); static constexpr auto first_if = typename type_unbox< decltype(DESCRIPTOR_LIST<DSCS...>::GetInterfaces().head()) >::bInterfaceNumber{}.value(); static constexpr auto if_cnt = DESCRIPTOR_LIST<DSCS...>::InterfacesCount(); using IA_DESCR = INTERFACE_ASSOCIATION_DESCRIPTOR<bFirstInterface<first_if>, bInterfaceCount<if_cnt>, TbFunctionClass, TbFunctionSubClass, TbFunctionProtocol, TiFunction>; public: constexpr INTERFACE_ASSOCIATION() { uint8_t *p = buf; copy_buf(IA_DESCR{}, &p); (copy_buf(DSCS{}, &p),...); } uint8_t buf[sz]{}; }; //============================================================================== // CDC Header Functional Descriptor Type //============================================================================== template<typename TbDescriptorSubType, typename TbcdCDC> struct CDC_HEADER_FUNCTIONAL_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CS_INTERFACE, TbDescriptorSubType, TbcdCDC>, CDC_HEADER_FUNCTIONAL_DESCRIPTOR_BASE { static_assert(is_bDescriptorSubType<TbDescriptorSubType>(), "Not bDescriptorSubType record"); static_assert(is_bcdCDC<TbcdCDC>(), "Not bcdCDC record"); }; //============================================================================== // CDC ACM Functional Descriptor Type //============================================================================== template<typename TbDescriptorSubType, typename TbmCapabilities> struct CDC_ACM_FUNCTIONAL_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CS_INTERFACE, TbDescriptorSubType, TbmCapabilities>, CDC_ACM_FUNCTIONAL_DESCRIPTOR_BASE { static_assert(is_bDescriptorSubType<TbDescriptorSubType>(), "Not bFirstInterface record"); static_assert(is_bmCapabilities<TbmCapabilities>(), "Not bmCapabilities record"); }; //============================================================================== // CDC Union Functional Descriptor Type //============================================================================== template<typename TbDescriptorSubType, typename TbControlInterface, typename TbSubordinateInterface0> struct CDC_UNION_FUNCTIONAL_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CS_INTERFACE, TbDescriptorSubType, TbControlInterface, TbSubordinateInterface0>, CDC_UNION_FUNCTIONAL_DESCRIPTOR_BASE { static_assert(is_bDescriptorSubType<TbDescriptorSubType>(), "Not bFirstInterface record"); static_assert(is_bControlInterface<TbControlInterface>(), "Not bControlInterface record"); static_assert(is_bSubordinateInterface0<TbSubordinateInterface0>(), "Not bSubordinateInterface0 record"); }; //============================================================================== // CDC Call Management Functional Descriptor Type //============================================================================== template<typename TbDescriptorSubType, typename TbmCapabilities, typename TbDataInterface> struct CDC_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CS_INTERFACE, TbDescriptorSubType, TbmCapabilities, TbDataInterface>, CDC_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR_BASE { static_assert(is_bDescriptorSubType<TbDescriptorSubType>(), "Not bFirstInterface record"); static_assert(is_bmCapabilities<TbmCapabilities>(), "Not bmCapabilities record"); static_assert(is_bDataInterface<TbDataInterface>(), "Not bDataInterface record"); }; //============================================================================== // Custom HID Descriptor Type //============================================================================== template<typename TbcdHID, // HID Version ( 1.11 ) typename TbCountryCode, // Код страны локализованного устройства typename TbNumDescriptors, // Количество дескрипторов в классе typename TbDescriptorType_0, // Тип дескриптора Report Descriptor typename TwDescriptorLength_0> // Длина Report Descriptor struct CUSTOM_HID_DESCRIPTOR : public DESCRIPTOR<DescriptorType::HID, TbcdHID, TbCountryCode, TbNumDescriptors, TbDescriptorType_0, TwDescriptorLength_0>, CUSTOM_HID_DESCRIPTOR_BASE { static_assert(is_bcdHID<TbcdHID>(), "Not bcdHID record"); static_assert(is_bCountryCode<TbCountryCode>(), "Not bCountryCode record"); static_assert(is_bNumDescriptors<TbNumDescriptors>(), "Not bDataInterface record"); static_assert(is_bDescriptorType_0<TbDescriptorType_0>(), "Not bDescriptorType_0 record"); static_assert(is_wDescriptorLength_0<TwDescriptorLength_0>(),"Not wDescriptorLength_0 record"); }; template<typename T> constexpr bool is_CustomHID() { return std::is_base_of_v<CUSTOM_HID_DESCRIPTOR_BASE,T>; } namespace HID_REPORT { namespace PRIV { enum class ITEM_TYPE : uint8_t { // Main Items Input=0x80, Output=0x90, Feature=0xB0, Collection=0xA0, EndCollection=0xC0, // Global Items UsagePage=0x04, LogicalMin=0x14, LogicalMax=0x24, PhysicalMin=0x34, PhysicalMax=0x44, UnitExponent=0x54, Unit=0x64, ReportSize=0x74, ReportID=0x84, ReportCount=0x94, // Local Items Usage=0x08, UsageMin=0x18, UsageMax=0x28, DesignatorIndex=0x38, DesignatorMin=0x48, DesignatorMax=0x58, StringIndex=0x68, StringMin=0x78, StringMax=0x88 }; template <uint8_t... data> struct U8_DATA { uint8_t buf[sizeof...(data)]{data...}; }; template<typename TRCRD> constexpr auto copy_buf(TRCRD rcrd, uint8_t **p) { for(auto &x : rcrd.buf) *(*p)++ = x; } template <typename... RCRDS> struct BUF_COLLECTOR { constexpr BUF_COLLECTOR() { uint8_t *p = buf; (copy_buf(RCRDS{}, &p),...); } uint8_t buf[(sizeof(RCRDS::buf)+...)]{}; }; template<ITEM_TYPE it, int32_t value> class ITEM_SIGN_VALUE { static constexpr uint32_t S2U() { if constexpr (value>=0) return value; else if constexpr (value>=-128 )return ((0xFFFF'FFFFU-uint32_t(-value))+1) & 0xFF; else if constexpr (value>=-32768 )return ((0xFFFF'FFFFU-uint32_t(-value))+1) & 0xFFFF; else return (0xFFFF'FFFFU-uint32_t(-value))+1; } static constexpr auto CalcBytes() { if constexpr (value>=0) if constexpr (value>0x0000'7FFF) return 4; else if constexpr (value>0x0000'007F) return 2; else return 1; else if constexpr (S2U()>0x0000'FFFF) return 4; else if constexpr (S2U()>0x0000'00FF) return 2; else return 1; } static constexpr auto sz=CalcBytes()+1; public: constexpr ITEM_SIGN_VALUE() { auto x = S2U(); buf[0] = (uint8_t)it + ((sz<4)?(sz-1):3); for(auto i=0; i<sz-1; x>>=8) buf[1+i++]=x; } static constexpr auto Value() { return value; } uint8_t buf[sz]{}; }; template<ITEM_TYPE it, uint32_t value, uint32_t value_mask=0xFFFF'FFFF> class ITEM_UNSIGN_VALUE { static_assert( (value&~value_mask)==0, " Reserved bits check"); static constexpr auto CalcBytes() { if constexpr (value>0x0000'FFFF) return 4; else if constexpr (value>0x0000'00FF) return 2; else return 1; } static constexpr auto sz=CalcBytes()+1; public: constexpr ITEM_UNSIGN_VALUE() { auto x = value; buf[0] = (uint8_t)it + ((sz<4)?(sz-1):3); for(auto i=0; i<sz-1; x>>=8) buf[1+i++]=x; } static constexpr auto Value() { return value; } uint8_t buf[sz]{}; }; template<typename TMIN, typename TMAX> class ITEM_MINMAX { static_assert(TMIN::Value()<TMAX::Value(),"MIN < MAX"); using T = PRIV::BUF_COLLECTOR<TMIN,TMAX>; public: constexpr ITEM_MINMAX() { uint8_t *p = buf; PRIV::copy_buf(T{}, &p); } uint8_t buf[sizeof(T::buf)]{}; }; enum class COLLECTIONS : uint8_t { Physical=0, Application=1, Logical=2, Report=3, NamedArray=4, UsageSwitch=5, UsageModifier=6 }; template <COLLECTIONS cl, typename... RCRDS> using COLLECTION = PRIV::BUF_COLLECTOR<ITEM_UNSIGN_VALUE<ITEM_TYPE::Collection,(uint8_t)cl>, RCRDS..., PRIV::U8_DATA<(uint8_t)ITEM_TYPE::EndCollection>>; } // namespace PRIV template <typename... RCRDS> using HID_REPORT_DESCRIPTOR = PRIV::BUF_COLLECTOR<RCRDS...>; // Main Items template<uint32_t data> using Input = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::Input, data, 0x17F>; template<uint32_t data> using Output = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::Output, data, 0x1FF>; template<uint32_t data> using Feature = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::Feature, data, 0x1FF>; // Collections template<typename... RCRDS> using COLLECTION_PHYSICAL = PRIV::COLLECTION<PRIV::COLLECTIONS::Physical, RCRDS...>; template<typename... RCRDS> using COLLECTION_APPLICATION = PRIV::COLLECTION<PRIV::COLLECTIONS::Application, RCRDS...>; template<typename... RCRDS> using COLLECTION_LOGICAL = PRIV::COLLECTION<PRIV::COLLECTIONS::Logical, RCRDS...>; template<typename... RCRDS> using COLLECTION_REPORT = PRIV::COLLECTION<PRIV::COLLECTIONS::Report, RCRDS...>; template<typename... RCRDS> using COLLECTION_NAMEDARRAY = PRIV::COLLECTION<PRIV::COLLECTIONS::NamedArray, RCRDS...>; template<typename... RCRDS> using COLLECTION_USAGESWITCH = PRIV::COLLECTION<PRIV::COLLECTIONS::UsageSwitch, RCRDS...>; template<typename... RCRDS> using COLLECTION_USAGEMODIFIER = PRIV::COLLECTION<PRIV::COLLECTIONS::UsageModifier, RCRDS...>; // Global Items enum class USAGE_PAGE : int16_t { UNDEFINED=0, GENERIC_DESCTOP=1, SIMULATION=2, VR=3, SPORT=4, GAME=5, DEV_CONTROLS=6, KEYBOARD=7, LED=8, BUTTON=9, ORDINALS=0xA, TELEPHONY_DEVICE=0xB, CONSUMER_DEVICE=0xC, DIGITIZER=0xD, UNICODE=0x10, ALPHANUMERIC_DISPLAY=0x14, MONITOR=-128, MONITOR_ENUMERATED_VALUES=-127, VESA_VIRTUAL_CONTROLS=-126, VESA_COMMAND=-125, POWER_DEVICE=-124, BATTARY_SYSTEM=-123, VENDOR_DEFINED_PAGE_1=-256 }; template<USAGE_PAGE data> using UsagePage = PRIV::ITEM_SIGN_VALUE<PRIV::ITEM_TYPE::UsagePage, (int16_t)data>; template<int32_t data> using LogicalMin = PRIV::ITEM_SIGN_VALUE<PRIV::ITEM_TYPE::LogicalMin, data>; template<int32_t data> using LogicalMax = PRIV::ITEM_SIGN_VALUE<PRIV::ITEM_TYPE::LogicalMax, data>; template<int32_t min, int32_t max> using LogicalMinMax = PRIV::ITEM_MINMAX<LogicalMin<min>, LogicalMax<max>> ; template<int32_t data> using PhysicalMin = PRIV::ITEM_SIGN_VALUE<PRIV::ITEM_TYPE::PhysicalMin, data>; template<int32_t data> using PhysicalMax = PRIV::ITEM_SIGN_VALUE<PRIV::ITEM_TYPE::PhysicalMax, data>; template<int32_t min, int32_t max> using PhysicalMinMax = PRIV::ITEM_MINMAX<PhysicalMin<min>,PhysicalMax<max>>; template<uint32_t data> using ReportSize = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::ReportSize, data>; template<uint8_t data> using ReportID = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::ReportID, data>; template<uint32_t data> using ReportCount = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::ReportCount, data>; template<uint32_t sz, int32_t cnt> using ReportFormat = PRIV::BUF_COLLECTOR<ReportSize<sz>,ReportCount<cnt>>; // ??? using PUSH = PRIV::U8_DATA<0xA4>; using POP = PRIV::U8_DATA<0xB4>; // Local Items template<uint8_t data> using Usage = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::Usage, data>; template<uint8_t data> using UsageMin = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::UsageMin, data>; template<uint8_t data> using UsageMax = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::UsageMax, data>; template<uint8_t min, uint8_t max> using UsageMinMax = PRIV::ITEM_MINMAX<UsageMin<min>,UsageMax<max>>; template<uint32_t data> using DesignatorIndex = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::DesignatorIndex, data>; template<uint32_t data> using DesignatorMin = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::DesignatorMin, data>; template<uint32_t data> using DesignatorMax = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::DesignatorMax, data>; template<uint32_t min, uint32_t max> using DesignatorMinMax = PRIV::ITEM_MINMAX<DesignatorMin<min>,DesignatorMax<max>>; template<uint32_t data> using StringIndex = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::StringIndex, data>; template<uint32_t data> using StringMin = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::StringMin, data>; template<uint32_t data> using StringMax = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::StringMax, data>; template<uint32_t min, uint32_t max> using StringMinMax = PRIV::ITEM_MINMAX<StringMin<min>,StringMax<max>>; } // namespace HID_REPORT } // namespace USB_DESCRIPTOR // ============================================================================= // Заполнение дескрипторов // ============================================================================= using namespace USB_DESCRIPTORS; //============================================================================== // Device Descriptor //============================================================================== constexpr DEVICE_DESCRIPTOR < bcdUSB<0x02'00>, // версия usb 2.0 bDeviceClass<2>, // Communications and CDC Control bDeviceSubClass<2>, // bDeviceProtocol<0>, // No class specific protocol required bMaxPacketSize0<64>, idVendor<0x0483>, // VID idProduct<0x5740>, // PID bcdDevice<0x0200>, iManufacturer<1>, iProduct<2>, iSerialNumber<3>, bNumConfigurations<1> > Device_Descriptor_CDC; //============================================================================== // Device Qualifier Descriptor //============================================================================== constexpr DEVICE_QUALIFIER_DESCRIPTOR < bcdUSB<0x02'00>, // версия usb 2.0 bDeviceClass<2>, // Communications and CDC Control bDeviceSubClass<2>, // bDeviceProtocol<0>, // No class specific protocol required bMaxPacketSize0<64>, bNumConfigurations<0> > Device_Qualifier_Descriptor_CDC; //============================================================================== // CDC VCP Configuration Descriptor //============================================================================== constexpr DEVICE_CONFIGURATION_DESCRIPTOR < bConfigurationValue<1>, // configuration 1 iConfiguration<0>, // No String Descriptor bmAttributes<cfg_Attr::SelfPowered>, // Self powered bMaxPower<100/2>, // 100 mA INTERFACE // Interface 0 - CDC Communication < bInterfaceNumber<0>, bAlternateSetting<0>, bInterfaceClass<2>, // Communications and CDC Control bInterfaceSubClass<2>, // Abstract Control Model bInterfaceProtocol<1>, // AT Commands defined by ITU-T V.250 etc iInterface<0>, CDC_HEADER_FUNCTIONAL_DESCRIPTOR < bDescriptorSubType<0>, // Header Functional Descriptor bcdCDC<0x01'10> >, // CDC Version 1.10 CDC_ACM_FUNCTIONAL_DESCRIPTOR < bDescriptorSubType<2>, // Abstract Control Management Functional Descriptor bmCapabilities<2> >, // CDC_UNION_FUNCTIONAL_DESCRIPTOR < bDescriptorSubType<6>, // Union Functional Descriptor bControlInterface<0>, // Interface 0 - bSubordinateInterface0<1> >, // Interface 1 - Data Class Interface CDC_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR < bDescriptorSubType<1>, // Call Management Functional Descriptor bmCapabilities<0>, bDataInterface<1> >, // ENDPOINT_DESCRIPTOR // EP2 In Interrupt EndPoint < bEndpointAddress<2, epDIR::IN>, bmAttributes<epTYPE::Interrupt>, wMaxPacketSize<8>, bInterval<255> > >, INTERFACE // Interface 1 - Data Interface < bInterfaceNumber<1>, bAlternateSetting<0>, bInterfaceClass<0x0A>, // CDC-Data bInterfaceSubClass<0>, bInterfaceProtocol<0>, iInterface<0>, ENDPOINT_DESCRIPTOR< // EP1 OUT Bulk EndPoint bEndpointAddress<1, epDIR::OUT>, bmAttributes<epTYPE::Bulk>, wMaxPacketSize<64>, bInterval<0> >, ENDPOINT_DESCRIPTOR< // EP1 IN Bulk EndPoint bEndpointAddress<1, epDIR::IN>, bmAttributes<epTYPE::Bulk>, wMaxPacketSize<64>, bInterval<0> > > > Configuration_Descriptor_CDC; //============================================================================== // HID Report Descriptor //============================================================================== using namespace HID_REPORT; constexpr HID_REPORT_DESCRIPTOR< UsagePage<USAGE_PAGE::VENDOR_DEFINED_PAGE_1>, Usage<1>, COLLECTION_APPLICATION< ReportID<1>, Usage<1>, LogicalMinMax<0,1>, ReportFormat<8,1>, Feature<0x82>, ReportID<1>, Usage<1>, Output<0x82>, ReportID<2>, Usage<2>, LogicalMinMax<0,1>, ReportFormat<8,1>, Feature<0x82>, ReportID<2>, Usage<2>, Output<0x82>, ReportID<3>, Usage<3>, LogicalMinMax<0,255>, ReportFormat<8,1>, Feature<0x82>, ReportID<3>, Usage<3>, Output<0x82>, ReportID<4>, Usage<3>, LogicalMinMax<0,255>, ReportFormat<8,1>, Feature<0x82>, ReportID<4>, Usage<3>, Output<0x82>, ReportID<5>, Usage<4>, ReportFormat<8,1>, Input<0x02> > > HidReportDescriptor; //============================================================================== // HID Configuration Descriptor //============================================================================== constexpr DEVICE_CONFIGURATION_DESCRIPTOR < bConfigurationValue<1>, // configuration 1 iConfiguration<0>, // No String Descriptor bmAttributes<cfg_Attr::SelfPowered>, // Self powered bMaxPower<100/2>, // 100 mA INTERFACE // Interface 0 - CUSTOM HID < bInterfaceNumber<0>, bAlternateSetting<0>, bInterfaceClass<3>, // Custom HID bInterfaceSubClass<0>, // 1=BOOT, 0=no boot bInterfaceProtocol<0>, // 0=none, 1=keyboard, 2=mouse iInterface<0>, CUSTOM_HID_DESCRIPTOR< bcdHID<0x01'11>, // HID Version ( 1.11 ) bCountryCode<HID_Localization::Not_Localized>, // HID_Localization::Not_Localized, bNumDescriptors<1>, // Количество дескрипторов в классе bDescriptorType_0<DescriptorType::REPORT>, wDescriptorLength_0<sizeof(HidReportDescriptor)> >,// Длина Report Descriptor ENDPOINT_DESCRIPTOR< // EP1 IN Interrupt EndPoint bEndpointAddress<1,epDIR::IN>, bmAttributes<epTYPE::Interrupt>, wMaxPacketSize<2>, bInterval<20> >, ENDPOINT_DESCRIPTOR< // EP1 OUT Interrupt EndPoint bEndpointAddress<1,epDIR::OUT>, bmAttributes<epTYPE::Interrupt>, wMaxPacketSize<2>, bInterval<0> > > > Configuration_Descriptor_HID; //============================================================================== // 2 x CDC VCP Configuration Descriptor //============================================================================== template<uint8_t first_if, uint8_t ctrl_ep_num, uint8_t data_ep_num, uint8_t iString=0> using VCP = INTERFACE_ASSOCIATION < bFunctionClass<2>, bFunctionSubClass<2>, bFunctionProtocol<0>, iFunction<0>, INTERFACE // Interface 0 - CDC Communication < bInterfaceNumber<first_if>, bAlternateSetting<0>, bInterfaceClass<2>, // Communications and CDC Control bInterfaceSubClass<2>, // Abstract Control Model bInterfaceProtocol<1>, // AT Commands defined by ITU-T V.250 etc iInterface<iString>, CDC_HEADER_FUNCTIONAL_DESCRIPTOR < bDescriptorSubType<0>, // Header Functional Descriptor bcdCDC<0x01'10> >, // CDC Version 1.10 CDC_ACM_FUNCTIONAL_DESCRIPTOR < bDescriptorSubType<2>, // Abstract Control Management Functional Descriptor bmCapabilities<2> >, // CDC_UNION_FUNCTIONAL_DESCRIPTOR < bDescriptorSubType<6>, // Union Functional Descriptor bControlInterface<0>, // Interface 0 - bSubordinateInterface0<1> >, // Interface 1 - Data Class Interface CDC_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR < bDescriptorSubType<1>, // Call Management Functional Descriptor bmCapabilities<0>, bDataInterface<1> >, // ENDPOINT_DESCRIPTOR // EP2 In Interrupt EndPoint < bEndpointAddress<ctrl_ep_num, epDIR::IN>, bmAttributes<epTYPE::Interrupt>, wMaxPacketSize<8>, bInterval<255> > >, INTERFACE // Interface 1 - Data Interface < bInterfaceNumber<first_if+1>, bAlternateSetting<0>, bInterfaceClass<0x0A>, // CDC-Data bInterfaceSubClass<0>, bInterfaceProtocol<0>, iInterface<0>, ENDPOINT_DESCRIPTOR< // EP1 OUT Bulk EndPoint bEndpointAddress<data_ep_num, epDIR::OUT>, bmAttributes<epTYPE::Bulk>, wMaxPacketSize<64>, bInterval<0> >, ENDPOINT_DESCRIPTOR< // EP1 IN Bulk EndPoint bEndpointAddress<data_ep_num, epDIR::IN>, bmAttributes<epTYPE::Bulk>, wMaxPacketSize<64>, bInterval<0> > > >; constexpr DEVICE_CONFIGURATION_DESCRIPTOR < bConfigurationValue<1>, // Configuration 1 iConfiguration<0>, // No String Descriptor bmAttributes<cfg_Attr::SelfPowered>, // Self powered bMaxPower<100/2>, // 100 mA VCP<0, // Интерфейсы (0 и 1) 3, // Control EP num 1, // Data EP num 4 >, // Номер строкового дескриптора интерфейса VCP<2, // Интерфейсы (2 и 3) 4, // Control EP num 2, // Data EP num 5> // Номер строкового дескриптора интерфейса > Configuration_Descriptor_2CDC; // ---------------------- // Тест // ---------------------- int main() { printf("CDC Device descriptor %i bytes:\n", sizeof(Device_Descriptor_CDC)); for(auto &x : Device_Descriptor_CDC.buf) printf("%.2X ", x); printf("\nCDC Device Qualifier descriptor %i bytes:\n", sizeof(Device_Qualifier_Descriptor_CDC)); for(auto &x : Device_Qualifier_Descriptor_CDC.buf) printf("%.2X ", x); printf("\nCDC Configuration descriptor %i bytes:\n", sizeof(Configuration_Descriptor_CDC)); for(auto &x : Configuration_Descriptor_CDC.buf) printf("%.2X ", x); printf("\nCUSTOM HID REPORT descriptor %i bytes:\n", sizeof(HidReportDescriptor)); for(auto &x : HidReportDescriptor.buf) printf("%.2X ", x); printf("\nCUSTOM HID Configuration descriptor %i bytes:\n", sizeof(Configuration_Descriptor_HID)); for(auto &x : Configuration_Descriptor_HID.buf) printf("%.2X ", x); printf("\n2xCDC Configuration descriptor %i bytes:\n", sizeof(Configuration_Descriptor_2CDC)); for(auto &x : Configuration_Descriptor_2CDC.buf) printf("%.2X ", x); Configuration_Descriptor_2CDC.GetDescriptorList().GetEndpoints().foreach ( [](auto ep) { printf("\nEP = %02X \r", type_unbox<decltype(ep)>::GetEpAddress() ); } ); }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
About the author
Statistics
Changelog
Version tree