mirror of
https://github.com/whowechina/mai_pico.git
synced 2026-10-08 23:00:06 +03:00
Firmware copied from chu pico
This commit is contained in:
@@ -9,4 +9,3 @@ set(CMAKE_C_STANDARD 11)
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(lib/pico-mpr121 mpr121)
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# IIDX Pico Firmware
|
||||
|
||||
Features:
|
||||
* 1000Hz polling rate.
|
||||
* HID lights.
|
||||
* RGB turntable.
|
||||
* Configuration save.
|
||||
* Customizable through board_defs.h
|
||||
* Dymanic settings.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
add_library(pico-mpr121 INTERFACE)
|
||||
|
||||
target_include_directories(pico-mpr121
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/include
|
||||
)
|
||||
|
||||
target_link_libraries(pico-mpr121
|
||||
INTERFACE
|
||||
hardware_i2c
|
||||
)
|
||||
|
||||
target_sources(pico-mpr121
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/mpr121.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/include/mpr121.h
|
||||
)
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Antonio González
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _MPR121_H_
|
||||
#define _MPR121_H_
|
||||
|
||||
#include "pico.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
/** \file mpr121.h
|
||||
* \brief Library for using an MPR121-based touch sensor with the
|
||||
* Raspberry Pi Pico
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct mpr121_sensor {
|
||||
i2c_inst_t *i2c_port;
|
||||
uint8_t i2c_addr;
|
||||
// uint8_t i2c_sda;
|
||||
// uint8_t ic2_scl;
|
||||
} mpr121_sensor_t;
|
||||
|
||||
/*! \brief MPR121 register map
|
||||
*/
|
||||
enum mpr121_register {
|
||||
MPR121_TOUCH_STATUS_REG = 0x00u,
|
||||
MPR121_OUT_OF_RANGE_STATUS_0_REG = 0x02u,
|
||||
MPR121_OUT_OF_RANGE_STATUS_1_REG = 0x03u,
|
||||
MPR121_ELECTRODE_FILTERED_DATA_REG = 0x04u,
|
||||
MPR121_BASELINE_VALUE_REG = 0x1Eu,
|
||||
// Registers 0x2B ~ 0x7F are control and configuration registers
|
||||
MPR121_MAX_HALF_DELTA_RISING_REG = 0x2Bu,
|
||||
MPR121_NOISE_HALF_DELTA_RISING_REG = 0x2Cu,
|
||||
MPR121_NOISE_COUNT_LIMIT_RISING_REG = 0x2Du,
|
||||
MPR121_FILTER_DELAY_COUNT_RISING_REG = 0x2Eu,
|
||||
MPR121_MAX_HALF_DELTA_FALLING_REG = 0x2Fu,
|
||||
MPR121_NOISE_HALF_DELTA_FALLING_REG = 0x30u,
|
||||
MPR121_NOISE_COUNT_LIMIT_FALLING_REG = 0x31u,
|
||||
MPR121_FILTER_DELAY_COUNT_FALLING_REG = 0x32u,
|
||||
MPR121_NOISE_HALF_DELTA_TOUCHED_REG = 0x33u,
|
||||
MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG = 0x34u,
|
||||
MPR121_FILTER_DELAY_COUNT_TOUCHED_REG = 0x35u,
|
||||
// (ELEPROX 0x36 .. 0x40)
|
||||
MPR121_TOUCH_THRESHOLD_REG = 0x41u,
|
||||
MPR121_RELEASE_THRESHOLD_REG = 0x42u,
|
||||
// (ELEPROX 0x59 .. 0x5A)
|
||||
MPR121_DEBOUNCE_REG = 0x5Bu,
|
||||
MPR121_AFE_CONFIG_REG = 0x5Cu,
|
||||
MPR121_FILTER_CONFIG_REG = 0x5Du,
|
||||
MPR121_ELECTRODE_CONFIG_REG = 0x5Eu,
|
||||
MPR121_ELECTRODE_CURRENT_REG = 0x5Fu,
|
||||
MPR121_ELECTRODE_CHARGE_TIME_REG = 0x6Cu,
|
||||
MPR121_GPIO_CTRL_0_REG = 0x73u,
|
||||
MPR121_GPIO_CTRL_1_REG = 0x74u,
|
||||
MPR121_GPIO_DATA_REG = 0x75u,
|
||||
MPR121_GPIO_DIRECTION_REG = 0x76u,
|
||||
MPR121_GPIO_ENABLE_REG = 0x77u,
|
||||
MPR121_GPIO_DATA_SET_REG = 0x78u,
|
||||
MPR121_GPIO_DATA_CLEAR_REG = 0x79u,
|
||||
MPR121_GPIO_DATA_TOGGLE_REG = 0x7Au,
|
||||
MPR121_AUTOCONFIG_CONTROL_0_REG = 0x7Bu,
|
||||
MPR121_AUTOCONFIG_CONTROL_1_REG = 0x7Cu,
|
||||
MPR121_AUTOCONFIG_USL_REG = 0x7Du,
|
||||
MPR121_AUTOCONFIG_LSL_REG = 0x7Eu,
|
||||
MPR121_AUTOCONFIG_TARGET_REG = 0x7Fu,
|
||||
MPR121_SOFT_RESET_REG = 0x80u
|
||||
};
|
||||
|
||||
/*! \brief Initialise the MPR121 and configure registers
|
||||
*
|
||||
* The default parameters used here to configure the sensor are as in
|
||||
* the MPR121 Quick Start Guide (AN3944).
|
||||
*
|
||||
* \param i2c_port The I2C instance, either i2c0 or i2c1
|
||||
* \param i2c_addr The I2C address of the MPR121 device
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
void mpr121_init(i2c_inst_t *i2c_port, uint8_t i2c_addr,
|
||||
mpr121_sensor_t *sensor);
|
||||
|
||||
/*! \brief Write a value to the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param val The value to write
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_write(enum mpr121_register reg, uint8_t val,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t buf[] = {reg, val};
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, buf, 2,
|
||||
false);
|
||||
}
|
||||
|
||||
/*! \brief Read a byte from the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_read(enum mpr121_register reg, uint8_t *dst,
|
||||
mpr121_sensor_t *sensor) {
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, ®, 1,
|
||||
true);
|
||||
i2c_read_blocking(sensor->i2c_port, sensor->i2c_addr, dst, 1,
|
||||
false);
|
||||
}
|
||||
|
||||
/*! \brief Read a 2-byte value from the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_read16(enum mpr121_register reg, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t vals[2];
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, ®, 1,
|
||||
true);
|
||||
i2c_read_blocking(sensor->i2c_port, sensor->i2c_addr, vals, 2,
|
||||
false);
|
||||
*dst = vals[1] << 8 | vals[0];
|
||||
}
|
||||
|
||||
/*! \brief Set touch and release thresholds
|
||||
*
|
||||
* From the MPR121 datasheet (section 5.6):
|
||||
* > In a typical application, touch threshold is in the range 4--16,
|
||||
* > and it is several counts larger than the release threshold. This
|
||||
* > is to provide hysteresis and to prevent noise and jitter.
|
||||
*
|
||||
* \param touch Touch threshold in the range 0--255
|
||||
* \param release Release threshold in the range 0--255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_thresholds(uint8_t touch, uint8_t release,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
if (config != 0){
|
||||
// Stop mode
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
}
|
||||
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
mpr121_write(MPR121_TOUCH_THRESHOLD_REG + i * 2, touch, sensor);
|
||||
mpr121_write(MPR121_RELEASE_THRESHOLD_REG + i * 2, release,
|
||||
sensor);
|
||||
}
|
||||
|
||||
if (config != 0){
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Enable only the number of electrodes specified
|
||||
*
|
||||
* \param nelec Number of electrodes to enable
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* E.g. if `nelec` is 3, electrodes 0 to 2 will be enabled; if `nelec`
|
||||
* is 6, electrodes 0 to 5 will be enabled. From the datasheet:
|
||||
* "Enabling specific channels will save the scan time and sensing
|
||||
* field power spent on the unused channels."
|
||||
*/
|
||||
static void mpr121_enable_electrodes(uint8_t nelec,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
|
||||
// Clear bits 3-0, which controls the operation of the 12
|
||||
// electrodes.
|
||||
config &= ~0x0f;
|
||||
|
||||
// Set number of electrodes enabled
|
||||
config |= nelec;
|
||||
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Read the touch/release status of all 13 input channels
|
||||
*
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* In the value read, bits 11-0 represent electrodes 11 to 0,
|
||||
* respectively, and bit 12 is the proximity detection channel. Each
|
||||
* bit represent the status of these channels: 1 if the channel is
|
||||
* touched, 0 if it is released.
|
||||
*/
|
||||
static void mpr121_touched(uint16_t *dst, mpr121_sensor_t *sensor) {
|
||||
mpr121_read16(MPR121_TOUCH_STATUS_REG, dst, sensor);
|
||||
*dst &= 0x0fff;
|
||||
}
|
||||
|
||||
/*! \brief Determine whether an electrode has been touched
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_is_touched(uint8_t electrode, bool *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint16_t touched;
|
||||
mpr121_touched(&touched, sensor);
|
||||
*dst = (bool) ((touched >> electrode) & 1);
|
||||
}
|
||||
|
||||
/*! \brief Read an electrode's filtered data value
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* The data range of the filtered data is 0 to 1024.
|
||||
* \sa mpr121_baseline_value
|
||||
*/
|
||||
static void mpr121_filtered_data(uint8_t electrode, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
mpr121_read16(MPR121_ELECTRODE_FILTERED_DATA_REG + (electrode * 2),
|
||||
dst, sensor);
|
||||
// Filtered data is 10-bit
|
||||
*dst &= 0x3ff;
|
||||
}
|
||||
|
||||
/*! \brief Read an electrode's baseline value
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* From the MPR112 datasheet:
|
||||
* > Along with the 10-bit electrode filtered data output, each channel
|
||||
* > also has a 10-bit baseline value. These values are the output of
|
||||
* > the internal baseline filter operation tracking the slow-voltage
|
||||
* > variation of the background capacitance change. Touch/release
|
||||
* > detection is made based on the comparison between the 10-bit
|
||||
* > electrode filtered data and the 10-bit baseline value.
|
||||
*
|
||||
* > Although internally the baseline value is 10-bit, users can only
|
||||
* > access the 8 MSB of the 10-bit baseline value through the baseline
|
||||
* > value registers.
|
||||
*
|
||||
* \sa mpr121_filtered_data
|
||||
*/
|
||||
static void mpr121_baseline_value(uint8_t electrode, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint8_t baseline;
|
||||
mpr121_read(MPR121_BASELINE_VALUE_REG + electrode, &baseline,
|
||||
sensor);
|
||||
// From the datasheet: Although internally the baseline value is
|
||||
// 10-bit, users can only access the 8 MSB of the 10-bit baseline
|
||||
// value through the baseline value registers. The read out from the
|
||||
// baseline register must be left shift two bits before comparing it
|
||||
// with the 10-bit electrode data.
|
||||
*dst = baseline << 2;
|
||||
}
|
||||
|
||||
/*! \brief Set the Max Half Delta
|
||||
*
|
||||
* The Max Half Delta determines the largest magnitude of variation to
|
||||
* pass through the third level filter. See application note MPR121
|
||||
* Baseline System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 1~63
|
||||
* \param falling Value in the range 1~63
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_max_half_delta(uint8_t rising, uint8_t falling,
|
||||
mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write MHD values
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_FALLING_REG, falling, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Noise Half Delta
|
||||
*
|
||||
* The Noise Half Delta determines the incremental change when
|
||||
* non-noise drift is detected. See application note MPR121 Baseline
|
||||
* System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 1~63
|
||||
* \param falling Value in the range 1~63
|
||||
* \param touched Value in the range 1~63
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_noise_half_delta(uint8_t rising, uint8_t falling,
|
||||
uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write NHD values
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_FALLING_REG, falling, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_TOUCHED_REG, touched, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Noise Count Limit
|
||||
*
|
||||
* The Noise Count Limit determines the number of samples consecutively
|
||||
* greater than the Max Half Delta necessary before it can be
|
||||
* determined that it is non-noise. See application note MPR121 Baseline
|
||||
* System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 0~255
|
||||
* \param falling Value in the range 0~255
|
||||
* \param touched Value in the range 0~255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_noise_count_limit(uint8_t rising,
|
||||
uint8_t falling, uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write new NCL values
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_FALLING_REG, falling, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG, touched, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Filter Delay Limit
|
||||
*
|
||||
* The Filter Delay Limit determines the rate of operation of the
|
||||
* filter. A larger number makes it operate slower. See application
|
||||
* note MPR121 Baseline System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 0~255
|
||||
* \param falling Value in the range 0~255
|
||||
* \param touched Value in the range 0~255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_filter_delay_limit(uint8_t rising,
|
||||
uint8_t falling, uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write new FDL values
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_FALLING_REG, falling,
|
||||
sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_TOUCHED_REG, touched,
|
||||
sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Antonio González
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "mpr121.h"
|
||||
|
||||
void mpr121_init(i2c_inst_t *i2c_port, uint8_t i2c_addr,
|
||||
mpr121_sensor_t *sensor) {
|
||||
sensor->i2c_port = i2c_port;
|
||||
sensor->i2c_addr = i2c_addr;
|
||||
|
||||
// Enter stop mode by setting ELEPROX_EN and ELE_EN bits to zero.
|
||||
// This is needed because register write operations can only take
|
||||
// place in stop mode.
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
|
||||
// Writing 0x80 (SOFT_RESET) with 0x63 asserts soft reset.
|
||||
mpr121_write(MPR121_SOFT_RESET_REG, 0x63, sensor);
|
||||
|
||||
// == Capacitance sensing settings (AN2889), Filtering and =========
|
||||
// timing settings (AN3890)
|
||||
|
||||
// These settings are configured in two registers: the Filter and
|
||||
// Global CDC CDT Configuration registers (0x5C, 0x5D).
|
||||
//
|
||||
// Charge-discharge current (CDC) and charge-discharge time (CDT)
|
||||
// can be configured globally or on a per-electrode basis. Here,
|
||||
// The global CDC and CDT values are set to their defaults, and then
|
||||
// these values are overriden by independently configuring each
|
||||
// electrode (auto-configuration).
|
||||
|
||||
// Filter/global CDC configuration register (0x5C)
|
||||
//
|
||||
// First filter iterations (FFI), bits 7-6. Number of samples taken
|
||||
// as input to the first level of filtering. Default is 0b00 (sets
|
||||
// samples taken to 6)
|
||||
//
|
||||
// Charge-discharge current (CDC), bits 5-0. Sets the value of
|
||||
// charge-discharge current applied to the electrode. Max is 63 µA
|
||||
// in 1 µA steps. Default is 0b010000 (16 µA)
|
||||
//
|
||||
// AFE configuration register default, 0b00010000 = 0x10
|
||||
mpr121_write(MPR121_AFE_CONFIG_REG, 0x10, sensor);
|
||||
|
||||
// Filter/global CDC configuration register (0x5D)
|
||||
//
|
||||
// Charge discharge time (CDT), bits 7-5. Selects the global value
|
||||
// of charge time applied to electrode. The maximum is 32 μs,
|
||||
// programmable as 2^(n-2) μs. Default is 0b001 (time is set to
|
||||
// 0.5 µs)
|
||||
//
|
||||
// Second filter iterations (SFI), bits 4-3. Selects the number of
|
||||
// samples taken for the second level filter. Default is 0b00
|
||||
// (number of samples is set to 4)
|
||||
//
|
||||
// Electrode sample interval (ESI), bits 2-0. Controls the sampling
|
||||
// rate of the device. The maximum is 128 ms, programmable to 2^n
|
||||
// ms. Decrease this value for better response time, increase to
|
||||
// save power. Default is 0b100 (period set to 16 ms).
|
||||
//
|
||||
// Filter configuration register default, 0b00100100 = 0x24
|
||||
// I do not need power saving features but I want fast responses,
|
||||
// so I set this to 0x20.
|
||||
mpr121_write(MPR121_FILTER_CONFIG_REG, 0x20, sensor);
|
||||
|
||||
// Auto-configuration
|
||||
//
|
||||
// Sets automatically charge current (CDC) and time (CDT) values for
|
||||
// each electrode.
|
||||
//
|
||||
// Autoconfig USL register: the upper limit for the
|
||||
// auto-configuration. This value (and those that follow below)
|
||||
// were calculated based on Vdd = 3.3 V and following the equations
|
||||
// in NXP Application Note AN3889.
|
||||
// USL = 201 = 0xC9
|
||||
mpr121_write(MPR121_AUTOCONFIG_USL_REG, 0xC9, sensor);
|
||||
|
||||
// Autoconfig target level register: the target level for the
|
||||
// auto-configuration baseline search.
|
||||
// TL = 181 = 0xB5
|
||||
mpr121_write(MPR121_AUTOCONFIG_TARGET_REG, 0xB5, sensor);
|
||||
|
||||
// Autoconfig LSL register: the lower limit for the
|
||||
// auto-configuration.
|
||||
// LSL = 131 = 0x83
|
||||
mpr121_write(MPR121_AUTOCONFIG_LSL_REG, 0x83, sensor);
|
||||
|
||||
// Autoconfiguration control register. Default value is 0b00001011 =
|
||||
// 0x0B, where:
|
||||
//
|
||||
// First filter iterations (FFI), bits 7-6. Must be the same value
|
||||
// of FFI as in register MPR121_AFE_CONFIG_REG (0x5C) above;
|
||||
// default is 0b00.
|
||||
//
|
||||
// Retry, bits 5-4. Default is disabled, 0b00.
|
||||
//
|
||||
// Baseline value adjust (BVA), bits 3-2. This value must be the
|
||||
// same as the CL (calibration lock) value in the Electrode
|
||||
// Configuration Register, below, i.e. 0b10.
|
||||
//
|
||||
// Automatic Reconfiguration Enable (ARE), bit 1. Default is 0b1,
|
||||
// enabled.
|
||||
//
|
||||
// Automatic Reconfiguration Enable (ACE), bit 0. Default is 0b1,
|
||||
// enabled.
|
||||
mpr121_write(MPR121_AUTOCONFIG_CONTROL_0_REG, 0x0B, sensor);
|
||||
|
||||
// == Baseline system (AN3891) =====================================
|
||||
|
||||
// Maximum Half Delta (MHD): Determines the largest magnitude of
|
||||
// variation to pass through the baseline filter. The range of the
|
||||
// effective value is 1~63.
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_RISING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_FALLING_REG, 0x01, sensor);
|
||||
|
||||
// Noise Half Delta (NHD): Determines the incremental change when
|
||||
// non-noise drift is detected. The range of the effective value is
|
||||
// 1~63.
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_RISING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_FALLING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_TOUCHED_REG, 0x01, sensor);
|
||||
|
||||
// Noise Count Limit (NCL): Determines the number of samples
|
||||
// consecutively greater than the Max Half Delta value. This is
|
||||
// necessary to determine that it is not noise. The range of the
|
||||
// effective value is 0~255.
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_RISING_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_FALLING_REG, 0xFF, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG, 0x00, sensor);
|
||||
|
||||
// Filter Delay Count Limit (FDL): Determines the operation rate of
|
||||
// the filter. A larger count limit means the filter delay is
|
||||
// operating more slowly. The range of the effective value is 0~255.
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_RISING_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_FALLING_REG, 0x02, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_TOUCHED_REG, 0x00, sensor);
|
||||
|
||||
// == Debounce and thresholds (AN3892) =============================
|
||||
|
||||
// Debounce. Value range for each is 0~7.
|
||||
// Bits 2-0, debounce touch (DT).
|
||||
// Bits 6-4, debounce release (DR).
|
||||
mpr121_write(MPR121_DEBOUNCE_REG, 0x00, sensor);
|
||||
|
||||
// Touch and release threshold values for all electrodes.
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
mpr121_write(MPR121_TOUCH_THRESHOLD_REG + i * 2, 0x0F, sensor);
|
||||
mpr121_write(MPR121_RELEASE_THRESHOLD_REG + i * 2, 0x0A, sensor);
|
||||
}
|
||||
|
||||
// Electrode Configuration Register (ECR, 0x5E). This must be the
|
||||
// last register to write to because setting ELEPROX_EN and/or
|
||||
// ELE_EN to non-zero puts the sensor in Run Mode.
|
||||
//
|
||||
// Calibration lock (CL), bits 7-6. The default on reset is 0b00
|
||||
// (CL enabled). Here I set this instead to 0b10 because this
|
||||
// enables baseline tracking with initial baseline value loaded
|
||||
// with the 5 high bits of the first electrode data value, which
|
||||
// makes the sensor stabilise sooner. Note that ths value must
|
||||
// match BVA bits in the Auto-configure Control Register above.
|
||||
//
|
||||
// Proximity enable (ELEPROX_EN), bits 5-4. Default, 0b00
|
||||
// (proximity detection disabled).
|
||||
//
|
||||
// Electrode enabled (ELE_EN), bits 3-0. Default, 0b1100 (enable
|
||||
// all 12 electrodes).
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x8C, sensor);
|
||||
}
|
||||
Binary file not shown.
@@ -4,8 +4,8 @@ set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip)
|
||||
function(make_firmware board board_def)
|
||||
pico_sdk_init()
|
||||
add_executable(${board}
|
||||
main.c buttons.c rgb.c save.c config.c setup.c
|
||||
usb_descriptors.c)
|
||||
main.c touch.c rgb.c save.c config.c cmd.c
|
||||
mpr121.c usb_descriptors.c)
|
||||
target_compile_definitions(${board} PUBLIC ${board_def})
|
||||
pico_enable_stdio_usb(${board} 1)
|
||||
pico_enable_stdio_uart(${board} 0)
|
||||
@@ -21,13 +21,13 @@ function(make_firmware board board_def)
|
||||
target_link_libraries(${board} PRIVATE
|
||||
pico_multicore pico_stdlib hardware_pio hardware_pwm hardware_flash
|
||||
hardware_adc hardware_i2c hardware_watchdog
|
||||
tinyusb_device tinyusb_board pico-mpr121)
|
||||
tinyusb_device tinyusb_board)
|
||||
|
||||
pico_add_extra_outputs(${board})
|
||||
|
||||
add_custom_command(TARGET ${board} POST_BUILD
|
||||
COMMAND cp ${board}.uf2 /mnt/d/Code/iidx_pico/firmware/build)
|
||||
COMMAND cp ${board}.uf2 ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||
endfunction()
|
||||
|
||||
make_firmware(mai_pico BOARD_IIDX_PICO)
|
||||
make_firmware(mai_pico BOARD_MAI_PICO)
|
||||
|
||||
|
||||
@@ -1,32 +1,19 @@
|
||||
/*
|
||||
* IIDX Controller Board Definitions
|
||||
* Mai Controller Board Definitions
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#if defined BOARD_IIDX_PICO
|
||||
/* List of button pins */
|
||||
#define BUTTON_DEF { 8, 7, 6, 5, 4, 3, 2, 12, 11, 10, 9, 1, 0 }
|
||||
#if defined BOARD_MAI_PICO
|
||||
|
||||
#define BUTTON_RGB_PIN 13
|
||||
#define BUTTON_RGB_ORDER GRB // or RGB
|
||||
#define I2C_PORT i2c0
|
||||
#define I2C_SDA 16
|
||||
#define I2C_SCL 17
|
||||
#define I2C_FREQ 733*1000
|
||||
|
||||
#define BUTTON_RGB_NUM 11
|
||||
#define BUTTON_RGB_MAP { 6, 0, 5, 1, 4, 2, 3, 7, 8, 9, 10}
|
||||
|
||||
|
||||
#define TT_RGB_PIN 28
|
||||
#define TT_RGB_ORDER GRB // or RGB
|
||||
|
||||
#define TT_AS5600_ANALOG 26
|
||||
#define TT_AS5600_SCL 27
|
||||
#define TT_AS5600_SDA 26
|
||||
#define TT_AS5600_I2C i2c1
|
||||
|
||||
// Alternative I2C pins
|
||||
//#define TT_AS5600_SCL 21
|
||||
//#define TT_AS5600_SDA 20
|
||||
//#define TT_AS5600_I2C i2c0
|
||||
#define RGB_PIN 2
|
||||
#define RGB_ORDER GRB // or RGB
|
||||
|
||||
#define NKRO_KEYMAP "1aqz2swx3dec4frv5gtb6hyn7jum8ki90olp,."
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Controller Buttons
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
* A button consists of a switch and an LED
|
||||
*/
|
||||
|
||||
#include "buttons.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bsp/board.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
#include "board_defs.h"
|
||||
|
||||
static const uint8_t BUTTON_GPIOS[] = BUTTON_DEF;
|
||||
#define BUTTON_NUM (sizeof(BUTTON_GPIOS))
|
||||
|
||||
static bool sw_val[BUTTON_NUM]; /* true if pressed */
|
||||
static uint64_t sw_freeze_time[BUTTON_NUM];
|
||||
|
||||
#define LIMIT_MAX(a, max, def) { if (a > max) a = def; }
|
||||
|
||||
void button_init()
|
||||
{
|
||||
for (int i = 0; i < BUTTON_NUM; i++) {
|
||||
sw_val[i] = false;
|
||||
sw_freeze_time[i] = 0;
|
||||
int8_t gpio = BUTTON_GPIOS[i];
|
||||
gpio_init(gpio);
|
||||
gpio_set_function(gpio, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(gpio, GPIO_IN);
|
||||
gpio_pull_up(gpio);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t button_num()
|
||||
{
|
||||
return BUTTON_NUM;
|
||||
}
|
||||
|
||||
uint8_t button_gpio(uint8_t id)
|
||||
{
|
||||
return BUTTON_GPIOS[id];
|
||||
}
|
||||
|
||||
/* If a switch flips, it freezes for a while */
|
||||
#define DEBOUNCE_FREEZE_TIME_US 5000
|
||||
uint16_t button_read()
|
||||
{
|
||||
uint64_t now = time_us_64();
|
||||
uint16_t buttons = 0;
|
||||
|
||||
for (int i = BUTTON_NUM - 1; i >= 0; i--) {
|
||||
bool sw_pressed = !gpio_get(BUTTON_GPIOS[i]);
|
||||
|
||||
if (now >= sw_freeze_time[i]) {
|
||||
if (sw_pressed != sw_val[i]) {
|
||||
sw_val[i] = sw_pressed;
|
||||
sw_freeze_time[i] = now + DEBOUNCE_FREEZE_TIME_US;
|
||||
}
|
||||
}
|
||||
|
||||
buttons <<= 1;
|
||||
if (sw_val[i]) {
|
||||
buttons |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Controller Buttons
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#ifndef BUTTONS_H
|
||||
#define BUTTONS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void button_init();
|
||||
uint8_t button_num();
|
||||
uint8_t button_gpio(uint8_t id);
|
||||
|
||||
uint16_t button_read();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,416 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "pico/stdio.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "touch.h"
|
||||
#include "save.h"
|
||||
|
||||
#define SENSE_LIMIT_MAX 9
|
||||
#define SENSE_LIMIT_MIN -9
|
||||
|
||||
#define MAX_COMMANDS 20
|
||||
#define MAX_PARAMETERS 5
|
||||
#define MAX_PARAMETER_LENGTH 20
|
||||
|
||||
const char *mai_prompt = "mai_pico>";
|
||||
|
||||
typedef void (*cmd_handler_t)(int argc, char *argv[]);
|
||||
|
||||
static const char *commands[MAX_COMMANDS];
|
||||
static cmd_handler_t handlers[MAX_COMMANDS];
|
||||
static int num_commands = 0;
|
||||
|
||||
static void register_command(const char *cmd, cmd_handler_t handler)
|
||||
{
|
||||
if (num_commands < MAX_COMMANDS) {
|
||||
commands[num_commands] = cmd;
|
||||
handlers[num_commands] = handler;
|
||||
num_commands++;
|
||||
}
|
||||
}
|
||||
|
||||
// return -1 if not matched, return -2 if ambiguous
|
||||
static int match_prefix(const char *str[], int num, const char *prefix)
|
||||
{
|
||||
int match = -1;
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; (i < num) && str[i]; i++) {
|
||||
if (strncmp(str[i], prefix, strlen(prefix)) == 0) {
|
||||
if (found) {
|
||||
return -2;
|
||||
}
|
||||
found = true;
|
||||
match = i;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static void handle_help(int argc, char *argv[])
|
||||
{
|
||||
printf("Available commands:\n");
|
||||
for (int i = 0; i < num_commands; i++) {
|
||||
printf("%s\n", commands[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void disp_colors()
|
||||
{
|
||||
printf("[Colors]\n");
|
||||
printf(" Key on: %06x, off: %06x\n",
|
||||
mai_cfg->colors.key_on, mai_cfg->colors.key_off);
|
||||
}
|
||||
|
||||
static void disp_style()
|
||||
{
|
||||
printf("[Style]\n");
|
||||
printf(" Key: %d, Level: %d\n", mai_cfg->style.key, mai_cfg->style.level);
|
||||
}
|
||||
|
||||
static void disp_sense()
|
||||
{
|
||||
printf("[Sense]\n");
|
||||
printf(" Filter: %d, %d\n", mai_cfg->sense.filter >> 4, mai_cfg->sense.filter & 0xf);
|
||||
printf(" Sensitivity (global: %+d):\n", mai_cfg->sense.global);
|
||||
printf(" | 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|\n");
|
||||
printf(" ---------------------------------------------------\n");
|
||||
printf(" A |");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%+2d|", mai_cfg->sense.keys[i * 2]);
|
||||
}
|
||||
printf("\n B |");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%+2d|", mai_cfg->sense.keys[i * 2 + 1]);
|
||||
}
|
||||
printf("\n");
|
||||
printf(" Debounce (touch, release): %d, %d\n",
|
||||
mai_cfg->sense.debounce_touch, mai_cfg->sense.debounce_release);
|
||||
}
|
||||
|
||||
static void disp_hid()
|
||||
{
|
||||
printf("[HID]\n");
|
||||
printf(" Joy: %s, NKRO: %s.\n",
|
||||
mai_cfg->hid.joy ? "on" : "off",
|
||||
mai_cfg->hid.nkro ? "on" : "off" );
|
||||
}
|
||||
|
||||
void handle_display(int argc, char *argv[])
|
||||
{
|
||||
const char *usage = "Usage: display [colors|style|tof|sense|hid]\n";
|
||||
if (argc > 1) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
disp_colors();
|
||||
disp_style();
|
||||
disp_sense();
|
||||
disp_hid();
|
||||
return;
|
||||
}
|
||||
|
||||
const char *choices[] = {"colors", "style", "sense", "hid"};
|
||||
switch (match_prefix(choices, 5, argv[0])) {
|
||||
case 0:
|
||||
disp_colors();
|
||||
break;
|
||||
case 1:
|
||||
disp_style();
|
||||
break;
|
||||
case 2:
|
||||
disp_sense();
|
||||
break;
|
||||
case 3:
|
||||
disp_hid();
|
||||
break;
|
||||
default:
|
||||
printf(usage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int fps[2];
|
||||
void fps_count(int core)
|
||||
{
|
||||
static uint32_t last[2] = {0};
|
||||
static int counter[2] = {0};
|
||||
|
||||
counter[core]++;
|
||||
|
||||
uint32_t now = time_us_32();
|
||||
if (now - last[core] < 1000000) {
|
||||
return;
|
||||
}
|
||||
last[core] = now;
|
||||
fps[core] = counter[core];
|
||||
counter[core] = 0;
|
||||
}
|
||||
|
||||
static void handle_fps(int argc, char *argv[])
|
||||
{
|
||||
printf("FPS: core 0: %d, core 1: %d\n", fps[0], fps[1]);
|
||||
}
|
||||
|
||||
static void handle_hid(int argc, char *argv[])
|
||||
{
|
||||
const char *usage = "Usage: hid <joy|nkro|both>\n";
|
||||
if (argc != 1) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *choices[] = {"joy", "nkro", "both"};
|
||||
int match = match_prefix(choices, 3, argv[0]);
|
||||
if (match < 0) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
mai_cfg->hid.joy = ((match == 0) || (match == 2)) ? 1 : 0;
|
||||
mai_cfg->hid.nkro = ((match == 1) || (match == 2)) ? 1 : 0;
|
||||
config_changed();
|
||||
disp_hid();
|
||||
}
|
||||
|
||||
static int extract_non_neg_int(const char *param, int len)
|
||||
{
|
||||
if (len == 0) {
|
||||
len = strlen(param);
|
||||
}
|
||||
int result = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!isdigit(param[i])) {
|
||||
return -1;
|
||||
}
|
||||
result = result * 10 + param[i] - '0';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void handle_filter(int argc, char *argv[])
|
||||
{
|
||||
const char *usage = "Usage: filter <first> <second>\n"
|
||||
" first, second: 0..3\n";
|
||||
if ((argc < 2) || (argc > 2)) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
int ffi = extract_non_neg_int(argv[0], 0);
|
||||
int sfi = extract_non_neg_int(argv[1], 0);
|
||||
|
||||
if ((ffi < 0) || (ffi > 3) || (sfi < 0) || (sfi > 3)) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
mai_cfg->sense.filter = (ffi << 4) | sfi;
|
||||
|
||||
touch_update_config();
|
||||
config_changed();
|
||||
disp_sense();
|
||||
}
|
||||
|
||||
static uint8_t *extract_key(const char *param)
|
||||
{
|
||||
int len = strlen(param);
|
||||
|
||||
int offset;
|
||||
if (toupper(param[len - 1]) == 'A') {
|
||||
offset = 0;
|
||||
} else if (toupper(param[len - 1]) == 'B') {
|
||||
offset = 1;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int id = extract_non_neg_int(param, len - 1) - 1;
|
||||
if ((id < 0) || (id > 15)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &mai_cfg->sense.keys[id * 2 + offset];
|
||||
}
|
||||
|
||||
static void sense_do_op(int8_t *target, char op)
|
||||
{
|
||||
if (op == '+') {
|
||||
if (*target < SENSE_LIMIT_MAX) {
|
||||
(*target)++;
|
||||
}
|
||||
} else if (op == '-') {
|
||||
if (*target > SENSE_LIMIT_MIN) {
|
||||
(*target)--;
|
||||
}
|
||||
} else if (op == '0') {
|
||||
*target = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_sense(int argc, char *argv[])
|
||||
{
|
||||
const char *usage = "Usage: sense [key|*] <+|-|0>\n"
|
||||
"Example:\n"
|
||||
" >sense +\n"
|
||||
" >sense -\n"
|
||||
" >sense 1A +\n"
|
||||
" >sense 13B -\n";
|
||||
" >sense * 0\n";
|
||||
if ((argc < 1) || (argc > 2)) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *op = argv[argc - 1];
|
||||
if ((strlen(op) != 1) || !strchr("+-0", op[0])) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
sense_do_op(&mai_cfg->sense.global, op[0]);
|
||||
} else {
|
||||
if (strcmp(argv[0], "*") == 0) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
sense_do_op(&mai_cfg->sense.keys[i], op[0]);
|
||||
}
|
||||
} else {
|
||||
uint8_t *key = extract_key(argv[0]);
|
||||
if (!key) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
sense_do_op(key, op[0]);
|
||||
}
|
||||
}
|
||||
|
||||
touch_update_config();
|
||||
config_changed();
|
||||
disp_sense();
|
||||
}
|
||||
|
||||
static void handle_debounce(int argc, char *argv[])
|
||||
{
|
||||
const char *usage = "Usage: debounce <touch> [release]\n"
|
||||
" touch, release: 0..7\n";
|
||||
if ((argc < 1) || (argc > 2)) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
int touch = mai_cfg->sense.debounce_touch;
|
||||
int release = mai_cfg->sense.debounce_release;
|
||||
if (argc >= 1) {
|
||||
touch = extract_non_neg_int(argv[0], 0);
|
||||
}
|
||||
if (argc == 2) {
|
||||
release = extract_non_neg_int(argv[1], 0);
|
||||
}
|
||||
|
||||
if ((touch < 0) || (release < 0) ||
|
||||
(touch > 7) || (release > 7)) {
|
||||
printf(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
mai_cfg->sense.debounce_touch = touch;
|
||||
mai_cfg->sense.debounce_release = release;
|
||||
|
||||
touch_update_config();
|
||||
config_changed();
|
||||
disp_sense();
|
||||
}
|
||||
|
||||
static void handle_save()
|
||||
{
|
||||
save_request(true);
|
||||
}
|
||||
|
||||
static void handle_factory_reset()
|
||||
{
|
||||
config_factory_reset();
|
||||
printf("Factory reset done.\n");
|
||||
}
|
||||
|
||||
void cmd_init()
|
||||
{
|
||||
register_command("?", handle_help);
|
||||
register_command("display", handle_display);
|
||||
register_command("fps", handle_fps);
|
||||
register_command("hid", handle_hid);
|
||||
register_command("filter", handle_filter);
|
||||
register_command("sense", handle_sense);
|
||||
register_command("debounce", handle_debounce);
|
||||
register_command("save", handle_save);
|
||||
register_command("factory", config_factory_reset);
|
||||
}
|
||||
|
||||
static char cmd_buf[256];
|
||||
static int cmd_len = 0;
|
||||
|
||||
static void process_cmd()
|
||||
{
|
||||
char *argv[MAX_PARAMETERS];
|
||||
int argc;
|
||||
|
||||
char *cmd = strtok(cmd_buf, " \n");
|
||||
|
||||
if (strlen(cmd) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
argc = 0;
|
||||
while ((argc < MAX_PARAMETERS) &&
|
||||
(argv[argc] = strtok(NULL, " \n")) != NULL) {
|
||||
argc++;
|
||||
}
|
||||
|
||||
int match = match_prefix(commands, num_commands, cmd);
|
||||
if (match == -2) {
|
||||
printf("Ambiguous command.\n");
|
||||
return;
|
||||
}
|
||||
if (match == -1) {
|
||||
printf("Unknown command.\n");
|
||||
handle_help(0, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
handlers[match](argc, argv);
|
||||
}
|
||||
|
||||
void cmd_run()
|
||||
{
|
||||
int c = getchar_timeout_us(0);
|
||||
if (c == EOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((c != '\n') && (c != '\r')) {
|
||||
if (cmd_len < sizeof(cmd_buf) - 2) {
|
||||
cmd_buf[cmd_len] = c;
|
||||
printf("%c", c);
|
||||
cmd_len++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cmd_buf[cmd_len] = '\0';
|
||||
cmd_len = 0;
|
||||
|
||||
printf("\n");
|
||||
|
||||
process_cmd();
|
||||
|
||||
printf(mai_prompt);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Mai Controller Command Line
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#ifndef CMD_H
|
||||
#define CMD_H
|
||||
|
||||
void cmd_init();
|
||||
void cmd_run();
|
||||
void fps_count(int core);
|
||||
|
||||
#endif
|
||||
+38
-43
@@ -1,68 +1,63 @@
|
||||
/*
|
||||
* Controller Config Data
|
||||
* Controller Config and Runtime Data
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
* Config is a global data structure that stores all the configuration
|
||||
* Runtime is something to share between files.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "save.h"
|
||||
|
||||
iidx_cfg_t *iidx_cfg;
|
||||
mai_cfg_t *mai_cfg;
|
||||
|
||||
static iidx_cfg_t default_cfg = {
|
||||
.key_off = { {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}},
|
||||
.key_on = { {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40},
|
||||
{40,40,40}, {40,40,40}, {40,40,40}, {40,40,40}, {40,40,40},
|
||||
static mai_cfg_t default_cfg = {
|
||||
.colors = {
|
||||
.key_on = 0x00FF00,
|
||||
.key_off = 0x000000,
|
||||
},
|
||||
.tt_led = {
|
||||
.start = 0,
|
||||
.num = 24,
|
||||
.effect = 0,
|
||||
.param = 0,
|
||||
.mode = 0,
|
||||
.style = {
|
||||
.key = 0,
|
||||
.level = 7,
|
||||
},
|
||||
.tt_sensor = {
|
||||
.mode = 2,
|
||||
.deadzone = 1,
|
||||
.ppr = 1,
|
||||
.sense = {
|
||||
.filter = 0x11,
|
||||
.debounce_touch = 1,
|
||||
.debounce_release = 2,
|
||||
},
|
||||
.hid = {
|
||||
.joy = 1,
|
||||
.nkro = 0,
|
||||
},
|
||||
.effects = {
|
||||
.e1 = 255,
|
||||
.e2 = 128,
|
||||
.e3 = 128,
|
||||
.e4 = 128,
|
||||
},
|
||||
.level = 128,
|
||||
.konami = false,
|
||||
};
|
||||
|
||||
mai_runtime_t *mai_runtime;
|
||||
|
||||
static void config_loaded()
|
||||
{
|
||||
if (iidx_cfg->tt_led.num == 0) {
|
||||
iidx_cfg->tt_led.num = 24;
|
||||
if (mai_cfg->style.level > 10) {
|
||||
mai_cfg->style.level = default_cfg.style.level;
|
||||
config_changed();
|
||||
}
|
||||
if ((iidx_cfg->tt_led.start > 8) ||
|
||||
(iidx_cfg->tt_led.start + iidx_cfg->tt_led.num > 128)) {
|
||||
iidx_cfg->tt_led.start = 0;
|
||||
iidx_cfg->tt_led.num = 24;
|
||||
if ((mai_cfg->sense.filter & 0x0f) > 3 ||
|
||||
((mai_cfg->sense.filter >> 4) & 0x0f) > 3) {
|
||||
mai_cfg->sense.filter = default_cfg.sense.filter;
|
||||
config_changed();
|
||||
}
|
||||
if (iidx_cfg->tt_sensor.deadzone > 2) {
|
||||
iidx_cfg->tt_sensor.deadzone = 0;
|
||||
if ((mai_cfg->sense.global > 9) || (mai_cfg->sense.global < -9)) {
|
||||
mai_cfg->sense.global = default_cfg.sense.global;
|
||||
config_changed();
|
||||
}
|
||||
if (iidx_cfg->tt_led.mode > 2) {
|
||||
iidx_cfg->tt_led.mode = 0;
|
||||
config_changed();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if ((mai_cfg->sense.keys[i] > 9) || (mai_cfg->sense.keys[i] < -9)) {
|
||||
mai_cfg->sense.keys[i] = default_cfg.sense.keys[i];
|
||||
config_changed();
|
||||
}
|
||||
}
|
||||
if (iidx_cfg->tt_sensor.mode > 3) {
|
||||
iidx_cfg->tt_sensor.mode = 2;
|
||||
config_changed();
|
||||
}
|
||||
if (iidx_cfg->tt_sensor.ppr > 3) {
|
||||
iidx_cfg->tt_sensor.ppr = 1;
|
||||
if ((mai_cfg->sense.debounce_touch > 7) |
|
||||
(mai_cfg->sense.debounce_release > 7)) {
|
||||
mai_cfg->sense.debounce_touch = default_cfg.sense.debounce_touch;
|
||||
mai_cfg->sense.debounce_release = default_cfg.sense.debounce_release;
|
||||
config_changed();
|
||||
}
|
||||
}
|
||||
@@ -74,11 +69,11 @@ void config_changed()
|
||||
|
||||
void config_factory_reset()
|
||||
{
|
||||
*iidx_cfg = default_cfg;
|
||||
*mai_cfg = default_cfg;
|
||||
save_request(true);
|
||||
}
|
||||
|
||||
void config_init()
|
||||
{
|
||||
iidx_cfg = (iidx_cfg_t *)save_alloc(sizeof(iidx_cfg), &default_cfg, config_loaded);
|
||||
mai_cfg = (mai_cfg_t *)save_alloc(sizeof(*mai_cfg), &default_cfg, config_loaded);
|
||||
}
|
||||
|
||||
+26
-30
@@ -9,38 +9,34 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct __attribute ((packed)) {
|
||||
uint8_t h; // hue;
|
||||
uint8_t s; // saturation;
|
||||
uint8_t v; // value;
|
||||
} hsv_t;
|
||||
typedef struct __attribute__((packed)) {
|
||||
struct {
|
||||
uint32_t key_on;
|
||||
uint32_t key_off;
|
||||
} colors;
|
||||
struct {
|
||||
uint8_t key;
|
||||
uint8_t level;
|
||||
} style;
|
||||
struct {
|
||||
int8_t filter;
|
||||
int8_t global;
|
||||
uint8_t debounce_touch;
|
||||
uint8_t debounce_release;
|
||||
int8_t keys[34];
|
||||
} sense;
|
||||
struct {
|
||||
uint8_t joy : 4;
|
||||
uint8_t nkro : 4;
|
||||
} hid;
|
||||
} mai_cfg_t;
|
||||
|
||||
typedef struct __attribute ((packed)) {
|
||||
hsv_t key_off[11];
|
||||
hsv_t key_on[11];
|
||||
struct {
|
||||
uint8_t start;
|
||||
uint8_t num;
|
||||
uint8_t effect;
|
||||
uint8_t param;
|
||||
uint8_t mode; /* 0: on, 1: reversed, 2: off */
|
||||
} tt_led;
|
||||
struct {
|
||||
uint8_t mode; /* 0: analog, 1: analog reversed, 2: i2c, 3: i2c reversed */
|
||||
uint8_t deadzone; /* only for analog */
|
||||
uint8_t ppr; /* 0: 256, 1: 128, 2: 96, 3: 64, other: 256 */
|
||||
} tt_sensor;
|
||||
struct {
|
||||
uint8_t e1;
|
||||
uint8_t e2;
|
||||
uint8_t e3;
|
||||
uint8_t e4;
|
||||
} effects;
|
||||
uint8_t level; /* led brightness limit */
|
||||
bool konami; /* konami spoof */
|
||||
} iidx_cfg_t;
|
||||
typedef struct {
|
||||
uint16_t fps[2];
|
||||
} mai_runtime_t;
|
||||
|
||||
extern iidx_cfg_t *iidx_cfg;
|
||||
extern mai_cfg_t *mai_cfg;
|
||||
extern mai_runtime_t *mai_runtime;
|
||||
|
||||
void config_init();
|
||||
void config_changed(); // Notify the config has changed
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "../.."
|
||||
},
|
||||
{
|
||||
"path": "../../../pico-examples"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"files.associations": {
|
||||
"turntable.h": "c",
|
||||
"stdint.h": "c",
|
||||
"_default_types.h": "c",
|
||||
"limits.h": "c",
|
||||
"cdefs.h": "c",
|
||||
"gpio.h": "c",
|
||||
"pico.h": "c",
|
||||
"flash.h": "c",
|
||||
"bootrom.h": "c",
|
||||
"multicore.h": "c",
|
||||
"stdbool.h": "c",
|
||||
"sync.h": "c",
|
||||
"stdio.h": "c",
|
||||
"config.h": "c",
|
||||
"stdlib.h": "c",
|
||||
"setup.h": "c",
|
||||
"config_autogen.h": "c",
|
||||
"board_defs.h": "c",
|
||||
"rgb.h": "c",
|
||||
"type_traits": "c",
|
||||
"cmath": "c",
|
||||
"*.tcc": "c",
|
||||
"cinttypes": "c",
|
||||
"cstdlib": "c"
|
||||
}
|
||||
}
|
||||
}
|
||||
+150
-156
@@ -3,202 +3,183 @@
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "pico/stdio.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "bsp/board.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "pico/stdio.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/adc.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#include "mpr121.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "usb_descriptors.h"
|
||||
|
||||
/* Measure the time of a function call */
|
||||
#define RUN_TIME(func) \
|
||||
{ uint64_t _t = time_us_64(); func; \
|
||||
printf(#func ":%lld\n", time_us_64() - _t); }
|
||||
#include "board_defs.h"
|
||||
|
||||
struct {
|
||||
uint16_t buttons;
|
||||
uint8_t joy[6];
|
||||
} hid_report;
|
||||
#include "save.h"
|
||||
#include "config.h"
|
||||
#include "cmd.h"
|
||||
|
||||
#include "touch.h"
|
||||
#include "rgb.h"
|
||||
|
||||
struct __attribute__((packed)) {
|
||||
uint16_t buttons; // 16 buttons; see JoystickButtons_t for bit mapping
|
||||
uint8_t HAT; // HAT switch; one nibble w/ unused nibble
|
||||
uint32_t axis; // slider touch data
|
||||
uint8_t VendorSpec;
|
||||
} hid_joy;
|
||||
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t modifier;
|
||||
uint8_t keymap[15];
|
||||
} hid_nkro, sent_hid_nkro;
|
||||
|
||||
void report_usb_hid()
|
||||
{
|
||||
if (tud_hid_ready()) {
|
||||
hid_report.joy[2] = 0;
|
||||
hid_report.joy[3] = 64;
|
||||
hid_report.joy[4] = 128;
|
||||
hid_report.joy[5] = 192;
|
||||
tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_report, sizeof(hid_report));
|
||||
hid_joy.HAT = 0;
|
||||
hid_joy.VendorSpec = 0;
|
||||
if (mai_cfg->hid.joy) {
|
||||
tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy));
|
||||
}
|
||||
if (mai_cfg->hid.nkro &&
|
||||
(memcmp(&hid_nkro, &sent_hid_nkro, sizeof(hid_nkro)) != 0)) {
|
||||
sent_hid_nkro = hid_nkro;
|
||||
tud_hid_n_report(0x02, 0, &sent_hid_nkro, sizeof(sent_hid_nkro));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool request_core1_pause = false;
|
||||
|
||||
static void pause_core1(bool pause)
|
||||
static void gen_joy_report()
|
||||
{
|
||||
request_core1_pause = pause;
|
||||
if (pause) {
|
||||
sleep_ms(5); /* wait for any IO ops to finish */
|
||||
hid_joy.axis = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (touch_touched(i * 2)) {
|
||||
hid_joy.axis |= 1 << (30 - i * 2);
|
||||
}
|
||||
if (touch_touched(i * 2 + 1)) {
|
||||
hid_joy.axis |= 1 << (31 - i * 2);
|
||||
}
|
||||
|
||||
}
|
||||
hid_joy.axis ^= 0x80808080; // some magic number from CrazyRedMachine
|
||||
hid_joy.buttons = 0x0;
|
||||
}
|
||||
|
||||
const uint8_t keycode_table[128][2] = { HID_ASCII_TO_KEYCODE };
|
||||
const char keymap[38 + 1] = NKRO_KEYMAP; // 32 keys, 6 air keys, 1 terminator
|
||||
static void gen_nkro_report()
|
||||
{
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t code = keycode_table[keymap[i]][1];
|
||||
uint8_t byte = code / 8;
|
||||
uint8_t bit = code % 8;
|
||||
if (touch_touched(i)) {
|
||||
hid_nkro.keymap[byte] |= (1 << bit);
|
||||
} else {
|
||||
hid_nkro.keymap[byte] &= ~(1 << bit);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 6; i++) {
|
||||
uint8_t code = keycode_table[keymap[32 + i]][1];
|
||||
uint8_t byte = code / 8;
|
||||
uint8_t bit = code % 8;
|
||||
if (hid_joy.buttons & (1 << i)) {
|
||||
hid_nkro.keymap[byte] |= (1 << bit);
|
||||
} else {
|
||||
hid_nkro.keymap[byte] &= ~(1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t last_hid_time = 0;
|
||||
|
||||
static void run_lights()
|
||||
{
|
||||
uint64_t now = time_us_64();
|
||||
if (now - last_hid_time < 1000000) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t colors[] = {0x000000, 0x0000ff, 0xff0000, 0xffff00,
|
||||
0x00ff00, 0x00ffff, 0xffffff};
|
||||
|
||||
for (int i = 0; i < 15; i++) {
|
||||
int x = 15 - i;
|
||||
uint8_t r = (x & 0x01) ? 10 : 0;
|
||||
uint8_t g = (x & 0x02) ? 10 : 0;
|
||||
uint8_t b = (x & 0x04) ? 10 : 0;
|
||||
rgb_gap_color(i, rgb32(r, g, b, false));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
bool r = touch_touched(i * 2);
|
||||
bool g = touch_touched(i * 2 + 1);
|
||||
rgb_set_color(30 - i * 2, rgb32(r ? 80 : 0, g ? 80 : 0, 0, false));
|
||||
}
|
||||
}
|
||||
|
||||
static mutex_t core1_io_lock;
|
||||
static void core1_loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// I2C definitions: port and pin numbers
|
||||
#define MPR121_PORT i2c0
|
||||
#define MPR121_SDA 16
|
||||
#define MPR121_SCL 17
|
||||
|
||||
// MPR121 I2C definitions: address and frequency.
|
||||
#define MPR121_ADDR 0x5A
|
||||
#define MPR121_I2C_FREQ 400000
|
||||
|
||||
// Touch and release thresholds.
|
||||
#define MPR121_TOUCH_THRESHOLD 16
|
||||
#define MPR121_RELEASE_THRESHOLD 10
|
||||
|
||||
#define GP2Y_PORT i2c0
|
||||
#define GP2Y_I2C_FREQ 200000
|
||||
#define GP2Y_SDA 16
|
||||
#define GP2Y_SCL 17
|
||||
|
||||
static void core0_loop_gp2y()
|
||||
{
|
||||
i2c_init(GP2Y_PORT, GP2Y_I2C_FREQ);
|
||||
gpio_set_function(GP2Y_SDA, GPIO_FUNC_I2C);
|
||||
gpio_set_function(GP2Y_SCL, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(GP2Y_SDA);
|
||||
gpio_pull_up(GP2Y_SCL);
|
||||
|
||||
while(1) {
|
||||
tud_task();
|
||||
|
||||
hid_report.buttons = 0xcccc;
|
||||
report_usb_hid();
|
||||
|
||||
uint8_t reg = 0x00;
|
||||
i2c_write_blocking(GP2Y_PORT, 0x40, ®, 1, true);
|
||||
|
||||
uint16_t v = 0x00;
|
||||
i2c_read_blocking(GP2Y_PORT, 0x5e, (uint8_t *)&v, 2, false);
|
||||
|
||||
printf("%4x\n", v);
|
||||
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void core0_loop_adc()
|
||||
{
|
||||
adc_init();
|
||||
adc_gpio_init(28);
|
||||
adc_select_input(2);
|
||||
|
||||
while(1) {
|
||||
tud_task();
|
||||
|
||||
hid_report.buttons = 0xcccc;
|
||||
report_usb_hid();
|
||||
|
||||
uint16_t result = adc_read();
|
||||
printf("%6o\n", result);
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void core0_loop_mpr121()
|
||||
{
|
||||
// Initialise I2C.
|
||||
i2c_init(MPR121_PORT, MPR121_I2C_FREQ);
|
||||
gpio_set_function(MPR121_SDA, GPIO_FUNC_I2C);
|
||||
gpio_set_function(MPR121_SCL, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(MPR121_SDA);
|
||||
gpio_pull_up(MPR121_SCL);
|
||||
|
||||
struct mpr121_sensor mpr121[3];
|
||||
for (int m = 0; m < 3; m++)
|
||||
{
|
||||
mpr121_init(MPR121_PORT, MPR121_ADDR + m, mpr121 + m);
|
||||
mpr121_set_thresholds(MPR121_TOUCH_THRESHOLD,
|
||||
MPR121_RELEASE_THRESHOLD, mpr121 + m);
|
||||
// Enable only one touch sensor (electrode 0).
|
||||
mpr121_enable_electrodes(12, mpr121 + m);
|
||||
}
|
||||
|
||||
int16_t baseline[34] = {0};
|
||||
|
||||
uint32_t counter[34] = {0};
|
||||
for (int c = 0; c < 1000; c++) {
|
||||
tud_task();
|
||||
hid_report.buttons = 0xcccc;
|
||||
report_usb_hid();
|
||||
for (int i = 0; i < 34; i++) {
|
||||
int16_t touch_data;
|
||||
mpr121_baseline_value(i % 12, &touch_data, mpr121 + i / 12);
|
||||
counter[i] += touch_data;
|
||||
while (1) {
|
||||
if (mutex_try_enter(&core1_io_lock, NULL)) {
|
||||
run_lights();
|
||||
rgb_update();
|
||||
mutex_exit(&core1_io_lock);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 34; i++) {
|
||||
baseline[i] = counter[i] / 1000;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
tud_task();
|
||||
|
||||
hid_report.buttons = 0xcccc;
|
||||
report_usb_hid();
|
||||
|
||||
for (int i = 0; i < 34; i++) {
|
||||
int16_t touch_data;
|
||||
mpr121_baseline_value(i % 12, &touch_data, mpr121 + i / 12);
|
||||
int16_t display_data = (baseline[i] - touch_data) / 4;
|
||||
if (display_data) {
|
||||
printf("%2d", display_data);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%c", i % 12 == 11 ? ':' : ' ');
|
||||
}
|
||||
printf("\n");
|
||||
fps_count(1);
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void core0_loop()
|
||||
{
|
||||
core0_loop_mpr121();
|
||||
while(1) {
|
||||
cmd_run();
|
||||
save_loop();
|
||||
fps_count(0);
|
||||
|
||||
touch_update();
|
||||
|
||||
gen_joy_report();
|
||||
gen_nkro_report();
|
||||
report_usb_hid();
|
||||
tud_task();
|
||||
}
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
sleep_ms(100);
|
||||
set_sys_clock_khz(150000, true);
|
||||
board_init();
|
||||
tusb_init();
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
config_init();
|
||||
mutex_init(&core1_io_lock);
|
||||
save_init(0xca34cafe, &core1_io_lock);
|
||||
|
||||
touch_init();
|
||||
rgb_init();
|
||||
|
||||
cmd_init();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
sleep_ms(1000);
|
||||
|
||||
init();
|
||||
//multicore_launch_core1(core1_loop);
|
||||
|
||||
multicore_launch_core1(core1_loop);
|
||||
core0_loop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -209,6 +190,7 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id,
|
||||
hid_report_type_t report_type, uint8_t *buffer,
|
||||
uint16_t reqlen)
|
||||
{
|
||||
printf("Get from USB %d-%d\n", report_id, report_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -218,10 +200,22 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id,
|
||||
hid_report_type_t report_type, uint8_t const *buffer,
|
||||
uint16_t bufsize)
|
||||
{
|
||||
if ((report_id == REPORT_ID_LIGHTS) &&
|
||||
(report_type == HID_REPORT_TYPE_OUTPUT)) {
|
||||
if (bufsize >= 0) {
|
||||
return;
|
||||
if (report_type == HID_REPORT_TYPE_OUTPUT) {
|
||||
if (report_id == REPORT_ID_LED_touch_16) {
|
||||
rgb_set_brg(0, buffer, bufsize / 3);
|
||||
} else if (report_id == REPORT_ID_LED_touch_15) {
|
||||
rgb_set_brg(16, buffer, bufsize / 3);
|
||||
} else if (report_id == REPORT_ID_LED_TOWER_6) {
|
||||
rgb_set_brg(31, buffer, bufsize / 3);
|
||||
}
|
||||
last_hid_time = time_us_64();
|
||||
return;
|
||||
}
|
||||
|
||||
if (report_type == HID_REPORT_TYPE_FEATURE) {
|
||||
if (report_id == REPORT_ID_LED_COMPRESSED) {
|
||||
}
|
||||
last_hid_time = time_us_64();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* MP121 Captive Touch Sensor
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#include "mpr121.h"
|
||||
#include "board_defs.h"
|
||||
|
||||
#define IO_TIMEOUT_US 1000
|
||||
|
||||
#define TOUCH_THRESHOLD_BASE 17
|
||||
#define RELEASE_THRESHOLD_BASE 12
|
||||
|
||||
#define MPR121_TOUCH_STATUS_REG 0x00
|
||||
#define MPR121_OUT_OF_RANGE_STATUS_0_REG 0x02
|
||||
#define MPR121_OUT_OF_RANGE_STATUS_1_REG 0x03
|
||||
#define MPR121_ELECTRODE_FILTERED_DATA_REG 0x04
|
||||
#define MPR121_BASELINE_VALUE_REG 0x1E
|
||||
|
||||
#define MPR121_MAX_HALF_DELTA_RISING_REG 0x2B
|
||||
#define MPR121_NOISE_HALF_DELTA_RISING_REG 0x2C
|
||||
#define MPR121_NOISE_COUNT_LIMIT_RISING_REG 0x2D
|
||||
#define MPR121_FILTER_DELAY_COUNT_RISING_REG 0x2E
|
||||
#define MPR121_MAX_HALF_DELTA_FALLING_REG 0x2F
|
||||
#define MPR121_NOISE_HALF_DELTA_FALLING_REG 0x30
|
||||
#define MPR121_NOISE_COUNT_LIMIT_FALLING_REG 0x31
|
||||
#define MPR121_FILTER_DELAY_COUNT_FALLING_REG 0x32
|
||||
#define MPR121_NOISE_HALF_DELTA_TOUCHED_REG 0x33
|
||||
#define MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG 0x34
|
||||
#define MPR121_FILTER_DELAY_COUNT_TOUCHED_REG 0x35
|
||||
|
||||
#define MPR121_TOUCH_THRESHOLD_REG 0x41
|
||||
#define MPR121_RELEASE_THRESHOLD_REG 0x42
|
||||
|
||||
#define MPR121_DEBOUNCE_REG 0x5B
|
||||
#define MPR121_AFE_CONFIG_REG 0x5C
|
||||
#define MPR121_FILTER_CONFIG_REG 0x5D
|
||||
#define MPR121_ELECTRODE_CONFIG_REG 0x5E
|
||||
#define MPR121_ELECTRODE_CURRENT_REG 0x5F
|
||||
#define MPR121_ELECTRODE_CHARGE_TIME_REG 0x6C
|
||||
#define MPR121_GPIO_CTRL_0_REG 0x73
|
||||
#define MPR121_GPIO_CTRL_1_REG 0x74
|
||||
#define MPR121_GPIO_DATA_REG 0x75
|
||||
#define MPR121_GPIO_DIRECTION_REG 0x76
|
||||
#define MPR121_GPIO_ENABLE_REG 0x77
|
||||
#define MPR121_GPIO_DATA_SET_REG 0x78
|
||||
#define MPR121_GPIO_DATA_CLEAR_REG 0x79
|
||||
#define MPR121_GPIO_DATA_TOGGLE_REG 0x7A
|
||||
#define MPR121_AUTOCONFIG_CONTROL_0_REG 0x7B
|
||||
#define MPR121_AUTOCONFIG_CONTROL_1_REG 0x7C
|
||||
#define MPR121_AUTOCONFIG_USL_REG 0x7D
|
||||
#define MPR121_AUTOCONFIG_LSL_REG 0x7E
|
||||
#define MPR121_AUTOCONFIG_TARGET_REG 0x7F
|
||||
#define MPR121_SOFT_RESET_REG 0x80
|
||||
|
||||
static void write_reg(uint8_t addr, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t buf[] = {reg, val};
|
||||
i2c_write_blocking_until(I2C_PORT, addr, buf, 2, false,
|
||||
time_us_64() + IO_TIMEOUT_US);
|
||||
}
|
||||
|
||||
static uint8_t read_reg(uint8_t addr, uint8_t reg)
|
||||
{
|
||||
uint8_t value;
|
||||
i2c_write_blocking_until(I2C_PORT, addr, ®, 1, true,
|
||||
time_us_64() + IO_TIMEOUT_US);
|
||||
i2c_read_blocking_until(I2C_PORT, addr, &value, 1, false,
|
||||
time_us_64() + IO_TIMEOUT_US);
|
||||
return value;
|
||||
}
|
||||
|
||||
void mpr121_init(uint8_t i2c_addr)
|
||||
{
|
||||
write_reg(i2c_addr, 0x80, 0x63); // Soft reset MPR121 if not reset correctly
|
||||
|
||||
//touch pad baseline filter
|
||||
//rising: baseline quick rising
|
||||
write_reg(i2c_addr, 0x2B, 0x01); // Max half delta Rising
|
||||
write_reg(i2c_addr, 0x2C, 0x01); // Noise half delta Rising
|
||||
write_reg(i2c_addr, 0x2D, 0x00); // Noise count limit Rising
|
||||
write_reg(i2c_addr, 0x2E, 0x00); // Delay limit Rising
|
||||
|
||||
//falling: baseline slow falling
|
||||
write_reg(i2c_addr, 0x2F, 0x01); // Max half delta Falling
|
||||
write_reg(i2c_addr, 0x30, 0x01); // Noise half delta Falling
|
||||
write_reg(i2c_addr, 0x31, 0xFF); // Noise count limit Falling
|
||||
write_reg(i2c_addr, 0x32, 0x0F); // Delay limit Falling
|
||||
|
||||
//touched: baseline keep
|
||||
write_reg(i2c_addr, 0x33, 0x00); // Noise half delta Touched
|
||||
write_reg(i2c_addr, 0x34, 0x00); // Noise count Touched
|
||||
write_reg(i2c_addr, 0x35, 0x00); // Delay limit Touched
|
||||
|
||||
//Touch pad threshold
|
||||
for (int i = 0; i < 12; i++) {
|
||||
write_reg(i2c_addr, 0x41 + i * 2, TOUCH_THRESHOLD_BASE);
|
||||
write_reg(i2c_addr, 0x42 + i * 2, RELEASE_THRESHOLD_BASE);
|
||||
}
|
||||
|
||||
//touch and release debounce
|
||||
write_reg(i2c_addr, 0x5B, 0x00);
|
||||
|
||||
//AFE and filter configuration
|
||||
write_reg(i2c_addr, 0x5C, 0b00010000); // AFES=6 samples, same as AFES in 0x7B, Global CDC=16uA
|
||||
write_reg(i2c_addr, 0x5D, 0b00101000); // CT=0.5us, TDS=4samples, TDI=16ms
|
||||
write_reg(i2c_addr, 0x5E, 0x80); // Set baseline calibration enabled, baseline loading 5MSB
|
||||
|
||||
//Auto Configuration
|
||||
write_reg(i2c_addr, 0x7B, 0b00001011); // AFES=6 samples, same as AFES in 0x5C
|
||||
// retry=2b00, no retry,
|
||||
// BVA=2b10, load 5MSB after AC,
|
||||
// ARE/ACE=2b11, auto configuration enabled
|
||||
//write_reg(i2c_addr, 0x7C,0x80); // Skip charge time search, use setting in 0x5D,
|
||||
// OOR, AR, AC IE disabled
|
||||
// Not used. Possible Proximity CDC shall over 63uA
|
||||
// if only use 0.5uS CDT, the TGL for proximity cannot meet
|
||||
// Possible if manually set Register0x72=0x03
|
||||
// (Auto configure result) alone.
|
||||
write_reg(i2c_addr, 0x7D, 0xc8); // AC up limit /C8/BD/C0/9C
|
||||
write_reg(i2c_addr, 0x7E, 0x82); // AC low limit /82/7A/7C/65
|
||||
write_reg(i2c_addr, 0x7F, 0xb4); // AC target /B4/AA/AC/8C target for /3.0V/2.8V/1.8V
|
||||
write_reg(i2c_addr, 0x5E, 0x8C); // Run 12 touch, CL=2b10, load 5MSB to baseline
|
||||
}
|
||||
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
static void mpr121_read_many(uint8_t addr, uint8_t reg, uint8_t *buf, size_t n)
|
||||
{
|
||||
i2c_write_blocking_until(I2C_PORT, addr, ®, 1, true,
|
||||
time_us_64() + IO_TIMEOUT_US);
|
||||
i2c_read_blocking_until(I2C_PORT, addr, buf, n, false,
|
||||
time_us_64() + IO_TIMEOUT_US * n / 2);
|
||||
}
|
||||
|
||||
static void mpr121_read_many16(uint8_t addr, uint8_t reg, uint16_t *buf, size_t n)
|
||||
{
|
||||
uint8_t vals[n * 2];
|
||||
mpr121_read_many(addr, reg, vals, n * 2);
|
||||
for (int i = 0; i < n; i++) {
|
||||
buf[i] = (vals[i * 2 + 1] << 8) | vals[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t mpr121_touched(uint8_t addr)
|
||||
{
|
||||
uint16_t touched;
|
||||
mpr121_read_many16(addr, MPR121_TOUCH_STATUS_REG, &touched, 2);
|
||||
return touched;
|
||||
}
|
||||
|
||||
static uint8_t mpr121_stop(uint8_t addr)
|
||||
{
|
||||
uint8_t ecr = read_reg(addr, MPR121_ELECTRODE_CONFIG_REG);
|
||||
write_reg(addr, MPR121_ELECTRODE_CONFIG_REG, ecr & 0xC0);
|
||||
return ecr;
|
||||
}
|
||||
|
||||
static uint8_t mpr121_resume(uint8_t addr, uint8_t ecr)
|
||||
{
|
||||
write_reg(addr, MPR121_ELECTRODE_CONFIG_REG, ecr);
|
||||
}
|
||||
|
||||
void mpr121_filter(uint8_t addr, uint8_t ffi, uint8_t sfi)
|
||||
{
|
||||
uint8_t ecr = mpr121_stop(addr);
|
||||
|
||||
uint8_t afe = read_reg(addr, MPR121_AFE_CONFIG_REG);
|
||||
write_reg(addr, MPR121_AFE_CONFIG_REG, (afe & 0x3f) | ffi << 6);
|
||||
uint8_t acc = read_reg(addr, MPR121_AUTOCONFIG_CONTROL_0_REG);
|
||||
write_reg(addr, MPR121_AUTOCONFIG_CONTROL_0_REG, (acc & 0x3f) | ffi << 6);
|
||||
uint8_t fcr = read_reg(addr, MPR121_FILTER_CONFIG_REG);
|
||||
write_reg(addr, MPR121_FILTER_CONFIG_REG, (fcr & 0xe7) | (sfi & 3) << 3);
|
||||
|
||||
mpr121_resume(addr, ecr);
|
||||
}
|
||||
|
||||
void mpr121_sense(uint8_t addr, int8_t sense, int8_t *sense_keys)
|
||||
{
|
||||
uint8_t ecr = mpr121_stop(addr);
|
||||
for (int i = 0; i < 12; i++) {
|
||||
int8_t delta = sense + sense_keys[i];
|
||||
write_reg(addr, MPR121_TOUCH_THRESHOLD_REG + i * 2,
|
||||
TOUCH_THRESHOLD_BASE - delta);
|
||||
write_reg(addr, MPR121_RELEASE_THRESHOLD_REG + i * 2,
|
||||
RELEASE_THRESHOLD_BASE - delta / 2);
|
||||
}
|
||||
mpr121_resume(addr, ecr);
|
||||
}
|
||||
|
||||
void mpr121_debounce(uint8_t addr, uint8_t touch, uint8_t release)
|
||||
{
|
||||
uint8_t ecr = mpr121_stop(addr);
|
||||
write_reg(addr, 0x5B, (release & 0x07) << 4 | (touch & 0x07));
|
||||
mpr121_resume(addr, ecr);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* MP121 Captive Touch Sensor
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MP121_H
|
||||
#define MP121_H
|
||||
|
||||
void mpr121_init(uint8_t addr);
|
||||
|
||||
uint16_t mpr121_touched(uint8_t addr);
|
||||
|
||||
void mpr121_filter(uint8_t addr, uint8_t ffi, uint8_t sfi);
|
||||
void mpr121_sense(uint8_t addr, int8_t sense, int8_t *sense_keys);
|
||||
void mpr121_debounce(uint8_t addr, uint8_t touch, uint8_t release);
|
||||
|
||||
#endif
|
||||
+58
-234
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "rgb.h"
|
||||
|
||||
#include "buttons.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
@@ -23,12 +22,7 @@
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
static const uint8_t button_rgb_map[BUTTON_RGB_NUM] = BUTTON_RGB_MAP;
|
||||
|
||||
static void trap() {}
|
||||
static tt_effect_t effects[10] = { {trap, trap, trap, 0} };
|
||||
static size_t effect_num = 0;
|
||||
static unsigned current_effect = 0;
|
||||
static uint32_t rgb_buf[47]; // 16(Keys) + 15(Gaps) + 16(maximum ToF indicators)
|
||||
|
||||
#define _MAP_LED(x) _MAKE_MAPPER(x)
|
||||
#define _MAKE_MAPPER(x) MAP_LED_##x
|
||||
@@ -40,10 +34,6 @@ static unsigned current_effect = 0;
|
||||
|
||||
static inline uint32_t _rgb32(uint32_t c1, uint32_t c2, uint32_t c3, bool gamma_fix)
|
||||
{
|
||||
c1 = c1 * iidx_cfg->level / 255;
|
||||
c2 = c2 * iidx_cfg->level / 255;
|
||||
c3 = c3 * iidx_cfg->level / 255;
|
||||
|
||||
if (gamma_fix) {
|
||||
c1 = ((c1 + 1) * (c1 + 1) - 1) >> 8;
|
||||
c2 = ((c2 + 1) * (c2 + 1) - 1) >> 8;
|
||||
@@ -53,7 +43,7 @@ static inline uint32_t _rgb32(uint32_t c1, uint32_t c2, uint32_t c3, bool gamma_
|
||||
return (c1 << 16) | (c2 << 8) | (c3 << 0);
|
||||
}
|
||||
|
||||
uint32_t button_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix)
|
||||
uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix)
|
||||
{
|
||||
#if BUTTON_RGB_ORDER == GRB
|
||||
return _rgb32(g, r, b, gamma_fix);
|
||||
@@ -62,250 +52,84 @@ uint32_t button_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix)
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t tt_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix)
|
||||
static void drive_led()
|
||||
{
|
||||
#if TT_RGB_ORDER == GRB
|
||||
return _rgb32(g, r, b, gamma_fix);
|
||||
#else
|
||||
return _rgb32(r, g, b, gamma_fix);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t rgb_button_num()
|
||||
{
|
||||
return BUTTON_RGB_NUM;
|
||||
}
|
||||
|
||||
uint8_t button_lights[BUTTON_RGB_NUM];
|
||||
uint32_t tt_led_buf[128] = {0};
|
||||
uint32_t tt_led_angle = 0;
|
||||
|
||||
static uint32_t button_led_buf[BUTTON_RGB_NUM] = {0};
|
||||
|
||||
void set_effect(uint32_t index)
|
||||
{
|
||||
if (index < effect_num) {
|
||||
current_effect = index;
|
||||
effects[current_effect].init(effects[current_effect].context);
|
||||
} else {
|
||||
current_effect = effect_num;
|
||||
}
|
||||
}
|
||||
|
||||
void drive_led()
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(button_led_buf); i++) {
|
||||
pio_sm_put_blocking(pio0, 0, button_led_buf[i] << 8u);
|
||||
}
|
||||
|
||||
if (iidx_cfg->tt_led.mode == 2) {
|
||||
static uint64_t last = 0;
|
||||
uint64_t now = time_us_64();
|
||||
if (now - last < 4000) { // no faster than 250Hz
|
||||
return;
|
||||
}
|
||||
last = now;
|
||||
|
||||
for (int i = 0; i < iidx_cfg->tt_led.start; i++) {
|
||||
pio_sm_put_blocking(pio1, 0, 0);
|
||||
for (int i = 30; i >= 0; i--) {
|
||||
pio_sm_put_blocking(pio0, 0, rgb_buf[i] << 8u);
|
||||
}
|
||||
for (int i = 0; i < TT_LED_NUM; i++) {
|
||||
bool reversed = iidx_cfg->tt_led.mode & 0x01;
|
||||
uint8_t id = reversed ? TT_LED_NUM - i - 1 : i;
|
||||
pio_sm_put_blocking(pio1, 0, tt_led_buf[id] << 8u);
|
||||
}
|
||||
for (int i = 0; i < 8; i++) { // a few more to wipe out the last led
|
||||
pio_sm_put_blocking(pio1, 0, 0);
|
||||
for (int i = 31; i < ARRAY_SIZE(rgb_buf); i++) {
|
||||
pio_sm_put_blocking(pio0, 0, rgb_buf[i] << 8u);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t rgb32_from_hsv(hsv_t hsv)
|
||||
void rgb_set_colors(const uint32_t *colors, unsigned index, size_t num)
|
||||
{
|
||||
uint32_t region, remainder, p, q, t;
|
||||
|
||||
if (hsv.s == 0) {
|
||||
return hsv.v << 16 | hsv.v << 8 | hsv.v;
|
||||
}
|
||||
|
||||
region = hsv.h / 43;
|
||||
remainder = (hsv.h % 43) * 6;
|
||||
|
||||
p = (hsv.v * (255 - hsv.s)) >> 8;
|
||||
q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8;
|
||||
t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8;
|
||||
|
||||
switch (region) {
|
||||
case 0:
|
||||
return hsv.v << 16 | t << 8 | p;
|
||||
case 1:
|
||||
return q << 16 | hsv.v << 8 | p;
|
||||
case 2:
|
||||
return p << 16 | hsv.v << 8 | t;
|
||||
case 3:
|
||||
return p << 16 | q << 8 | hsv.v;
|
||||
case 4:
|
||||
return t << 16 | p << 8 | hsv.v;
|
||||
default:
|
||||
return hsv.v << 16 | p << 8 | q;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t button_hsv(hsv_t hsv)
|
||||
{
|
||||
uint32_t rgb = rgb32_from_hsv(hsv);
|
||||
uint32_t r = (rgb >> 16) & 0xff;
|
||||
uint32_t g = (rgb >> 8) & 0xff;
|
||||
uint32_t b = (rgb >> 0) & 0xff;
|
||||
#if BUTTON_RGB_ORDER == GRB
|
||||
return _rgb32(g, r, b, false);
|
||||
#else
|
||||
return _rgb32(r, g, b, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t tt_hsv(hsv_t hsv)
|
||||
{
|
||||
uint32_t rgb = rgb32_from_hsv(hsv);
|
||||
uint32_t r = (rgb >> 16) & 0xff;
|
||||
uint32_t g = (rgb >> 8) & 0xff;
|
||||
uint32_t b = (rgb >> 0) & 0xff;
|
||||
#if TT_RGB_ORDER == GRB
|
||||
return _rgb32(g, r, b, false);
|
||||
#else
|
||||
return _rgb32(r, g, b, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define HID_EXPIRE_DURATION 1000000ULL
|
||||
static uint64_t hid_expire_time = 0;
|
||||
|
||||
static void button_lights_update()
|
||||
{
|
||||
for (int i = 0; i < BUTTON_RGB_NUM; i++) {
|
||||
int led = button_rgb_map[i];
|
||||
if (button_lights[i] > 0) {
|
||||
button_led_buf[led] = button_hsv(iidx_cfg->key_on[i]);
|
||||
} else {
|
||||
button_led_buf[led] = button_hsv(iidx_cfg->key_off[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rgb_set_angle(uint32_t angle)
|
||||
{
|
||||
tt_led_angle = angle;
|
||||
effects[current_effect].set_angle(angle);
|
||||
}
|
||||
|
||||
void rgb_set_button_light(uint16_t buttons)
|
||||
{
|
||||
if (time_us_64() < hid_expire_time) {
|
||||
if (index >= ARRAY_SIZE(rgb_buf)) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < BUTTON_RGB_NUM; i++) {
|
||||
uint16_t flag = 1 << i;
|
||||
button_lights[i] = (buttons & flag) > 0 ? 0xff : 0;
|
||||
if (index + num > ARRAY_SIZE(rgb_buf)) {
|
||||
num = ARRAY_SIZE(rgb_buf) - index;
|
||||
}
|
||||
memcpy(&rgb_buf[index], colors, num * sizeof(*colors));
|
||||
}
|
||||
|
||||
void rgb_set_color(unsigned index, uint32_t color)
|
||||
{
|
||||
if (index >= ARRAY_SIZE(rgb_buf)) {
|
||||
return;
|
||||
}
|
||||
rgb_buf[index] = color;
|
||||
}
|
||||
|
||||
void rgb_key_color(unsigned index, uint32_t color)
|
||||
{
|
||||
if (index > 16) {
|
||||
return;
|
||||
}
|
||||
rgb_buf[index * 2] = color;
|
||||
}
|
||||
|
||||
void rgb_gap_color(unsigned index, uint32_t color)
|
||||
{
|
||||
if (index > 15) {
|
||||
return;
|
||||
}
|
||||
rgb_buf[index * 2 + 1] = color;
|
||||
}
|
||||
|
||||
void rgb_set_brg(unsigned index, const uint8_t *brg_array, size_t num)
|
||||
{
|
||||
if (index >= ARRAY_SIZE(rgb_buf)) {
|
||||
return;
|
||||
}
|
||||
if (index + num > ARRAY_SIZE(rgb_buf)) {
|
||||
num = ARRAY_SIZE(rgb_buf) - index;
|
||||
}
|
||||
for (int i = 0; i < num; i++) {
|
||||
uint8_t b = brg_array[i * 3 + 0];
|
||||
uint8_t r = brg_array[i * 3 + 1];
|
||||
uint8_t g = brg_array[i * 3 + 2];
|
||||
rgb_buf[index + i] = rgb32(r, g, b, false);
|
||||
}
|
||||
}
|
||||
|
||||
void rgb_set_hid_light(uint8_t const *lights, uint8_t num)
|
||||
{
|
||||
memcpy(button_lights, lights, num);
|
||||
hid_expire_time = time_us_64() + HID_EXPIRE_DURATION;
|
||||
}
|
||||
|
||||
static void effect_update()
|
||||
{
|
||||
effects[current_effect].update(effects[current_effect].context);
|
||||
}
|
||||
|
||||
#define FORCE_EXPIRE_DURATION 100000ULL
|
||||
static uint64_t force_expire_time = 0;
|
||||
uint32_t *force_buttons = NULL;
|
||||
uint32_t *force_tt = NULL;
|
||||
|
||||
void force_update()
|
||||
{
|
||||
for (int i = 0; i < BUTTON_RGB_NUM; i++) {
|
||||
int led = button_rgb_map[i];
|
||||
button_led_buf[led] = force_buttons[i];
|
||||
}
|
||||
|
||||
memcpy(tt_led_buf, force_tt, TT_LED_NUM * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void rgb_force_display(uint32_t *buttons, uint32_t *tt)
|
||||
{
|
||||
force_buttons = buttons;
|
||||
force_tt = tt;
|
||||
force_expire_time = time_us_64() + FORCE_EXPIRE_DURATION;
|
||||
}
|
||||
|
||||
static void wipe_out_tt_led()
|
||||
{
|
||||
sleep_ms(5);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
pio_sm_put_blocking(pio1, 0, 0);
|
||||
}
|
||||
sleep_ms(5);
|
||||
}
|
||||
|
||||
static uint pio1_offset;
|
||||
static bool pio1_running = false;
|
||||
|
||||
static void pio1_run()
|
||||
{
|
||||
gpio_set_drive_strength(TT_RGB_PIN, GPIO_DRIVE_STRENGTH_8MA);
|
||||
ws2812_program_init(pio1, 0, pio1_offset, TT_RGB_PIN, 800000, false);
|
||||
}
|
||||
|
||||
static void pio1_stop()
|
||||
{
|
||||
wipe_out_tt_led();
|
||||
pio_sm_set_enabled(pio1, 0, false);
|
||||
|
||||
gpio_set_function(TT_RGB_PIN, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(TT_RGB_PIN, GPIO_IN);
|
||||
gpio_disable_pulls(TT_RGB_PIN);
|
||||
}
|
||||
|
||||
void rgb_init()
|
||||
{
|
||||
uint pio0_offset = pio_add_program(pio0, &ws2812_program);
|
||||
pio1_offset = pio_add_program(pio1, &ws2812_program);
|
||||
|
||||
gpio_set_drive_strength(BUTTON_RGB_PIN, GPIO_DRIVE_STRENGTH_2MA);
|
||||
ws2812_program_init(pio0, 0, pio0_offset, BUTTON_RGB_PIN, 800000, false);
|
||||
|
||||
/* We don't start the tt LED program yet */
|
||||
}
|
||||
|
||||
static void follow_mode_change()
|
||||
{
|
||||
bool pio1_should_run = (iidx_cfg->tt_led.mode != 2);
|
||||
if (pio1_should_run == pio1_running) {
|
||||
return;
|
||||
}
|
||||
pio1_running = pio1_should_run;
|
||||
if (pio1_should_run) {
|
||||
pio1_run();
|
||||
} else {
|
||||
pio1_stop();
|
||||
}
|
||||
gpio_set_drive_strength(RGB_PIN, GPIO_DRIVE_STRENGTH_2MA);
|
||||
ws2812_program_init(pio0, 0, pio0_offset, RGB_PIN, 800000, false);
|
||||
}
|
||||
|
||||
void rgb_update()
|
||||
{
|
||||
follow_mode_change();
|
||||
set_effect(iidx_cfg->tt_led.effect);
|
||||
if (time_us_64() > force_expire_time) {
|
||||
effect_update();
|
||||
button_lights_update();
|
||||
} else {
|
||||
force_update();
|
||||
}
|
||||
drive_led();
|
||||
}
|
||||
|
||||
void rgb_reg_tt_effect(tt_effect_t effect)
|
||||
{
|
||||
effects[effect_num] = effect;
|
||||
effect_num++;
|
||||
effects[effect_num] = (tt_effect_t) { trap, trap, trap, 0 };
|
||||
}
|
||||
|
||||
+8
-29
@@ -6,44 +6,23 @@
|
||||
#ifndef RGB_H
|
||||
#define RGB_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void rgb_init();
|
||||
void rgb_set_hardware(uint16_t tt_start, uint16_t tt_num, bool tt_reversed);
|
||||
|
||||
uint8_t rgb_button_num();
|
||||
void rgb_update();
|
||||
|
||||
void rgb_set_angle(uint32_t angle);
|
||||
void rgb_set_level(uint8_t level);
|
||||
uint32_t rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix);
|
||||
|
||||
void rgb_set_button_light(uint16_t buttons);
|
||||
void rgb_set_hid_light(uint8_t const *lights, uint8_t num);
|
||||
void rgb_set_colors(const uint32_t *colors, unsigned index, size_t num);
|
||||
void rgb_set_color(unsigned index, uint32_t color);
|
||||
void rgb_key_color(unsigned index, uint32_t color);
|
||||
void rgb_gap_color(unsigned index, uint32_t color);
|
||||
|
||||
void rgb_force_display(uint32_t *keyboard, uint32_t *tt);
|
||||
|
||||
typedef struct {
|
||||
void (*init)(uint32_t context);
|
||||
void (*set_angle)(uint32_t angle);
|
||||
void (*update)(uint32_t context);
|
||||
uint32_t context;
|
||||
} tt_effect_t;
|
||||
|
||||
void rgb_reg_tt_effect(tt_effect_t effect);
|
||||
|
||||
extern uint32_t tt_led_buf[];
|
||||
#define TT_LED_NUM (iidx_cfg->tt_led.num)
|
||||
|
||||
/* These global variables meant to be accessed by effect codes */
|
||||
extern uint32_t tt_led_angle;
|
||||
|
||||
|
||||
uint32_t button_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix);
|
||||
uint32_t tt_rgb32(uint32_t r, uint32_t g, uint32_t b, bool gamma_fix);
|
||||
uint32_t button_hsv(hsv_t hsv);
|
||||
uint32_t tt_hsv(hsv_t hsv);
|
||||
/* num of the rgb leds, num*3 bytes in the array */
|
||||
void rgb_set_brg(unsigned index, const uint8_t *brg_array, size_t num);
|
||||
|
||||
#endif
|
||||
|
||||
+31
-27
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Controller Save Save and Load
|
||||
* Controller Config Save and Load
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
* Save is stored in last sector of flash
|
||||
* Config is stored in last sector of flash
|
||||
*/
|
||||
|
||||
#include "save.h"
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "pico/stdio.h"
|
||||
|
||||
#include "hardware/flash.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "pico/multicore.h"
|
||||
|
||||
static struct {
|
||||
size_t size;
|
||||
@@ -27,7 +27,10 @@ static struct {
|
||||
} modules[8] = {0};
|
||||
static int module_num = 0;
|
||||
|
||||
#define SAVE_PAGE_MAGIC 0x13424321
|
||||
static uint32_t my_magic = 0xcafecafe;
|
||||
|
||||
#define SAVE_TIMEOUT_US 5000000
|
||||
|
||||
#define SAVE_SECTOR_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE)
|
||||
|
||||
typedef struct __attribute ((packed)) {
|
||||
@@ -43,30 +46,34 @@ static int data_page = -1;
|
||||
static bool requesting_save = false;
|
||||
static uint64_t requesting_time = 0;
|
||||
|
||||
static io_locker_func io_lock;
|
||||
static mutex_t *io_lock;
|
||||
|
||||
static void save_program()
|
||||
{
|
||||
old_data = new_data;
|
||||
|
||||
data_page = (data_page + 1) % (FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE);
|
||||
printf("Program Flash %d %8lx\n", data_page, old_data.magic);
|
||||
io_lock(true);
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
if (data_page == 0) {
|
||||
flash_range_erase(SAVE_SECTOR_OFFSET, FLASH_SECTOR_SIZE);
|
||||
printf("\nProgram Flash %d %8lx\n", data_page, old_data.magic);
|
||||
if (mutex_enter_timeout_us(io_lock, 100000)) {
|
||||
sleep_ms(10); /* wait for all io operations to finish */
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
if (data_page == 0) {
|
||||
flash_range_erase(SAVE_SECTOR_OFFSET, FLASH_SECTOR_SIZE);
|
||||
}
|
||||
flash_range_program(SAVE_SECTOR_OFFSET + data_page * FLASH_PAGE_SIZE,
|
||||
(uint8_t *)&old_data, FLASH_PAGE_SIZE);
|
||||
restore_interrupts(ints);
|
||||
mutex_exit(io_lock);
|
||||
} else {
|
||||
printf("Program Flash Failed.\n");
|
||||
}
|
||||
flash_range_program(SAVE_SECTOR_OFFSET + data_page * FLASH_PAGE_SIZE,
|
||||
(uint8_t *)&old_data, FLASH_PAGE_SIZE);
|
||||
restore_interrupts(ints);
|
||||
io_lock(false);
|
||||
}
|
||||
|
||||
static void load_default()
|
||||
{
|
||||
printf("Load Default\n");
|
||||
new_data = default_data;
|
||||
new_data.magic = SAVE_PAGE_MAGIC;
|
||||
new_data.magic = my_magic;
|
||||
}
|
||||
|
||||
static const page_t *get_page(int id)
|
||||
@@ -78,7 +85,7 @@ static const page_t *get_page(int id)
|
||||
static void save_load()
|
||||
{
|
||||
for (int i = 0; i < FLASH_SECTOR_SIZE / FLASH_PAGE_SIZE; i++) {
|
||||
if (get_page(i)->magic != SAVE_PAGE_MAGIC) {
|
||||
if (get_page(i)->magic != my_magic) {
|
||||
break;
|
||||
}
|
||||
data_page = i;
|
||||
@@ -102,8 +109,9 @@ static void save_loaded()
|
||||
}
|
||||
}
|
||||
|
||||
void save_init(io_locker_func locker)
|
||||
void save_init(uint32_t magic, mutex_t *locker)
|
||||
{
|
||||
my_magic = magic;
|
||||
io_lock = locker;
|
||||
save_load();
|
||||
save_loop();
|
||||
@@ -112,17 +120,13 @@ void save_init(io_locker_func locker)
|
||||
|
||||
void save_loop()
|
||||
{
|
||||
if (requesting_save && (time_us_64() - requesting_time > 1000000)) {
|
||||
if (requesting_save && (time_us_64() - requesting_time > SAVE_TIMEOUT_US)) {
|
||||
requesting_save = false;
|
||||
printf("Time to save.\n");
|
||||
/* only when data is actually changed */
|
||||
for (int i = 0; i < sizeof(old_data); i++) {
|
||||
if (((uint8_t *)&old_data)[i] != ((uint8_t *)&new_data)[i]) {
|
||||
save_program();
|
||||
return;
|
||||
}
|
||||
if (memcmp(&old_data, &new_data, sizeof(old_data)) == 0) {
|
||||
return;
|
||||
}
|
||||
printf("No change.\n");
|
||||
save_program();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,9 +144,9 @@ void *save_alloc(size_t size, void *def, void (*after_load)())
|
||||
void save_request(bool immediately)
|
||||
{
|
||||
if (!requesting_save) {
|
||||
printf("Save marked.\n");
|
||||
printf("Save requested.\n");
|
||||
requesting_save = true;
|
||||
new_data.magic = SAVE_PAGE_MAGIC;
|
||||
new_data.magic = my_magic;
|
||||
requesting_time = time_us_64();
|
||||
}
|
||||
if (immediately) {
|
||||
|
||||
+4
-1
@@ -7,11 +7,14 @@
|
||||
#define SAVE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "pico/multicore.h"
|
||||
|
||||
/* It's safer to lock other I/O ops during saving, so we need a locker */
|
||||
typedef void (*io_locker_func)(bool pause);
|
||||
void save_init(io_locker_func locker);
|
||||
void save_init(uint32_t magic, mutex_t *lock);
|
||||
|
||||
void save_loop();
|
||||
|
||||
|
||||
@@ -1,725 +0,0 @@
|
||||
/*
|
||||
* Controller Setup Menu
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
* Setup is a mode, so one can change settings live
|
||||
*/
|
||||
|
||||
#include "setup.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bsp/board.h"
|
||||
#include "pico/bootrom.h"
|
||||
|
||||
#include "rgb.h"
|
||||
#include "config.h"
|
||||
|
||||
static iidx_cfg_t cfg_save;
|
||||
|
||||
static uint64_t setup_tick_ms = 0;
|
||||
#define CONCAT(a, b) a ## b
|
||||
#define TVAR(line) CONCAT(a, line)
|
||||
#define RUN_EVERY_N_MS(a, ms) { static uint64_t TVAR(__LINE__) = 0; \
|
||||
if (setup_tick_ms - TVAR(__LINE__) >= ms) { a; TVAR(__LINE__) = setup_tick_ms; } }
|
||||
static uint32_t blink_fast = 0xffffffff;
|
||||
static uint32_t blink_slow = 0xffffffff;
|
||||
|
||||
uint32_t setup_led_tt[128];
|
||||
uint32_t setup_led_button[BUTTON_RGB_NUM];
|
||||
|
||||
typedef enum {
|
||||
MODE_NONE,
|
||||
MODE_TURNTABLE,
|
||||
MODE_ANALOG,
|
||||
MODE_LEVEL,
|
||||
MODE_TT_THEME,
|
||||
MODE_KEY_THEME,
|
||||
MODE_KEY_OFF,
|
||||
MODE_KEY_ON,
|
||||
} setup_mode_t;
|
||||
static setup_mode_t current_mode = MODE_NONE;
|
||||
|
||||
static struct {
|
||||
uint16_t last_keys;
|
||||
uint16_t keys;
|
||||
uint16_t just_pressed;
|
||||
uint16_t just_released;
|
||||
|
||||
int16_t last_angle;
|
||||
int16_t angle;
|
||||
int16_t rotate;
|
||||
} input = { 0 };
|
||||
|
||||
#define KEY_1 0x0001
|
||||
#define KEY_2 0x0002
|
||||
#define KEY_3 0x0004
|
||||
#define KEY_4 0x0008
|
||||
#define KEY_5 0x0010
|
||||
#define KEY_6 0x0020
|
||||
#define KEY_7 0x0040
|
||||
#define E1 0x0080
|
||||
#define E2 0x0100
|
||||
#define E3 0x0200
|
||||
#define E4 0x0400
|
||||
#define AUX_NO 0x0800
|
||||
#define AUX_YES 0x1000
|
||||
|
||||
#define LED_KEY_1 0
|
||||
#define LED_KEY_2 1
|
||||
#define LED_KEY_3 2
|
||||
#define LED_KEY_4 3
|
||||
#define LED_KEY_5 4
|
||||
#define LED_KEY_6 5
|
||||
#define LED_KEY_7 6
|
||||
#define LED_E1 7
|
||||
#define LED_E2 8
|
||||
#define LED_E3 9
|
||||
#define LED_E4 10
|
||||
|
||||
#define PRESSED_ALL(k) ((input.keys & (k)) == (k))
|
||||
#define PRESSED_ANY(k) (input.keys & (k))
|
||||
#define JUST_PRESSED(k) (input.just_pressed & (k))
|
||||
#define JUST_RELEASED(k) (input.just_released & (k))
|
||||
|
||||
#define RED button_rgb32(99, 0, 0, false)
|
||||
#define GREEN button_rgb32(0, 99, 0, false)
|
||||
#define CYAN button_rgb32(0, 40, 99, false)
|
||||
#define YELLOW button_rgb32(99, 99, 0, false)
|
||||
#define SILVER button_rgb32(60, 60, 60, false)
|
||||
|
||||
#define TT_RED tt_rgb32(99, 0, 0, false)
|
||||
#define TT_GREEN tt_rgb32(0, 99, 0, false)
|
||||
#define TT_CYAN tt_rgb32(0, 40, 99, false)
|
||||
#define TT_YELLOW tt_rgb32(99, 99, 0, false)
|
||||
#define TT_SILVER tt_rgb32(60, 60, 60, false)
|
||||
|
||||
typedef void (*mode_func)();
|
||||
|
||||
static void join_mode(setup_mode_t new_mode);
|
||||
static void quit_mode(bool apply);
|
||||
|
||||
static void nop()
|
||||
{
|
||||
}
|
||||
|
||||
static void check_exit()
|
||||
{
|
||||
if (JUST_PRESSED(AUX_YES)) {
|
||||
quit_mode(true);
|
||||
} else if (JUST_PRESSED(AUX_NO)) {
|
||||
quit_mode(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t input_delta(int16_t start_angle)
|
||||
{
|
||||
int16_t delta = input.angle - start_angle;
|
||||
if (delta > 128) {
|
||||
delta -= 256;
|
||||
}
|
||||
if (delta < -128) {
|
||||
delta += 256;
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
static setup_mode_t key_to_mode[11] = {
|
||||
MODE_KEY_THEME, MODE_TT_THEME, MODE_KEY_ON, MODE_KEY_OFF,
|
||||
MODE_NONE, MODE_NONE, MODE_NONE,
|
||||
MODE_ANALOG, MODE_ANALOG, MODE_ANALOG, MODE_ANALOG,
|
||||
};
|
||||
|
||||
static struct {
|
||||
bool escaped;
|
||||
uint64_t escape_time;
|
||||
uint16_t start_angle;
|
||||
} none_ctx = { 0 };
|
||||
|
||||
static void none_rotate()
|
||||
{
|
||||
if (!none_ctx.escaped) {
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t delta = input_delta(none_ctx.start_angle);
|
||||
if (abs(delta) > 10) {
|
||||
join_mode(MODE_LEVEL);
|
||||
none_ctx.escaped = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void none_loop()
|
||||
{
|
||||
if (PRESSED_ALL(AUX_YES | AUX_NO)) {
|
||||
if (!none_ctx.escaped) {
|
||||
none_ctx.escaped = true;
|
||||
none_ctx.escape_time = time_us_64();
|
||||
none_ctx.start_angle = input.angle;
|
||||
}
|
||||
} else {
|
||||
none_ctx.escaped = false;
|
||||
}
|
||||
|
||||
if (!none_ctx.escaped) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 11; i++) {
|
||||
if (PRESSED_ANY(KEY_1 << i)) {
|
||||
none_ctx.escaped = false;
|
||||
join_mode(key_to_mode[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (time_us_64() - none_ctx.escape_time > 5000000) {
|
||||
none_ctx.escaped = false;
|
||||
join_mode(MODE_TURNTABLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
uint8_t adjust_led; /* 0: nothing, 1: adjust start, 2: adjust stop */
|
||||
int16_t start_angle;
|
||||
} tt_ctx;
|
||||
|
||||
static void tt_enter()
|
||||
{
|
||||
tt_ctx.start_angle = input.angle;
|
||||
}
|
||||
|
||||
static void tt_key_change()
|
||||
{
|
||||
if (JUST_PRESSED(E1)) {
|
||||
tt_ctx.adjust_led = (tt_ctx.adjust_led == 1) ? 0 : 1;
|
||||
tt_ctx.start_angle = input.angle;
|
||||
} else if (JUST_PRESSED(E2)) {
|
||||
tt_ctx.adjust_led = (tt_ctx.adjust_led == 2) ? 0 : 2;
|
||||
tt_ctx.start_angle = input.angle;
|
||||
} else if (JUST_PRESSED(E3)) {
|
||||
iidx_cfg->tt_led.mode = (iidx_cfg->tt_led.mode + 1) % 3;
|
||||
} else if (JUST_PRESSED(E4)) {
|
||||
iidx_cfg->tt_sensor.mode = (iidx_cfg->tt_sensor.mode + 1) % 4;
|
||||
} else if (JUST_PRESSED(KEY_2)) {
|
||||
iidx_cfg->tt_sensor.deadzone = 0;
|
||||
} else if (JUST_PRESSED(KEY_4)) {
|
||||
iidx_cfg->tt_sensor.deadzone = 1;
|
||||
} else if (JUST_PRESSED(KEY_6)) {
|
||||
iidx_cfg->tt_sensor.deadzone = 2;
|
||||
} else if (JUST_PRESSED(KEY_1)) {
|
||||
iidx_cfg->tt_sensor.ppr = 0;
|
||||
} else if (JUST_PRESSED(KEY_3)) {
|
||||
iidx_cfg->tt_sensor.ppr = 1;
|
||||
} else if (JUST_PRESSED(KEY_5)) {
|
||||
iidx_cfg->tt_sensor.ppr = 2;
|
||||
} else if (JUST_PRESSED(KEY_7)) {
|
||||
iidx_cfg->tt_sensor.ppr = 3;
|
||||
}
|
||||
|
||||
check_exit();
|
||||
}
|
||||
|
||||
static void tt_rotate()
|
||||
{
|
||||
int16_t delta = input_delta(tt_ctx.start_angle);
|
||||
if (abs(delta) > 8) {
|
||||
tt_ctx.start_angle = input.angle;
|
||||
|
||||
#define LED_START iidx_cfg->tt_led.start
|
||||
#define LED_NUM iidx_cfg->tt_led.num
|
||||
|
||||
if (tt_ctx.adjust_led == 1) {
|
||||
if ((delta > 0) & (LED_START < 8)) {
|
||||
LED_START++;
|
||||
if (LED_NUM > 1) {
|
||||
LED_NUM--;
|
||||
}
|
||||
} else if ((delta < 0) & (LED_START > 0)) {
|
||||
LED_START--;
|
||||
LED_NUM++;
|
||||
}
|
||||
} else if (tt_ctx.adjust_led == 2) {
|
||||
if ((delta > 0) & (LED_NUM + LED_START < 128)) {
|
||||
LED_NUM++;
|
||||
} else if ((delta < 0) & (LED_NUM > 1)) { // at least 1 led
|
||||
LED_NUM--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tt_loop()
|
||||
{
|
||||
for (int i = 1; i < iidx_cfg->tt_led.num - 1; i++) {
|
||||
setup_led_tt[i] = tt_rgb32(10, 10, 10, false);
|
||||
}
|
||||
|
||||
bool led_reversed = (iidx_cfg->tt_led.mode == 1);
|
||||
int head = led_reversed ? TT_LED_NUM - 1 : 0;
|
||||
int tail = led_reversed ? 0 : TT_LED_NUM - 1;
|
||||
|
||||
setup_led_tt[head] = tt_rgb32(0xa0, 0, 0, false);
|
||||
setup_led_tt[tail] = tt_rgb32(0, 0xa0, 0, false);
|
||||
setup_led_button[LED_E2] = button_rgb32(0, 10, 0, false);
|
||||
setup_led_button[LED_E1] = button_rgb32(10, 0, 0, false);
|
||||
|
||||
if (tt_ctx.adjust_led == 1) {
|
||||
setup_led_tt[head] &= blink_fast;
|
||||
setup_led_button[LED_E1] = RED & blink_fast;
|
||||
} else if (tt_ctx.adjust_led == 2) {
|
||||
setup_led_tt[tail] &= blink_fast;
|
||||
setup_led_button[LED_E2] = GREEN & blink_fast;
|
||||
}
|
||||
|
||||
switch (iidx_cfg->tt_led.mode) {
|
||||
case 0:
|
||||
setup_led_button[LED_E3] = GREEN;
|
||||
break;
|
||||
case 1:
|
||||
setup_led_button[LED_E3] = RED;
|
||||
break;
|
||||
default:
|
||||
setup_led_button[LED_E3] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (iidx_cfg->tt_sensor.mode) {
|
||||
case 0:
|
||||
setup_led_button[LED_E4] = GREEN;
|
||||
break;
|
||||
case 1:
|
||||
setup_led_button[LED_E4] = RED;
|
||||
break;
|
||||
case 2:
|
||||
setup_led_button[LED_E4] = CYAN;
|
||||
break;
|
||||
default:
|
||||
setup_led_button[LED_E4] = YELLOW;
|
||||
break;
|
||||
}
|
||||
setup_led_button[LED_KEY_2] = iidx_cfg->tt_sensor.deadzone == 0 ? SILVER : 0;
|
||||
setup_led_button[LED_KEY_4] = iidx_cfg->tt_sensor.deadzone == 1 ? SILVER : 0;
|
||||
setup_led_button[LED_KEY_6] = iidx_cfg->tt_sensor.deadzone == 2 ? SILVER : 0;
|
||||
setup_led_button[LED_KEY_1] = iidx_cfg->tt_sensor.ppr == 0 ? SILVER : 0;
|
||||
setup_led_button[LED_KEY_3] = iidx_cfg->tt_sensor.ppr == 1 ? SILVER : 0;
|
||||
setup_led_button[LED_KEY_5] = iidx_cfg->tt_sensor.ppr == 2 ? SILVER : 0;
|
||||
setup_led_button[LED_KEY_7] = iidx_cfg->tt_sensor.ppr == 3 ? SILVER : 0;
|
||||
}
|
||||
|
||||
static void level_rotate()
|
||||
{
|
||||
int16_t new_value = iidx_cfg->level;
|
||||
new_value += input.rotate;
|
||||
if (new_value < 0) {
|
||||
new_value = 0;
|
||||
} else if (new_value > 255) {
|
||||
new_value = 255;
|
||||
}
|
||||
iidx_cfg->level = new_value;
|
||||
printf("Level: %d\n", iidx_cfg->level);
|
||||
}
|
||||
|
||||
static void level_key_change()
|
||||
{
|
||||
if (JUST_PRESSED(KEY_1)) {
|
||||
iidx_cfg->level = 0;
|
||||
} else if (JUST_PRESSED(KEY_2)) {
|
||||
iidx_cfg->level = 20;
|
||||
} else if (JUST_PRESSED(KEY_3)) {
|
||||
iidx_cfg->level = 50;
|
||||
} else if (JUST_PRESSED(KEY_4)) {
|
||||
iidx_cfg->level = 85;
|
||||
} else if (JUST_PRESSED(KEY_5)) {
|
||||
iidx_cfg->level = 130;
|
||||
} else if (JUST_PRESSED(KEY_6)) {
|
||||
iidx_cfg->level = 190;
|
||||
} else if (JUST_PRESSED(KEY_7)) {
|
||||
iidx_cfg->level = 255;
|
||||
}
|
||||
|
||||
check_exit();
|
||||
}
|
||||
|
||||
static void level_loop()
|
||||
{
|
||||
for (int i = 0; i < 7; i++) {
|
||||
hsv_t key_color = {i * 255 / 7, 255, 255 };
|
||||
setup_led_button[i] = button_hsv(key_color);
|
||||
}
|
||||
|
||||
uint16_t pos = iidx_cfg->level * iidx_cfg->tt_led.num / 256;
|
||||
for (unsigned i = 0; i < iidx_cfg->tt_led.num; i++) {
|
||||
setup_led_tt[i] = (i == pos) ? tt_rgb32(90, 90, 90, false) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
uint8_t channel; /* 0:E1(Start), 1:E2(Effect), 2:E3(VEFX), 3:E4 */
|
||||
volatile uint8_t *value;
|
||||
int16_t start_angle;
|
||||
} analog_ctx;
|
||||
|
||||
static void analog_key_change()
|
||||
{
|
||||
if (JUST_PRESSED(E1)) {
|
||||
analog_ctx.channel = 0;
|
||||
analog_ctx.value = &iidx_cfg->effects.e1;
|
||||
} else if (JUST_PRESSED(E2)) {
|
||||
analog_ctx.channel = 1;
|
||||
analog_ctx.value = &iidx_cfg->effects.e2;
|
||||
} else if (JUST_PRESSED(E3)) {
|
||||
analog_ctx.channel = 2;
|
||||
analog_ctx.value = &iidx_cfg->effects.e3;
|
||||
} else if (JUST_PRESSED(E4)) {
|
||||
analog_ctx.channel = 3;
|
||||
analog_ctx.value = &iidx_cfg->effects.e4;
|
||||
} else if (JUST_PRESSED(KEY_1)) {
|
||||
*analog_ctx.value = 0;
|
||||
} else if (JUST_PRESSED(KEY_2)) {
|
||||
*analog_ctx.value = 43;
|
||||
} else if (JUST_PRESSED(KEY_3)) {
|
||||
*analog_ctx.value = 85;
|
||||
} else if (JUST_PRESSED(KEY_4)) {
|
||||
*analog_ctx.value = 128;
|
||||
} else if (JUST_PRESSED(KEY_5)) {
|
||||
*analog_ctx.value = 170;
|
||||
} else if (JUST_PRESSED(KEY_6)) {
|
||||
*analog_ctx.value = 213;
|
||||
} else if (JUST_PRESSED(KEY_7)) {
|
||||
*analog_ctx.value = 255;
|
||||
}
|
||||
|
||||
check_exit();
|
||||
}
|
||||
|
||||
static void analog_enter()
|
||||
{
|
||||
analog_key_change();
|
||||
}
|
||||
|
||||
static void analog_rotate()
|
||||
{
|
||||
int16_t new_value = *analog_ctx.value;
|
||||
new_value += input.rotate;
|
||||
if (new_value < 0) {
|
||||
new_value = 0;
|
||||
} else if (new_value > 255) {
|
||||
new_value = 255;
|
||||
}
|
||||
*analog_ctx.value = new_value;
|
||||
}
|
||||
|
||||
static uint32_t scale_color(uint32_t color, uint8_t value, uint8_t factor)
|
||||
{
|
||||
uint8_t r = (color >> 16) & 0xff;
|
||||
uint8_t g = (color >> 8) & 0xff;
|
||||
uint8_t b = color & 0xff;
|
||||
|
||||
r = (r * value) / factor;
|
||||
g = (g * value) / factor;
|
||||
b = (b * value) / factor;
|
||||
|
||||
return (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
static void analog_loop()
|
||||
{
|
||||
uint32_t colors[4] = { RED, GREEN, CYAN, YELLOW};
|
||||
uint32_t tt_colors[4] = { TT_RED, TT_GREEN, TT_CYAN, TT_YELLOW };
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint32_t color = colors[i];
|
||||
if (analog_ctx.channel == i) {
|
||||
color &= blink_fast;
|
||||
}
|
||||
setup_led_button[LED_E1 + i] = color;
|
||||
}
|
||||
|
||||
int tt_split = (int)*analog_ctx.value * iidx_cfg->tt_led.num / 255;
|
||||
|
||||
for (int i = 1; i < iidx_cfg->tt_led.num - 1; i++) {
|
||||
setup_led_tt[i] = i < tt_split ? tt_colors[analog_ctx.channel] : 0;
|
||||
}
|
||||
|
||||
int button_split = *analog_ctx.value / 37;
|
||||
int scale = *analog_ctx.value % 37;
|
||||
for (int i = 0; i < 7; i++) {
|
||||
uint32_t color = colors[analog_ctx.channel];
|
||||
if (i == button_split) {
|
||||
color = scale_color(color, scale, 37);
|
||||
} else if (i > button_split) {
|
||||
color = 0;
|
||||
}
|
||||
setup_led_button[LED_KEY_1 + i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
uint8_t phase; /* 0:H, 1:S, 2:V */
|
||||
hsv_t hsv;
|
||||
uint8_t *value;
|
||||
int16_t start_angle;
|
||||
uint16_t keys;
|
||||
hsv_t *leds;
|
||||
} key_ctx;
|
||||
|
||||
static void key_apply()
|
||||
{
|
||||
for (int i = 0; i < 11; i++) {
|
||||
if (key_ctx.keys & (1 << i)) {
|
||||
key_ctx.leds[i] = key_ctx.hsv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void key_change()
|
||||
{
|
||||
if (JUST_PRESSED(AUX_NO)) {
|
||||
quit_mode(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (JUST_PRESSED(AUX_YES)) {
|
||||
key_ctx.phase++;
|
||||
if (key_ctx.phase == 3) {
|
||||
key_apply();
|
||||
quit_mode(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (key_ctx.phase == 1) {
|
||||
key_ctx.value = &key_ctx.hsv.s;
|
||||
} else {
|
||||
key_ctx.value = &key_ctx.hsv.v;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
key_ctx.keys ^= input.just_pressed;
|
||||
}
|
||||
|
||||
static void key_rotate()
|
||||
{
|
||||
int16_t new_value = *key_ctx.value;
|
||||
new_value += input.rotate;
|
||||
if (key_ctx.phase > 0) {
|
||||
if (new_value < 0) {
|
||||
new_value = 0;
|
||||
} else if (new_value > 255) {
|
||||
new_value = 255;
|
||||
}
|
||||
}
|
||||
*key_ctx.value = (uint8_t)new_value;
|
||||
}
|
||||
|
||||
static void key_loop()
|
||||
{
|
||||
for (int i = 0; i < 11; i ++) {
|
||||
if (key_ctx.keys == 0) {
|
||||
setup_led_button[i] = button_hsv(key_ctx.hsv) & blink_slow;
|
||||
} else if (key_ctx.keys & (1 << i)) {
|
||||
setup_led_button[i] = button_hsv(key_ctx.hsv);
|
||||
} else {
|
||||
setup_led_button[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t pos = *key_ctx.value * iidx_cfg->tt_led.num / 256;
|
||||
for (unsigned i = 0; i < iidx_cfg->tt_led.num; i++) {
|
||||
setup_led_tt[i] = (i == pos) ? tt_rgb32(90, 90, 90, false) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void key_enter()
|
||||
{
|
||||
key_ctx = (typeof(key_ctx)) {
|
||||
.phase = 0,
|
||||
.hsv = { .h = 200, .s = 255, .v = 128 },
|
||||
.value = &key_ctx.hsv.h,
|
||||
.start_angle = input.angle,
|
||||
.keys = 0,
|
||||
.leds = iidx_cfg->key_on,
|
||||
};
|
||||
|
||||
if (current_mode == MODE_KEY_OFF) {
|
||||
key_ctx.hsv = (hsv_t) { .h = 60, .s = 255, .v = 5 };
|
||||
key_ctx.leds = iidx_cfg->key_off;
|
||||
}
|
||||
}
|
||||
|
||||
#define K0_WHITE {.v = 5}
|
||||
#define K0_SKY {.h = 215, .s = 255, .v = 20}
|
||||
#define K0_RED {.h = 87, .s = 255, .v = 20}
|
||||
#define K0_GREEN {.h = 0, .s = 255, .v = 20}
|
||||
|
||||
#define K1_WHITE {.v = 200}
|
||||
#define K1_SKY {.h = 215, .s = 255, .v = 230}
|
||||
#define K1_RED {.h = 87, .s = 255, .v = 230}
|
||||
#define K1_GREEN {.h = 0, .s = 255, .v = 230}
|
||||
|
||||
#define K0_RAINBOW(x) {.h = 23 * x, .s = 255, .v = 20}
|
||||
#define K1_RAINBOW(x) {.h = 23 * x, .s = 255, .v = 230}
|
||||
|
||||
static struct {
|
||||
hsv_t key_off[11];
|
||||
hsv_t key_on[11];
|
||||
} themes[7] = {
|
||||
{{ { 0 }, },
|
||||
{ K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE,
|
||||
K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE },
|
||||
},
|
||||
{{ { 0 }, },
|
||||
{ K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE,
|
||||
K1_RED, K1_GREEN, K1_GREEN, K1_SKY },
|
||||
},
|
||||
{{ { 0 }, },
|
||||
{ K1_RED, K1_SKY, K1_RED, K1_SKY, K1_RED, K1_SKY, K1_RED,
|
||||
K1_RED, K1_GREEN, K1_GREEN, K1_GREEN },
|
||||
},
|
||||
{{ K0_WHITE, K0_WHITE, K0_WHITE, K0_WHITE, K0_WHITE, K0_WHITE, K0_WHITE,
|
||||
K0_WHITE, K0_WHITE, K0_WHITE, K0_WHITE },
|
||||
{ K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE,
|
||||
K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE },
|
||||
},
|
||||
{{ K0_RED, K0_SKY, K0_RED, K0_SKY, K0_RED, K0_SKY, K0_RED,
|
||||
K0_RED, K0_GREEN, K0_GREEN, K0_GREEN },
|
||||
{ K1_RED, K1_SKY, K1_RED, K1_SKY, K1_RED, K1_SKY, K1_RED,
|
||||
K1_RED, K1_GREEN, K1_GREEN, K1_GREEN },
|
||||
},
|
||||
{{ K0_RAINBOW(0), K0_RAINBOW(1), K0_RAINBOW(2), K0_RAINBOW(3),
|
||||
K0_RAINBOW(4), K0_RAINBOW(5), K0_RAINBOW(6),
|
||||
K0_RAINBOW(7), K0_RAINBOW(8), K0_RAINBOW(9), K0_RAINBOW(10)
|
||||
},
|
||||
{ K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE,
|
||||
K1_WHITE, K1_WHITE, K1_WHITE, K1_WHITE },
|
||||
},
|
||||
{{ K0_RAINBOW(0), K0_RAINBOW(1), K0_RAINBOW(2), K0_RAINBOW(3),
|
||||
K0_RAINBOW(4), K0_RAINBOW(5), K0_RAINBOW(6),
|
||||
K0_RAINBOW(7), K0_RAINBOW(8), K0_RAINBOW(9), K0_RAINBOW(10)
|
||||
},
|
||||
{ K1_RAINBOW(0), K1_RAINBOW(1), K1_RAINBOW(2), K1_RAINBOW(3),
|
||||
K1_RAINBOW(4), K1_RAINBOW(5), K1_RAINBOW(6),
|
||||
K1_RAINBOW(7), K1_RAINBOW(8), K1_RAINBOW(9), K1_RAINBOW(10)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static void key_theme_key_change()
|
||||
{
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (JUST_PRESSED(KEY_1 << i)) {
|
||||
memcpy(iidx_cfg->key_off, themes[i].key_off, sizeof(iidx_cfg->key_off));
|
||||
memcpy(iidx_cfg->key_on, themes[i].key_on, sizeof(iidx_cfg->key_on));
|
||||
break;
|
||||
}
|
||||
}
|
||||
check_exit();
|
||||
}
|
||||
|
||||
static void key_theme_loop()
|
||||
{
|
||||
for (int i = 0; i < 11; i++) {
|
||||
if (blink_slow) {
|
||||
setup_led_button[i] = button_hsv(iidx_cfg->key_on[i]);
|
||||
} else {
|
||||
setup_led_button[i] = button_hsv(iidx_cfg->key_off[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tt_theme_key_change()
|
||||
{
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (JUST_PRESSED(KEY_1 << i)) {
|
||||
iidx_cfg->tt_led.effect = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
check_exit();
|
||||
}
|
||||
|
||||
static void tt_theme_loop()
|
||||
{
|
||||
for (int i = 0; i < 7; i++) {
|
||||
setup_led_button[i] = iidx_cfg->tt_led.effect == i ? SILVER : 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
mode_func key_change;
|
||||
mode_func rotate;
|
||||
mode_func loop;
|
||||
mode_func enter;
|
||||
} mode_defs[] = {
|
||||
[MODE_NONE] = { nop, none_rotate, none_loop, nop},
|
||||
[MODE_TURNTABLE] = { tt_key_change, tt_rotate, tt_loop, tt_enter},
|
||||
[MODE_ANALOG] = { analog_key_change, analog_rotate, analog_loop, analog_enter},
|
||||
[MODE_LEVEL] = { level_key_change, level_rotate, level_loop, nop},
|
||||
[MODE_TT_THEME] = { tt_theme_key_change, nop, tt_theme_loop, nop},
|
||||
[MODE_KEY_THEME] = { key_theme_key_change, nop, key_theme_loop, nop},
|
||||
[MODE_KEY_OFF] = { key_change, key_rotate, key_loop, key_enter},
|
||||
[MODE_KEY_ON] = { key_change, key_rotate, key_loop, key_enter},
|
||||
};
|
||||
|
||||
static void join_mode(setup_mode_t new_mode)
|
||||
{
|
||||
cfg_save = *iidx_cfg;
|
||||
memset(&setup_led_tt, 0, sizeof(setup_led_tt));
|
||||
memset(&setup_led_button, 0, sizeof(setup_led_button));
|
||||
current_mode = new_mode;
|
||||
mode_defs[current_mode].enter();
|
||||
printf("Entering setup %d\n", new_mode);
|
||||
}
|
||||
|
||||
static void quit_mode(bool apply)
|
||||
{
|
||||
if (apply) {
|
||||
config_changed();
|
||||
} else {
|
||||
*iidx_cfg = cfg_save;
|
||||
}
|
||||
current_mode = MODE_NONE;
|
||||
printf("Quit setup %s\n", apply ? "saved." : "discarded.");
|
||||
}
|
||||
|
||||
bool setup_run(uint16_t keys, uint16_t angle)
|
||||
{
|
||||
setup_tick_ms = time_us_64() / 1000;
|
||||
input.keys = keys;
|
||||
input.angle = angle;
|
||||
input.just_pressed = keys & ~input.last_keys;
|
||||
input.just_released = ~keys & input.last_keys;
|
||||
input.rotate = input_delta(input.last_angle);
|
||||
if (input.rotate != 0) {
|
||||
printf("@ %3d %2x\n", input.rotate, input.angle);
|
||||
mode_defs[current_mode].rotate();
|
||||
}
|
||||
if (input.just_pressed) {
|
||||
printf("+ %04x\n", input.just_pressed);
|
||||
}
|
||||
if (input.just_released) {
|
||||
printf("- %04x\n", input.just_released);
|
||||
}
|
||||
|
||||
if (input.just_pressed || input.just_released) {
|
||||
mode_defs[current_mode].key_change();
|
||||
}
|
||||
|
||||
RUN_EVERY_N_MS(blink_fast = ~blink_fast, 100);
|
||||
RUN_EVERY_N_MS(blink_slow = ~blink_slow, 500);
|
||||
|
||||
mode_defs[current_mode].loop();
|
||||
|
||||
input.last_keys = keys;
|
||||
input.last_angle = angle;
|
||||
|
||||
return current_mode != MODE_NONE;
|
||||
}
|
||||
|
||||
void setup_init()
|
||||
{
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Controller Setup
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#ifndef SETUP_H
|
||||
#define SETUP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "board_defs.h"
|
||||
|
||||
void setup_init();
|
||||
bool setup_run(uint16_t key_flag, uint16_t tt_angle);
|
||||
|
||||
extern uint32_t setup_led_tt[];
|
||||
extern uint32_t setup_led_button[BUTTON_RGB_NUM];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Mai Pico Silder Keys
|
||||
* WHowe <github.com/whowechina>
|
||||
*
|
||||
* MPR121 CapSense based Keys
|
||||
*/
|
||||
|
||||
#include "touch.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bsp/board.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#include "board_defs.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "mpr121.h"
|
||||
|
||||
#define MPR121_ADDR 0x5A
|
||||
|
||||
static uint16_t baseline[36];
|
||||
static int16_t error[36];
|
||||
static uint16_t readout[36];
|
||||
static bool touched[36];
|
||||
static uint16_t touch[3];
|
||||
|
||||
void touch_init()
|
||||
{
|
||||
i2c_init(I2C_PORT, I2C_FREQ);
|
||||
gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
|
||||
gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SDA);
|
||||
gpio_pull_up(I2C_SCL);
|
||||
|
||||
for (int m = 0; m < 3; m++) {
|
||||
mpr121_init(MPR121_ADDR + m);
|
||||
}
|
||||
touch_update_config();
|
||||
}
|
||||
|
||||
void touch_update()
|
||||
{
|
||||
touch[0] = mpr121_touched(MPR121_ADDR);
|
||||
touch[1] = mpr121_touched(MPR121_ADDR + 1);
|
||||
touch[2] = mpr121_touched(MPR121_ADDR + 2);
|
||||
}
|
||||
|
||||
bool touch_touched(unsigned key)
|
||||
{
|
||||
if (key >= 32) {
|
||||
return 0;
|
||||
}
|
||||
return touch[key / 12] & (1 << (key % 12));
|
||||
}
|
||||
|
||||
void touch_update_config()
|
||||
{
|
||||
for (int m = 0; m < 3; m++) {
|
||||
mpr121_debounce(MPR121_ADDR + m, mai_cfg->sense.debounce_touch,
|
||||
mai_cfg->sense.debounce_release);
|
||||
mpr121_sense(MPR121_ADDR + m, mai_cfg->sense.global, mai_cfg->sense.keys + m * 12);
|
||||
mpr121_filter(MPR121_ADDR + m, mai_cfg->sense.filter & 0x0f,
|
||||
(mai_cfg->sense.filter >> 4) & 0x0f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Mai Pico Touch Keys
|
||||
* WHowe <github.com/whowechina>
|
||||
*/
|
||||
|
||||
#ifndef TOUCH_H
|
||||
#define TOUCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void touch_init();
|
||||
void touch_update();
|
||||
bool touch_touched(unsigned key);
|
||||
void touch_update_config();
|
||||
|
||||
#endif
|
||||
@@ -96,7 +96,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID 1
|
||||
#define CFG_TUD_HID 3
|
||||
#define CFG_TUD_CDC 1
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
|
||||
+105
-79
@@ -36,8 +36,8 @@
|
||||
*/
|
||||
#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))
|
||||
(0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4))
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
@@ -51,8 +51,11 @@ tusb_desc_device_t desc_device_joy = {
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = 0xCaff,
|
||||
.idProduct = USB_PID,
|
||||
// To match CrazyRedMachine dll
|
||||
// vid 0x0f0d, pid 0x0092, interface 1
|
||||
|
||||
.idVendor = 0x0f0d,
|
||||
.idProduct = 0x0092,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
@@ -64,7 +67,7 @@ tusb_desc_device_t desc_device_joy = {
|
||||
// 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_joy;
|
||||
return (uint8_t const*)&desc_device_joy;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -72,27 +75,49 @@ uint8_t const* tud_descriptor_device_cb(void) {
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
uint8_t const desc_hid_report_joy[] = {
|
||||
GAMECON_REPORT_DESC_JOYSTICK(HID_REPORT_ID(REPORT_ID_JOYSTICK)),
|
||||
GAMECON_REPORT_DESC_LIGHTS(HID_REPORT_ID(REPORT_ID_LIGHTS))
|
||||
MAIPICO_REPORT_DESC_JOYSTICK,
|
||||
};
|
||||
|
||||
uint8_t const desc_hid_report_led[] = {
|
||||
MAIPICO_LED_HEADER,
|
||||
MAIPICO_REPORT_DESC_LED_touch_16,
|
||||
MAIPICO_REPORT_DESC_LED_touch_15,
|
||||
MAIPICO_REPORT_DESC_LED_TOWER_6,
|
||||
MAIPICO_REPORT_DESC_LED_COMPRESSED,
|
||||
MAIPICO_LED_FOOTER
|
||||
};
|
||||
|
||||
uint8_t const desc_hid_report_nkro[] = {
|
||||
MAIPICO_REPORT_DESC_NKRO,
|
||||
};
|
||||
|
||||
// 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 itf) {
|
||||
(void)itf;
|
||||
return desc_hid_report_joy;
|
||||
uint8_t const* tud_hid_descriptor_report_cb(uint8_t itf)
|
||||
{
|
||||
switch (itf) {
|
||||
case 0:
|
||||
return desc_hid_report_joy;
|
||||
case 1:
|
||||
return desc_hid_report_led;
|
||||
case 2:
|
||||
return desc_hid_report_nkro;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum { ITF_NUM_HID, ITF_NUM_CDC, ITF_NUM_CDC_DATA, ITF_NUM_TOTAL };
|
||||
enum { ITF_NUM_JOY, ITF_NUM_LED, ITF_NUM_NKRO, 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 CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN * 3 + TUD_CDC_DESC_LEN)
|
||||
|
||||
#define EPNUM_HID 0x84
|
||||
#define EPNUM_JOY 0x84
|
||||
#define EPNUM_LED 0x85
|
||||
#define EPNUM_KEY 0x86
|
||||
#define EPNUM_CDC_NOTIF 0x81
|
||||
#define EPNUM_CDC_OUT 0x02
|
||||
#define EPNUM_CDC_IN 0x82
|
||||
@@ -101,25 +126,31 @@ uint8_t const desc_configuration_joy[] = {
|
||||
// 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),
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 200),
|
||||
|
||||
// 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_joy), EPNUM_HID,
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_JOY, 4, HID_ITF_PROTOCOL_NONE,
|
||||
sizeof(desc_hid_report_joy), EPNUM_JOY,
|
||||
CFG_TUD_HID_EP_BUFSIZE, 1),
|
||||
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF,
|
||||
8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64)
|
||||
|
||||
};
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_LED, 5, HID_ITF_PROTOCOL_NONE,
|
||||
sizeof(desc_hid_report_led), EPNUM_LED,
|
||||
CFG_TUD_HID_EP_BUFSIZE, 4),
|
||||
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_NKRO, 6, HID_ITF_PROTOCOL_NONE,
|
||||
sizeof(desc_hid_report_nkro), EPNUM_KEY,
|
||||
CFG_TUD_HID_EP_BUFSIZE, 1),
|
||||
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 7, EPNUM_CDC_NOTIF,
|
||||
8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64)
|
||||
};
|
||||
|
||||
// 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
|
||||
return desc_configuration_joy;
|
||||
return desc_configuration_joy;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -130,66 +161,61 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
|
||||
const char *string_desc_arr[] = {
|
||||
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
||||
"WHowe" , // 1: Manufacturer
|
||||
"Pico IIDX Controller", // 2: Product
|
||||
"654321", // 3: Serials, should use chip ID
|
||||
"Button 1",
|
||||
"Button 2",
|
||||
"Button 3",
|
||||
"Button 4",
|
||||
"Button 5",
|
||||
"Button 6",
|
||||
"Button 7",
|
||||
"E1",
|
||||
"E2",
|
||||
"E3",
|
||||
"E4"
|
||||
"Mai Pico Controller", // 2: Product
|
||||
"123456", // 3: Serials, should use chip ID
|
||||
"Mai Pico Joystick",
|
||||
"Mai Pico LED",
|
||||
"Mai Pico NKRO",
|
||||
"Mai Pico Serial Port",
|
||||
};
|
||||
|
||||
static uint16_t _desc_str[64];
|
||||
|
||||
// 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 < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) {
|
||||
const char* str = string_desc_arr[index];
|
||||
|
||||
// Cap at max char
|
||||
chr_count = strlen(str);
|
||||
if (chr_count > 63) chr_count = 63;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for (uint8_t i = 0; i < chr_count; i++) {
|
||||
_desc_str[1 + i] = str[i];
|
||||
}
|
||||
} else {
|
||||
_desc_str[1] = 'X';
|
||||
chr_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void konami_mode()
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
desc_device_joy.idVendor = 0x1ccf;
|
||||
desc_device_joy.idProduct = 0x8048;
|
||||
string_desc_arr[1] = "Konami Amusement";
|
||||
string_desc_arr[2] = "beatmania IIDX controller premium model";
|
||||
static uint16_t _desc_str[64];
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
_desc_str[0] = (TUSB_DESC_STRING << 8) | (2 + 2);
|
||||
return _desc_str;
|
||||
}
|
||||
|
||||
const size_t base_num = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]);
|
||||
const char *colors[] = {"Blue", "Red", "Green"};
|
||||
char str[64];
|
||||
|
||||
if (index < base_num) {
|
||||
strcpy(str, string_desc_arr[index]);
|
||||
} else if (index < base_num + 48 + 45) {
|
||||
const char *names[] = {"Key ", "Splitter "};
|
||||
int led = index - base_num;
|
||||
int id = led / 6 + 1;
|
||||
int type = led / 3 % 2;
|
||||
int brg = led % 3;
|
||||
sprintf(str, "%s%02d %s", names[type], id, colors[brg]);
|
||||
} else if (index < base_num + 48 + 45 + 18) {
|
||||
int led = index - base_num - 48 - 45;
|
||||
int id = led / 3 + 1;
|
||||
int brg = led % 3;
|
||||
sprintf(str, "Tower %02d %s", id, colors[brg]);
|
||||
} else {
|
||||
sprintf(str, "Unknown %d", index);
|
||||
}
|
||||
|
||||
uint8_t chr_count = strlen(str);
|
||||
if (chr_count > 63) {
|
||||
chr_count = 63;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
+117
-47
@@ -5,10 +5,11 @@
|
||||
#include "device/usbd.h"
|
||||
|
||||
enum {
|
||||
REPORT_ID_JOYSTICK = 1,
|
||||
REPORT_ID_LIGHTS,
|
||||
REPORT_ID_KEYBOARD,
|
||||
REPORT_ID_MOUSE,
|
||||
REPORT_ID_JOYSTICK = 1,
|
||||
REPORT_ID_LED_touch_16 = 4,
|
||||
REPORT_ID_LED_touch_15 = 5,
|
||||
REPORT_ID_LED_TOWER_6 = 6,
|
||||
REPORT_ID_LED_COMPRESSED = 11,
|
||||
};
|
||||
|
||||
// because they are missing from tusb_hid.h
|
||||
@@ -21,51 +22,120 @@ enum {
|
||||
|
||||
// Joystick Report Descriptor Template - Based off Drewol/rp2040-gamecon
|
||||
// Button Map | X | Y
|
||||
#define GAMECON_REPORT_DESC_JOYSTICK(...) \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_JOYSTICK), \
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
|
||||
__VA_ARGS__ HID_USAGE_PAGE(HID_USAGE_PAGE_BUTTON), HID_USAGE_MIN(1), \
|
||||
HID_USAGE_MAX(13), \
|
||||
HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), HID_REPORT_COUNT(13), \
|
||||
HID_REPORT_SIZE(1), HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
HID_REPORT_COUNT(1), HID_REPORT_SIZE(16 - 13), /*Padding*/ \
|
||||
HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_LOGICAL_MIN(0x00), \
|
||||
HID_LOGICAL_MAX_N(0x00ff, 2), /* Below is Joystick/analog */ \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_X), HID_USAGE(HID_USAGE_DESKTOP_Y), \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_Z), HID_USAGE(HID_USAGE_DESKTOP_RX), \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_RY), HID_USAGE(HID_USAGE_DESKTOP_RZ), \
|
||||
HID_REPORT_COUNT(6), HID_REPORT_SIZE(8), \
|
||||
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), HID_COLLECTION_END
|
||||
#define MAIPICO_REPORT_DESC_JOYSTICK \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_JOYSTICK), \
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
|
||||
HID_REPORT_ID(REPORT_ID_JOYSTICK) \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_BUTTON), \
|
||||
HID_USAGE_MIN(1), HID_USAGE_MAX(16), \
|
||||
HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \
|
||||
HID_REPORT_COUNT(16), HID_REPORT_SIZE(1), \
|
||||
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
\
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_HAT_SWITCH), \
|
||||
HID_LOGICAL_MIN(1), HID_LOGICAL_MAX(8), \
|
||||
HID_PHYSICAL_MIN(0), HID_PHYSICAL_MAX_N(315, 2), \
|
||||
HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), \
|
||||
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
\
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_X), HID_USAGE(HID_USAGE_DESKTOP_Y), \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_Z), HID_USAGE(HID_USAGE_DESKTOP_RX), \
|
||||
HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX(0xff), /* Analog */ \
|
||||
HID_REPORT_SIZE(8), HID_REPORT_COUNT(4), \
|
||||
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
\
|
||||
HID_USAGE_PAGE_N(HID_USAGE_PAGE_VENDOR, 2), \
|
||||
HID_USAGE(0), \
|
||||
HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX(0xff), \
|
||||
HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), \
|
||||
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
HID_COLLECTION_END
|
||||
|
||||
// Light Map
|
||||
#define GAMECON_REPORT_DESC_LIGHTS(...) \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
|
||||
__VA_ARGS__ HID_REPORT_COUNT(11), /* LED NUM */ \
|
||||
HID_REPORT_SIZE(8), HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), HID_STRING_MINIMUM(4), \
|
||||
HID_STRING_MAXIMUM(16), HID_USAGE_MIN(1), HID_USAGE_MAX(16), \
|
||||
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), HID_REPORT_COUNT(1), \
|
||||
HID_REPORT_SIZE(8), /*Padding*/ \
|
||||
HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
HID_COLLECTION_END
|
||||
#define MAIPICO_LED_HEADER \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
|
||||
HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), \
|
||||
HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE)
|
||||
|
||||
// NKRO Descriptor
|
||||
#define GAMECON_REPORT_DESC_NKRO(...) \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(HID_USAGE_PAGE_KEYBOARD), \
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
|
||||
__VA_ARGS__ HID_REPORT_SIZE(1), HID_REPORT_COUNT(8), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), HID_USAGE_MIN(224), \
|
||||
HID_USAGE_MAX(231), HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \
|
||||
HID_INPUT(HID_VARIABLE), HID_REPORT_SIZE(1), HID_REPORT_COUNT(31 * 8), \
|
||||
HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), HID_USAGE_MIN(0), \
|
||||
HID_USAGE_MAX(31 * 8 - 1), HID_INPUT(HID_VARIABLE), HID_COLLECTION_END
|
||||
#define MAIPICO_LED_FOOTER \
|
||||
HID_COLLECTION_END
|
||||
|
||||
// Slider First 16 LEDs (48 rgb zones, BRG order)
|
||||
#define MAIPICO_REPORT_DESC_LED_touch_16 \
|
||||
HID_REPORT_ID(REPORT_ID_LED_touch_16) \
|
||||
HID_REPORT_COUNT(48), HID_REPORT_SIZE(8), \
|
||||
HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \
|
||||
HID_USAGE_MIN(1), HID_USAGE_MAX(48), \
|
||||
HID_STRING_MINIMUM(8), HID_STRING_MAXIMUM(55), \
|
||||
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE)
|
||||
|
||||
/* Enable Konami spoof mode */
|
||||
void konami_mode();
|
||||
// Slider Remaining 15 LEDs (45 rgb zones, BRG order)
|
||||
#define MAIPICO_REPORT_DESC_LED_touch_15 \
|
||||
HID_REPORT_ID(REPORT_ID_LED_touch_15) \
|
||||
HID_REPORT_COUNT(45), HID_REPORT_SIZE(8), \
|
||||
HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \
|
||||
HID_USAGE_MIN(49), HID_USAGE_MAX(93), \
|
||||
HID_STRING_MINIMUM(8), HID_STRING_MAXIMUM(52), /* Delta to previous */ \
|
||||
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE)
|
||||
|
||||
#endif /* USB_DESCRIPTORS_H_ */
|
||||
// Tower LEDs (18 rgb zones, BRG order)
|
||||
#define MAIPICO_REPORT_DESC_LED_TOWER_6 \
|
||||
HID_REPORT_ID(REPORT_ID_LED_TOWER_6) \
|
||||
HID_REPORT_COUNT(18), HID_REPORT_SIZE(8), \
|
||||
HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \
|
||||
HID_USAGE_MIN(94), HID_USAGE_MAX(111), \
|
||||
HID_STRING_MINIMUM(8), HID_STRING_MAXIMUM(25), /* Delta to previous */ \
|
||||
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE)
|
||||
|
||||
// LEDs Compressed
|
||||
#define MAIPICO_REPORT_DESC_LED_COMPRESSED \
|
||||
HID_REPORT_ID(REPORT_ID_LED_COMPRESSED) \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \
|
||||
HID_USAGE(0x00), \
|
||||
HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \
|
||||
HID_REPORT_SIZE(8), HID_REPORT_COUNT(63), \
|
||||
HID_FEATURE(HID_DATA | HID_VARIABLE | HID_ABSOLUTE)
|
||||
|
||||
#define MAIPICO_REPORT_DESC_NKRO \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \
|
||||
HID_USAGE(HID_USAGE_DESKTOP_KEYBOARD), \
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
|
||||
/* Modifier */ \
|
||||
HID_REPORT_SIZE(1), \
|
||||
HID_REPORT_COUNT(8), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), \
|
||||
HID_USAGE_MIN(224), \
|
||||
HID_USAGE_MAX(231), \
|
||||
HID_LOGICAL_MIN(0), \
|
||||
HID_LOGICAL_MAX(1), \
|
||||
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
/* LED output that we don't care */ \
|
||||
HID_REPORT_COUNT(5), \
|
||||
HID_REPORT_SIZE(1), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_LED), \
|
||||
HID_USAGE_MIN(1), \
|
||||
HID_USAGE_MAX(5), \
|
||||
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
HID_REPORT_COUNT(1), \
|
||||
HID_REPORT_SIZE(3), \
|
||||
HID_OUTPUT(HID_CONSTANT), \
|
||||
/* Full Keyboard Bitmap */ \
|
||||
HID_REPORT_SIZE(1), \
|
||||
HID_REPORT_COUNT(120), \
|
||||
HID_LOGICAL_MIN(0), \
|
||||
HID_LOGICAL_MAX(1), \
|
||||
HID_USAGE_PAGE(HID_USAGE_PAGE_KEYBOARD), \
|
||||
HID_USAGE_MIN(0), \
|
||||
HID_USAGE_MAX(119), \
|
||||
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||
HID_COLLECTION_END
|
||||
|
||||
// HID_REPORT_ID(REPORT_ID_NKRO)
|
||||
|
||||
#endif /* USB_DESCRIPTORS_H_ */
|
||||
|
||||
Reference in New Issue
Block a user