From 7fc402f3b5a6f0d320959b86d5a18c425cbc0b3f Mon Sep 17 00:00:00 2001
From: Sandeep Mistry <s.mistry@bcmi-labs.cc>
Date: Thu, 31 Aug 2017 14:09:09 -0400
Subject: [PATCH] Leverage SERCOM h/w functionality for RTS and CTS

---
 cores/arduino/SERCOM.cpp | 10 ++++++++++
 cores/arduino/SERCOM.h   |  2 ++
 cores/arduino/Uart.cpp   | 41 ++++++++++++++++++++--------------------
 3 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp
index 42c46d01..d0f50a6b 100644
--- a/cores/arduino/SERCOM.cpp
+++ b/cores/arduino/SERCOM.cpp
@@ -183,6 +183,16 @@ void SERCOM::disableDataRegisterEmptyInterruptUART()
   sercom->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE;
 }
 
+void SERCOM::enableReceiveCompleteInterruptUART()
+{
+  sercom->USART.INTENSET.reg |= SERCOM_USART_INTENSET_RXC;
+}
+
+void SERCOM::disableReceiveCompleteInterruptUART()
+{
+  sercom->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_RXC;
+}
+
 /*	=========================
  *	===== Sercom SPI
  *	=========================
diff --git a/cores/arduino/SERCOM.h b/cores/arduino/SERCOM.h
index 6b7c703a..77609f87 100644
--- a/cores/arduino/SERCOM.h
+++ b/cores/arduino/SERCOM.h
@@ -165,6 +165,8 @@ class SERCOM
 		void acknowledgeUARTError() ;
 		void enableDataRegisterEmptyInterruptUART();
 		void disableDataRegisterEmptyInterruptUART();
+		void enableReceiveCompleteInterruptUART();
+		void disableReceiveCompleteInterruptUART();
 
 		/* ========== SPI ========== */
 		void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) ;
diff --git a/cores/arduino/Uart.cpp b/cores/arduino/Uart.cpp
index 6ef5338f..2b54787f 100644
--- a/cores/arduino/Uart.cpp
+++ b/cores/arduino/Uart.cpp
@@ -46,12 +46,11 @@ void Uart::begin(unsigned long baudrate, uint16_t config)
   pinPeripheral(uc_pinTX, g_APinDescription[uc_pinTX].ulPinType);
 
   if (uc_pinRTS != NO_RTS_PIN) {
-    pinMode(uc_pinRTS, OUTPUT);
-    digitalWrite(uc_pinRTS, LOW);
+    pinPeripheral(uc_pinRTS, g_APinDescription[uc_pinRTS].ulPinType);
   }
 
   if (uc_pinCTS != NO_CTS_PIN) {
-    pinMode(uc_pinCTS, INPUT);
+    pinPeripheral(uc_pinCTS, g_APinDescription[uc_pinCTS].ulPinType);
   }
 
   sercom->initUART(UART_INT_CLOCK, SAMPLE_RATE_x16, baudrate);
@@ -86,9 +85,10 @@ void Uart::IrqHandler()
     rxBuffer.store_char(sercom->readDataUART());
 
     if (uc_pinRTS != NO_RTS_PIN) {
-      // if there is NOT enough space in the RX buffer, de-assert RTS
+      // if there is NOT enough space in the RX buffer,
+      // diable the receive complete interrupt
       if (rxBuffer.availableForStore() < RTS_RX_THRESHOLD) {
-        digitalWrite(uc_pinRTS, HIGH);
+        sercom->disableReceiveCompleteInterruptUART();
       }
     }
   }
@@ -132,9 +132,10 @@ int Uart::read()
   int c = rxBuffer.read_char();
 
   if (uc_pinRTS != NO_RTS_PIN) {
-    // if there is enough space in the RX buffer, assert RTS
+    // if there is enough space in the RX buffer, 
+    // enable the receive completer interrupt
     if (rxBuffer.availableForStore() > RTS_RX_THRESHOLD) {
-      digitalWrite(uc_pinRTS, LOW);
+      sercom->enableReceiveCompleteInterruptUART();
     }
   }
 
@@ -143,16 +144,6 @@ int Uart::read()
 
 size_t Uart::write(const uint8_t data)
 {
-  if (uc_pinRTS != NO_RTS_PIN) {
-    // assert RTS
-    digitalWrite(uc_pinRTS, LOW);
-  }
-
-  if (uc_pinCTS != NO_CTS_PIN) {
-    // wait until CTS is asserted
-    while (digitalRead(uc_pinCTS) != LOW);
-  }
-
   if (sercom->isDataRegisterEmptyUART() && txBuffer.available() == 0) {
     sercom->writeDataUART(data);
   } else {
@@ -217,14 +208,22 @@ SercomParityMode Uart::extractParity(uint16_t config)
 
 int Uart::attachRts(uint8_t pin)
 {
-  uc_pinRTS = pin;
+  if (uc_padTX == UART_TX_RTS_CTS_PAD_0_2_3) {
+    uc_pinRTS = pin;
 
-  return 1;
+    return 1;
+  }
+
+  return 0;
 }
 
 int Uart::attachCts(uint8_t pin)
 {
-  uc_pinCTS = pin;
+  if (uc_padTX == UART_TX_RTS_CTS_PAD_0_2_3) {
+    uc_pinCTS = pin;
 
-  return 1;
+    return 1;
+  }
+
+  return 0;
 }
-- 
GitLab