MHVLib  20111011
An efficiency oriented runtime library for AVR microcontrollers
A:/eclipse/mhvlib/MHV_PinChangeManager.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, Make, Hack, Void Inc
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *  * Redistributions of source code must retain the above copyright
00008  *    notice, this list of conditions and the following disclaimer.
00009  *  * Redistributions in binary form must reproduce the above copyright
00010  *    notice, this list of conditions and the following disclaimer in the
00011  *    documentation and/or other materials provided with the distribution.
00012  *  * Neither the name of the Make, Hack, Void nor the
00013  *    names of its contributors may be used to endorse or promote products
00014  *    derived from this software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019  * DISCLAIMED. IN NO EVENT SHALL MAKE, HACK, VOID BE LIABLE FOR ANY
00020  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 #include <MHV_PinChangeManager.h>
00028 
00033 MHV_PinChangeManager::MHV_PinChangeManager() {
00034         for (uint8_t i = 0; i < MHV_PC_INT_COUNT; i++) {
00035                 _pins[i].port = NULL;
00036         }
00037 }
00038 
00042 void MHV_PinChangeManager::pinChange0() {
00043         pinChange(0);
00044 }
00045 
00046 #if MHV_PC_INT_COUNT > 7
00047 
00050 void MHV_PinChangeManager::pinChange1() {
00051         pinChange(8);
00052 }
00053 #endif
00054 
00055 #if MHV_PC_INT_COUNT > 15
00056 
00059 void MHV_PinChangeManager::pinChange2() {
00060         pinChange(16);
00061 }
00062 #endif
00063 
00068 void MHV_PinChangeManager::pinChange(uint8_t offset) {
00069         MHV_EVENT_PIN *pin = _pins + offset;
00070         MHV_EVENT_PIN *maxPin = pin + 8;
00071 
00072         for (; pin < maxPin; ++pin) {
00073                 if (NULL == pin->port) {
00074                         continue;
00075                 }
00076 
00077                 bool cur = *(pin->port) & pin->mask;
00078                 if (cur != pin->previous) {
00079                         // Pin has changed
00080                         pin->previous = cur;
00081                         pin->changed = 1;
00082                         pin->listener->pinChanged(pin - _pins, cur);
00083                 }
00084         }
00085 }
00086 
00096 void MHV_PinChangeManager::registerListener(volatile uint8_t *pinDir, volatile uint8_t *pinOut,
00097                 volatile uint8_t *pinIn, uint8_t pinBit, int8_t pinChangeInterrupt,
00098                 MHV_PinEventListener *listener) {
00099 
00100         mhv_setInput(pinDir, pinOut, pinIn, pinBit, pinChangeInterrupt);
00101 
00102         _pins[pinChangeInterrupt].port = pinIn;
00103         _pins[pinChangeInterrupt].mask = _BV(pinBit);
00104         _pins[pinChangeInterrupt].listener = listener;
00105         _pins[pinChangeInterrupt].previous = mhv_pinRead(pinDir, pinOut, pinIn, pinBit, pinChangeInterrupt);
00106         _pins[pinChangeInterrupt].changed = false;
00107 
00108         // Enable the interrupt
00109         uint8_t bit = pinChangeInterrupt;
00110 #if MHV_PC_INT_COUNT > 15
00111         if (pinChangeInterrupt > 15) {
00112                 bit -= 16;
00113                 PCMSK2 |= _BV(bit);
00114                 PCICR |= _BV(PCIE2);
00115         } else
00116 #endif
00117 #if MHV_PC_INT_COUNT > 7
00118         if (pinChangeInterrupt > 7) {
00119                 bit -= 8;
00120                 PCMSK1 |= _BV(bit);
00121                 PCICR |= _BV(PCIE1);
00122         } else
00123 #endif
00124 #ifdef PCMSK0
00125         {
00126                 PCMSK0 |= _BV(bit);
00127                 PCICR |= _BV(PCIE0);
00128         }
00129 #else
00130         {
00131                 PCMSK |= _BV(bit);
00132                 GIMSK |= _BV(PCIE);
00133         }
00134 #endif
00135 }
00136 
00145 void MHV_PinChangeManager::deregisterListener(volatile uint8_t *pinDir, volatile uint8_t *pinOut,
00146                 volatile uint8_t *pinIn, uint8_t pinBit, int8_t pinChangeInterrupt) {
00147 
00148         _pins[pinChangeInterrupt].listener = NULL;
00149         _pins[pinChangeInterrupt].changed = false;
00150 
00151 // Disable the interrupt
00152         uint8_t bit = pinChangeInterrupt;
00153 #if MHV_PC_INT_COUNT > 15
00154         if (pinChangeInterrupt > 15) {
00155                 bit -= 16;
00156                 PCMSK2 &= ~_BV(bit);
00157         } else
00158 #endif
00159 #if MHV_PC_INT_COUNT > 7
00160         if (pinChangeInterrupt > 7) {
00161                 bit -= 8;
00162                 PCMSK1 &= ~_BV(bit);
00163         } else
00164 #endif
00165 #ifdef PCMSK0
00166         {
00167                 PCMSK0 &= ~_BV(bit);
00168         }
00169 #else
00170         {
00171                 PCMSK &= ~_BV(bit);
00172         }
00173 #endif
00174 }
00175 
00179 void MHV_PinChangeManager::handleEvents() {
00180         uint8_t i;
00181 
00182         for (i = 0; i < MHV_PC_INT_COUNT; i++) {
00183                 if (_pins[i].changed) {
00184                         _pins[i].changed = 0;
00185                         _pins[i].listener->pinChanged(i, _pins[i].previous);
00186                 }
00187         }
00188 }