From ab9d1830245406d46bd6faada7df39ae17fef504 Mon Sep 17 00:00:00 2001
From: Robert F-C <rfc@exemail.com.au>
Date: Mon, 5 Nov 2012 21:34:27 +1100
Subject: [PATCH] Make serial port configurable.

This change makes the choice of serial port configurable so that
wireless capability can be easily added by connecting Bluetooth modules
(such as BlueSmirf or JY-MCU) to the expansion port pins.
---
 Marlin/Configuration.h  |  7 ++++++
 Marlin/MarlinSerial.cpp | 42 +++++++++++++++-------------------
 Marlin/MarlinSerial.h   | 50 ++++++++++++++++++++++++++++++++++++-----
 3 files changed, 69 insertions(+), 30 deletions(-)

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 1d2bb292a08..12f26246214 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -331,6 +331,13 @@ const bool Z_ENDSTOPS_INVERTING = true; // set to true to invert the logic of th
 // SF send wrong arc g-codes when using Arc Point as fillet procedure
 //#define SF_ARC_FIX
 
+
+// SERIAL_PORT selects which serial port should be used for communication with the host.
+// This allows the use of wireless adapters (for instance) which are connected to 
+// non-default serial port pins.
+#define SERIAL_PORT 2
+
+
 #include "Configuration_adv.h"
 #include "thermistortables.h"
 
diff --git a/Marlin/MarlinSerial.cpp b/Marlin/MarlinSerial.cpp
index e369800b893..0d2aceb3f2a 100644
--- a/Marlin/MarlinSerial.cpp
+++ b/Marlin/MarlinSerial.cpp
@@ -28,7 +28,7 @@
 // this is so I can support Attiny series and any other chip without a uart
 #if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
 
-#if defined(UBRRH) || defined(UBRR0H)
+#if UART_PRESENT(SERIAL_PORT)
   ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
 #endif
 
@@ -48,18 +48,12 @@ FORCE_INLINE void store_char(unsigned char c)
 
 
 //#elif defined(SIG_USART_RECV)
-#if defined(USART0_RX_vect)
+#if defined(M_USARTx_RX_vect)
   // fixed by Mark Sproul this is on the 644/644p
   //SIGNAL(SIG_USART_RECV)
-  SIGNAL(USART0_RX_vect)
+  SIGNAL(M_USARTx_RX_vect)
   {
-  #if defined(UDR0)
-    unsigned char c  =  UDR0;
-  #elif defined(UDR)
-    unsigned char c  =  UDR;  //  atmega8, atmega32
-  #else
-    #error UDR not defined
-  #endif
+    unsigned char c  =  M_UDRx;
     store_char(c);
   }
 #endif
