Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added callback support for USB host suspend/wake #4241

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

robvdveer
Copy link

This patch allows the Arduino sketch to respond to USB Host suspend/wake by settings a callback functions or using the isSuspended() function on the USBDevice instance. The suspend handler will be called when the host PC is put to sleep (or shuts down), and the WakeUp handler is called when the PC resumes from sleep.

PS. I apologise for the changes in whitespace I was unable to avoid that.

Usage:

void setup()
{
 USBDevice.setWakeUpHandler(&handleWakeup); 
 USBDevice.setSuspendHandler(&handleSuspend);
}

...

void handleWakeup()
{
}

void handleSuspend()
{
}

or

void loop()
{
   if(USBDevice.isSuspended())
   {
     ....
   }
}

@NicoHood
Copy link
Contributor

NicoHood commented Dec 3, 2015

How much overhead does this add?
I like the idea, not sure if the overhead is worth it.

However the isSuspended() function can be added anyways, that is nice! (not tested)

@robvdveer
Copy link
Author

Thank you NicoHood!

The only overhead is 2 function pointers and the amount of code you execute in the delegate functions. The original code already has guard classes against needless calls. The frequency of unplug/replug states if less than 1 second at most so I don't think this will be a real issue.

I decided to provide both the callback hooks and the isSuspended() function to allow people to use the method they prefer.

I did think about a setSuspendStateChangedHandler() API but this would require and additional boolean and additional testing for wake/sleep state in the handler, so I considered it bad design.

@delphinny
Copy link

I tried this but I keep getting an error when I compile it:

C:\Users\delphinny\Documents\Arduino\MyArduinotest3\MyArduinotest3.ino: In function 'void setup()':

MyArduinotest3:6: error: 'USBDevice' was not declared in this scope

USBDevice.setWakeUpHandler(&handleWakeup);

^

exit status 1
'USBDevice' was not declared in this scope

@facchinm
Copy link
Member

@delphinny this patch only targets boards with Atmega32u4 microcontroller (so Micro, Leonardo and similar). If you try to compile on a UNO, for example, you'll get the error you are reporting.
Just for reference, the rebased patch is

diff --git a/hardware/arduino/avr/cores/arduino/USBAPI.h b/hardware/arduino/avr/cores/arduino/USBAPI.h
index 358444ed2..b84cd34c9 100644
--- a/hardware/arduino/avr/cores/arduino/USBAPI.h
+++ b/hardware/arduino/avr/cores/arduino/USBAPI.h
@@ -55,6 +55,8 @@ typedef unsigned long u32;
 #define EP_TYPE_ISOCHRONOUS_IN		((1<<EPTYPE0) | (1<<EPDIR))
 #define EP_TYPE_ISOCHRONOUS_OUT		(1<<EPTYPE0)
 
+typedef void (*usbDeviceCallBack)();
+
 class USBDevice_
 {
 public:
@@ -65,6 +67,10 @@ public:
 	void detach();	// Serial port goes down too...
 	void poll();
 	bool wakeupHost(); // returns false, when wakeup cannot be processed
+
+	void setWakeUpHandler(usbDeviceCallBack delegate);
+	void setSuspendHandler(usbDeviceCallBack delegate);
+	bool isSuspended();
 };
 extern USBDevice_ USBDevice;
 
diff --git a/hardware/arduino/avr/cores/arduino/USBCore.cpp b/hardware/arduino/avr/cores/arduino/USBCore.cpp
index e00fb028e..84bdd281c 100644
--- a/hardware/arduino/avr/cores/arduino/USBCore.cpp
+++ b/hardware/arduino/avr/cores/arduino/USBCore.cpp
@@ -80,6 +80,9 @@ volatile u8 _usbConfiguration = 0;
 volatile u8 _usbCurrentStatus = 0; // meaning of bits see usb_20.pdf, Figure 9-4. Information Returned by a GetStatus() Request to a Device
 volatile u8 _usbSuspendState = 0; // copy of UDINT to check SUSPI and WAKEUPI bits
 
+volatile usbDeviceCallBack usbWakeUpDelegate;
+volatile usbDeviceCallBack usbSuspendDelegate;
+
 static inline void WaitIN(void)
 {
 	while (!(UEINTX & (1<<TXINI)))
@@ -777,6 +780,11 @@ ISR(USB_GEN_vect)
 		//USB_ClockEnable();
 		UDINT &= ~(1<<WAKEUPI);
 		_usbSuspendState = (_usbSuspendState & ~(1<<SUSPI)) | (1<<WAKEUPI);
+
+		if(usbWakeUpDelegate)
+		{
+			usbWakeUpDelegate();
+		}
 	}
 	else if (udint & (1<<SUSPI)) // only one of the WAKEUPI / SUSPI bits can be active at time
 	{
@@ -787,6 +795,11 @@ ISR(USB_GEN_vect)
 
 		UDINT &= ~((1<<WAKEUPI) | (1<<SUSPI)); // clear any already pending WAKEUP IRQs and the SUSPI request
 		_usbSuspendState = (_usbSuspendState & ~(1<<WAKEUPI)) | (1<<SUSPI);
+
+		if(usbSuspendDelegate)
+		{
+			usbSuspendDelegate();
+		}
 	}
 }
 
@@ -862,4 +875,19 @@ bool USBDevice_::wakeupHost()
 	return false;
 }
 
+void USBDevice_::setWakeUpHandler(usbDeviceCallBack delegate)
+{
+	usbWakeUpDelegate = delegate;
+}
+
+void USBDevice_::setSuspendHandler(usbDeviceCallBack delegate)
+{
+	usbSuspendDelegate = delegate;
+}
+
+bool USBDevice_::isSuspended()
+{
+	return (_usbSuspendState & (1 << SUSPI));
+}
+
 #endif /* if defined(USBCON) */

@robvdveer
Copy link
Author

I just noticed this conflict, i'm terribly ill, without computer access. What do i need to do to fix this?

@facchinm facchinm added Architecture: AVR Applies only to the AVR microcontrollers (Uno, etc.) Component: USB Device Opposed to USB Host. Related to the USB subsystem (SerialUSB, HID, ...) labels Sep 11, 2017
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@gaby64
Copy link

gaby64 commented Mar 5, 2023

how could I use this, I cant find any documentation on USBDevice or USBAPI
I have an arduino nano

@per1234 per1234 added Component: Core Related to the code for the standard Arduino API feature request A request to make an enhancement (not a bug fix) labels Mar 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Architecture: AVR Applies only to the AVR microcontrollers (Uno, etc.) Component: Core Related to the code for the standard Arduino API Component: USB Device Opposed to USB Host. Related to the USB subsystem (SerialUSB, HID, ...) feature request A request to make an enhancement (not a bug fix)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants