From 31e0c941240f2b1d0e4f97d6e65d3a1ad66fbae5 Mon Sep 17 00:00:00 2001
From: Matthijs Kooijman <matthijs@stdin.nl>
Date: Thu, 30 Jul 2015 15:33:37 +0200
Subject: Add Serial_::readBreak() to process SEND_BREAK requests

This allows detecting when the USB host sends a break request and what
the value of the request was. See the comments in USBAPI.h for details.

This just modifies the avr core, not the sam core.
---
 cores/arduino/CDC.cpp   | 18 ++++++++++++++++++
 cores/arduino/USBAPI.h  | 17 +++++++++++++++++
 cores/arduino/USBCore.h |  1 +
 3 files changed, 36 insertions(+)

(limited to 'cores')

diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp
index 90a1698..5e872c5 100644
--- a/cores/arduino/CDC.cpp
+++ b/cores/arduino/CDC.cpp
@@ -32,6 +32,7 @@ typedef struct
 } LineInfo;
 
 static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
+static volatile int32_t breakValue = -1;
 
 #define WEAK __attribute__ ((weak))
 
@@ -76,6 +77,11 @@ bool CDC_Setup(USBSetup& setup)
 
 	if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
 	{
+		if (CDC_SEND_BREAK == r)
+		{
+			breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
+		}
+
 		if (CDC_SET_LINE_CODING == r)
 		{
 			USB_RecvControl((void*)&_usbLineInfo,7);
@@ -207,6 +213,7 @@ Serial_::operator bool() {
 }
 
 unsigned long Serial_::baud() {
+	// Disable interrupts while reading a multi-byte value
 	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
 		return _usbLineInfo.dwDTERate;
 	}
@@ -232,6 +239,17 @@ bool Serial_::rts() {
 	return _usbLineInfo.lineState & 0x2;
 }
 
+int32_t Serial_::readBreak() {
+	int32_t ret;
+	// Disable IRQs while reading and clearing breakValue to make
+	// sure we don't overwrite a value just set by the ISR.
+	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+		ret = breakValue;
+		breakValue = -1;
+	}
+	return ret;
+}
+
 Serial_ Serial;
 
 #endif /* if defined(USBCON) */
diff --git a/cores/arduino/USBAPI.h b/cores/arduino/USBAPI.h
index ada73b0..3d355d2 100644
--- a/cores/arduino/USBAPI.h
+++ b/cores/arduino/USBAPI.h
@@ -102,6 +102,23 @@ public:
 	volatile uint8_t _rx_buffer_tail;
 	unsigned char _rx_buffer[SERIAL_BUFFER_SIZE];
 
+	// This method allows processing "SEND_BREAK" requests sent by
+	// the USB host. Those requests indicate that the host wants to
+	// send a BREAK signal and are accompanied by a single uint16_t
+	// value, specifying the duration of the break. The value 0
+	// means to end any current break, while the value 0xffff means
+	// to start an indefinite break.
+	// readBreak() will return the value of the most recent break
+	// request, but will return it at most once, returning -1 when
+	// readBreak() is called again (until another break request is
+	// received, which is again returned once).
+	// This also mean that if two break requests are received
+	// without readBreak() being called in between, the value of the
+	// first request is lost.
+	// Note that the value returned is a long, so it can return
+	// 0-0xffff as well as -1.
+	int32_t readBreak();
+
 	// These return the settings specified by the USB host for the
 	// serial port. These aren't really used, but are offered here
 	// in case a sketch wants to act on these settings.
diff --git a/cores/arduino/USBCore.h b/cores/arduino/USBCore.h
index 66f8c05..eaeecef 100644
--- a/cores/arduino/USBCore.h
+++ b/cores/arduino/USBCore.h
@@ -57,6 +57,7 @@
 #define CDC_SET_LINE_CODING			0x20
 #define CDC_GET_LINE_CODING			0x21
 #define CDC_SET_CONTROL_LINE_STATE	0x22
+#define CDC_SEND_BREAK				0x23
 
 #define MSC_RESET					0xFF
 #define MSC_GET_MAX_LUN				0xFE
-- 
cgit v1.2.3-18-g5258