mirror of
				https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
				synced 2025-10-30 18:55:21 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			809 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			809 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
 | |
| 
 | |
| /*
 | |
|   Part of the Wiring project - http://wiring.uniandes.edu.co
 | |
| 
 | |
|   Copyright (c) 2004-05 Hernando Barragan
 | |
| 
 | |
|   This library is free software; you can redistribute it and/or
 | |
|   modify it under the terms of the GNU Lesser General Public
 | |
|   License as published by the Free Software Foundation; either
 | |
|   version 2.1 of the License, or (at your option) any later version.
 | |
| 
 | |
|   This library is distributed in the hope that it will be useful,
 | |
|   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|   Lesser General Public License for more details.
 | |
| 
 | |
|   You should have received a copy of the GNU Lesser General
 | |
|   Public License along with this library; if not, write to the
 | |
|   Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 | |
|   Boston, MA  02111-1307  USA
 | |
| 
 | |
|   Modified 24 November 2006 by David A. Mellis
 | |
|   Modified 1 August 2010 by Mark Sproul
 | |
| 
 | |
|   Updated for 'xmega' core by bob frazier, S.F.T. Inc. - http://mrp3.com/
 | |
| 
 | |
|   In some cases, the xmega updates make assumptions about the pin assignments.
 | |
|   See 'pins_arduino.h' for more detail.
 | |
| 
 | |
| */
 | |
| 
 | |
| #include <inttypes.h>
 | |
| #include <avr/io.h>
 | |
| #include <avr/interrupt.h>
 | |
| #include <avr/pgmspace.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #include "wiring_private.h"
 | |
| 
 | |
| // interrupts on the xmega are handled differently than the mega
 | |
| // there are 2 interrupt vectors for each port.  Typical xmega
 | |
| // will use ports A, B, C, D, E, and R.  The vectors for those
 | |
| // are as follows:
 | |
| //
 | |
| //   PORTn_INT0_vect
 | |
| //   - and -
 | |
| //   PORTn_INT1_vect
 | |
| //
 | |
| // where 'n' is A, B, C, D, E, or R
 | |
| //
 | |
| // Additional vectors are:
 | |
| //
 | |
| //   OSC_XOSCF_vect  (external oscillator failure, NMI)
 | |
| //
 | |
| //   RTC_OVF_vect    (real-time clock overflow)
 | |
| //   RTC_COMP_vect   (real-time clock compare)
 | |
| //
 | |
| //   TWIC_TWIS_vect  (2-wire slave on port C)
 | |
| //   TWIC_TWIM_vect  (2-wire master on port C)
 | |
| //   TWIE_TWIS_vect  (2-wire slave on port E)
 | |
| //   TWIE_TWIM_vect  (2-wire master on port E)
 | |
| //
 | |
| //   timers - 'n' is C or D
 | |
| //   TCn0_OVF_vect   (n timer 0 overflow)
 | |
| //   TCn1_OVF_vect   (n timer 1 overflow)
 | |
| //   TCn2_LUNF_vect  (n timer 2 low byte underflow)
 | |
| //   TCn2_HUNF_vect  (n timer 2 high byte underflow)
 | |
| //   TCE0_OVF_vect   (E timer 0 overflow)
 | |
| //   TCn0_ERR_vect   (n timer 0 error)
 | |
| //   TCn1_ERR_vect   (n timer 1 error)
 | |
| //   TCE0_ERR_vect   (E timer 0 error)
 | |
| //   TCn0_CCA_vect   (n timer 0 compare or capture A)
 | |
| //   TCn1_CCA_vect   (n timer 1 compare or capture A)
 | |
| //   TCn2_LCMPA_vect (n timer 2 low-byte compare or capture A)
 | |
| //   TCE0_CCA_vect   (E timer 0 compare or capture A)
 | |
| //   TCn0_CCB_vect   (n timer 0 compare or capture B)
 | |
| //   TCn1_CCB_vect   (n timer 1 compare or capture B)
 | |
| //   TCn2_LCMPB_vect (n timer 2 low-byte compare or capture B)
 | |
| //   TCE0_CCB_vect   (E timer 0 compare or capture B)
 | |
| //   TCn0_CCC_vect   (n timer 0 compare or capture C)
 | |
