[pico-stuff] initial upload
This commit is contained in:
parent
a24a4dff09
commit
b473b13985
5
pico-stuff/.clang-format
Normal file
5
pico-stuff/.clang-format
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
UseTab: Always
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
24
pico-stuff/CMakeLists.txt
Normal file
24
pico-stuff/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(sandbox)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
add_executable(test)
|
||||
|
||||
target_sources(test PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/test.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c
|
||||
)
|
||||
|
||||
# Make sure TinyUSB can find tusb_config.h
|
||||
target_include_directories(test PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
pico_enable_stdio_usb(test 1)
|
||||
|
||||
target_link_libraries(test PUBLIC pico_stdlib tinyusb_device pico_unique_id)
|
||||
|
||||
pico_add_extra_outputs(test)
|
9
pico-stuff/README.md
Normal file
9
pico-stuff/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# raspberry pi pico playground
|
||||
|
||||
- `morse.c`: morse blinker (with a shell over serial to send messages to blink)
|
||||
- `monstrosity.c`: driver code for random components i had laying around
|
||||
- `test.c`: morse code HID keyboard (needs two buttons). can use vim with it
|
||||
- `tablegen.py`: helper to generate keymaps for `test.c` morse
|
||||
|
||||
you will need to put the raspberry pi pico sdk somewhere and export `PICO_SDK_PATH` to point to it.
|
||||
also, it could be useful to export `CMAKE_EXPORT_COMPILE_COMMANDS=1` to get a `compile_commands.json`.
|
154
pico-stuff/monstrosity.c
Normal file
154
pico-stuff/monstrosity.c
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/stdio.h"
|
||||
#include <stdio.h>
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/pwm.h"
|
||||
|
||||
const uint BOARD_LED_PIN = PICO_DEFAULT_LED_PIN;
|
||||
const uint LED_PIN = 15;
|
||||
const uint LED2_PIN = 17;
|
||||
const uint BUTTON_PIN = 9;
|
||||
const uint ROT_CLK = 11;
|
||||
const uint ROT_DT = 10;
|
||||
|
||||
|
||||
const uint DOT_PERIOD_MS = 100;
|
||||
|
||||
const char *morse_letters[] = {
|
||||
".-", // A
|
||||
"-...", // B
|
||||
"-.-.", // C
|
||||
"-..", // D
|
||||
".", // E
|
||||
"..-.", // F
|
||||
"--.", // G
|
||||
"....", // H
|
||||
"..", // I
|
||||
".---", // J
|
||||
"-.-", // K
|
||||
".-..", // L
|
||||
"--", // M
|
||||
"-.", // N
|
||||
"---", // O
|
||||
".--.", // P
|
||||
"--.-", // Q
|
||||
".-.", // R
|
||||
"...", // S
|
||||
"-", // T
|
||||
"..-", // U
|
||||
"...-", // V
|
||||
".--", // W
|
||||
"-..-", // X
|
||||
"-.--", // Y
|
||||
"--.." // Z
|
||||
};
|
||||
|
||||
void put_morse_letter(uint led_pin, const char *pattern) {
|
||||
for (; *pattern; ++pattern) {
|
||||
gpio_put(led_pin, 1);
|
||||
if (*pattern == '.')
|
||||
sleep_ms(DOT_PERIOD_MS);
|
||||
else
|
||||
sleep_ms(DOT_PERIOD_MS * 3);
|
||||
gpio_put(led_pin, 0);
|
||||
sleep_ms(DOT_PERIOD_MS * 1);
|
||||
}
|
||||
sleep_ms(DOT_PERIOD_MS * 2);
|
||||
}
|
||||
|
||||
void put_morse_str(uint led_pin, char *str) {
|
||||
for (; *str; ++str) {
|
||||
if (*str >= 'A' && *str <= 'Z') {
|
||||
put_morse_letter(led_pin, morse_letters[*str - 'A']);
|
||||
} else if (*str >= 'a' && *str <= 'z') {
|
||||
put_morse_letter(led_pin, morse_letters[*str - 'a']);
|
||||
} else if (*str == ' ') {
|
||||
sleep_ms(DOT_PERIOD_MS * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rotCt = 0;
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
#ifndef PICO_DEFAULT_LED_PIN
|
||||
#warning picoboard/blinky example requires a board with a regular LED
|
||||
#else
|
||||
gpio_set_function(LED2_PIN, GPIO_FUNC_PWM);
|
||||
uint slice_num = pwm_gpio_to_slice_num(LED2_PIN);
|
||||
pwm_config config = pwm_get_default_config();
|
||||
pwm_config_set_clkdiv(&config, 4.f);
|
||||
pwm_init(slice_num, &config, true);
|
||||
|
||||
|
||||
gpio_init(ROT_CLK);
|
||||
gpio_init(ROT_DT);
|
||||
gpio_set_dir(ROT_CLK, GPIO_IN);
|
||||
gpio_set_dir(ROT_DT, GPIO_IN);
|
||||
|
||||
gpio_init(BOARD_LED_PIN);
|
||||
gpio_set_dir(BOARD_LED_PIN, GPIO_OUT);
|
||||
|
||||
gpio_init(LED_PIN);
|
||||
gpio_set_dir(LED_PIN, GPIO_OUT);
|
||||
|
||||
gpio_init(BUTTON_PIN);
|
||||
gpio_set_dir(BUTTON_PIN, GPIO_IN);
|
||||
|
||||
int rotClkState = gpio_get(ROT_CLK);
|
||||
int lastClkState = rotClkState;
|
||||
|
||||
const int bufSz = 50;
|
||||
char buf[bufSz];
|
||||
int bufIdx = 0;
|
||||
|
||||
put_morse_str(LED_PIN, "hi");
|
||||
put_morse_str(BOARD_LED_PIN, "fox");
|
||||
|
||||
while (1) {
|
||||
unsigned int c = getchar_timeout_us(20);
|
||||
if (c != PICO_ERROR_TIMEOUT) {
|
||||
printf("%c", c);
|
||||
if (c == 0x0d) {
|
||||
buf[bufIdx] = '\0';
|
||||
printf("\n");
|
||||
put_morse_str(LED_PIN, buf);
|
||||
printf(">>> ");
|
||||
bufIdx = 0;
|
||||
} else if (bufIdx < bufSz-1) {
|
||||
buf[bufIdx++] = c;
|
||||
}
|
||||
}
|
||||
if (gpio_get(BUTTON_PIN)) {
|
||||
gpio_put(BOARD_LED_PIN, 1);
|
||||
} else {
|
||||
gpio_put(BOARD_LED_PIN, 0);
|
||||
}
|
||||
|
||||
rotClkState = gpio_get(ROT_CLK);
|
||||
if (lastClkState != rotClkState && rotClkState == 1) {
|
||||
if (gpio_get(ROT_DT) != rotClkState) {
|
||||
rotCt -= 10;
|
||||
} else {
|
||||
rotCt += 10;
|
||||
}
|
||||
if (rotCt >= 256) {
|
||||
rotCt = 255;
|
||||
} else if (rotCt < 0) {
|
||||
rotCt = 0;
|
||||
}
|
||||
printf("%d\n", rotCt);
|
||||
pwm_set_gpio_level(LED2_PIN, rotCt*rotCt);
|
||||
}
|
||||
lastClkState = rotClkState;
|
||||
}
|
||||
#endif
|
||||
}
|
100
pico-stuff/morse.c
Normal file
100
pico-stuff/morse.c
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pico/stdio.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
const uint DOT_PERIOD_MS = 100;
|
||||
|
||||
const char *morse_letters[] = {
|
||||
".-", // A
|
||||
"-...", // B
|
||||
"-.-.", // C
|
||||
"-..", // D
|
||||
".", // E
|
||||
"..-.", // F
|
||||
"--.", // G
|
||||
"....", // H
|
||||
"..", // I
|
||||
".---", // J
|
||||
"-.-", // K
|
||||
".-..", // L
|
||||
"--", // M
|
||||
"-.", // N
|
||||
"---", // O
|
||||
".--.", // P
|
||||
"--.-", // Q
|
||||
".-.", // R
|
||||
"...", // S
|
||||
"-", // T
|
||||
"..-", // U
|
||||
"...-", // V
|
||||
".--", // W
|
||||
"-..-", // X
|
||||
"-.--", // Y
|
||||
"--.." // Z
|
||||
};
|
||||
|
||||
void put_morse_letter(uint led_pin, const char *pattern) {
|
||||
for (; *pattern; ++pattern) {
|
||||
gpio_put(led_pin, 1);
|
||||
if (*pattern == '.')
|
||||
sleep_ms(DOT_PERIOD_MS);
|
||||
else
|
||||
sleep_ms(DOT_PERIOD_MS * 3);
|
||||
gpio_put(led_pin, 0);
|
||||
sleep_ms(DOT_PERIOD_MS * 1);
|
||||
}
|
||||
sleep_ms(DOT_PERIOD_MS * 2);
|
||||
}
|
||||
|
||||
void put_morse_str(uint led_pin, char *str) {
|
||||
for (; *str; ++str) {
|
||||
if (*str >= 'A' && *str <= 'Z') {
|
||||
put_morse_letter(led_pin, morse_letters[*str - 'A']);
|
||||
} else if (*str >= 'a' && *str <= 'z') {
|
||||
put_morse_letter(led_pin, morse_letters[*str - 'a']);
|
||||
} else if (*str == ' ') {
|
||||
sleep_ms(DOT_PERIOD_MS * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
#ifndef PICO_DEFAULT_LED_PIN
|
||||
#warning picoboard/blinky example requires a board with a regular LED
|
||||
#else
|
||||
// const uint LED_PIN = PICO_DEFAULT_LED_PIN;
|
||||
const uint LED_PIN = 15;
|
||||
gpio_init(LED_PIN);
|
||||
gpio_set_dir(LED_PIN, GPIO_OUT);
|
||||
|
||||
const int bufSz = 50;
|
||||
char buf[bufSz];
|
||||
int bufIdx = 0;
|
||||
|
||||
put_morse_str(LED_PIN, "quick brown");
|
||||
|
||||
while (1) {
|
||||
unsigned int c = getchar_timeout_us(20);
|
||||
if (c != PICO_ERROR_TIMEOUT) {
|
||||
printf("%c", c);
|
||||
if (c == 0x0d) {
|
||||
buf[bufIdx] = '\0';
|
||||
printf("\n");
|
||||
put_morse_str(LED_PIN, buf);
|
||||
printf(">>> ");
|
||||
bufIdx = 0;
|
||||
} else if (bufIdx < bufSz-1) {
|
||||
buf[bufIdx++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
59
pico-stuff/pico_extras_import_optional.cmake
Normal file
59
pico-stuff/pico_extras_import_optional.cmake
Normal file
@ -0,0 +1,59 @@
|
||||
# This is a copy of <PICO_EXTRAS_PATH>/external/pico_extras_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate pico-extras
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
if (DEFINED ENV{PICO_EXTRAS_PATH} AND (NOT PICO_EXTRAS_PATH))
|
||||
set(PICO_EXTRAS_PATH $ENV{PICO_EXTRAS_PATH})
|
||||
message("Using PICO_EXTRAS_PATH from environment ('${PICO_EXTRAS_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_EXTRAS_FETCH_FROM_GIT} AND (NOT PICO_EXTRAS_FETCH_FROM_GIT))
|
||||
set(PICO_EXTRAS_FETCH_FROM_GIT $ENV{PICO_EXTRAS_FETCH_FROM_GIT})
|
||||
message("Using PICO_EXTRAS_FETCH_FROM_GIT from environment ('${PICO_EXTRAS_FETCH_FROM_GIT}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_EXTRAS_FETCH_FROM_GIT_PATH} AND (NOT PICO_EXTRAS_FETCH_FROM_GIT_PATH))
|
||||
set(PICO_EXTRAS_FETCH_FROM_GIT_PATH $ENV{PICO_EXTRAS_FETCH_FROM_GIT_PATH})
|
||||
message("Using PICO_EXTRAS_FETCH_FROM_GIT_PATH from environment ('${PICO_EXTRAS_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (NOT PICO_EXTRAS_PATH)
|
||||
if (PICO_EXTRAS_FETCH_FROM_GIT)
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||
if (PICO_EXTRAS_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_EXTRAS_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
FetchContent_Declare(
|
||||
pico_extras
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-extras
|
||||
GIT_TAG master
|
||||
)
|
||||
if (NOT pico_extras)
|
||||
message("Downloading Raspberry Pi Pico Extras")
|
||||
FetchContent_Populate(pico_extras)
|
||||
set(PICO_EXTRAS_PATH ${pico_extras_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
if (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../pico-extras")
|
||||
set(PICO_EXTRAS_PATH ${PICO_SDK_PATH}/../pico-extras)
|
||||
message("Defaulting PICO_EXTRAS_PATH as sibling of PICO_SDK_PATH: ${PICO_EXTRAS_PATH}")
|
||||
endif()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (PICO_EXTRAS_PATH)
|
||||
set(PICO_EXTRAS_PATH "${PICO_EXTRAS_PATH}" CACHE PATH "Path to the PICO EXTRAS")
|
||||
set(PICO_EXTRAS_FETCH_FROM_GIT "${PICO_EXTRAS_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of PICO EXTRAS from git if not otherwise locatable")
|
||||
set(PICO_EXTRAS_FETCH_FROM_GIT_PATH "${PICO_EXTRAS_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download EXTRAS")
|
||||
|
||||
get_filename_component(PICO_EXTRAS_PATH "${PICO_EXTRAS_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${PICO_EXTRAS_PATH})
|
||||
message(FATAL_ERROR "Directory '${PICO_EXTRAS_PATH}' not found")
|
||||
endif ()
|
||||
|
||||
set(PICO_EXTRAS_PATH ${PICO_EXTRAS_PATH} CACHE PATH "Path to the PICO EXTRAS" FORCE)
|
||||
add_subdirectory(${PICO_EXTRAS_PATH} pico_extras)
|
||||
endif()
|
73
pico-stuff/pico_sdk_import.cmake
Normal file
73
pico-stuff/pico_sdk_import.cmake
Normal file
@ -0,0 +1,73 @@
|
||||
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
||||
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT)
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
)
|
||||
else ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
FetchContent_Populate(pico_sdk)
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${PICO_SDK_PATH})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||
|
||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
64
pico-stuff/tablegen.py
Normal file
64
pico-stuff/tablegen.py
Normal file
@ -0,0 +1,64 @@
|
||||
# generate a flat binary tree for morse decoding
|
||||
|
||||
from functools import reduce
|
||||
|
||||
# https://stackoverflow.com/questions/71099952
|
||||
encode_table = {
|
||||
"A": ".-",
|
||||
"B": "-...",
|
||||
"C": "-.-.",
|
||||
"D": "-..",
|
||||
"E": ".",
|
||||
"F": "..-.",
|
||||
"G": "--.",
|
||||
"H": "....",
|
||||
"I": "..",
|
||||
"J": ".---",
|
||||
"K": "-.-",
|
||||
"L": ".-..",
|
||||
"M": "--",
|
||||
"N": "-.",
|
||||
"O": "---",
|
||||
"P": ".--.",
|
||||
"Q": "--.-",
|
||||
"R": ".-.",
|
||||
"S": "...",
|
||||
"T": "-",
|
||||
"U": "..-",
|
||||
"V": "...-",
|
||||
"W": ".--",
|
||||
"X": "-..-",
|
||||
"Y": "-.--",
|
||||
"Z": "--..",
|
||||
"0": "-----",
|
||||
"1": ".----",
|
||||
"2": "..---",
|
||||
"3": "...--",
|
||||
"4": "....-",
|
||||
"5": ".....",
|
||||
"6": "-....",
|
||||
"7": "--...",
|
||||
"8": "---..",
|
||||
"9": "----.",
|
||||
".": ".-.-.-",
|
||||
",": "--..--",
|
||||
"?": "..--..",
|
||||
"\\n": "-..-..",
|
||||
"\\b": ".-.-",
|
||||
"\\e": "..--",
|
||||
" ": "----",
|
||||
}
|
||||
|
||||
maxLen = reduce(lambda x, y: max(x, y), [len(code) for code in encode_table.values()])
|
||||
|
||||
letters = ['*'] + ['*'] * 2**(maxLen + 1)
|
||||
|
||||
for sym, code in encode_table.items():
|
||||
idx = 1
|
||||
for lett in code:
|
||||
idx *= 2
|
||||
if lett == '-':
|
||||
idx += 1;
|
||||
letters[idx] = sym
|
||||
|
||||
print("".join(letters))
|
324
pico-stuff/test.c
Normal file
324
pico-stuff/test.c
Normal file
@ -0,0 +1,324 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "device/usbd.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "pico/stdio.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "tusb.h"
|
||||
#include "usb_descriptors.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define max(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||
|
||||
const uint DOT_PERIOD_MS = 100;
|
||||
// wait this time before registering a morse letter
|
||||
const uint MORSE_WAIT_MS = DOT_PERIOD_MS * 3;
|
||||
|
||||
const char *morse_letters[] = {
|
||||
".-", // A
|
||||
"-...", // B
|
||||
"-.-.", // C
|
||||
"-..", // D
|
||||
".", // E
|
||||
"..-.", // F
|
||||
"--.", // G
|
||||
"....", // H
|
||||
"..", // I
|
||||
".---", // J
|
||||
"-.-", // K
|
||||
".-..", // L
|
||||
"--", // M
|
||||
"-.", // N
|
||||
"---", // O
|
||||
".--.", // P
|
||||
"--.-", // Q
|
||||
".-.", // R
|
||||
"...", // S
|
||||
"-", // T
|
||||
"..-", // U
|
||||
"...-", // V
|
||||
".--", // W
|
||||
"-..-", // X
|
||||
"-.--", // Y
|
||||
"--.." // Z
|
||||
};
|
||||
|
||||
void put_morse_letter(uint led_pin, const char *pattern) {
|
||||
for (; *pattern; ++pattern) {
|
||||
gpio_put(led_pin, 1);
|
||||
if (*pattern == '.')
|
||||
sleep_ms(DOT_PERIOD_MS);
|
||||
else
|
||||
sleep_ms(DOT_PERIOD_MS * 3);
|
||||
gpio_put(led_pin, 0);
|
||||
sleep_ms(DOT_PERIOD_MS * 1);
|
||||
}
|
||||
sleep_ms(DOT_PERIOD_MS * 2);
|
||||
}
|
||||
|
||||
void put_morse_str(uint led_pin, char *str) {
|
||||
for (; *str; ++str) {
|
||||
if (*str >= 'A' && *str <= 'Z') {
|
||||
put_morse_letter(led_pin, morse_letters[*str - 'A']);
|
||||
} else if (*str >= 'a' && *str <= 'z') {
|
||||
put_morse_letter(led_pin, morse_letters[*str - 'a']);
|
||||
} else if (*str == ' ') {
|
||||
sleep_ms(DOT_PERIOD_MS * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decodes a letter
|
||||
char morseDecode(char *code) {
|
||||
// flat binary tree (see gentable.py)
|
||||
const char morseTable[] =
|
||||
"**ETIANMSURWDKGOHVF\eL\bPJBXCYZQ* "
|
||||
"54*3***2*******16*******7***8*90************?********.**************"
|
||||
"\n**************,*************";
|
||||
|
||||
int tableIdx = 1;
|
||||
|
||||
for (; *code && tableIdx < sizeof(morseTable) / sizeof(char) - 1; code++) {
|
||||
tableIdx *= 2;
|
||||
if (*code == '-') {
|
||||
tableIdx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return morseTable[tableIdx];
|
||||
}
|
||||
|
||||
const uint DEBOUNCE_CHECK_MS = 5;
|
||||
const uint DEBOUNCE_PRESS_MS = 10;
|
||||
const uint DEBOUNCE_RELEASE_MS = 50;
|
||||
|
||||
typedef struct DebounceState {
|
||||
bool pressed;
|
||||
bool changed;
|
||||
|
||||
// ms timestamp of last change
|
||||
uint64_t lastChange;
|
||||
// ms since last change
|
||||
uint64_t sinceChange;
|
||||
// ms timestamp of last check
|
||||
uint64_t lastCheck;
|
||||
// countdown timer
|
||||
uint count;
|
||||
} DebounceState;
|
||||
|
||||
// call this in the main loop
|
||||
void debounce_get(bool rawState, DebounceState *state) {
|
||||
uint time_ms = time_us_64() / 1000;
|
||||
|
||||
if (state->lastChange == 0)
|
||||
state->lastChange = time_ms;
|
||||
state->sinceChange = time_ms - state->lastChange;
|
||||
|
||||
state->changed = false;
|
||||
|
||||
if (time_ms - state->lastCheck < DEBOUNCE_CHECK_MS) {
|
||||
return;
|
||||
}
|
||||
state->lastCheck = time_ms;
|
||||
|
||||
if (rawState == state->pressed) {
|
||||
// set timer when state is stable
|
||||
state->count = state->pressed ? DEBOUNCE_RELEASE_MS / DEBOUNCE_CHECK_MS
|
||||
: DEBOUNCE_PRESS_MS / DEBOUNCE_CHECK_MS;
|
||||
} else {
|
||||
// process change
|
||||
if (--state->count == 0) {
|
||||
// timer expires
|
||||
state->pressed = rawState;
|
||||
state->changed = true;
|
||||
state->lastChange = time_ms;
|
||||
state->count = state->pressed
|
||||
? DEBOUNCE_RELEASE_MS / DEBOUNCE_CHECK_MS
|
||||
: DEBOUNCE_PRESS_MS / DEBOUNCE_CHECK_MS;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void send_hid_report(uint8_t report_id, char key) {
|
||||
if (!tud_ready())
|
||||
return;
|
||||
|
||||
switch (report_id) {
|
||||
case REPORT_ID_KEYBOARD: {
|
||||
// counter for how many null reports to send
|
||||
// idk why sending less makes it register as a continuous keypress
|
||||
// sometimes
|
||||
const uint NULL_REPORTS = 15;
|
||||
static uint nullCounter = NULL_REPORTS;
|
||||
if (key) {
|
||||
uint8_t keycode[6] = {0};
|
||||
if ('A' <= key && 'Z' >= key) {
|
||||
keycode[0] = HID_KEY_A + (key - 'A');
|
||||
} else if ('1' <= key && key <= '9') {
|
||||
keycode[0] = HID_KEY_1 + (key - '1');
|
||||
} else {
|
||||
switch (key) {
|
||||
case '0':
|
||||
// 0 is after rather than before like in ASCII so special
|
||||
// treatment here
|
||||
keycode[0] = HID_KEY_0;
|
||||
break;
|
||||
case '\n':
|
||||
keycode[0] = HID_KEY_ENTER;
|
||||
break;
|
||||
case '\b':
|
||||
keycode[0] = HID_KEY_BACKSPACE;
|
||||
break;
|
||||
case '\e':
|
||||
keycode[0] = HID_KEY_ESCAPE;
|
||||
break;
|
||||
case ' ':
|
||||
keycode[0] = HID_KEY_SPACE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode);
|
||||
nullCounter = NULL_REPORTS;
|
||||
} else {
|
||||
if (nullCounter > 0) {
|
||||
nullCounter--;
|
||||
// this print statement adds a necessary delay for the null reports
|
||||
printf("sent null %d\n", nullCounter);
|
||||
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when sent REPORT successfully to host
|
||||
// Application can use this to send the next report
|
||||
// Note: For composite reports, report[0] is report ID
|
||||
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report,
|
||||
uint16_t len) {
|
||||
(void)instance;
|
||||
(void)len;
|
||||
|
||||
uint8_t next_report_id = report[0] + 1;
|
||||
|
||||
if (next_report_id < REPORT_ID_COUNT) {
|
||||
// send_hid_report(next_report_id, board_button_read());
|
||||
}
|
||||
}
|
||||
|
||||
const uint PIN_DASH = 17;
|
||||
const uint PIN_DOT = 16;
|
||||
|
||||
#define BUF_LEN 50
|
||||
|
||||
// return letter read
|
||||
char morse_task(void) {
|
||||
static DebounceState dotState = {0};
|
||||
static DebounceState dashState = {0};
|
||||
|
||||
static char buf[BUF_LEN + 1];
|
||||
buf[BUF_LEN] = '\0';
|
||||
static uint bufIdx = 0;
|
||||
|
||||
debounce_get(!gpio_get(PIN_DOT), &dotState);
|
||||
debounce_get(!gpio_get(PIN_DASH), &dashState);
|
||||
|
||||
uint64_t sincePress = min(dotState.sinceChange, dashState.sinceChange);
|
||||
|
||||
if (bufIdx < BUF_LEN) {
|
||||
if (dotState.pressed && dotState.changed) {
|
||||
buf[bufIdx++] = '.';
|
||||
} else if (dashState.pressed && dashState.changed) {
|
||||
buf[bufIdx++] = '-';
|
||||
}
|
||||
}
|
||||
|
||||
char c = '\0';
|
||||
|
||||
if (!dotState.pressed && !dashState.pressed) {
|
||||
if (sincePress >= MORSE_WAIT_MS && bufIdx != 0) {
|
||||
buf[bufIdx] = '\0';
|
||||
c = morseDecode(buf);
|
||||
printf("%c", c);
|
||||
|
||||
if (c == '\b') {
|
||||
printf(" \b");
|
||||
}
|
||||
|
||||
bufIdx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dotState.pressed || dashState.pressed) {
|
||||
if (tud_suspended()) {
|
||||
tud_remote_wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id,
|
||||
hid_report_type_t report_type, uint8_t const *buffer,
|
||||
uint16_t bufsize) {
|
||||
(void)instance;
|
||||
}
|
||||
|
||||
// Invoked when received GET_REPORT control request
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id,
|
||||
hid_report_type_t report_type, uint8_t *buffer,
|
||||
uint16_t reqlen) {
|
||||
// TODO not Implemented
|
||||
(void)instance;
|
||||
(void)report_id;
|
||||
(void)report_type;
|
||||
(void)buffer;
|
||||
(void)reqlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
stdio_init_all();
|
||||
#ifndef PICO_DEFAULT_LED_PIN
|
||||
#warning picoboard/blinky example requires a board with a regular LED
|
||||
#else
|
||||
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
|
||||
gpio_init(LED_PIN);
|
||||
gpio_set_dir(LED_PIN, GPIO_OUT);
|
||||
#endif
|
||||
|
||||
tusb_init();
|
||||
|
||||
put_morse_str(LED_PIN, "a");
|
||||
|
||||
gpio_init(PIN_DASH);
|
||||
gpio_init(PIN_DOT);
|
||||
gpio_set_dir(PIN_DASH, GPIO_IN);
|
||||
gpio_pull_up(PIN_DASH);
|
||||
gpio_set_dir(PIN_DOT, GPIO_IN);
|
||||
gpio_pull_up(PIN_DOT);
|
||||
|
||||
while (1) {
|
||||
tud_task();
|
||||
|
||||
char c = morse_task();
|
||||
send_hid_report(REPORT_ID_KEYBOARD, c);
|
||||
}
|
||||
}
|
118
pico-stuff/tusb_config.h
Normal file
118
pico-stuff/tusb_config.h
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by board.mk
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_DEVICE_RHPORT_NUM
|
||||
#define BOARD_DEVICE_RHPORT_NUM 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
|
||||
#ifndef BOARD_DEVICE_RHPORT_SPEED
|
||||
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
|
||||
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
|
||||
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
|
||||
#else
|
||||
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Device mode with rhport and speed defined by board.mk
|
||||
#if BOARD_DEVICE_RHPORT_NUM == 0
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||
#elif BOARD_DEVICE_RHPORT_NUM == 1
|
||||
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||
#else
|
||||
#error "Incorrect RHPort configuration"
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||
// #define CFG_TUSB_DEBUG 0
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID 1
|
||||
#define CFG_TUD_CDC 1
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 64
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
// CDC Endpoint transfer buffer size, more is faster
|
||||
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
244
pico-stuff/usb_descriptors.c
Normal file
244
pico-stuff/usb_descriptors.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "device/usbd.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "tusb.h"
|
||||
#include "usb_descriptors.h"
|
||||
|
||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||
*
|
||||
* Auto ProductID layout's Bitmap:
|
||||
* [MSB] HID | MSC | CDC [LSB]
|
||||
*/
|
||||
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
||||
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
|
||||
|
||||
#define USB_VID 0xCafe
|
||||
#define USB_BCD 0x0200
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_desc_device_t const desc_device =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = USB_BCD,
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = USB_VID,
|
||||
.idProduct = USB_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const * tud_descriptor_device_cb(void)
|
||||
{
|
||||
return (uint8_t const *) &desc_device;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HID Report Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD )),
|
||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(REPORT_ID_MOUSE )),
|
||||
TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(REPORT_ID_CONSUMER_CONTROL )),
|
||||
TUD_HID_REPORT_DESC_GAMEPAD ( HID_REPORT_ID(REPORT_ID_GAMEPAD ))
|
||||
};
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance)
|
||||
{
|
||||
(void) instance;
|
||||
return desc_hid_report;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum
|
||||
{
|
||||
ITF_NUM_HID,
|
||||
ITF_NUM_CDC,
|
||||
ITF_NUM_CDC_DATA,
|
||||
ITF_NUM_TOTAL
|
||||
};
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||
|
||||
#define EPNUM_HID 0x84
|
||||
|
||||
#define EPNUM_CDC_NOTIF 0x81
|
||||
#define EPNUM_CDC_OUT 0x02
|
||||
#define EPNUM_CDC_IN 0x82
|
||||
|
||||
uint8_t const desc_configuration[] =
|
||||
{
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
|
||||
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5),
|
||||
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64)
|
||||
};
|
||||
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
|
||||
|
||||
// other speed configuration
|
||||
uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
|
||||
|
||||
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
|
||||
tusb_desc_device_qualifier_t const desc_device_qualifier =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0x00
|
||||
};
|
||||
|
||||
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
|
||||
// device_qualifier descriptor describes information about a high-speed capable device that would
|
||||
// change if the device were operating at the other speed. If not highspeed capable stall this request.
|
||||
uint8_t const* tud_descriptor_device_qualifier_cb(void)
|
||||
{
|
||||
return (uint8_t const*) &desc_device_qualifier;
|
||||
}
|
||||
|
||||
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
|
||||
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
|
||||
{
|
||||
(void) index; // for multiple configurations
|
||||
|
||||
// other speed config is basically configuration with type = OHER_SPEED_CONFIG
|
||||
memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN);
|
||||
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
|
||||
|
||||
// this example use the same configuration for both high and full speed mode
|
||||
return desc_other_speed_config;
|
||||
}
|
||||
|
||||
#endif // highspeed
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
(void) index; // for multiple configurations
|
||||
|
||||
// This example use the same configuration for both high and full speed mode
|
||||
return desc_configuration;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// buffer to hold flash ID
|
||||
char serial[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const* string_desc_arr [] =
|
||||
{
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
"dogeystamp", // 1: Manufacturer
|
||||
"Morse-inator 2000", // 2: Product
|
||||
serial, // 3: Serials, uses the flash ID
|
||||
"Morse-inator 2000 Serial" // 4: CDC interface
|
||||
};
|
||||
|
||||
static uint16_t _desc_str[32];
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
(void) langid;
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if ( index == 0)
|
||||
{
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
}else
|
||||
{
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if (index == 3) pico_get_unique_board_id_string(serial, sizeof(serial));
|
||||
|
||||
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
|
||||
|
||||
const char* str = string_desc_arr[index];
|
||||
|
||||
// Cap at max char
|
||||
chr_count = strlen(str);
|
||||
if ( chr_count > 31 ) chr_count = 31;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for(uint8_t i=0; i<chr_count; i++)
|
||||
{
|
||||
_desc_str[1+i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
||||
|
||||
return _desc_str;
|
||||
}
|
37
pico-stuff/usb_descriptors.h
Normal file
37
pico-stuff/usb_descriptors.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef USB_DESCRIPTORS_H_
|
||||
#define USB_DESCRIPTORS_H_
|
||||
|
||||
enum
|
||||
{
|
||||
REPORT_ID_KEYBOARD = 1,
|
||||
REPORT_ID_MOUSE,
|
||||
REPORT_ID_CONSUMER_CONTROL,
|
||||
REPORT_ID_GAMEPAD,
|
||||
REPORT_ID_COUNT
|
||||
};
|
||||
|
||||
#endif /* USB_DESCRIPTORS_H_ */
|
Loading…
Reference in New Issue
Block a user