Codec confiuguration implementation.
This commit is contained in:
parent
9beeb23c89
commit
eae22f28a8
|
@ -56,12 +56,12 @@ static const default_configuration default_config = {
|
|||
.f4 = { HIGHSHELF, {0}, 8400, 2, 0.7 },
|
||||
.f5 = { PEAKING, {0}, 4800, 3, 5 }
|
||||
},
|
||||
.preprocessing = { .header = { PREPROCESSING_CONFIGURATION, sizeof(default_config.preprocessing) }, -0.1f, false, {0} }
|
||||
.preprocessing = { .header = { PREPROCESSING_CONFIGURATION, sizeof(default_config.preprocessing) }, -0.2f, false, {0} }
|
||||
};
|
||||
|
||||
// Grab the last 4k page of flash for our configuration strutures.
|
||||
#ifndef TEST_TARGET
|
||||
static const size_t USER_CONFIGURATION_OFFSET = PICO_FLASH_SIZE_BYTES - 0x1000;
|
||||
static const size_t USER_CONFIGURATION_OFFSET = PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE;
|
||||
const uint8_t *user_configuration = (const uint8_t *) (XIP_BASE + USER_CONFIGURATION_OFFSET);
|
||||
#endif
|
||||
/**
|
||||
|
@ -74,8 +74,6 @@ static uint8_t inactive_working_configuration = 0;
|
|||
static uint8_t result_buffer[256] = { U16_TO_U8S_LE(NOK), U16_TO_U8S_LE(4) };
|
||||
|
||||
static bool reload_config = false;
|
||||
static bool save_config = false;
|
||||
static bool factory_reset = false;
|
||||
static uint16_t write_offset = 0;
|
||||
static uint16_t read_offset = 0;
|
||||
|
||||
|
@ -208,13 +206,20 @@ bool validate_configuration(tlv_header *config) {
|
|||
break;
|
||||
case PREPROCESSING_CONFIGURATION: {
|
||||
preprocessing_configuration_tlv* preprocessing_config = (preprocessing_configuration_tlv*) tlv;
|
||||
//printf("Preproc %0.2f %d\n", preprocessing_config->preamp, preprocessing_config->reverse_stereo);
|
||||
if (tlv->length != sizeof(preprocessing_configuration_tlv)) {
|
||||
printf("Preprocessing size missmatch: %u != %zu\n", tlv->length, sizeof(preprocessing_configuration_tlv));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PCM3060_CONFIGURATION: {
|
||||
pcm3060_configuration_tlv* pcm3060_config = (pcm3060_configuration_tlv*) tlv;
|
||||
if (tlv->length != sizeof(pcm3060_configuration_tlv)) {
|
||||
printf("PCM3060 config size missmatch: %u != %zu\n", tlv->length, sizeof(pcm3060_configuration_tlv));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Unknown TLVs are not invalid, just ignored.
|
||||
break;
|
||||
|
@ -253,6 +258,14 @@ bool apply_configuration(tlv_header *config) {
|
|||
preprocessing.reverse_stereo = preprocessing_config->reverse_stereo;
|
||||
break;
|
||||
}
|
||||
case PCM3060_CONFIGURATION: {
|
||||
pcm3060_configuration_tlv* pcm3060_config = (pcm3060_configuration_tlv*) tlv;
|
||||
audio_state.oversampling = pcm3060_config->oversampling;
|
||||
audio_state.phase = pcm3060_config->phase;
|
||||
audio_state.rolloff = pcm3060_config->rolloff;
|
||||
audio_state.de_emphasis = pcm3060_config->de_emphasis;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -275,15 +288,16 @@ void load_config() {
|
|||
}
|
||||
|
||||
#ifndef TEST_TARGET
|
||||
// Must be in RAM
|
||||
uint8_t flash_buffer[FLASH_PAGE_SIZE];
|
||||
bool __no_inline_not_in_flash_func(save_configuration)() {
|
||||
const uint8_t active_configuration = inactive_working_configuration ? 0 : 1;
|
||||
tlv_header* config = (tlv_header*) working_configuration[active_configuration];
|
||||
|
||||
if (validate_configuration(config)) {
|
||||
power_down_dac();
|
||||
|
||||
const size_t config_length = config->length - (size_t)((size_t)config->value - (size_t)config);
|
||||
// Write data to flash
|
||||
uint8_t flash_buffer[FLASH_PAGE_SIZE];
|
||||
flash_header_tlv* flash_header = (flash_header_tlv*) flash_buffer;
|
||||
flash_header->header.type = FLASH_HEADER;
|
||||
flash_header->header.length = sizeof(flash_header) + config_length;
|
||||
|
@ -291,8 +305,6 @@ bool __no_inline_not_in_flash_func(save_configuration)() {
|
|||
flash_header->version = CONFIG_VERSION;
|
||||
memcpy((void*)(flash_header->tlvs), config->value, config_length);
|
||||
|
||||
power_down_dac();
|
||||
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE);
|
||||
flash_range_program(USER_CONFIGURATION_OFFSET, flash_buffer, FLASH_PAGE_SIZE);
|
||||
|
@ -305,6 +317,15 @@ bool __no_inline_not_in_flash_func(save_configuration)() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool __no_inline_not_in_flash_func(factory_reset)() {
|
||||
power_down_dac();
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE);
|
||||
restore_interrupts(ints);
|
||||
power_up_dac();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool process_cmd(tlv_header* cmd) {
|
||||
tlv_header* result = ((tlv_header*) result_buffer);
|
||||
switch (cmd->type) {
|
||||
|
@ -318,8 +339,7 @@ bool process_cmd(tlv_header* cmd) {
|
|||
}
|
||||
break;
|
||||
case SAVE_CONFIGURATION: {
|
||||
if (cmd->length == 4) {
|
||||
save_config = true;
|
||||
if (cmd->length == 4 && save_configuration()) {
|
||||
result->type = OK;
|
||||
result->length = 4;
|
||||
return true;
|
||||
|
@ -327,8 +347,7 @@ bool process_cmd(tlv_header* cmd) {
|
|||
break;
|
||||
}
|
||||
case FACTORY_RESET: {
|
||||
if (cmd->length == 4) {
|
||||
factory_reset = true;
|
||||
if (cmd->length == 4 && factory_reset()) {
|
||||
flash_header_tlv flash_header = { 0 };
|
||||
result->type = OK;
|
||||
result->length = 4;
|
||||
|
@ -411,21 +430,6 @@ void config_in_packet(struct usb_endpoint *ep) {
|
|||
usb_packet_done(ep);
|
||||
}
|
||||
|
||||
void apply_core0_config() {
|
||||
if (save_config) {
|
||||
save_config = false;
|
||||
save_configuration();
|
||||
}
|
||||
if (factory_reset) {
|
||||
factory_reset = false;
|
||||
power_down_dac();
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE);
|
||||
restore_interrupts(ints);
|
||||
power_up_dac();
|
||||
}
|
||||
}
|
||||
|
||||
void apply_core1_config() {
|
||||
if (reload_config) {
|
||||
reload_config = false;
|
||||
|
|
|
@ -41,7 +41,6 @@ struct usb_endpoint;
|
|||
void config_in_packet(struct usb_endpoint *ep);
|
||||
void config_out_packet(struct usb_endpoint *ep);
|
||||
extern void load_config();
|
||||
extern void apply_core0_config();
|
||||
extern void apply_core1_config();
|
||||
|
||||
#endif // CONFIGURATION_MANAGER_H
|
|
@ -96,6 +96,15 @@ typedef struct __attribute__((__packed__)) _filter_configuration_tlv {
|
|||
const uint8_t filters[];
|
||||
} filter_configuration_tlv;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _pcm3060_configuration_tlv {
|
||||
tlv_header header;
|
||||
const uint8_t oversampling;
|
||||
const uint8_t phase;
|
||||
const uint8_t rolloff;
|
||||
const uint8_t de_emphasis;
|
||||
} pcm3060_configuration_tlv;
|
||||
|
||||
|
||||
typedef struct __attribute__((__packed__)) _version_status_tlv {
|
||||
tlv_header header;
|
||||
uint16_t current_version;
|
||||
|
|
|
@ -51,6 +51,7 @@ static uint8_t *userbuf;
|
|||
|
||||
audio_state_config audio_state = {
|
||||
.freq = 48000,
|
||||
.de_emphasis_frequency = 0x1, // 48khz
|
||||
};
|
||||
|
||||
preprocessing_config preprocessing = {
|
||||
|
@ -97,8 +98,6 @@ static void _as_audio_packet(struct usb_endpoint *ep) {
|
|||
int32_t *out = (int32_t *) userbuf;
|
||||
int samples = usb_buffer->data_len / 2;
|
||||
|
||||
// Update filters if required
|
||||
apply_core0_config();
|
||||
|
||||
if (preprocessing.reverse_stereo) {
|
||||
for (int i = 0; i < samples; i+=2) {
|
||||
|
@ -152,6 +151,15 @@ static void update_volume()
|
|||
|
||||
audio_state._volume = audio_state._target_volume;
|
||||
}
|
||||
|
||||
if (audio_state.pcm3060_registers != audio_state._target_pcm3060_registers) {
|
||||
uint8_t buf[3];
|
||||
buf[0] = 68; // register addr
|
||||
buf[1] = audio_state.target_pcm3060_registers[0]; // Reg 68
|
||||
buf[2] = audio_state.target_pcm3060_registers[1]; // Reg 69
|
||||
i2c_write_blocking(i2c0, PCM_I2C_ADDR, buf, 3, false);
|
||||
audio_state.pcm3060_registers = audio_state._target_pcm3060_registers;
|
||||
}
|
||||
}
|
||||
|
||||
void core1_entry() {
|
||||
|
@ -589,7 +597,7 @@ static bool do_get_current(struct usb_setup_packet *setup) {
|
|||
if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
|
||||
switch (setup->wValue >> 8u) {
|
||||
case 1: { // mute
|
||||
usb_start_tiny_control_in_transfer(audio_state.mute, 1);
|
||||
usb_start_tiny_control_in_transfer((audio_state.mute != 0), 1);
|
||||
return true;
|
||||
}
|
||||
case 2: { // volume
|
||||
|
@ -705,11 +713,7 @@ static void audio_cmd_packet(struct usb_endpoint *ep) {
|
|||
if (audio_control_cmd_t.type == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
|
||||
switch (audio_control_cmd_t.cs) {
|
||||
case 1: { // mute
|
||||
audio_state.mute = buffer->data[0];
|
||||
uint8_t buf[2];
|
||||
buf[0] = 68; // register addr
|
||||
buf[1] = buffer->data[0] ? 0x3 : 0x0; // data
|
||||
i2c_write_blocking(i2c0, PCM_I2C_ADDR, buf, 2, false);
|
||||
audio_state.mute = buffer->data[0] ? 0x3 : 0x0;
|
||||
break;
|
||||
}
|
||||
case 2: { // volume
|
||||
|
@ -741,7 +745,11 @@ static const struct usb_transfer_type _audio_cmd_transfer_type = {
|
|||
|
||||
static bool as_set_alternate(struct usb_interface *interface, uint alt) {
|
||||
assert(interface == &as_op_interface);
|
||||
return alt < 2;
|
||||
switch (alt) {
|
||||
case 0: power_down_dac(); return true;
|
||||
case 1: power_up_dac(); return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool do_set_current(struct usb_setup_packet *setup) {
|
||||
|
|
|
@ -56,7 +56,26 @@ typedef struct _audio_state_config {
|
|||
int16_t target_volume[2];
|
||||
int32_t _target_volume;
|
||||
};
|
||||
bool mute;
|
||||
union {
|
||||
struct {
|
||||
// Register 68
|
||||
uint8_t mute: 2;
|
||||
uint8_t phase: 1;
|
||||
uint8_t reserved1: 3;
|
||||
uint8_t oversampling: 1;
|
||||
uint8_t reserved2: 1;
|
||||
// Register 69
|
||||
uint8_t zero_fn: 1;
|
||||
uint8_t zero_polarity: 1;
|
||||
uint8_t reserved3: 2;
|
||||
uint8_t de_emphasis: 1;
|
||||
uint8_t de_emphasis_frequency: 2;
|
||||
uint8_t rolloff: 1;
|
||||
};
|
||||
int8_t target_pcm3060_registers[2];
|
||||
int16_t _target_pcm3060_registers;
|
||||
};
|
||||
int16_t pcm3060_registers;
|
||||
} audio_state_config;
|
||||
extern audio_state_config audio_state;
|
||||
|
||||
|
|
Loading…
Reference in New Issue