| //   TCn2_LCMPC_vect (n timer 2 low-byte compare or capture C)
 | |
| //   TCE0_CCC_vect   (E timer 0 compare or capture C)
 | |
| //   TCn0_CCD_vect   (n timer 0 compare or capture D)
 | |
| //   TCn2_LCMPD_vect (n timer 2 low-byte compare or capture D)
 | |
| //   TCE0_CCD_vect   (E timer 0 compare or capture D)
 | |
| //
 | |
| //   SPIn_INT_vect   (SPI C or D)
 | |
| //
 | |
| //   USARTn0_RXC_vect (USART 'n' [C or D] receive complete)
 | |
| //   USARTn0_DRE_vect (USART 'n' [C or D] data reg empty)
 | |
| //   USARTn0_TXC_vect (USART 'n' [C or D] transmit complete)
 | |
| //
 | |
| // NOTE:  a 'USARTE' interrupt vector also exists, but isn't
 | |
| // implemented on the D4 series
 | |
| //
 | |
| // ASYNC interrupts are only possible on pin 2 for each of the 5
 | |
| // ports ('R' only has 2 pins, 0 and 1, so no async interrupt).
 | |
| // Sleep modes typically need ASYNC interrupts to wake up.
 | |
| 
 | |
| // The interrupt will be handled for a particular port, and not for
 | |
| // a particular interrupt.  The 'attachInterrupt' function will default
 | |
| // to pin 2 (asynchronous interrupt) unless otherwise specified in the
 | |
| // 'mode' parameter.
 | |
| 
 | |
| // BOOTLOADER NOTES
 | |
| //
 | |
| // Bit 6 of the CTRL reg must be assigned to '0'.  Bit 7 can be assigned
 | |
| // to '1' to enable 'round robin' scheduling using the priority bits.
 | |
| // Bits 0-2 (HILVLEN, MEDLVLEN, LOLVLEN) should also be assigned to '1'
 | |
| // to allow all 3 interrupt levels to execute.  ('D' manual 10.8.3 pg 102)
 | |
| // The CTRL reg can be assigned to b10000111 to accomplish this.  Bit 6
 | |
| // needs to use the "configuration change protection" method to change it
 | |
| // and may need to be assigned separately.
 | |
| 
 | |
| 
 | |
| 
 | |
| // interrupt mode - predefined values are LOW, CHANGE, RISING, FALLING, HIGH
 | |
| // additional bits are 'or'd with mode
 | |
| 
 | |
| static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
 | |
| static volatile uint8_t intPins[EXTERNAL_NUM_INTERRUPTS]; // added - store pins for this interrupt
 | |
| // volatile static voidFuncPtr twiIntFunc;
 | |
| 
 | |
| 
 | |
| // NOTE: I _HATE_ K&R style so I'll make it Allman style as I go along...
 | |
| 
 | |
| void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)
 | |
