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<typename T> using TypeBox = std::type_identity<T>; template<auto value> using TypeUnBox = typename decltype(value)::type; template <auto Value> struct ValueBox { static constexpr auto value = Value; }; template<typename T> consteval auto value_unbox() { return T::type::value; } template<typename... Ts> struct TypeList { static consteval auto size() { return sizeof...(Ts); } static consteval bool is_empty() { return (sizeof...(Ts) == 0); } static consteval auto head() { return []<typename T, typename... Us>(TypeList<T, Us...>){ return TypeBox<T>{}; }(TypeList<Ts...>{}); } static consteval auto tail() { return[]<typename T, typename... Us>(TypeList<T, Us...>) { return TypeList<Us...>{}; }(TypeList<Ts...>{}); } static consteval auto back() { return (TypeBox<Ts>{}, ...); } template<typename T> static consteval auto push_front() { return TypeList<T, Ts...>{}; } template<typename T> static consteval auto push_front(TypeBox<T>) { return push_front<T>(); } template<typename T> static consteval auto push_back() { return TypeList<Ts..., T>{}; } template<typename T> static consteval auto push_back(TypeBox<T>) { return push_back<T>(); } template<typename T> static consteval bool contains() { return (... || std::is_same_v<T, Ts>); } template<typename T> static consteval bool contains(TypeBox<T>) { return contains<T>(); } static consteval bool is_unique(auto func) { return is_unique_<Ts...>(func); } static consteval bool is_unique() { return is_unique([](auto v1, auto v2) { return std::is_same_v<TypeUnBox<v1>, TypeUnBox<v2>>; }); } static consteval auto accumulate(auto func) { return (TypeList<>{} + ... + func(TypeBox<Ts>{})); } static inline void foreach(auto func) { (func(TypeBox<Ts> {}), ...); } template<auto I, typename T> static consteval auto generate() { return[]<auto... Is>(std::index_sequence<Is...>) { return TypeList < TypeUnBox < (Is, TypeBox<T>{}) > ... > {}; } (std::make_index_sequence<I>()); } static consteval auto transform(auto func) { return TypeList<TypeUnBox<func(TypeBox<Ts>{})>...>{}; } template<typename T> static consteval auto filter(auto pred) { return (TypeList<>{}+ ... +std::conditional_t<pred(TypeBox<T>{}, TypeBox<Ts>{}),TypeList<Ts>,TypeList<>>{}); } template<typename T> static consteval auto filter(TypeBox<T> box, auto pred) { return filter<T>(pred); } static consteval auto filter(auto pred) { return (TypeList<>{} + ... + std::conditional_t<pred(TypeBox<Ts>{}), TypeList<Ts>, TypeList<>>{}); } private: static consteval bool is_unique_(auto func) { return true; } template <typename T, typename... Us> static consteval bool is_unique_(auto func) { return !(func(TypeBox<T>{}, TypeBox<Us>{}) || ...) && is_unique_<Us...>(func); } }; template<typename... Ts, typename... Us> consteval 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 }; //============================================================================== // String Descriptors //============================================================================== #define STRING_DESCRIPTOR(idx, name, text) \ inline constexpr struct __attribute__((__packed__)) \ { \ uint8_t bIndex; \ uint8_t bLength; \ DescriptorType bDescriptorType; \ char16_t Text[std::size(text)]; \ } name = { idx, sizeof(text), DescriptorType::STRING, text }; 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 {}; //============================================================================== // Определение полей дескрипторов //============================================================================== #define REC_U8(X) template<typename T> concept is_##X = value_unbox<T>() == REC_TYPE::X; \ template<uint8_t x> using X = HOLDER<REC_TYPE::X, (uint8_t)x> #define REC_U16(X) template<typename T> concept is_##X = value_unbox<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> concept is_##X = value_unbox<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>; consteval 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> concept is_Descriptor = std::is_base_of_v<DESCRIPTOR_BASE, T>; template<typename T> concept is_DescriptorList = std::is_base_of_v<DESCRIPTOR_LIST_BASE, T>; template<typename T> concept is_DescriptorListElement = is_Descriptor<T> || is_DescriptorList<T>; template<typename T> concept is_ConfigurationDescriptor = std::is_base_of_v<CONFIGURATION_DESCRIPTOR_BASE, T>; template<typename T> concept is_InterfaceDescriptor = std::is_base_of_v<INTERFACE_DESCRIPTOR_BASE, T>; template<typename T> concept is_EndpointDescriptor = std::is_base_of_v<ENDPOINT_DESCRIPTOR_BASE, T>; template<typename T> concept is_Interface_Association = std::is_base_of_v<INTERFACE_ASSOCIATION_DESCRIPTOR_BASE, T>; template<typename T> concept is_CustomHID = std::is_base_of_v<CUSTOM_HID_DESCRIPTOR_BASE, T>; template<typename T> concept Is_Interface = std::is_base_of_v<INTERFACE_BASE, T>; // Концепты для полей дескрипторов template<typename T> concept is_bmAttributes = std::is_base_of_v<BMATTRIBUTES_BASE, T>; template<typename T> concept is_bmAttributes_EP = is_bmAttributes<T> && std::is_same_v<typename T::sub_type, epTYPE>; template<typename T> concept is_bmAttributes_CONFIG = is_bmAttributes<T> && std::is_same_v<typename T::sub_type, cfg_Attr>; template<typename T> concept is_bEndpointAddress = std::is_base_of_v<ENDPOINT_ADDRES_BASE, T>; constexpr auto copy_buf(auto rcrd, uint8_t** p) { for (auto& x : rcrd.buf) *(*p)++ = x; } //============================================================================== // Контейнер для дескриптора //============================================================================== template<DescriptorType dt, typename... RCRDS> class DESCRIPTOR : 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 <is_DescriptorListElement... DSCS> class DESCRIPTOR_LIST : DESCRIPTOR_LIST_BASE { static constexpr auto ExpandDL = [](auto x) { using T = TypeUnBox<x>; static_assert(is_DescriptorListElement<T>, "Only DESCRIPTOR or DESCRIPTOR_LIST"); 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<TypeUnBox<x>>; }); } static constexpr auto GetInterfaces() { return dscs_.filter([](auto x) { return is_InterfaceDescriptor<TypeUnBox<x>>; }); } static constexpr auto EndpointsCount() { return GetEndpoints().size(); } static constexpr auto InterfacesCount() { return GetInterfaces().size(); } uint8_t buf[(sizeof(DSCS::buf) + ...)]{}; }; //============================================================================== // Device Descriptor Type //============================================================================== template<is_bcdUSB TbcdUSB, // версия usb is_bDeviceClass TbDeviceClass, // класс устройства is_bDeviceSubClass TbDeviceSubClass, // подкласс is_bDeviceProtocol TbDeviceProtocol, // протокол is_bMaxPacketSize0 TbMaxPacketSize0, // максимальный размер пакета для нулевой конечной точки is_idVendor TidVendor, // VID is_idProduct TidProduct, is_bcdDevice TbcdDevice, is_iManufacturer TiManufacturer, is_iProduct TiProduct, is_iSerialNumber TiSerialNumber, is_bNumConfigurations TbNumConfigurations> class DEVICE_DESCRIPTOR : public DESCRIPTOR< DescriptorType::DEVICE, TbcdUSB, TbDeviceClass, TbDeviceSubClass,TbDeviceProtocol, TbMaxPacketSize0, TidVendor, TidProduct, TbcdDevice, TiManufacturer, TiProduct, TiSerialNumber, TbNumConfigurations > { static constexpr auto ep0sz = TbMaxPacketSize0{}.value(); static_assert((ep0sz == 8) || (ep0sz == 16) || (ep0sz == 32) || (ep0sz == 64), "Wrong TbMaxPacketSize0 size"); }; //============================================================================== // Device Qualifier Descriptor Type //============================================================================== template<is_bcdUSB TbcdUSB, is_bDeviceClass TbDeviceClass, is_bDeviceSubClass TbDeviceSubClass, is_bDeviceProtocol TbDeviceProtocol, is_bMaxPacketSize0 TbMaxPacketSize0, is_bNumConfigurations TbNumConfigurations> struct DEVICE_QUALIFIER_DESCRIPTOR : public DESCRIPTOR<DescriptorType::DEVICE_QUALIFIER, TbcdUSB, TbDeviceClass, TbDeviceSubClass, TbDeviceProtocol, TbMaxPacketSize0, TbNumConfigurations, bReserved<0>> { }; //============================================================================== // Configuration Descriptor Type //============================================================================== template<auto... args> class bmAttributes : BMATTRIBUTES_BASE { static_assert((sizeof...(args) > 0) && (sizeof...(args) < 4), "Wrong parameters"); 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 arguments"); return arg1; } template<auto arg1, auto arg2> static constexpr auto Chek2Args() { static_assert(std::is_same_v<decltype(arg1), epTYPE>, "Wrong arguments"); static_assert(std::is_same_v<decltype(arg2), epSYNC> || std::is_same_v<decltype(arg2), epUSAGE>, "Wrong arguments"); return arg1; } template<auto arg1, auto arg2, auto arg3> static constexpr auto Chek3Args() { static_assert(std::is_same_v<decltype(arg1), epTYPE>, "Wrong 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 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<is_wTotalLength TwTotalLength, is_bNumInterfaces TbNumInterfaces, is_bConfigurationValue TbConfigurationValue, is_iConfiguration TiConfiguration, is_bmAttributes_CONFIG TbmAttributes, is_bMaxPower 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; }; //============================================================================== // Device Configuration Descriptor Type //============================================================================== template<is_bConfigurationValue TbConfigurationValue, is_iConfiguration TiConfiguration, is_bmAttributes TbmAttributes, is_bMaxPower TbMaxPower, is_DescriptorListElement... DSCS> class DEVICE_CONFIGURATION_DESCRIPTOR { static constexpr auto sz = (sizeof(DSCS::buf)+...+9); static constexpr auto CalcInterfacesNum() { return DESCRIPTOR_LIST<DSCS...>::GetDescriptors().filter( [](auto x) { return is_InterfaceDescriptor<TypeUnBox<x>>; }).size(); } using CFG_DESCR = CONFIGURATION_DESCRIPTOR<wTotalLength<sz>, bNumInterfaces<CalcInterfacesNum()>, TbConfigurationValue, TiConfiguration, TbmAttributes, TbMaxPower>; static_assert(DESCRIPTOR_LIST<DSCS...>::GetEndpoints().transform( [](auto eps) { return TypeBox<typename TypeUnBox<eps>::bEndpointAddress>{}; }).is_unique(), "Duplicate Endpoints!"); static_assert(DESCRIPTOR_LIST<DSCS...>::GetInterfaces().transform( [](auto eps) { return TypeBox<typename TypeUnBox<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<is_bInterfaceNumber TbInterfaceNumber, is_bAlternateSetting TbAlternateSetting, is_bNumEndpoints TbNumEndpoints, is_bInterfaceClass TbInterfaceClass, is_bInterfaceSubClass TbInterfaceSubClass, is_bInterfaceProtocol TbInterfaceProtocol, is_iInterface TiInterface> struct INTERFACE_DESCRIPTOR : public DESCRIPTOR<DescriptorType::INTERFACE, TbInterfaceNumber, TbAlternateSetting, TbNumEndpoints, TbInterfaceClass, TbInterfaceSubClass, TbInterfaceProtocol, TiInterface>, INTERFACE_DESCRIPTOR_BASE { using bInterfaceNumber = TbInterfaceNumber; }; //============================================================================== // Endpoint Descriptor Type //============================================================================== template <uint8_t number, epDIR dir> class bEndpointAddress : 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<is_bEndpointAddress TbEndpointAddress, is_bmAttributes_EP TbmAttributes, is_wMaxPacketSize TwMaxPacketSize, is_bInterval TbInterval> struct ENDPOINT_DESCRIPTOR : public DESCRIPTOR<DescriptorType::ENDPOINT, TbEndpointAddress, TbmAttributes, TwMaxPacketSize, TbInterval>, ENDPOINT_DESCRIPTOR_BASE { using bEndpointAddress = TbEndpointAddress; static constexpr auto GetEpAddress() { return bEndpointAddress::GetEpAddress(); } }; //============================================================================== // Interface Type //============================================================================== template<is_bInterfaceNumber TbInterfaceNumber, is_bAlternateSetting TbAlternateSetting, is_bInterfaceClass TbInterfaceClass, is_bInterfaceSubClass TbInterfaceSubClass, is_bInterfaceProtocol TbInterfaceProtocol, is_iInterface TiInterface, is_DescriptorListElement...DSCS> class INTERFACE : public DESCRIPTOR_LIST< INTERFACE_DESCRIPTOR<TbInterfaceNumber, TbAlternateSetting, bNumEndpoints<0>, TbInterfaceClass, TbInterfaceSubClass, TbInterfaceProtocol, TiInterface>, DSCS...>, INTERFACE_BASE { 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]{}; }; //============================================================================== // Interface Association Descriptor Type //============================================================================== template<is_bFirstInterface TbFirstInterface, is_bInterfaceCount TbInterfaceCount, is_bFunctionClass TbFunctionClass, is_bFunctionSubClass TbFunctionSubClass, is_bFunctionProtocol TbFunctionProtocol, is_iFunction TiFunction> struct INTERFACE_ASSOCIATION_DESCRIPTOR : public DESCRIPTOR<DescriptorType::INTERFACE_ASSOCIATION, TbFirstInterface, TbInterfaceCount, TbFunctionClass, TbFunctionSubClass, TbFunctionProtocol, TiFunction> { }; //============================================================================== // 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 TypeUnBox<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<is_bDescriptorSubType TbDescriptorSubType, is_bcdCDC TbcdCDC> struct CDC_HEADER_FUNCTIONAL_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CS_INTERFACE, TbDescriptorSubType, TbcdCDC>, CDC_HEADER_FUNCTIONAL_DESCRIPTOR_BASE { }; //============================================================================== // CDC ACM Functional Descriptor Type //============================================================================== template<is_bDescriptorSubType TbDescriptorSubType, is_bmCapabilities TbmCapabilities> struct CDC_ACM_FUNCTIONAL_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CS_INTERFACE, TbDescriptorSubType, TbmCapabilities>, CDC_ACM_FUNCTIONAL_DESCRIPTOR_BASE { }; //============================================================================== // CDC Union Functional Descriptor Type //============================================================================== template<is_bDescriptorSubType TbDescriptorSubType, is_bControlInterface TbControlInterface, is_bSubordinateInterface0 TbSubordinateInterface0> struct CDC_UNION_FUNCTIONAL_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CS_INTERFACE, TbDescriptorSubType, TbControlInterface, TbSubordinateInterface0>, CDC_UNION_FUNCTIONAL_DESCRIPTOR_BASE {}; //============================================================================== // CDC Call Management Functional Descriptor Type //============================================================================== template<is_bDescriptorSubType TbDescriptorSubType, is_bmCapabilities TbmCapabilities, is_bDataInterface TbDataInterface> struct CDC_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR : public DESCRIPTOR<DescriptorType::CS_INTERFACE, TbDescriptorSubType, TbmCapabilities, TbDataInterface>, CDC_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR_BASE {}; //============================================================================== // CUSTOM HID Descriptor Type //============================================================================== template<is_bcdHID TbcdHID, // HID Version ( 1.11 ) is_bCountryCode TbCountryCode, // Код страны локализованного устройства is_bNumDescriptors TbNumDescriptors, // Количество дескрипторов в классе is_bDescriptorType_0 TbDescriptorType_0, // Тип дескриптора Report Descriptor is_wDescriptorLength_0 TwDescriptorLength_0> // Длина Report Descriptor struct CUSTOM_HID_DESCRIPTOR : public DESCRIPTOR<DescriptorType::HID, TbcdHID, TbCountryCode, TbNumDescriptors, TbDescriptorType_0, TwDescriptorLength_0>, CUSTOM_HID_DESCRIPTOR_BASE {}; namespace HID_REPORT { namespace PRIV { template <uint8_t... data> struct U8_DATA { uint8_t buf[sizeof...(data)]{data...}; }; constexpr auto copy_buf(auto 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)+...)]{}; }; 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<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; } uint8_t buf[sz]{}; }; template<ITEM_TYPE it, uint32_t value> class ITEM_UNSIGN_VALUE { 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; } uint8_t buf[sz]{}; }; 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> requires ((data&~0x17F)==0) using Input = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::Input, data>; template <uint32_t data> requires ((data&~0x1FF)==0) using Output = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::Output, data>; template <uint32_t data> requires ((data&~0x1FF)==0) using Feature = PRIV::ITEM_UNSIGN_VALUE<PRIV::ITEM_TYPE::Feature, data>; // 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> requires (min<max) using LogicalMinMax = PRIV::BUF_COLLECTOR<LogicalMin<min>,LogicalMax<max>>; template<int32_t min, int32_t max> requires (min<max) using LogicalMinMax = PRIV::BUF_COLLECTOR<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> requires (min<max) using PhysicalMinMax = PRIV::BUF_COLLECTOR<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> requires (min<max) using UsageMinMax = PRIV::BUF_COLLECTOR<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> requires (min<max) using DesignatorMinMax = PRIV::BUF_COLLECTOR<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> requires (min<max) using StringMinMax = PRIV::BUF_COLLECTOR<StringMin<min>,StringMax<max>>; } // namespace } // 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", TypeUnBox<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