Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 9Rmain
  • anon/gpndemo
  • anon/update-sim
  • anon/webflasher
  • audio_input
  • audio_io
  • bl00mbox
  • bl00mbox_old
  • captouch-threshold
  • ch3/bl00mbox_docs
  • ci-1690580595
  • compressor
  • dev_p4
  • dev_p4-iggy
  • dev_p4-iggy-rebased
  • dos
  • dos-main-patch-50543
  • events
  • fm_fix
  • fm_fix2
  • fpletz/flake
  • history-rewrite
  • icon-flower
  • iggy/stemming
  • iggy/stemming_merge
  • json-error
  • main
  • main+schneider
  • media-buf
  • micropython_api
  • moon2_applications
  • moon2_demo_temp
  • moon2_gay_drums
  • passthrough
  • phhw
  • pippin/display-python-errors-on-display
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pippin/media_framework
  • pippin/uhm_flash_access_bust
  • pressable_bugfix
  • q3k/doom-poc
  • rahix/big-flow3r
  • rahix/flow3rseeds
  • raw_captouch_new
  • raw_captouch_old
  • release/1.0.0
  • release/1.1.0
  • release/1.1.1
  • rev4_micropython
  • schneider/application-remove-name
  • schneider/bhi581
  • schneider/factory_test
  • schneider/recovery
  • scope
  • scope_hack
  • sdkconfig-spiram-tinyusb
  • sec/auto-nick
  • sec/blinky
  • simtest
  • slewtest
  • t
  • test
  • test2
  • uctx-wip
  • view-think
  • vm-pending
  • vsync
  • wave
  • wip-docs
  • wip-tinyusb
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
83 results

Target

Select target project
  • flow3r/flow3r-firmware
  • Vespasian/flow3r-firmware
  • alxndr42/flow3r-firmware
  • pl/flow3r-firmware
  • Kari/flow3r-firmware
  • raimue/flow3r-firmware
  • grandchild/flow3r-firmware
  • mu5tach3/flow3r-firmware
  • Nervengift/flow3r-firmware
  • arachnist/flow3r-firmware
  • TheNewCivilian/flow3r-firmware
  • alibi/flow3r-firmware
  • manuel_v/flow3r-firmware
  • xeniter/flow3r-firmware
  • maxbachmann/flow3r-firmware
  • yGifoom/flow3r-firmware
  • istobic/flow3r-firmware
  • EiNSTeiN_/flow3r-firmware
  • gnudalf/flow3r-firmware
  • 999eagle/flow3r-firmware
  • toerb/flow3r-firmware
  • pandark/flow3r-firmware
  • teal/flow3r-firmware
  • x42/flow3r-firmware
  • alufers/flow3r-firmware
  • dos/flow3r-firmware
  • yrlf/flow3r-firmware
  • LuKaRo/flow3r-firmware
  • ThomasElRubio/flow3r-firmware
  • ai/flow3r-firmware
  • T_X/flow3r-firmware
  • highTower/flow3r-firmware
  • beanieboi/flow3r-firmware
  • Woazboat/flow3r-firmware
  • gooniesbro/flow3r-firmware
  • marvino/flow3r-firmware
  • kressnerd/flow3r-firmware
  • quazgar/flow3r-firmware
  • aoid/flow3r-firmware
  • jkj/flow3r-firmware
  • naomi/flow3r-firmware
41 results
Select Git revision
  • 89-apps-should-be-able-to-specify-if-they-want-wifi-to-be-disabled-when-entering-them
  • 9Rmain
  • allow-reloading-sunmenu
  • always-have-a-wifi-instance
  • anon/gpndemo
  • anon/update-sim
  • anon/webflasher
  • app_text_viewer
  • audio_input
  • audio_io
  • blm_dev_chan
  • ch3/bl00mbox_docs
  • ci-1690580595
  • dev_p4
  • dev_p4-iggy
  • dev_p4-iggy-rebased
  • dx/dldldld
  • dx/fb-save-restore
  • dx/hint-hint
  • dx/jacksense-headset-mic-only
  • events
  • fil3s-limit-filesize
  • fil3s-media
  • fpletz/flake
  • gr33nhouse-improvements
  • history-rewrite
  • icon-flower
  • iggy/stemming
  • iggy/stemming_merge
  • led_fix_fix
  • main
  • main+schneider
  • media_has_video_has_audio
  • micropython_api
  • mixer2
  • moon2_demo_temp
  • moon2_migrate_apps
  • more-accurate-battery
  • pippin/ctx_sprite_sheet_support
  • pippin/display-python-errors-on-display
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pippin/more-accurate-battery
  • pippin/tcp_redirect_hack
  • pippin/tune_ctx_config_update_from_upstream
  • pippin/uhm_flash_access_bust
  • pressable_bugfix
  • py_only_update_fps_overlay_when_changing
  • q3k/doom-poc
  • q3k/render-to-texture
  • rahix/flow3rseeds
  • raw_captouch_new
  • raw_captouch_old
  • release/1.0.0
  • release/1.1.0
  • release/1.1.1
  • release/1.2.0
  • release/1.3.0
  • release/1.4.0
  • restore_blit
  • return_of_melodic_demo
  • rev4_micropython
  • schneider/application-remove-name
  • schneider/bhi581
  • schneider/factory_test
  • schneider/recovery
  • scope_hack
  • sdkconfig-spiram-tinyusb
  • sec/auto-nick
  • sec/blinky
  • sector_size_512
  • shoegaze-fps
  • smaller_gradient_lut
  • store_delta_ms_and_ins_as_class_members
  • task_cleanup
  • uctx-wip
  • w1f1-in-sim
  • widgets_draw
  • wifi-json-error-handling
  • wip-docs
  • wip-tinyusb
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
  • v1.4.0