@@ -76,39 +70,39 @@ MarlinSerial::MarlinSerial()
 void MarlinSerial::begin(long baud)
 {
   uint16_t baud_setting;
-  bool useU2X0 = true;
+  bool useU2X = true;
 
-#if F_CPU == 16000000UL
+#if F_CPU == 16000000UL && SERIAL_PORT == 0
   // hardcoded exception for compatibility with the bootloader shipped
   // with the Duemilanove and previous boards and the firmware on the 8U2
   // on the Uno and Mega 2560.
   if (baud == 57600) {
-    useU2X0 = false;
+    useU2X = false;
   }
 #endif
   
-  if (useU2X0) {
-    UCSR0A = 1 << U2X0;
+  if (useU2X) {
+    M_UCSRxA = 1 << M_U2Xx;
     baud_setting = (F_CPU / 4 / baud - 1) / 2;
   } else {
-    UCSR0A = 0;
+    M_UCSRxA = 0;
     baud_setting = (F_CPU / 8 / baud - 1) / 2;
   }
 
   // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
-  UBRR0H = baud_setting >> 8;
-  UBRR0L = baud_setting;
+  M_UBRRxH = baud_setting >> 8;
+  M_UBRRxL = baud_setting;
 
-  sbi(UCSR0B, RXEN0);
-  sbi(UCSR0B, TXEN0);
-  sbi(UCSR0B, RXCIE0);
+  sbi(M_UCSRxB, M_RXENx);
+  sbi(M_UCSRxB, M_TXENx);
+  sbi(M_UCSRxB, M_RXCIEx);
 }
 
 void MarlinSerial::end()
 {
-  cbi(UCSR0B, RXEN0);
-  cbi(UCSR0B, TXEN0);
-  cbi(UCSR0B, RXCIE0);  
+  cbi(M_UCSRxB, M_RXENx);
+  cbi(M_UCSRxB, M_TXENx);
+  cbi(M_UCSRxB, M_RXCIEx);  
 }
 
 
diff --git a/Marlin/MarlinSerial.h b/Marlin/MarlinSerial.h
index 8525cba288d..c17f4719f08 100644
--- a/Marlin/MarlinSerial.h
+++ b/Marlin/MarlinSerial.h
@@ -23,6 +23,44 @@
 #define MarlinSerial_h
 #include "Marlin.h"
 
+#if !defined(SERIAL_PORT) 
+#error SERIAL_PORT not set 
+#endif
+
+// The presence of the UBRRH register is used to detect a UART.
+#define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \
+						(port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \
+						(port == 3 && defined(UBRR3H)))				
+						
+// These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor
+// requires two levels of indirection to expand macro values properly)
+#define SERIAL_REGNAME(registerbase,number,suffix) SERIAL_REGNAME_INTERNAL(registerbase,number,suffix)
+#define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix
+
+// Registers used by MarlinSerial class (these are expanded 
+// depending on selected serial port
+#define M_UCSRxA SERIAL_REGNAME(UCSR,SERIAL_PORT,A) // defines M_UCSRxA to be UCSRxA where x is the serial port number
+#define M_UCSRxB SERIAL_REGNAME(UCSR,SERIAL_PORT,B) 
+#define M_RXENx SERIAL_REGNAME(RXEN,SERIAL_PORT,)    
+#define M_TXENx SERIAL_REGNAME(TXEN,SERIAL_PORT,)    
+#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,)    
+#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,)    
+#if SERIAL_PORT == 0 && !defined(UDR0)
+  #if defined(UDR)
+    #define M_UDRx UDR  //  atmega8, atmega32
+  #else
+    #error UDR not defined
+  #endif
+#else
+  #define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,) 
+#endif  
+#define M_UBRRxH SERIAL_REGNAME(UBRR,SERIAL_PORT,H)
+#define M_UBRRxL SERIAL_REGNAME(UBRR,SERIAL_PORT,L)
+#define M_RXCx SERIAL_REGNAME(RXC,SERIAL_PORT,)
+#define M_USARTx_RX_vect SERIAL_REGNAME(USART,SERIAL_PORT,_RX_vect)
+#define M_U2Xx SERIAL_REGNAME(U2X,SERIAL_PORT,)
+
+
 
 #define DEC 10
 #define HEX 16
@@ -46,7 +84,7 @@ struct ring_buffer
   int tail;
 };
 
-#if defined(UBRRH) || defined(UBRR0H)
+#if UART_PRESENT(SERIAL_PORT)
   extern ring_buffer rx_buffer;
 #endif
 
@@ -68,17 +106,17 @@ class MarlinSerial //: public Stream
     
     FORCE_INLINE void write(uint8_t c)
     {
-      while (!((UCSR0A) & (1 << UDRE0)))
+      while (!((M_UCSRxA) & (1 << M_UDREx)))
         ;
 
-      UDR0 = c;
+      M_UDRx = c;
     }
     
     
     FORCE_INLINE void checkRx(void)
     {
-      if((UCSR0A & (1<<RXC0)) != 0) {
-        unsigned char c  =  UDR0;
+      if((M_UCSRxA & (1<<M_RXCx)) != 0) {
+        unsigned char c  =  M_UDRx;
         int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
 
         // if we should be storing the received character into the location
@@ -147,4 +185,4 @@ class MarlinSerial //: public Stream
 extern MarlinSerial MSerial;
 #endif // ! teensylu
 
-#endif
+#endif