| {
 | |
| uint8_t iPinBits, iPriBits, iModeBits, iInv, iNum, iMask;
 | |
| uint8_t oldSREG;
 | |
| uint8_t intInfo;
 | |
| PORT_t *port;
 | |
| 
 | |
| 
 | |
|   // for compatibility with newer IDE, 'interruptNum' can be encoded with pin information.
 | |
|   // if it is, then the pin info will be derived from pin info in 'mode' and 'interruptNum'
 | |
|   // pin info will be incorporated into it.
 | |
| 
 | |
|   intInfo = ((interruptNum & 0xe0) >> 5);  // is an int pin encoded here by digitalPinToInterrupt ?
 | |
|   interruptNum &= 0x1f; // so the rest of the code will work correctly
 | |
| 
 | |
|   if(interruptNum >= EXTERNAL_NUM_INTERRUPTS)
 | |
|   {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   iPinBits = (uint8_t)((mode & INT_MODE_PIN_MASK) >> 8);
 | |
| 
 | |
|   if(intInfo)
 | |
|   {
 | |
|     intInfo = ((intInfo + 2) & 7); // convert to actual pin number
 | |
| 
 | |
|     iPinBits |= _BV(intInfo); // set respective bit in 'iPinBits'
 | |
|   }
 | |
| 
 | |
|   if(!iPinBits)
 | |
|   {
 | |
|     if(interruptNum == PORTR_INT0
 | |
| #ifdef PORTR_INT1
 | |
|        || interruptNum == PORTR_INT1
 | |
| #endif // PORTR_INT1
 | |
|        ) // not valid for these
 | |
|     {
 | |
|       return; // do nothing (for now)
 | |
|     }
 | |
| 
 | |
|     iPinBits = _BV(2); // set bit for pin 2 if none specified [i.e. 'default']
 | |
|   }
 | |
| 
 | |
|   iPriBits = (mode & INT_MODE_PRI_MASK)
 | |
|            >> INT_MODE_PRI_SHIFT;
 | |
| 
 | |
|   if(!iPriBits) // not assigned
 | |
|   {
 | |
|     iPriBits = 3; // for now, just use the highest priority
 | |
|   }
 | |
| 
 | |
|   mode &= INT_MODE_MODE_MASK;
 | |
|   iInv = 0;
 | |
| 
 | |
|   if(mode == LOW) // normally will be this, for backward hardware compatibility
 | |
|   {
 | |
|     iModeBits = PORT_ISC_LEVEL_gc; // b011, high level continuously generates events
 | |
|   }
 | |
|   else if(mode == HIGH) // these constants correspond to the mega's bit mask on ISC00,ISC10
 | |
|   {
 | |
|     iModeBits = PORT_ISC_LEVEL_gc; // b011, high level continuously generates events
 | |
|     iInv = 1;                      // invert input (so 'high level' becomes 'low level')
 | |
| 
 | |
|     // NOTE:  this was verified by experimentation.  The documentation is misleading, suggesting
 | |
|     //        that a LEVEL interrupt triggered on HIGH, not on LOW.  But it triggers on LOW.  So
 | |
|     //        if you want HIGH, you must invert it.  Not the other way around.  Yeah.
 | |
|   }
 | |
|   else if(mode == CHANGE)
 | |
|   {
 | |
|     iModeBits = PORT_ISC_BOTHEDGES_gc; // BOTHEDGES - see table 11-6
 | |
|   }
 | |
|   else if(mode == RISING)
 | |
|   {
 | |
|     iModeBits = PORT_ISC_RISING_gc; // b001, RISING
 | |
|   }
 | |
|   else if(mode == FALLING)
 | |
|   {
 | |
|     iModeBits = PORT_ISC_FALLING_gc; // b010, FALLING
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     iModeBits = PORT_ISC_BOTHEDGES_gc; // BOTH (the default - note INTPUT_DISABLED (sic) won't buffer the input, so it's useless except for analog channels)
 | |
|   }
 | |
| 
 | |
|   if(iInv)
 | |
|   {
 | |
|     iModeBits |= _BV(PORT_INVEN_bp); // set the 'inverted' bit
 | |
|   }
 | |
| 
 | |
|   oldSREG = SREG; // store the interrupt flag basically
 | |
| 
 | |
|   cli(); // disable interrupts for a bit
 | |
| 
 | |
|   intFunc[interruptNum] = userFunc;
 | |
|   intPins[interruptNum] = iPinBits; // save what pins I used
 | |
| 
 | |
|   // Enable the interrupt (smaller code to use if/else and pointer)
 | |
| 
 | |
|   iNum = 0;
 | |
|   if(interruptNum == PORTA_INT0
 | |
| #ifdef PORTA_INT1
 | |
|      || interruptNum == PORTA_INT1
 | |
| #endif // PORTA_INT1
 | |
|      )
 | |
|   {
 | |
|     port = &PORTA;
 | |
| #ifdef PORTA_INT1
 | |
|     if(interruptNum == PORTA_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTA_INT1
 | |
|   }
 | |
| #if NUM_ANALOG_PINS > 8 /* which means we have PORT B */
 | |
|   else if(interruptNum == PORTB_INT0
 | |
| #ifdef PORTB_INT1
 | |
|           || interruptNum == PORTB_INT1
 | |
| #endif // PORTB_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTB;
 | |
| #ifdef PORTB_INT1
 | |
|     if(interruptNum == PORTB_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTB_INT1
 | |
|   }
 | |
| #endif // NUM_ANALOG_PINS > 8
 | |
|   else if(interruptNum == PORTC_INT0
 | |
| #ifdef PORTC_INT1
 | |
|           || interruptNum == PORTC_INT1
 | |
| #endif // PORTC_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTC;
 | |
| #ifdef PORTC_INT1
 | |
|     if(interruptNum == PORTC_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTC_INT1
 | |
|   }
 | |
|   else if(interruptNum == PORTD_INT0
 | |
| #ifdef PORTD_INT1
 | |
|           || interruptNum == PORTD_INT1
 | |
| #endif // PORTD_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTD;
 | |
| #ifdef PORTD_INT1
 | |
|     if(interruptNum == PORTD_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTC_INT1
 | |
|   }
 | |
| #if NUM_DIGITAL_PINS > 18 /* which means we have PORT E */
 | |
|   else if(interruptNum == PORTE_INT0
 | |
| #ifdef PORTE_INT1
 | |
|           || interruptNum == PORTE_INT1
 | |
| #endif // PORTE_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTE;
 | |
| #ifdef PORTE_INT1
 | |
|     if(interruptNum == PORTE_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTE_INT1
 | |
|   }
 | |
| #endif // NUM_DIGITAL_PINS > 18
 | |
|   else if(interruptNum == PORTR_INT0
 | |
| #ifdef PORTR_INT1
 | |
|           || interruptNum == PORTR_INT1
 | |
| #endif // PORTR_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTR;
 | |
| #ifdef PORTR_INT1
 | |
|     if(interruptNum == PORTR_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTR_INT1
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     return; // do nothing
 | |
|   }
 | |
| 
 | |
|   // On certain processors there's only one interrupt, so it's called 'INTMASK'
 | |
|   // we test for this here
 | |
| 
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
|   if(!iNum)
 | |
|   {
 | |
|     // set interrupt mask for PORT A, int 0 vector
 | |
|     port->INTMASK |= iPinBits; // enable int zero for these pins
 | |
|     port->INTCTRL = (port->INTCTRL & ~(PORT_INTLVL_gm))
 | |
|                   | (iPriBits & 3);
 | |
|   }
 | |
| #else // INT0MASK and INT1MASK supported
 | |
|   if(!iNum)
 | |
|   {
 | |
|     // set interrupt mask for PORT A, int 0 vector
 | |
|     port->INT0MASK |= iPinBits; // enable int zero for these pins
 | |
|     port->INTCTRL = (port->INTCTRL & ~(PORT_INT0LVL_gm))
 | |
|                   | (iPriBits & 3);
 | |
|   }
 | |
|   else // if(iNum == 1)
 | |
|   {
 | |
|     port->INT1MASK |= iPinBits; // enable int zero for these pins
 | |
|     port->INTCTRL = (port->INTCTRL & ~(PORT_INT1LVL_gm))
 | |
|                   | ((iPriBits & 3) << PORT_INT1LVL_gp);
 | |
|   }
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| 
 | |
|   for(iNum=0, iMask = 1; iNum < 8; iNum++, iMask <<= 1)
 | |
|   {
 | |
|     register8_t *pCTRL = &(port->PIN0CTRL) + iNum; // treat PIN0CTRL through PIN7CTRL as an array
 | |
| 
 | |
|     // set corresponding 'type' in the interrupt control regs for the individual bits
 | |
| 
 | |
|     if(iPinBits & iMask) // is this bit set in 'iPinBits'?
 | |
|     {
 | |
|       // enable the interrupt pin's mode bits and assign the 'invert' flag as needed
 | |
| 
 | |
|       *pCTRL = (*pCTRL & ~(PORT_ISC_gm | PORT_INVEN_bm))
 | |
|              | iModeBits;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   SREG = oldSREG; // restore it, interrupts (probably) re-enabled
 | |
|   // NOTE that this may throw an interrupt right away
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void detachInterrupt(uint8_t interruptNum)
 | |
| {
 | |
| uint8_t iPinBits, iNum, iMask;
 | |
| uint8_t oldSREG;
 | |
| PORT_t *port;
 | |
| 
 | |
| 
 | |
|   // NOTE:  this function will turn OFF the 'invert' bit if it's set for a HIGH level interrupt
 | |
|   //        and digitalRead _SHOULD_ be consistent before/after this call.
 | |
| 
 | |
|   if(interruptNum >= EXTERNAL_NUM_INTERRUPTS)
 | |
|   {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   oldSREG = SREG; // keep track of interrupt flag state
 | |
| 
 | |
|   cli(); // clear the interrupt flag
 | |
| 
 | |
|   // grab 'pin bits' so I know what to flip around
 | |
|   iPinBits = intPins[interruptNum]; // what I used when I added it
 | |
| 
 | |
|   intFunc[interruptNum] = 0;
 | |
|   intPins[interruptNum] = 0; // zero both of these
 | |
| 
 | |
|   // disable the interrupt
 | |
| 
 | |
|   // Enable the interrupt (smaller code to use if/else and pointer)
 | |
| 
 | |
|   iNum = 0;
 | |
|   if(interruptNum == PORTA_INT0
 | |
| #ifdef PORTA_INT1
 | |
|      || interruptNum == PORTA_INT1
 | |
| #endif // PORTA_INT1
 | |
|      )
 | |
|   {
 | |
|     port = &PORTA;
 | |
| #ifdef PORTA_INT1
 | |
|     if(interruptNum == PORTA_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTA_INT1
 | |
|   }
 | |
| #if NUM_ANALOG_PINS > 8 /* which means we have PORT B */
 | |
|   else if(interruptNum == PORTB_INT0
 | |
| #ifdef PORTB_INT1
 | |
|           || interruptNum == PORTB_INT1
 | |
| #endif // PORTB_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTB;
 | |
| #ifdef PORTB_INT1
 | |
|     if(interruptNum == PORTB_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTB_INT1
 | |
|   }
 | |
| #endif // NUM_ANALOG_PINS > 8
 | |
|   else if(interruptNum == PORTC_INT0
 | |
| #ifdef PORTC_INT1
 | |
|           || interruptNum == PORTC_INT1
 | |
| #endif // PORTC_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTC;
 | |
| #ifdef PORTC_INT1
 | |
|     if(interruptNum == PORTC_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTC_INT1
 | |
|   }
 | |
|   else if(interruptNum == PORTD_INT0
 | |
| #ifdef PORTD_INT1
 | |
|           || interruptNum == PORTD_INT1
 | |
| #endif // PORTD_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTD;
 | |
| #ifdef PORTD_INT1
 | |
|     if(interruptNum == PORTD_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTD_INT1
 | |
|   }
 | |
| #if NUM_DIGITAL_PINS > 18 /* which means we have PORT E */
 | |
|   else if(interruptNum == PORTE_INT0
 | |
| #ifdef PORTE_INT1
 | |
|           || interruptNum == PORTE_INT1
 | |
| #endif // PORTE_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTE;
 | |
| #ifdef PORTE_INT1
 | |
|     if(interruptNum == PORTE_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTE_INT1
 | |
|   }
 | |
| #endif // NUM_DIGITAL_PINS > 18
 | |
|   else if(interruptNum == PORTR_INT0
 | |
| #ifdef PORTR_INT1
 | |
|           || interruptNum == PORTR_INT1
 | |
| #endif // PORTR_INT1
 | |
|           )
 | |
|   {
 | |
|     port = &PORTR;
 | |
| #ifdef PORTR_INT1
 | |
|     if(interruptNum == PORTR_INT1)
 | |
|     {
 | |
|       iNum = 1;
 | |
|     }
 | |
| #endif // PORTR_INT1
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     return; // do nothing
 | |
|   }
 | |
| 
 | |
|   // On certain processors there's only one interrupt, so it's called 'INTMASK'
 | |
|   // we test for this here
 | |
| 
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
|   if(!iNum)
 | |
|   {
 | |
|     // set interrupt mask for PORT A, int 0 vector
 | |
|     port->INTMASK = 0;                  // disable interrupts - TODO, read this instead of 'iPinBits' ?
 | |
|     port->INTCTRL &= ~(PORT_INTLVL_gm); // set interrupt control to 'OFF'
 | |
|     port->INTFLAGS = _BV(0);            // clear the int flag
 | |
| 
 | |
| #else // INT0MASK and INT1MASK supported
 | |
|   if(!iNum)
 | |
|   {
 | |
|     // set interrupt mask for PORT A, int 0 vector
 | |
|     port->INT0MASK = 0;                  // disable interrupts - TODO, read this instead of 'iPinBits' ?
 | |
|     port->INTCTRL &= ~(PORT_INT0LVL_gm); // set interrupt control to 'OFF'
 | |
|     port->INTFLAGS = _BV(0);             // clear the int 0 flag
 | |
|   }
 | |
|   else // if(iNum == 1)
 | |
|   {
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
|     // if this matches a CTS port, I do _NOT_ want to disable interrupts
 | |
| #if defined(SERIAL_0_CTS_ENABLED) && defined(SERIAL_1_CTS_ENABLED)
 | |
|     if(SERIAL_0_CTS_PORT == port)
 | |
|     {
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
|       if(SERIAL_1_CTS_PORT == port)
 | |
|       {
 | |
|         port->INTMASK = SERIAL_0_CTS_PIN | SERIAL_1_CTS_PIN;   // disable interrupts but leave BOTH enabled
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         port->INTMASK = SERIAL_0_CTS_PIN;    // disable interrupts but leave THIS one enabled
 | |
|       }
 | |
| 
 | |
|       port->INTCTRL |= PORT_INTLVL_gm; // max priority when I do this
 | |
| #else // INT0MASK and INT1MASK supported
 | |
|       if(SERIAL_1_CTS_PORT == port)
 | |
|       {
 | |
|         port->INT1MASK = SERIAL_0_CTS_PIN | SERIAL_1_CTS_PIN;   // disable interrupts but leave BOTH enabled
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         port->INT1MASK = SERIAL_0_CTS_PIN;    // disable interrupts but leave THIS one enabled
 | |
|       }
 | |
| 
 | |
|       port->INTCTRL |= PORT_INT1LVL_gm; // max priority when I do this
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
|     }
 | |
|     else if(SERIAL_1_CTS_PORT == port)
 | |
|     {
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
|       port->INTMASK = SERIAL_1_CTS_PIN;    // disable interrupts but leave THIS one enabled
 | |
| 
 | |
|       port->INTCTRL |= PORT_INTLVL_gm; // max priority when I do this
 | |
| #else // INT0MASK and INT1MASK supported
 | |
|       port->INT1MASK = SERIAL_1_CTS_PIN;    // disable interrupts but leave THIS one enabled
 | |
| 
 | |
|       port->INTCTRL |= PORT_INT1LVL_gm; // max priority when I do this
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
|     }
 | |
| #elif defined(SERIAL_0_CTS_ENABLED)
 | |
|     if(SERIAL_0_CTS_PORT == port)
 | |
|     {
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
|       port->INTMASK = SERIAL_0_CTS_PIN;    // disable interrupts but leave THIS one enabled
 | |
| 
 | |
|       port->INTCTRL |= PORT_INTLVL_gm; // max priority when I do this
 | |
| #else // INT0MASK and INT1MASK supported
 | |
|       port->INT1MASK = SERIAL_0_CTS_PIN;    // disable interrupts but leave THIS one enabled
 | |
| 
 | |
|       port->INTCTRL |= PORT_INT1LVL_gm; // max priority when I do this
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
|     }
 | |
| #elif defined(SERIAL_1_CTS_ENABLED)
 | |
|     if(SERIAL_1_CTS_PORT == port)
 | |
|     {
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
|       port->INTMASK = SERIAL_1_CTS_PIN;    // disable interrupts but leave THIS one enabled
 | |
| 
 | |
|       port->INTCTRL |= PORT_INTLVL_gm; // max priority when I do this
 | |
| #else // INT0MASK and INT1MASK supported
 | |
|       port->INT1MASK = SERIAL_1_CTS_PIN;    // disable interrupts but leave THIS one enabled
 | |
| 
 | |
|       port->INTCTRL |= PORT_INT1LVL_gm; // max priority when I do this
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
|     }
 | |
| #endif // SERIAL_0/1_CTS_ENABLED
 | |
| 
 | |
| #if defined(SERIAL_0_CTS_ENABLED) || defined(SERIAL_1_CTS_ENABLED)
 | |
|     else
 | |
| #endif // SERIAL_0/1_CTS_ENABLED
 | |
| 
 | |
|     {
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
|       port->INTMASK = 0;                  // disable interrupts - TODO, read this instead of 'iPinBits' ?
 | |
|       port->INTCTRL &= ~(PORT_INTLVL_gm); // set interrupt control to 'OFF'
 | |
| #else // INT0MASK and INT1MASK supported
 | |
|       port->INT1MASK = 0;                  // disable interrupts - TODO, read this instead of 'iPinBits' ?
 | |
|       port->INTCTRL &= ~(PORT_INT1LVL_gm); // set interrupt control to 'OFF'
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
|     }
 | |
| 
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
|     port->INTFLAGS = _BV(0);             // clear the int 0 flag
 | |
| #else // INT0MASK and INT1MASK supported
 | |
|     port->INTFLAGS = _BV(1);             // clear the int 1 flag
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
|   }
 | |
| 
 | |
|   for(iNum=0, iMask = 1; iNum < 8; iNum++, iMask <<= 1)
 | |
|   {
 | |
|     register8_t *pCTRL = &(port->PIN0CTRL) + iNum; // treat PIN0CTRL through PIN7CTRL as an array
 | |
| 
 | |
|     // set corresponding 'type' in the interrupt control regs for the individual bits
 | |
| 
 | |
|     if(iPinBits & iMask) // is this bit set in 'iPinBits'?
 | |
|     {
 | |
|       *pCTRL &= ~(PORT_ISC_gm | PORT_INVEN_bm); // turn off invert flag and reset to 'BOTH' (the default)
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   SREG = oldSREG; // restore it, interrupts (probably) re-enabled
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
| ISR(PORTA_INT_vect)
 | |
| #else // INT0MASK and INT1MASK supported
 | |
| ISR(PORTA_INT0_vect)
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| {
 | |
|   if(intFunc[PORTA_INT0])
 | |
|     intFunc[PORTA_INT0]();
 | |
| 
 | |
| #ifdef PORTC_INT0MASK // INT0MASK and INT1MASK supported
 | |
| }
 | |
| 
 | |
| ISR(PORTA_INT1_vect)
 | |
| {
 | |
|   if(intFunc[PORTA_INT1])
 | |
|     intFunc[PORTA_INT1]();
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| 
 | |
| #if defined(SERIAL_0_CTS_ENABLED)
 | |
|   if(SERIAL_0_CTS_PORT == &(PORTA)) // this should compile as a constant expression
 | |
|   {
 | |
|     serial_0_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_0_CTS_ENABLED
 | |
| 
 | |
| #ifdef SERIAL_1_CTS_ENABLED
 | |
|   if(SERIAL_1_CTS_PORT == &(PORTA))
 | |
|   {
 | |
|     serial_1_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_1_CTS_ENABLED
 | |
| }
 | |
| 
 | |
| #if NUM_ANALOG_PINS > 8 /* which means we have PORT B */
 | |
| ISR(PORTB_INT0_vect)
 | |
| {
 | |
|   if(intFunc[PORTB_INT0])
 | |
|     intFunc[PORTB_INT0]();
 | |
| }
 | |
| 
 | |
| ISR(PORTB_INT1_vect)
 | |
| {
 | |
|   if(intFunc[PORTB_INT1])
 | |
|     intFunc[PORTB_INT1]();
 | |
| 
 | |
| #if defined(SERIAL_0_CTS_ENABLED)
 | |
|   if(SERIAL_0_CTS_PORT == &(PORTB)) // this should compile as a constant expression
 | |
|   {
 | |
|     serial_0_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_0_CTS_ENABLED
 | |
| 
 | |
| #ifdef SERIAL_1_CTS_ENABLED
 | |
|   if(SERIAL_1_CTS_PORT == &(PORTB))
 | |
|   {
 | |
|     serial_1_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_1_CTS_ENABLED
 | |
| }
 | |
| #endif // NUM_ANALOG_PINS > 8
 | |
| 
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
| ISR(PORTC_INT_vect)
 | |
| #else // INT0MASK and INT1MASK supported
 | |
| ISR(PORTC_INT0_vect)
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| {
 | |
|   if(intFunc[PORTC_INT0])
 | |
|     intFunc[PORTC_INT0]();
 | |
| #ifdef PORTC_INT0MASK // INT0MASK and INT1MASK supported
 | |
| }
 | |
| 
 | |
| ISR(PORTC_INT1_vect)
 | |
| {
 | |
|   if(intFunc[PORTC_INT1])
 | |
|     intFunc[PORTC_INT1]();
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| 
 | |
| #if defined(SERIAL_0_CTS_ENABLED)
 | |
|   if(SERIAL_0_CTS_PORT == &(PORTC)) // this should compile as a constant expression
 | |
|   {
 | |
|     serial_0_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_0_CTS_ENABLED
 | |
| 
 | |
| #ifdef SERIAL_1_CTS_ENABLED
 | |
|   if(SERIAL_1_CTS_PORT == &(PORTC))
 | |
|   {
 | |
|     serial_1_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_1_CTS_ENABLED
 | |
| }
 | |
| 
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
| ISR(PORTD_INT_vect)
 | |
| #else // INT0MASK and INT1MASK supported
 | |
| ISR(PORTD_INT0_vect)
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| {
 | |
|   if(intFunc[PORTD_INT0])
 | |
|     intFunc[PORTD_INT0]();
 | |
| #ifdef PORTC_INT0MASK // INT0MASK and INT1MASK supported
 | |
| }
 | |
| 
 | |
| ISR(PORTD_INT1_vect)
 | |
| {
 | |
|   if(intFunc[PORTD_INT1])
 | |
|     intFunc[PORTD_INT1]();
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| 
 | |
| #if defined(SERIAL_0_CTS_ENABLED)
 | |
|   if(SERIAL_0_CTS_PORT == &(PORTD)) // this should compile as a constant expression
 | |
|   {
 | |
|     serial_0_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_0_CTS_ENABLED
 | |
| 
 | |
| #ifdef SERIAL_1_CTS_ENABLED
 | |
|   if(SERIAL_1_CTS_PORT == &(PORTD))
 | |
|   {
 | |
|     serial_1_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_1_CTS_ENABLED
 | |
| }
 | |
| 
 | |
| 
 | |
| #if NUM_DIGITAL_PINS > 18 /* which means we have PORT E */
 | |
| ISR(PORTE_INT0_vect)
 | |
| {
 | |
|   if(intFunc[PORTE_INT0])
 | |
|     intFunc[PORTE_INT0]();
 | |
| }
 | |
| 
 | |
| ISR(PORTE_INT1_vect)
 | |
| {
 | |
|   if(intFunc[PORTE_INT1])
 | |
|     intFunc[PORTE_INT1]();
 | |
| 
 | |
| #if defined(SERIAL_0_CTS_ENABLED)
 | |
|   if(SERIAL_0_CTS_PORT == &(PORTE)) // this should compile as a constant expression
 | |
|   {
 | |
|     serial_0_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_0_CTS_ENABLED
 | |
| 
 | |
| #ifdef SERIAL_1_CTS_ENABLED
 | |
|   if(SERIAL_1_CTS_PORT == &(PORTE))
 | |
|   {
 | |
|     serial_1_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_1_CTS_ENABLED
 | |
| }
 | |
| #endif // NUM_DIGITAL_PINS > 18
 | |
| 
 | |
| // TODO:  ISRs for PORTF, PORTH, PORTJ, PORTK, PORTQ
 | |
| 
 | |
| #ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
 | |
| ISR(PORTR_INT_vect)
 | |
| #else // INT0MASK and INT1MASK supported
 | |
| ISR(PORTR_INT0_vect)
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| {
 | |
|   if(intFunc[PORTR_INT0])
 | |
|     intFunc[PORTR_INT0]();
 | |
| #ifdef PORTC_INT0MASK // INT0MASK and INT1MASK supported
 | |
| }
 | |
| 
 | |
| ISR(PORTR_INT1_vect)
 | |
| {
 | |
|   if(intFunc[PORTR_INT1])
 | |
|     intFunc[PORTR_INT1]();
 | |
| #endif // INT0MASK and INT1MASK supported
 | |
| 
 | |
| #if defined(SERIAL_0_CTS_ENABLED)
 | |
|   if(SERIAL_0_CTS_PORT == &(PORTR)) // this should compile as a constant expression
 | |
|   {
 | |
|     serial_0_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_0_CTS_ENABLED
 | |
| 
 | |
| #ifdef SERIAL_1_CTS_ENABLED
 | |
|   if(SERIAL_1_CTS_PORT == &(PORTR))
 | |
|   {
 | |
|     serial_1_cts_callback();
 | |
|   }
 | |
| #endif // SERIAL_1_CTS_ENABLED
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 |