Fix save config (#27)
* Fix save config * Fix save config when no audio is playing * Fix build issue with the github workflow compiler
This commit is contained in:
		
							parent
							
								
									84306c0922
								
							
						
					
					
						commit
						9c036f07f8
					
				|  | @ -96,6 +96,13 @@ static bool reload_config = false; | ||||||
| static uint16_t write_offset = 0; | static uint16_t write_offset = 0; | ||||||
| static uint16_t read_offset = 0; | static uint16_t read_offset = 0; | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     NormalOperation, | ||||||
|  |     SaveRequested, | ||||||
|  |     Saving | ||||||
|  | } State; | ||||||
|  | static State saveState = NormalOperation; | ||||||
|  | 
 | ||||||
| bool validate_filter_configuration(filter_configuration_tlv *filters) | bool validate_filter_configuration(filter_configuration_tlv *filters) | ||||||
| { | { | ||||||
|     if (filters->header.type != FILTER_CONFIGURATION) { |     if (filters->header.type != FILTER_CONFIGURATION) { | ||||||
|  | @ -357,37 +364,47 @@ void load_config() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifndef TEST_TARGET | #ifndef TEST_TARGET | ||||||
| bool __no_inline_not_in_flash_func(save_configuration)() { | bool __no_inline_not_in_flash_func(save_config)() { | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|      |  | ||||||
|     const uint8_t active_configuration = inactive_working_configuration ? 0 : 1; |     const uint8_t active_configuration = inactive_working_configuration ? 0 : 1; | ||||||
|     tlv_header* config = (tlv_header*) working_configuration[active_configuration]; |     tlv_header* config = (tlv_header*) working_configuration[active_configuration]; | ||||||
| 
 | 
 | ||||||
|     if (validate_configuration(config)) {       |     switch (saveState) { | ||||||
|  |         case SaveRequested: | ||||||
|  |             if (validate_configuration(config)) {       | ||||||
|  |                 /* Turn the DAC off so we don't make a huge noise when disrupting
 | ||||||
|  |                 real time audio operation. */ | ||||||
|  |                 power_down_dac(); | ||||||
| 
 | 
 | ||||||
|         const size_t config_length = config->length - ((size_t)config->value - (size_t)config); |                 const size_t config_length = config->length - ((size_t)config->value - (size_t)config); | ||||||
|         // Write data to flash
 |                 // Write data to flash
 | ||||||
|         uint8_t flash_buffer[CFG_BUFFER_SIZE]; |                 uint8_t flash_buffer[CFG_BUFFER_SIZE]; | ||||||
|         flash_header_tlv* flash_header = (flash_header_tlv*) flash_buffer; |                 flash_header_tlv* flash_header = (flash_header_tlv*) flash_buffer; | ||||||
|         flash_header->header.type = FLASH_HEADER; |                 flash_header->header.type = FLASH_HEADER; | ||||||
|         flash_header->header.length = sizeof(flash_header_tlv) + config_length; |                 flash_header->header.length = sizeof(flash_header_tlv) + config_length; | ||||||
|         flash_header->magic = FLASH_MAGIC; |                 flash_header->magic = FLASH_MAGIC; | ||||||
|         flash_header->version = CONFIG_VERSION; |                 flash_header->version = CONFIG_VERSION; | ||||||
|         memcpy((void*)(flash_header->tlvs), config->value, config_length); |                 memcpy((void*)(flash_header->tlvs), config->value, config_length); | ||||||
| 
 | 
 | ||||||
|         /* Turn the DAC off so we don't make a huge noise when disrupting
 |                 uint32_t ints = save_and_disable_interrupts(); | ||||||
|            real time audio operation. */ |                 flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE); | ||||||
|         power_down_dac(); |                 flash_range_program(USER_CONFIGURATION_OFFSET, flash_buffer, CFG_BUFFER_SIZE); | ||||||
|  |                 restore_interrupts(ints); | ||||||
|  |                 saveState = Saving; | ||||||
| 
 | 
 | ||||||
|         uint32_t ints = save_and_disable_interrupts(); |                 // Return true, so the caller skips processing audio
 | ||||||
|         flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE); |                 return true; | ||||||
|         flash_range_program(USER_CONFIGURATION_OFFSET, flash_buffer, CFG_BUFFER_SIZE); |             } | ||||||
|         restore_interrupts(ints); |             // Validation failed, give up.
 | ||||||
| 
 |             saveState = NormalOperation; | ||||||
|         power_up_dac(); |             break; | ||||||
| 
 |         case Saving: | ||||||
|         return true; |             /* Turn the DAC off so we don't make a huge noise when disrupting
 | ||||||
|  |             real time audio operation. */ | ||||||
|  |             power_up_dac(); | ||||||
|  |             saveState = NormalOperation; | ||||||
|  |             return false; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return false; |     return false; | ||||||
|  | @ -415,7 +432,14 @@ bool process_cmd(tlv_header* cmd) { | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SAVE_CONFIGURATION: { |         case SAVE_CONFIGURATION: { | ||||||
|             if (cmd->length == 4 && save_configuration()) { |             if (cmd->length == 4) { | ||||||
|  |                 saveState = SaveRequested; | ||||||
|  |                 if (audio_state.interface == 0) { | ||||||
|  |                     // The OS will configure the alternate "zero" interface when the device is not in use
 | ||||||
|  |                     // in this sate we can write to flash now. Otherwise, defer the save until we get the next
 | ||||||
|  |                     // usb packet.
 | ||||||
|  |                     save_config(); | ||||||
|  |                 } | ||||||
|                 result->type = OK; |                 result->type = OK; | ||||||
|                 result->length = 4; |                 result->length = 4; | ||||||
|                 return true; |                 return true; | ||||||
|  |  | ||||||
|  | @ -52,6 +52,7 @@ void config_in_packet(struct usb_endpoint *ep); | ||||||
| void config_out_packet(struct usb_endpoint *ep); | void config_out_packet(struct usb_endpoint *ep); | ||||||
| void configuration_ep_on_cancel(struct usb_endpoint *ep); | void configuration_ep_on_cancel(struct usb_endpoint *ep); | ||||||
| extern void load_config(); | extern void load_config(); | ||||||
|  | extern bool save_config(); | ||||||
| extern void apply_config_changes(); | extern void apply_config_changes(); | ||||||
| 
 | 
 | ||||||
| #endif // CONFIGURATION_MANAGER_H
 | #endif // CONFIGURATION_MANAGER_H
 | ||||||
|  | @ -52,6 +52,7 @@ static uint8_t *userbuf; | ||||||
| audio_state_config audio_state = { | audio_state_config audio_state = { | ||||||
|     .freq = 48000, |     .freq = 48000, | ||||||
|     .de_emphasis_frequency = 0x1, // 48khz
 |     .de_emphasis_frequency = 0x1, // 48khz
 | ||||||
|  |     .interface = 0 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| preprocessing_config preprocessing = { | preprocessing_config preprocessing = { | ||||||
|  | @ -125,6 +126,18 @@ static void __no_inline_not_in_flash_func(_as_audio_packet)(struct usb_endpoint | ||||||
|     int32_t *out = (int32_t *) userbuf; |     int32_t *out = (int32_t *) userbuf; | ||||||
|     int samples = usb_buffer->data_len / 2; |     int samples = usb_buffer->data_len / 2; | ||||||
| 
 | 
 | ||||||
|  |     // Make sure core 1 is ready for us.
 | ||||||
|  |     multicore_fifo_pop_blocking(); | ||||||
|  | 
 | ||||||
|  |     if (save_config()) { | ||||||
|  |         // Skip processing while we are writing to flash
 | ||||||
|  |         multicore_fifo_push_blocking(CORE0_ABORTED); | ||||||
|  |         // keep on truckin'
 | ||||||
|  |         usb_grow_transfer(ep->current_transfer, 1); | ||||||
|  |         usb_packet_done(ep); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (preprocessing.reverse_stereo) { |     if (preprocessing.reverse_stereo) { | ||||||
|         for (int i = 0; i < samples; i+=2) { |         for (int i = 0; i < samples; i+=2) { | ||||||
|             out[i] = in[i+1]; |             out[i] = in[i+1]; | ||||||
|  | @ -136,8 +149,6 @@ static void __no_inline_not_in_flash_func(_as_audio_packet)(struct usb_endpoint | ||||||
|             out[i] = in[i]; |             out[i] = in[i]; | ||||||
|     } |     } | ||||||
|   |   | ||||||
|     // Make sure core 1 is ready for us.
 |  | ||||||
|     multicore_fifo_pop_blocking(); |  | ||||||
|     multicore_fifo_push_blocking(CORE0_READY); |     multicore_fifo_push_blocking(CORE0_READY); | ||||||
|     multicore_fifo_push_blocking(samples); |     multicore_fifo_push_blocking(samples); | ||||||
| 
 | 
 | ||||||
|  | @ -186,8 +197,7 @@ void __no_inline_not_in_flash_func(core1_entry)() { | ||||||
| 
 | 
 | ||||||
|         // Block until the userbuf is filled with data
 |         // Block until the userbuf is filled with data
 | ||||||
|         uint32_t ready = multicore_fifo_pop_blocking(); |         uint32_t ready = multicore_fifo_pop_blocking(); | ||||||
|         while (ready != CORE0_READY) |         if (ready == CORE0_ABORTED) continue; | ||||||
|             ready = multicore_fifo_pop_blocking(); |  | ||||||
|          |          | ||||||
|         const uint32_t samples = multicore_fifo_pop_blocking(); |         const uint32_t samples = multicore_fifo_pop_blocking(); | ||||||
| 
 | 
 | ||||||
|  | @ -760,6 +770,7 @@ static const struct usb_transfer_type _audio_cmd_transfer_type = { | ||||||
| 
 | 
 | ||||||
| static bool as_set_alternate(struct usb_interface *interface, uint alt) { | static bool as_set_alternate(struct usb_interface *interface, uint alt) { | ||||||
|     assert(interface == &as_op_interface); |     assert(interface == &as_op_interface); | ||||||
|  |     audio_state.interface = alt; | ||||||
|     switch (alt) { |     switch (alt) { | ||||||
|         case 0: power_down_dac(); return true; |         case 0: power_down_dac(); return true; | ||||||
|         case 1: power_up_dac(); return true; |         case 1: power_up_dac(); return true; | ||||||
|  |  | ||||||
|  | @ -76,6 +76,7 @@ typedef struct _audio_state_config { | ||||||
|         int16_t _target_pcm3060_registers; |         int16_t _target_pcm3060_registers; | ||||||
|     }; |     }; | ||||||
|     int16_t pcm3060_registers; |     int16_t pcm3060_registers; | ||||||
|  |     int8_t interface; | ||||||
| } audio_state_config; | } audio_state_config; | ||||||
| extern audio_state_config audio_state; | extern audio_state_config audio_state; | ||||||
| 
 | 
 | ||||||
|  | @ -149,6 +150,7 @@ static char *descriptor_strings[] = { | ||||||
| #define SAMPLING_FREQ (CODEC_FREQ / 192) | #define SAMPLING_FREQ (CODEC_FREQ / 192) | ||||||
| 
 | 
 | ||||||
| #define CORE0_READY 19813219 | #define CORE0_READY 19813219 | ||||||
|  | #define CORE0_ABORTED 91231891 | ||||||
| #define CORE1_READY 72965426 | #define CORE1_READY 72965426 | ||||||
| 
 | 
 | ||||||
| /*****************************************************************************
 | /*****************************************************************************
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 George Norton
						George Norton