Basic support for rebooting into the bootloader. (#10)
This commit is contained in:
		
							parent
							
								
									992df01067
								
							
						
					
					
						commit
						69fdc8a4e2
					
				|  | @ -34,6 +34,7 @@ | ||||||
| #include "pico/stdlib.h" | #include "pico/stdlib.h" | ||||||
| #include "pico/usb_device.h" | #include "pico/usb_device.h" | ||||||
| #include "pico/multicore.h" | #include "pico/multicore.h" | ||||||
|  | #include "pico/bootrom.h" | ||||||
| #include "AudioClassCommon.h" | #include "AudioClassCommon.h" | ||||||
| 
 | 
 | ||||||
| #include "run.h" | #include "run.h" | ||||||
|  | @ -59,6 +60,10 @@ static struct { | ||||||
|     .freq = 48000, |     .freq = 48000, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum vendor_cmds { | ||||||
|  |     REBOOT_BOOTLOADER = 0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| int main(void) { | int main(void) { | ||||||
|     setup(); |     setup(); | ||||||
| 
 | 
 | ||||||
|  | @ -646,6 +651,20 @@ static bool do_set_current(struct usb_setup_packet *setup) { | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool ad_setup_request_handler(__unused struct usb_device *device, struct usb_setup_packet *setup) { | ||||||
|  |     setup = __builtin_assume_aligned(setup, 4); | ||||||
|  |     if (USB_REQ_TYPE_TYPE_VENDOR == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) { | ||||||
|  |         // To prevent badly behaving software from accidentally triggering a reboot, e expect
 | ||||||
|  |         // the wValue to be equal to the Ploopy vendor id.
 | ||||||
|  |         if (setup->bRequest == REBOOT_BOOTLOADER && setup->wValue == 0x2E8A) { | ||||||
|  |             reset_usb_boot(0, 0); | ||||||
|  |             // reset_usb_boot does not return, so we will not respond to this command.
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static bool ac_setup_request_handler(__unused struct usb_interface *interface, struct usb_setup_packet *setup) { | static bool ac_setup_request_handler(__unused struct usb_interface *interface, struct usb_setup_packet *setup) { | ||||||
|     setup = __builtin_assume_aligned(setup, 4); |     setup = __builtin_assume_aligned(setup, 4); | ||||||
|     if (USB_REQ_TYPE_TYPE_CLASS == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) { |     if (USB_REQ_TYPE_TYPE_CLASS == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) { | ||||||
|  | @ -726,6 +745,8 @@ void usb_sound_card_init() { | ||||||
|         count_of(boot_device_interfaces), _get_descriptor_string); |         count_of(boot_device_interfaces), _get_descriptor_string); | ||||||
| 
 | 
 | ||||||
|     assert(device); |     assert(device); | ||||||
|  | 
 | ||||||
|  |     device->setup_request_handler = ad_setup_request_handler; | ||||||
|     audio_set_volume(DEFAULT_VOLUME); |     audio_set_volume(DEFAULT_VOLUME); | ||||||
|     _audio_reconfigure(); |     _audio_reconfigure(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,7 +17,21 @@ Run `filter_test` to process the PCM samples. The `filter_test` program takes tw | ||||||
| You can listen to the PCM files using ffplay (which is usually included with ffmpeg): | You can listen to the PCM files using ffplay (which is usually included with ffmpeg): | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| ./ffplay -f s16le -ar 48000 -ac 2 output.pcm | ffplay -f s16le -ar 48000 -ac 2 output.pcm | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| If there are no obvious problems, go ahead and flash your firmware. | If there are no obvious problems, go ahead and flash your firmware. | ||||||
|  | 
 | ||||||
|  | ## reboot_bootloader.py | ||||||
|  | If your Ploopy Headphones firmware is new enough, it has support for a USB vendor command that will cause the RP2040 to reboot into the | ||||||
|  | bootloader. This will enable you to update the firmware without having to remove the case and short the pins on the board. | ||||||
|  | 
 | ||||||
|  | ### Usage | ||||||
|  | Connect the Ploopy headphones DAC and run: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | ./reboot_bootloader.py | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | You will need python3 and the pyusb module. If you get a permission denied error you may need to configure your udev rules, or run the | ||||||
|  | script with administrator privileges. | ||||||
|  | @ -0,0 +1,29 @@ | ||||||
|  | #!/usr/bin/python3 | ||||||
|  | import usb.core | ||||||
|  | from usb.util import * | ||||||
|  | 
 | ||||||
|  | REBOOT_BOOTLOADER = 0 | ||||||
|  | PLOOPY_VID = 0x2e8a | ||||||
|  | PLOOPY_PID = 0xfedd | ||||||
|  | 
 | ||||||
|  | device_count = 0 | ||||||
|  | 
 | ||||||
|  | # Find all connected Ploopy headphone devices | ||||||
|  | for dev in usb.core.find(find_all=True, idVendor=PLOOPY_VID, idProduct=PLOOPY_PID): | ||||||
|  |     device_count += 1 | ||||||
|  | 
 | ||||||
|  |     # The vendor command expects the wValue to be equal to the Ploopy vendor id. This | ||||||
|  |     # will hopefully prevent badly behaved software from accidentally triggering bootloader | ||||||
|  |     # mode. | ||||||
|  |     try: | ||||||
|  |         dev.ctrl_transfer(CTRL_RECIPIENT_DEVICE | CTRL_TYPE_VENDOR, REBOOT_BOOTLOADER, PLOOPY_VID) | ||||||
|  |     except Exception as e: | ||||||
|  |         # The headphones do not respond to the vendor command, as they have already rebooted, | ||||||
|  |         # so for now, we always end up here. | ||||||
|  |         if e.errno == 32: | ||||||
|  |             # libusb pipe error, this is expected. OpenUSB doesnt report an error. | ||||||
|  |             pass | ||||||
|  |         else: | ||||||
|  |             print(e) | ||||||
|  | 
 | ||||||
|  | print(f"Sent a reboot command to {device_count} Ploopy devices.") | ||||||
		Loading…
	
		Reference in New Issue
	
	 George Norton
						George Norton