94 results
Show changes
Showing
with 1474 additions and 0 deletions
idf_component_register(
SRCS
apa102LEDStrip.c
audio.c
captouch.c
display.c
espan.c
leds.c
scope.c
synth.c
spio.c
INCLUDE_DIRS
include
REQUIRES
badge23_hwconfig
gc9a01
espressif__led_strip
)
menu "Badge23 Config"
choice BADGE23_HW_GEN
prompt "Badge23 Hardware Generation"
default BADGE23_HW_GEN_P4
config BADGE23_HW_GEN_P1
help
Protoype version 1, a.k.a. proto1. Very early protoype.
Visual identifiers:
- No line in/out jacks
- White bottom board
- USB-C jack points side of leaf
bool "Prototype 1"
config BADGE23_HW_GEN_P3
help
Prototype version 3, a.k.a. proto3
Visual identifiers:
- Sticker with B3xx (xx being arbitrary digits) on the back
bool "Prototype 3"
config BADGE23_HW_GEN_P4
help
Prototype version 4, a.k.a. proto4
Visual identifiers:
- Sticker with B4xx (xx being arbitrary digits) on the back
bool "Prototype 4"
config BADGE23_HW_GEN_ADILESS
help
Prototype version 5, a.k.a. adi-less
Visual identifiers:
- Sticker with B5xx (xx being arbitrary digits) on the back
bool "Prototype 5 / ADI-less"
endchoice
endmenu
badge23/espan
===
Transitional component containing all custom C code for badge23, including drivers for peripherals and 'espan' application leftovers.
This will be likely split up into sub-components.
#include "badge23/apa102LEDStrip.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, unsigned char globalBrightness)
{
ledObject->_numLEDs = numLEDs;
ledObject->_bytesPerLED = bytesPerLED;
ledObject->_endFrameLength = 1;//round( (numLEDs/2)/8 );
ledObject->_frameLength = (1+numLEDs+ledObject->_endFrameLength)*bytesPerLED;
ledObject->_globalBrightness = globalBrightness;
ledObject->LEDs = (unsigned char *)malloc(ledObject->_frameLength*sizeof(unsigned char));
//Start Frame
ledObject->LEDs[0] = 0;
ledObject->LEDs[1] = 0;
ledObject->LEDs[2] = 0;
ledObject->LEDs[3] = 0;
//Driver frame+PIXEL frames
for(ledObject->_counter=ledObject->_bytesPerLED; ledObject->_counter<ledObject->_frameLength-(ledObject->_endFrameLength*ledObject->_bytesPerLED); ledObject->_counter+=ledObject->_bytesPerLED)
{
ledObject->LEDs[ledObject->_counter] = ledObject->_globalBrightness;
ledObject->LEDs[ledObject->_counter+1] = 0;
ledObject->LEDs[ledObject->_counter+2] = 0;
ledObject->LEDs[ledObject->_counter+3] = 0;
}
//END frames
for(ledObject->_counter=ledObject->_frameLength-(ledObject->_endFrameLength*ledObject->_bytesPerLED); ledObject->_counter<ledObject->_frameLength; ledObject->_counter+=ledObject->_bytesPerLED)
{
ledObject->LEDs[ledObject->_counter] = 255;
ledObject->LEDs[ledObject->_counter+1] = 255;
ledObject->LEDs[ledObject->_counter+2] = 255;
ledObject->LEDs[ledObject->_counter+3] = 255;
}
}
void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour)
{
ledObject->_counter = 4*(pixelIndex+1);
ledObject->LEDs[ ledObject->_counter + 1 ] = pixelColour[2];
ledObject->LEDs[ ledObject->_counter + 2 ] = pixelColour[1];
ledObject->LEDs[ ledObject->_counter + 3 ] = pixelColour[0];
}
void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour)
{
ledObject->_counter = 4*(pixelIndex+1);
pixelColour[2] = ledObject->LEDs[ ledObject->_counter + 1 ];
pixelColour[1] = ledObject->LEDs[ ledObject->_counter + 2 ];
pixelColour[0] = ledObject->LEDs[ ledObject->_counter + 3 ];
}
#include "badge23/audio.h"
#include "badge23/synth.h"
#include "badge23/scope.h"
#include "badge23_hwconfig.h"
#include "driver/i2s.h"
#include "driver/i2c.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#define TIMEOUT_MS 1000
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
static void audio_player_task(void* arg);
#define DMA_BUFFER_SIZE 64
#define DMA_BUFFER_COUNT 2
#define I2S_PORT 0
#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)
static uint8_t max98091_i2c_read(const uint8_t reg)
{
const uint8_t tx[] = {reg};
uint8_t rx[1];
esp_err_t ret = i2c_master_write_read_device(I2C_MASTER_NUM, 0x10, tx, sizeof(tx), rx, sizeof(rx), TIMEOUT_MS / portTICK_PERIOD_MS);
return rx[0];
}
static esp_err_t max98091_i2c_write(const uint8_t reg, const uint8_t data)
{
const uint8_t tx[] = {reg, data};
esp_err_t ret = i2c_master_write_to_device(I2C_MASTER_NUM, 0x10, tx, sizeof(tx), TIMEOUT_MS / portTICK_PERIOD_MS);
if(max98091_i2c_read(reg) != data) printf("Write of %04X to %02X apparently failed\n", data, reg);
return ret;
}
static void init_codec()
{
// Enable CODEC
vTaskDelay(10 / portTICK_PERIOD_MS);
ESP_ERROR_CHECK(max98091_i2c_write(0x00, 0x80)); // shutdown
vTaskDelay(10 / portTICK_PERIOD_MS);
ESP_ERROR_CHECK(max98091_i2c_write(0x45, 0)); // shutdown
ESP_ERROR_CHECK(max98091_i2c_write(0x1b, 1 << 4)); // pclk = mclk / 1
ESP_ERROR_CHECK(max98091_i2c_write(0x26, (1 << 7) | (1 << 6))); // music, dc filter in record
ESP_ERROR_CHECK(max98091_i2c_write(0x06, 1 << 2)); // Sets up DAI for left-justified slave mode operation.
ESP_ERROR_CHECK(max98091_i2c_write(0x07, 1 << 5)); // Sets up the DAC to speaker path
// Somehow this was needed to get an input signal to the ADC, even though
// all other registers should be taken care of later. Don't know why.
ESP_ERROR_CHECK(max98091_i2c_write(0x09, 1 << 6)); // Sets up the line in to adc path
ESP_ERROR_CHECK(max98091_i2c_write(0x25, (1 << 1) | (1 << 0))); // SDOUT, SDIN enabled
ESP_ERROR_CHECK(max98091_i2c_write(0x42, 1 << 0)); // bandgap bias
ESP_ERROR_CHECK(max98091_i2c_write(0x43, 1 << 0)); // high performane mode
// Table 51. Digital Audio Interface (DAI) Format Configuration Register
ESP_ERROR_CHECK(max98091_i2c_write(0x2E, 1)); // Left DAC -> Left Speaker
ESP_ERROR_CHECK(max98091_i2c_write(0x2F, 2)); // Right DAC -> Right Speaker
//max98091_i2c_write(0x2E, (1<<2) | (1<<1)); // Line A -> Left Speaker
//max98091_i2c_write(0x2F, (1<<3) | (1<<0)); // LIne B -> Right Speaker
ESP_ERROR_CHECK(max98091_i2c_write(0x29, 1)); // Left DAC -> Left HP
ESP_ERROR_CHECK(max98091_i2c_write(0x2A, 2)); // Right DAC -> Right HP
// Mic bias is off
ESP_ERROR_CHECK(max98091_i2c_write(0x3E, (1<<4) |(1<<3) | (1<<2) | (1<<1) | (1<<0))); // enable micbias, line input amps, ADCs
ESP_ERROR_CHECK(max98091_i2c_write(0x0D, (1<<3) | (1<<2))); // IN3 SE -> Line A, IN4 SE -> Line B
ESP_ERROR_CHECK(max98091_i2c_write(0x15, (1<<4) )); // line B -> left ADC
ESP_ERROR_CHECK(max98091_i2c_write(0x16, (1<<3) )); // line A -> right ADC
ESP_ERROR_CHECK(max98091_i2c_write(0x44, (1<<2) | (1<<1) | (1<<0) )); // 128x oversampling, dithering, high performance ADC
max98091_i2c_write(0x13, (1<<4) | (1<<5) | (1<<1) | (1<<0) ); // enable digital mic
// Enable headset mic
#if 0
max98091_i2c_write(0x13, 0);
ESP_ERROR_CHECK(max98091_i2c_write(0x0F, (0<<1) | (1<<0) )); // IN5/IN6 to MIC1
ESP_ERROR_CHECK(max98091_i2c_write(0x10, (1<<6) | (1<<4) | (1<<2) )); // 20 dB gain on MIC1
ESP_ERROR_CHECK(max98091_i2c_write(0x15, (1<<5) )); // MIC1 -> left ADC
ESP_ERROR_CHECK(max98091_i2c_write(0x16, (1<<5) )); // MIC1 -> right ADC
#endif
ESP_ERROR_CHECK(max98091_i2c_write(0x3F, (1<<1) | (1<<0))); // output enable: enable dacs
ESP_ERROR_CHECK(max98091_i2c_write(0x45, 1<<7)); // power up
//max98091_i2c_write(0x31, 0x2c); // 0db, no mute
//max98091_i2c_write(0x32, 0x2c); // 0db, no mute
ESP_ERROR_CHECK(max98091_i2c_write(0x3F, (1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<1) | (1<<0))); // enable outputs, dacs
//max98091_i2c_write(0x27, (1<<4) | (1<<5)); // full playback gain
//max98091_i2c_write(0x31, 0x3f); // +14 db speaker
//max98091_i2c_write(0x32, 0x3f); // +14 db speaker
ESP_ERROR_CHECK(max98091_i2c_write(0x41, 0x0));
ESP_ERROR_CHECK(max98091_i2c_write(0x3D, 1<<7)); // jack detect enable
}
static void i2s_init(void){
init_codec();
vTaskDelay(100 / portTICK_PERIOD_MS); // dunno if necessary
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
//.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB,
//^...technically wrong but works...? in idf v5 it's msb but don't try that late at night
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = DMA_BUFFER_COUNT,
.dma_buf_len = DMA_BUFFER_SIZE,
.use_apll = false
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 10,
.mck_io_num = 18,
.ws_io_num = 11,
.data_out_num = 12,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
}
#elif defined(CONFIG_BADGE23_HW_GEN_P1)
static void i2s_init(void){
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
//.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = DMA_BUFFER_COUNT,
.dma_buf_len = DMA_BUFFER_SIZE,
.use_apll = false
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 13,
.mck_io_num = 11,
.ws_io_num = 12,
.data_out_num = 14,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
}
#else
#error "audio not implemented for this badge generation"
#endif
typedef struct _audio_source_t{
void * render_data;
float (* render_function)(void *);
uint16_t index;
struct _audio_source_t * next;
} audio_source_t;
static audio_source_t * _audio_sources = NULL;
uint16_t add_audio_source(void * render_data, void * render_function){
//construct audio source struct
audio_source_t * src = malloc(sizeof(audio_source_t));
if(src == NULL) return;
src->render_data = render_data;
src->render_function = render_function;
src->next = NULL;
src->index = 0;
//handle empty list special case
if(_audio_sources == NULL){
_audio_sources = src;
return 0; //only nonempty lists from here on out!
}
//searching for lowest unused index
audio_source_t * index_source = _audio_sources;
while(1){
if(src->index == (index_source->index)){
src->index++; //someone else has index already, try next
index_source = _audio_sources; //start whole list for new index
} else {
index_source = index_source->next;
}
if(index_source == NULL){ //traversed the entire list
break;
}
}
audio_source_t * audio_source = _audio_sources;
//append new source to linked list
while(audio_source != NULL){
if(audio_source->next == NULL){
audio_source->next = src;
break;
} else {
audio_source = audio_source->next;
}
}
return src->index;
}
void remove_audio_source(uint16_t index){
audio_source_t * audio_source = _audio_sources;
audio_source_t * start_gap = NULL;
while(audio_source != NULL){
if(index == audio_source->index){
if(start_gap == NULL){
_audio_sources = audio_source->next;
} else {
start_gap->next = audio_source->next;
}
vTaskDelay(20 / portTICK_PERIOD_MS); //give other tasks time to stop using
free(audio_source); //terrible hack tbh
break;
}
start_gap = audio_source;
audio_source = audio_source->next;
}
}
uint16_t count_audio_sources(){
uint16_t ret = 0;
audio_source_t * audio_source = _audio_sources;
while(audio_source != NULL){
audio_source = audio_source->next;
ret++;
}
return ret;
}
static void _audio_init(void) {
init_scope(241);
i2s_init();
//ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
TaskHandle_t handle;
xTaskCreate(&audio_player_task, "Audio player", 3000, NULL, configMAX_PRIORITIES - 1, &handle);
}
#define LR_PHASE 1
#define NAT_LOG_DB 0.1151292546497023
static uint16_t _global_vol = 3000;
void set_global_vol_dB(int8_t vol_dB){
if(vol_dB < (BADGE_MIN_VOLUME_DB)){
_global_vol = 0;
} else {
if(vol_dB > (BADGE_MAX_VOLUME_DB)) vol_dB = (BADGE_MAX_VOLUME_DB);
uint16_t buf = 3000 * exp(vol_dB * NAT_LOG_DB);
if(buf > (BADGE_VOLUME_LIMIT)) buf = (BADGE_VOLUME_LIMIT);
_global_vol = buf;
}
}
static void audio_player_task(void* arg) {
int16_t buffer[DMA_BUFFER_SIZE * 2];
memset(buffer, 0, sizeof(buffer));
while(true) {
for(int i = 0; i < (DMA_BUFFER_SIZE * 2); i += 2){
float sample = 0;
audio_source_t * audio_source = _audio_sources;
while(audio_source != NULL){
sample += (*(audio_source->render_function))(audio_source->render_data);
audio_source = audio_source->next;
}
write_to_scope((int16_t) (1600. * sample));
sample = _global_vol * sample;
if(sample > 32767) sample = 32767;
if(sample < -32767) sample = -32767;
buffer[i] = (int16_t) sample;
buffer[i+1] = LR_PHASE * buffer[i];
}
size_t count = 0;
i2s_write(I2S_PORT, buffer, sizeof(buffer), &count, 1000);
if (count != sizeof(buffer)) {
printf("i2s_write_bytes: count (%d) != length (%d)\n", count, sizeof(buffer));
abort();
}
}
}
void audio_init() { _audio_init(); }
/*
#define NAT_LOG_SEMITONE 0.05776226504666215
void synth_set_bend(int i, float bend){
if(bend != bend) return;
if((bend > -0.0001) && (bend < 0.0001)){
synths[i].bend = 1;
} else {
synths[i].bend = exp(bend * NAT_LOG_SEMITONE);
}
}
*/
/*
void synth_stop(int i){
if(synths[i].env_phase){
synths[i].env_phase = 3;
}
}
void synth_fullstop(int i){
synths[i].env_phase = 0;
}
void synth_start(int i){
synths[i].env_phase = 1; //put into attack phase;
}
float synth_get_env(int i){
return synths[i].env;
}
*/
//#include <stdio.h>
//#include <string.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "badge23_hwconfig.h"
#include <stdint.h>
#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)
static const uint8_t top_map[] = {1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 8, 8}; //flipped top and bottom from bootstrap reference
static const uint8_t top_stages = 12;
static const uint8_t bot_map[] = {0, 0, 0, 2, 2, 2, 6, 6, 6, 4, 4, 4}; //idk y :~)
static const uint8_t bottom_stages = 12;
#elif defined(CONFIG_BADGE23_HW_GEN_P1)
static const uint8_t top_map[] = {2, 2, 2, 0, 0, 8, 8, 8, 6, 6, 4, 4};
static const uint8_t top_stages = 12;
static const uint8_t bot_map[] = {1, 1, 3, 3, 5, 5, 7, 7, 9, 9};
static const uint8_t bottom_stages = 10;
#else
#error "captouch not implemented for this badge generation"
#endif
static const char *TAG = "captouch";
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define AD7147_BASE_ADDR 0x2C
#define AD7147_REG_PWR_CONTROL 0x00
#define AD7147_REG_STAGE_CAL_EN 0x01
#define AD7147_REG_STAGE_HIGH_INT_ENABLE 0x06
#define AD7147_REG_DEVICE_ID 0x17
#define TIMEOUT_MS 1000
struct ad714x_chip {
uint8_t addr;
uint8_t gpio;
int afe_offsets[13];
int stages;
};
// Captouch sensor chips addresses are swapped on proto3. Whoops.
#if defined(CONFIG_BADGE23_HW_GEN_P3)
#define AD7147_BASE_ADDR_TOP (AD7147_BASE_ADDR)
#define AD7147_BASE_ADDR_BOT (AD7147_BASE_ADDR + 1)
#else
#define AD7147_BASE_ADDR_TOP (AD7147_BASE_ADDR + 1)
#define AD7147_BASE_ADDR_BOT (AD7147_BASE_ADDR)
#endif
static const struct ad714x_chip chip_top = {.addr = AD7147_BASE_ADDR_TOP, .gpio = 48, .afe_offsets = {24, 12, 16, 33, 30, 28, 31, 27, 22, 24, 18, 19, }, .stages=top_stages};
static const struct ad714x_chip chip_bot = {.addr = AD7147_BASE_ADDR_BOT, .gpio = 3, .afe_offsets = {3, 2, 1, 1 ,1, 1, 1, 1, 2, 3}, .stages=bottom_stages};
static esp_err_t ad714x_i2c_write(const struct ad714x_chip *chip, const uint16_t reg, const uint16_t data)
{
const uint8_t tx[] = {reg >> 8, reg & 0xFF, data >> 8, data & 0xFF};
ESP_LOGI(TAG, "AD7147 write reg %X-> %X", reg, data);
return i2c_master_write_to_device(I2C_MASTER_NUM, chip->addr, tx, sizeof(tx), TIMEOUT_MS / portTICK_PERIOD_MS);
}
static esp_err_t ad714x_i2c_read(const struct ad714x_chip *chip, const uint16_t reg, uint16_t *data, const size_t len)
{
const uint8_t tx[] = {reg >> 8, reg & 0xFF};
uint8_t rx[len * 2];
esp_err_t ret = i2c_master_write_read_device(I2C_MASTER_NUM, chip->addr, tx, sizeof(tx), rx, sizeof(rx), TIMEOUT_MS / portTICK_PERIOD_MS);
for(int i = 0; i < len; i++) {
data[i] = (rx[i * 2] << 8) | rx[i * 2 + 1];
}
return ret;
}
struct ad7147_stage_config {
unsigned int cinX_connection_setup[13];
unsigned int se_connection_setup:2;
unsigned int neg_afe_offset_disable:1;
unsigned int pos_afe_offset_disable:1;
unsigned int neg_afe_offset:6;
unsigned int neg_afe_offset_swap:1;
unsigned int pos_afe_offset:6;
unsigned int pos_afe_offset_swap:1;
unsigned int neg_threshold_sensitivity:4;
unsigned int neg_peak_detect:3;
unsigned int pos_threshold_sensitivity:4;
unsigned int pos_peak_detect:3;
};
#define CIN CDC_NONE 0
#define CIN_CDC_NEG 1
#define CIN_CDC_POS 2
#define CIN_BIAS 3
static const uint16_t bank2 = 0x80;
static void ad714x_set_stage_config(const struct ad714x_chip *chip, const uint8_t stage, const struct ad7147_stage_config * config)
{
const uint16_t connection_6_0 = (config->cinX_connection_setup[6] << 12) | (config->cinX_connection_setup[5] << 10) | (config->cinX_connection_setup[4] << 8) | (config->cinX_connection_setup[3] << 6) | (config->cinX_connection_setup[2] << 4) | (config->cinX_connection_setup[1] << 2) | (config->cinX_connection_setup[0] << 0);
const uint16_t connection_12_7 = (config->pos_afe_offset_disable << 15) | (config->neg_afe_offset_disable << 14) | (config->se_connection_setup << 12) | (config->cinX_connection_setup[12] << 10) | (config->cinX_connection_setup[11] << 8) | (config->cinX_connection_setup[10] << 6) | (config->cinX_connection_setup[9] << 4) | (config->cinX_connection_setup[8] << 2) | (config->cinX_connection_setup[7] << 0);
const uint16_t afe_offset = (config->pos_afe_offset_swap << 15) | (config->pos_afe_offset << 8) | (config->neg_afe_offset_swap << 7) | (config->neg_afe_offset << 0);
const uint16_t sensitivity = (config->pos_peak_detect << 12) | (config->pos_threshold_sensitivity << 8) | (config->neg_peak_detect << 4) | (config->neg_threshold_sensitivity << 0);
//ESP_LOGI(TAG, "Stage %d config-> %X %X %X %X", stage, connection_6_0, connection_12_7, afe_offset, sensitivity);
//ESP_LOGI(TAG, "Config: %X %X %X %X %X %X %X %X %X", config->pos_afe_offset_disable, config->pos_afe_offset_disable, config->se_connection_setup, config->cinX_connection_setup[12], config->cinX_connection_setup[11], config->cinX_connection_setup[10], config->cinX_connection_setup[9], config->cinX_connection_setup[8], config->cinX_connection_setup[7]);
ad714x_i2c_write(chip, bank2 + stage * 8, connection_6_0);
ad714x_i2c_write(chip, bank2 + stage * 8 + 1, connection_12_7);
ad714x_i2c_write(chip, bank2 + stage * 8 + 2, afe_offset);
ad714x_i2c_write(chip, bank2 + stage * 8 + 3, sensitivity);
}
struct ad7147_device_config {
unsigned int power_mode:2;
unsigned int lp_conv_delay:2;
unsigned int sequence_stage_num:4;
unsigned int decimation:2;
unsigned int sw_reset:1;
unsigned int int_pol:1;
unsigned int ext_source:1;
unsigned int cdc_bias:2;
unsigned int stage0_cal_en:1;
unsigned int stage1_cal_en:1;
unsigned int stage2_cal_en:1;
unsigned int stage3_cal_en:1;
unsigned int stage4_cal_en:1;
unsigned int stage5_cal_en:1;
unsigned int stage6_cal_en:1;
unsigned int stage7_cal_en:1;
unsigned int stage8_cal_en:1;
unsigned int stage9_cal_en:1;
unsigned int stage10_cal_en:1;
unsigned int stage11_cal_en:1;
unsigned int avg_fp_skip:2;
unsigned int avg_lp_skip:2;
unsigned int stage0_high_int_enable:1;
unsigned int stage1_high_int_enable:1;
unsigned int stage2_high_int_enable:1;
unsigned int stage3_high_int_enable:1;
unsigned int stage4_high_int_enable:1;
unsigned int stage5_high_int_enable:1;
unsigned int stage6_high_int_enable:1;
unsigned int stage7_high_int_enable:1;
unsigned int stage8_high_int_enable:1;
unsigned int stage9_high_int_enable:1;
unsigned int stage10_high_int_enable:1;
unsigned int stage11_high_int_enable:1;
};
static void ad714x_set_device_config(const struct ad714x_chip *chip, const struct ad7147_device_config * config)
{
const uint16_t pwr_control = (config->cdc_bias << 14) | (config->ext_source << 12) | (config->int_pol << 11) | (config->sw_reset << 10) | (config->decimation << 8) | (config->sequence_stage_num << 4) | (config->lp_conv_delay << 2) | (config->power_mode << 0);
const uint16_t stage_cal_en = (config->avg_lp_skip << 14) | (config->avg_fp_skip << 12) | (config->stage11_cal_en << 11) | (config->stage10_cal_en << 10) | (config->stage9_cal_en << 9) | (config->stage8_cal_en << 8) | (config->stage7_cal_en << 7) | (config->stage6_cal_en << 6) | (config->stage5_cal_en << 5) | (config->stage4_cal_en << 4) | (config->stage3_cal_en << 3) | (config->stage2_cal_en << 2) | (config->stage1_cal_en << 1) | (config->stage0_cal_en << 0);
const uint16_t stage_high_int_enable = (config->stage11_high_int_enable << 11) | (config->stage10_high_int_enable << 10) | (config->stage9_high_int_enable << 9) | (config->stage8_high_int_enable << 8) | (config->stage7_high_int_enable << 7) | (config->stage6_high_int_enable << 6) | (config->stage5_high_int_enable << 5) | (config->stage4_high_int_enable << 4) | (config->stage3_high_int_enable << 3) | (config->stage2_high_int_enable << 2) | (config->stage1_high_int_enable << 1) | (config->stage0_high_int_enable << 0);
ad714x_i2c_write(chip, AD7147_REG_PWR_CONTROL, pwr_control);
ad714x_i2c_write(chip, AD7147_REG_STAGE_CAL_EN, stage_cal_en);
ad714x_i2c_write(chip, AD7147_REG_STAGE_HIGH_INT_ENABLE, stage_high_int_enable);
}
static struct ad7147_stage_config ad714x_default_config(void)
{
return (struct ad7147_stage_config) {
.cinX_connection_setup={CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS},
.se_connection_setup=0b01,
.pos_afe_offset=0,
};
}
#define ESP_INTR_FLAG_DEFAULT 0
static QueueHandle_t gpio_evt_queue = NULL;
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
struct ad714x_chip* chip = (struct ad714x_chip *) arg;
xQueueSendFromISR(gpio_evt_queue, &chip, NULL);
}
static uint16_t pressed_top, pressed_bot;
static void captouch_chip_readout(struct ad714x_chip * chip){
uint16_t pressed;
ad714x_i2c_read(chip, 9, &pressed, 1);
ESP_LOGI(TAG, "Addr %x, High interrupt %X", chip->addr, pressed);
pressed &= ((1 << chip->stages) - 1);
if(chip == &chip_top) pressed_top = pressed;
if(chip == &chip_bot) pressed_bot = pressed;
}
void manual_captouch_readout(uint8_t top)
{
struct ad714x_chip* chip = top ? (&chip_top) : (&chip_bot);
captouch_chip_readout(chip);
//xQueueSend(gpio_evt_queue, &chip, NULL);
}
void gpio_event_handler(void* arg)
{
static unsigned long counter = 0;
struct ad714x_chip* chip;
while(true) {
if(xQueueReceive(gpio_evt_queue, &chip, portMAX_DELAY)) {
captouch_chip_readout(chip);
}
}
}
uint16_t read_captouch(){
uint16_t petals = 0;
uint16_t top = pressed_top;
uint16_t bot = pressed_bot;
for(int i=0; i<top_stages; i++) {
if(top & (1 << i)) {
petals |= (1<<top_map[i]);
}
}
for(int i=0; i<bottom_stages; i++) {
if(bot & (1 << i)) {
petals |= (1<<bot_map[i]);
}
}
return petals;
}
void captouch_force_calibration(){
ad714x_i2c_write(&chip_top, 2, (1 << 14));
ad714x_i2c_write(&chip_bot, 2, (1 << 14));
}
static void captouch_init_chip(const struct ad714x_chip* chip, const struct ad7147_device_config device_config)
{
uint16_t data;
ad714x_i2c_read(chip, AD7147_REG_DEVICE_ID, &data, 1);
ESP_LOGI(TAG, "DEVICE ID = %X", data);
ad714x_set_device_config(chip, &device_config);
for(int i=0; i<chip->stages; i++) {
struct ad7147_stage_config stage_config;
stage_config = ad714x_default_config();
stage_config.cinX_connection_setup[i] = CIN_CDC_POS;
stage_config.pos_afe_offset=chip->afe_offsets[i];
ad714x_set_stage_config(chip, i, &stage_config);
}
captouch_force_calibration();
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << chip->gpio);
io_conf.pull_up_en = 1;
io_conf.pull_down_en = 0;
gpio_config(&io_conf);
// gpio_isr_handler_add(chip->gpio, gpio_isr_handler, (void *)chip);
}
void captouch_init(void)
{
//gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
captouch_init_chip(&chip_top, (struct ad7147_device_config){.sequence_stage_num = 11,
.decimation = 1,
.stage0_cal_en = 1,
.stage1_cal_en = 1,
.stage2_cal_en = 1,
.stage3_cal_en = 1,
.stage4_cal_en = 1,
.stage5_cal_en = 1,
.stage6_cal_en = 1,
.stage7_cal_en = 1,
.stage8_cal_en = 1,
.stage9_cal_en = 1,
.stage10_cal_en = 1,
.stage11_cal_en = 1,
.stage0_high_int_enable = 1,
.stage1_high_int_enable = 1,
.stage2_high_int_enable = 1,
.stage3_high_int_enable = 1,
.stage4_high_int_enable = 1,
.stage5_high_int_enable = 1,
.stage6_high_int_enable = 1,
.stage7_high_int_enable = 1,
.stage8_high_int_enable = 1,
.stage9_high_int_enable = 1,
.stage10_high_int_enable = 1,
.stage11_high_int_enable = 1,
});
captouch_init_chip(&chip_bot, (struct ad7147_device_config){.sequence_stage_num = 11,
.decimation = 1,
.stage0_cal_en = 1,
.stage1_cal_en = 1,
.stage2_cal_en = 1,
.stage3_cal_en = 1,
.stage4_cal_en = 1,
.stage5_cal_en = 1,
.stage6_cal_en = 1,
.stage7_cal_en = 1,
.stage8_cal_en = 1,
.stage9_cal_en = 1,
.stage0_high_int_enable = 1,
.stage1_high_int_enable = 1,
.stage2_high_int_enable = 1,
.stage3_high_int_enable = 1,
.stage4_high_int_enable = 1,
.stage5_high_int_enable = 1,
.stage6_high_int_enable = 1,
.stage7_high_int_enable = 1,
.stage8_high_int_enable = 1,
.stage9_high_int_enable = 1,
});
gpio_evt_queue = xQueueCreate(10, sizeof(const struct ad714x_chip*));
//xTaskCreate(gpio_event_handler, "gpio_event_handler", 2048 * 2, NULL, configMAX_PRIORITIES - 2, NULL);
}
static void captouch_print_debug_info_chip(const struct ad714x_chip* chip)
{
uint16_t data[12] = {0,};
uint16_t ambient[12] = {0,};
const int stages = chip->stages;
#if 1
for(int stage=0; stage<stages; stage++) {
ad714x_i2c_read(chip, 0x0FA + stage * (0x104 - 0xE0), data, 1);
ESP_LOGI(TAG, "stage %d threshold: %X", stage, data[0]);
}
ad714x_i2c_read(chip, 0xB, data, stages);
ESP_LOGI(TAG, "CDC results: %X %X %X %X %X %X %X %X %X %X %X %X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
for(int stage=0; stage<stages; stage++) {
ad714x_i2c_read(chip, 0x0F1 + stage * (0x104 - 0xE0), &ambient[stage], 1);
ESP_LOGI(TAG, "stage %d ambient: %X diff: %d", stage, ambient[stage], data[stage] - ambient[stage]);
}
#endif
#if 1
ad714x_i2c_read(chip, 8, data, 1);
ESP_LOGI(TAG, "Low interrupt %X", data[0]);
ad714x_i2c_read(chip, 9, data, 1);
ESP_LOGI(TAG, "High interrupt %X", data[0]);
ad714x_i2c_read(chip, 0x42, data, 1);
ESP_LOGI(TAG, "Proximity %X", data[0]);
//ESP_LOGI(TAG, "CDC result = %X", data[0]);
//if(data[0] > 0xa000) {
//ESP_LOGI(TAG, "Touch! %X", data[0]);
//}
#endif
}
void captouch_print_debug_info(void)
{
captouch_print_debug_info_chip(&chip_top);
captouch_print_debug_info_chip(&chip_bot);
}
void captouch_get_cross(int paddle, int *x, int *y)
{
uint16_t data[12] = {0,};
uint16_t ambient[12] = {0,};
int result[2] = {0, 0};
float total = 0;
#if 0
if(paddle == 2) {
ad714x_i2c_read(&chip_top, 0xB, data, 3);
//ESP_LOGI(TAG, "CDC results: %X %X %X %X %X %X %X %X %X %X %X %X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
for(int stage=0; stage<3; stage++) {
ad714x_i2c_read(&chip_top, 0x0F1 + stage * (0x104 - 0xE0), &ambient[stage], 1);
//ESP_LOGI(TAG, "stage %d ambient: %X diff: %d", stage, ambient[stage], data[stage] - ambient[stage]);
}
int vectors[][2] = {{0, 0}, {0,240}, {240, 120}};
total = (data[0] - ambient[0]) + (data[1] - ambient[1]) + (data[2] - ambient[2]);
result[0] = vectors[0][0] * (data[0] - ambient[0]) + vectors[1][0] * (data[1] - ambient[1]) + vectors[2][0] * (data[2] - ambient[2]);
result[1] = vectors[0][1] * (data[0] - ambient[0]) + vectors[1][1] * (data[1] - ambient[1]) + vectors[2][1] * (data[2] - ambient[2]);
}
if(paddle == 8) {
ad714x_i2c_read(&chip_top, 0xB + 5, data + 5, 3);
//ESP_LOGI(TAG, "CDC results: %X %X %X %X %X %X %X %X %X %X %X %X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
for(int stage=5; stage<8; stage++) {
ad714x_i2c_read(&chip_top, 0x0F1 + stage * (0x104 - 0xE0), &ambient[stage], 1);
//ESP_LOGI(TAG, "stage %d ambient: %X diff: %d", stage, ambient[stage], data[stage] - ambient[stage]);
}
int vectors[][2] = {{240, 240}, {240, 0}, {0, 120}};
total = (data[5] - ambient[5]) + (data[6] - ambient[6]) + (data[7] - ambient[7]);
result[0] = vectors[0][0] * (data[5] - ambient[5]) + vectors[1][0] * (data[6] - ambient[6]) + vectors[2][0] * (data[7] - ambient[7]);
result[1] = vectors[0][1] * (data[5] - ambient[5]) + vectors[1][1] * (data[6] - ambient[6]) + vectors[2][1] * (data[7] - ambient[7]);
}
*x = result[0] / total;
*y = result[1] / total;
//ESP_LOGI(TAG, "x=%d y=%d\n", *x, *y);
#endif
const int paddle_info_1[] = {
4,
0,
1,
2,
11,
4,
9,
7,
6,
9,
};
const int paddle_info_2[] = {
3,
1,
0,
3,
10,
5,
8,
6,
5,
8,
};
struct ad714x_chip* chip;
if (paddle % 2 == 0) {
chip = &chip_top;
} else {
chip = &chip_bot;
}
ad714x_i2c_read(chip, 0xB, data, 12);
//ESP_LOGI(TAG, "CDC results: %X %X %X %X %X %X %X %X %X %X %X %X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
for(int stage=0; stage<12; stage++) {
ad714x_i2c_read(chip, 0x0F1 + stage * (0x104 - 0xE0), &ambient[stage], 1);
//ESP_LOGI(TAG, "stage %d ambient: %X diff: %d", stage, ambient[stage], data[stage] - ambient[stage]);
}
int diff1 = data[paddle_info_1[paddle]] - ambient[paddle_info_1[paddle]];
int diff2 = data[paddle_info_2[paddle]] - ambient[paddle_info_2[paddle]];
ESP_LOGI(TAG, "%10d %10d", diff1, diff2);
int vectors[][2] = {{240, 240}, {240, 0}, {0, 120}};
total = ((diff1) + (diff2));
result[0] = vectors[0][0] * (diff1) + vectors[1][0] * (diff2);
result[1] = vectors[0][1] * (diff1) + vectors[1][1] * (diff2);
*x = result[0] / total;
*y = result[1] / total;
}
#include "badge23/display.h"
#include "gc9a01.h"
#include "esp_log.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>
#include <freertos/queue.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "badge23/scope.h"
#include "esp_system.h"
uint16_t *pixels;
typedef struct leds_cfg {
bool active_paddles[10];
} display_cfg_t;
static QueueHandle_t display_queue = NULL;
static void display_task(TimerHandle_t aaaaa);
//static void display_task(void* arg);
static void _display_init() {
GC9A01_Init();
// GC9A01_Screen_Load(0,0,240,240,pixels);
GC9A01_Update();
/*
display_queue = xQueueCreate(1, sizeof(display_cfg_t));
TaskHandle_t handle;
xTaskCreate(&display_task, "Display", 4096, NULL, configMAX_PRIORITIES - 3, &handle);
*/
/* SCOPE TASK
TimerHandle_t aa = xTimerCreate("Display", pdMS_TO_TICKS(100), pdTRUE, (void *) 0, *display_task);
if( xTimerStart(aa, 0 ) != pdPASS )
{
}
*/
}
void display_update(){
GC9A01_Update();
}
void display_draw_pixel(uint8_t x, uint8_t y, uint16_t col){
GC9A01_DrawPixel(x, y, col);
}
uint16_t display_get_pixel(uint8_t x, uint8_t y){
return GC9A01_GetPixel(x,y);
}
void display_fill(uint16_t col){
GC9A01_FillRect(0, 0, 240, 240, col);
}
void display_draw_scope(){
//display_cfg_t display_;
uint16_t line[240];
/*
printf("waiting...\n");
xQueueReceive(display_queue, &display_, portMAX_DELAY);
printf("go...\n");
*/
//uint32_t t0 = esp_log_timestamp();
begin_scope_read();
for(int y=0; y<240; y++){
read_line_from_scope(&(line[0]), y);
memcpy(&ScreenBuff[y * 240], line, sizeof(line));
}
end_scope_read();
//uint32_t td = esp_log_timestamp() - t0;
// printf("it took %lu\n", td);
display_update();
}
//static void display_task(void* arg) {
static void display_task(TimerHandle_t aaaaa) {
display_draw_scope();
}
void display_init() { _display_init(); }
#include "badge23/captouch.h"
#include "badge23/audio.h"
#include "badge23/leds.h"
#include "badge23/display.h"
#include "badge23/spio.h"
#include "badge23_hwconfig.h"
#include "esp_log.h"
#include "driver/i2c.h"
#include "driver/spi_master.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
static const char *TAG = "espan";
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)
#define CONFIG_I2C_MASTER_SDA 2
#define CONFIG_I2C_MASTER_SCL 1
#elif defined(CONFIG_BADGE23_HW_GEN_P1)
#define CONFIG_I2C_MASTER_SDA 10
#define CONFIG_I2C_MASTER_SCL 9
#else
#error "i2c not implemented for this badge generation"
#endif
static esp_err_t i2c_master_init(void)
{
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = CONFIG_I2C_MASTER_SDA,
.scl_io_num = CONFIG_I2C_MASTER_SCL,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(i2c_master_port, &conf);
return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
#define CAPTOUCH_POLLING_PERIOD 10
void os_app_main(void)
{
ESP_LOGI(TAG, "Starting on %s...", badge23_hw_name);
ESP_ERROR_CHECK(i2c_master_init());
ESP_LOGI(TAG, "I2C initialized successfully");
set_global_vol_dB(-90);
audio_init();
leds_init();
init_buttons();
captouch_init();
vTaskDelay(2000 / portTICK_PERIOD_MS);
set_global_vol_dB(0);
display_init();
while(1) {
manual_captouch_readout(1);
vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
manual_captouch_readout(0);
vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
update_button_state();
vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
//display_draw_scope();
}
ESP_ERROR_CHECK(i2c_driver_delete(I2C_MASTER_NUM));
ESP_LOGI(TAG, "I2C de-initialized successfully");
}
#ifndef DEF_apa102LEDStrip
#define DEF_apa102LEDStrip
struct apa102LEDStrip
{
unsigned char *LEDs;
short int _frameLength;
short int _endFrameLength;
short int _numLEDs;
unsigned char _bytesPerLED;
short int _counter;
unsigned char _globalBrightness;
};
void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, unsigned char globalBrightness);
void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour);
void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour);
#endif
#pragma once
#include <stdint.h>
#define SAMPLE_RATE 16000
#define BADGE_MAX_VOLUME_DB 20
#define BADGE_MIN_VOLUME_DB (-80)
#define BADGE_VOLUME_LIMIT 30000
void audio_init();
void set_global_vol_dB(int8_t vol_dB);
uint16_t count_audio_sources();
uint16_t add_audio_source(void * render_data, void * render_function);
void remove_audio_source(uint16_t index);
#pragma once
#include <stdint.h>
void captouch_init(void);
void captouch_print_debug_info(void);
void gpio_event_handler(void * arg);
void manual_captouch_readout(uint8_t top);
void captouch_get_cross(int paddle, int * x, int * y);
void captouch_force_calibration();
uint16_t read_captouch();
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#define IMAGE_W 240
#define IMAGE_H 240
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Decode the jpeg ``image.jpg`` embedded into the program file into pixel data.
*
* @param pixels A pointer to a pointer for an array of rows, which themselves are an array of pixels.
* Effectively, you can get the pixel data by doing ``decode_image(&myPixels); pixelval=myPixels[ypos][xpos];``
* @return - ESP_ERR_NOT_SUPPORTED if image is malformed or a progressive jpeg file
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on succesful decode
*/
esp_err_t decode_image(uint16_t **pixels);
#ifdef __cplusplus
}
#endif
#pragma once
#include <stdbool.h>
#include <stdint.h>
void display_init();
void display_draw_scope();
void display_update();
void display_draw_pixel(uint8_t x, uint8_t y, uint16_t col);
uint16_t display_get_pixel(uint8_t x, uint8_t y);
void display_fill(uint16_t col);
#pragma once
void os_app_main(void);
#pragma once
#include <stdint.h>
void leds_init();
void leds_set_single_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
void leds_set_single_hsv(uint8_t index, float hue, float sat, float value);
void leds_update();
#pragma once
#include <stdint.h>
typedef struct {
int16_t * buffer;
int16_t buffer_size;
int16_t write_head_position; // last written value
volatile uint8_t is_being_read;
} scope_t;
void init_scope(uint16_t size);
void write_to_scope(int16_t value);
void begin_scope_read();
void end_scope_read();
void read_line_from_scope(uint16_t * line, int16_t point);
#pragma once
#include <stdint.h>
int8_t get_button_state(bool leftbutton);
void update_button_state();
void init_buttons();
#pragma once
#include <stdint.h>
#include <stdio.h>
#define TRAD_OSC_DECAY_STEP 0.01
#define TRAD_OSC_ATTACK_STEP 0.01
#define TRAD_OSC_MIN_ATTACK_ENV 0.01
#define TRAD_OSC_ATTACK_POP_BLOCK 16
typedef struct {
//user variables
float freq; //in hertz, negative frequencies for linFM allowed
float bend;
float vol; //output volume
float env;
uint8_t env_phase; //0: off, 1: attack, 2: hold, 3: decay
uint8_t skip_hold;
float gate; //below what volume the oscillator stops and returns 0
uint16_t decay_steps; //after how many sample rate steps the volume reduces
//by factor TRAD_OSC_DECAY_STEP, set 0 for no decay
uint16_t attack_steps;
uint8_t waveform; //0: sine, 1: fast sine, 2: tri, 3: saw,
//4: square, 5: 33% pulse, 6: 25% pulse
//internal data storage, not for user access
float counter; //state of central sawtooth oscillator, [-1..1] typ.
uint16_t env_counter;
int8_t overflow_event; //set to -1 when counter underflows (below -1),
//set to +1 when counter overflows (above 1)
//not reset or used by anything so far
uint16_t noise_reg;
} trad_osc_t;
//#define KS_BUFFER_SIZE (SAMPLE_RATE)/20
#define KS_BUFFER_SIZE 800
typedef struct {
//user variables
float freq; //frequency in hertz, negative frequencies are rectified,
//minimum freq determined by KS_BUFFER_SIZE
float feedback; //feedback value, will be compensated with frequency
//for equal decay across spectrum, [-1..1] without
//internal data storage, not for user access
float tape[KS_BUFFER_SIZE]; //the delay chain
float real_feedback; //compensated feedback value
} ks_osc_t; //karplus strong
float run_trad_osc(trad_osc_t * osc);
void trad_osc_set_freq_semitone(trad_osc_t * osc, float bend);
void trad_osc_set_freq_Hz(trad_osc_t * osc, float freq);
void trad_osc_set_waveform(trad_osc_t * osc, uint8_t waveform);
void trad_osc_set_attack(trad_osc_t * osc, uint16_t attack);
void trad_osc_set_decay(trad_osc_t * osc, uint16_t decay);
void trad_env_stop(trad_osc_t * osc);
void trad_env_fullstop(trad_osc_t * osc);
void trad_env_start(trad_osc_t * osc);
void render_audio(
instrument_descriptor_t instrument_descriptor,
instrument_t instance,
unsigned int sample_count,
float * output_vector
){
for(unsigned int i = 0; i < sample_count; i++){
instrument_descriptor->render_audio_sample(instance, sample_count, output_vector[2*i]);
}
}
void render_audio_adding(
instrument_descriptor_t instrument_descriptor,
instrument_t instance,
unsigned int sample_count,
float * output_vector,
float gain
){
if(gain <= 0.0000001) return;
float temp[2];
for(unsigned int i = 0; i < sample_count; i++){
instrument_descriptor->render_audio_sample(instance, sample_count, temp);
output_vector[2*i] += gain * buffer[0];
output_vector[2*i+1] += gain * buffer[1];
}
}
void append_instrument_descriptor(
instrument_descriptor_list_t * list,
void * construct_instrument_descriptor
){
lle_t * element = list;
while(element->next != NULL){
element = element->next;
}
element->next = malloc(sizeof(lle_t);
if(element->next == NULL) return;
element = element->next;
element->next = NULL;
element->content = construct_instrument_descriptor();
}
instrument_descriptor_list_t * list_builtin_instrument_descriptors(){
//really hope we can make this more elegant some day
instrument_descriptor_list_t * list = NULL;
//add your instrument here!
append_instrument_descriptor(list, &minimal_example_descriptor);
return list;
}
void instantiate_instrument(active_instrument_list_t instruments,
instrument_descriptor_t descriptor
){
descriptor->new_instrument
}
void mix_instruments_audio(active_instrument_list_t instruments,
unsigned int sample_count,
float * output_vector
){
active_instrument_t instrument = instruments;
while(instrument->next != NULL){
render_audio_adding(instrument->descriptor,
instrument->instrument,
sample_count,
output_vector,
instrument->gain)
instrument = instrument->next;
}
}
/* wip instrument api for badge23 (in large parts inspired by ladspa)
current status: none of this is hooked up or functional or compiles, just drafting things rn
some core concepts:
- several instruments can run at the same time (e.g., drum computer running in background),
with only one of them being in foreground and using buttons and display
- instruments are as "self contained" as possible, i.e. they access buttons and display with
minimal host involvement and pretty much just produce audio "on their own". aside from
scheduling the host mostly does some cap touch preprocessing and the audio output mixdown
- different timing requirements -> different "threads" for audio, buttons, display each
(leds: special case, see below)
open questions:
- led animations: instruments should be able to output led patterns. maybe keeping a dummy
led array in ram for each running instrument and allowing users to create and run "shaders"
would be a desirable functional mode; do we want this/does this need any extra api?
- for performance reasons: instruments are expected to behave themselves, i.e. not access hw
without permission or write to read-only locations, can we do better than that without
excessive overhead? and if we can, do we _want_ to? (devices that make electronic musical
instruments malfunction on purpose are not uncommon in general)
- badge link/cv data input/output: can probably be added to the descriptor easily? shouldn't
freeze api before tho
*/
//===========================================================================================
//some hardware dummy definitions, move somewhere else someday maybe
typedef struct {
int intensity; //touch strength, considered as no touch if below 0
int rad; //radial position
int az; //cw azimuthal position (only meaningful for top petals);
} petal_t;
typedef int button_t; //0: no press, -1: left, 1: right, 2: down
typedef struct { //read-only (shared between all instruments, unprotected)
petal_t petals[10]; //even: top, odd: bottom, 0 at usb-c jack, count ccw
button_t button; //can be either left or right, depending on host
//handedness settings. the other button is reserved for
//host use and is not exposed here.
} hardware_inputs_t;
//===========================================================================================
typedef void * instrument_t; //contains instrument instance data, not to be interpreted by host
typedef struct _instrument_descriptor_t {
unsigned int unique_id;
//null terminated instrument name
const char * name;
//allocates memory for new instance data and returns pointer to it (mandatory)
instrument_t (* new_instrument)(const struct _instrument_descriptor * descriptor,
unsigned int sample_rate,
hardware_inputs_t * hw);
//frees instance data memory (mandatory)
void (* delete_instrument) (instrument_t instance);
//renders a single stereo audio sample (optional, NULL if not supported)
void (* render_audio_sample) (instrument_t instance);
//handles petal/button/sensor input, ideally runs every 3-8ms (optional, NULL if not supported)
void (* process_user_input) (instrument_t instance);
//only runs when instrument is in foreground (optional, NULL if not supported)
void (* update_display) (instrument_t instance);
//(optional, NULL if not supported)
void (* update_leds) (instrument_t instance);
} instrument_descriptor_t;
// this function is called once per instrument type before use (i.e. around boot) and returns a
// filled out instrument descriptor struct to be used by the host for creating instrument instances
// returns null if allocation fails
const instrument_descriptor_t * contruct_instrument_descriptor();
//===========================================================================================
//host-side helper functions
void render_audio(
instrument_descriptor_t instrument_descriptor,
instrument_t instance,
unsigned int sample_count,
float * output_vector
);
void render_audio_adding(
instrument_descriptor_t instrument_descriptor,
instrument_t instance,
unsigned int sample_count,
float * output_vector,
float gain
);
typedef struct {
void * content;
lle_t * next;
} lle_t; //linked list element
typedef lle_t instrument_descriptor_list_t;
typedef struct {
instrument_t * instrument;
instrument_descriptor_t descriptor;
char is_foreground;
char is_rendering_leds;
float gain;
} active_instrument_t;
void append_instrument_descriptor(
instrument_descriptor_list_t * list,
void * construct_instrument_descriptor
);
instrument_descriptor_list_t * list_builtin_instrument_descriptors();
typedef lle_t active_instrument_list_t;
void mix_instruments_audio(active_instrument_list_t instruments,
unsigned int sample_count,
float * output_vector
);
//===========================================================================================