#ifndef PIN_GROUP_H #define PIN_GROUP_H #include "Pin.h" /** Class for simultaneous operations on Arduino I/O pins */ class PinGroup { public: template PinGroup(Pin (&pins)[N]) { _offset = pins[0].getOffset(); _PIN = pins[0].getPIN(); _PORT = pins[0].getPORT(); _DDR = pins[0].getDDR(); _numbers[0] = pins[0].getNumber(); _valid = true; for (int i = 1; i < N; i++) { if (_DDR != pins[i].getDDR()) { _valid = false; } _offset |= pins[i].getOffset(); _numbers[i] = pins[i].getNumber(); } _ioffset = ~_offset; } // ################################# Operators ################################# /** Compare the value of the pin @param value the state of the pin (HIGH, LOW) @return true if the value of all of the pins are equal to the value passed in, false otherwise */ bool operator==(uint8_t value) { uint8_t status = *_PIN; if ((status & _offset) == _offset) { return (value == HIGH); } else if ((status | _ioffset) == _ioffset) { return (value == LOW); } else { return false; } } /** Compare the value of the pin @param value the state of the pin (HIGH, LOW) @return true if the value of all of the pins are not equal to the value passed in, false otherwise */ bool operator!=(uint8_t value) { uint8_t status = *_PIN; if ((status & _offset) == _offset) { return (value == LOW); } else if ((status | _ioffset) == _ioffset) { return (value == HIGH); } else { return false; } } /** Set the pin state @param state the state of the pin (HIGH, LOW) */ PinGroup &operator=(uint8_t state) { oldSREG = SREG; cli(); if (state == LOW) { PORT_LOW; } else { PORT_HIGH; } SREG = oldSREG; return *this; } // ################################# Getters ################################# /** Get the pin numbers @return array of pin numbers */ uint8_t *getNumbers() { return _numbers; } /** Get the pin offset @return pin offset */ uint8_t getOffset() { return _offset; } /** Get the inverse pin offset @return inverse pin offset */ uint8_t getInverseOffset() { return _ioffset; } /** Get a pointer to the PIN register @return pointer to the PIN register */ volatile uint8_t *getPIN() { return _PIN; } /** Get a pointer to the PORT register @return pointer to the PORT register */ volatile uint8_t *getPORT() { return _PORT; } /** Get a pointer to the DDR register @return pointer to the DDR register */ volatile uint8_t *getDDR() { return _DDR; } /** Get the mode of the pin from the DDR register @return mode of the pin (OUTPUT, INPUT, -1) */ uint8_t getMode() { uint8_t status = *_DDR; if ((status & _offset) == _offset) { return OUTPUT; } else if ((status | _ioffset) == _ioffset) { return INPUT; } else { return -1; } } /** Get the state of the pin from the PORT register @return state of the pin (HIGH, LOW, -1) */ uint8_t getState() { uint8_t status = *_PORT; if ((status & _offset) == _offset) { return HIGH; } else if ((status | _ioffset) == _ioffset) { return LOW; } else { return -1; } } /** Get the value of the pin from the PIN register @return value of the pin (HIGH, LOW, -1) */ uint8_t getValue() { uint8_t status = *_PIN; if ((status & _offset) == _offset) { return HIGH; } else if ((status | _ioffset) == _ioffset) { return LOW; } else { return -1; } } /** Check the group to ensure all pins use the same registers @return true if the pins in the group all use the same registers, false otherwise */ bool isValid() { return _valid; } // ################################# Setters ################################# // #################### Generic #################### /** Set the pin mode and pin state @param mode the mode of the pin (OUTPUT, INPUT) @param state the state of the pin (HIGH, LOW) */ void set(uint8_t mode, uint8_t state) { oldSREG = SREG; cli(); if (mode == INPUT) { DDR_LOW; } else { DDR_HIGH; } if (state == LOW) { PORT_LOW; } else { PORT_HIGH; } SREG = oldSREG; } /** Set the pin mode @param mode the mode of the pin (OUTPUT, INPUT) */ void setMode(uint8_t mode) { oldSREG = SREG; cli(); if (mode == INPUT) { DDR_LOW; } else { DDR_HIGH; } SREG = oldSREG; } /** Set the pin state @param state the state of the pin (HIGH, LOW) */ void setState(uint8_t state) { oldSREG = SREG; cli(); if (state == LOW) { PORT_LOW; } else { PORT_HIGH; } SREG = oldSREG; } // #################### Input #################### /** Set the pin mode to input */ void setInput() { oldSREG = SREG; cli(); DDR_LOW; SREG = oldSREG; } /** Set the pin pullup resistor to on */ void setPullupOn() { oldSREG = SREG; cli(); PORT_HIGH; SREG = oldSREG; } /** Set the pin pullup resistor to off */ void setPullupOff() { oldSREG = SREG; cli(); PORT_LOW; SREG = oldSREG; } /** Set the pin mode to input and the pin pullup resistor to on */ void setInputPullupOn() { oldSREG = SREG; cli(); DDR_LOW; PORT_HIGH; SREG = oldSREG; } /** Set the pin mode to input and the pin pullup resistor to off */ void setInputPullupOff() { oldSREG = SREG; cli(); DDR_LOW; PORT_LOW; SREG = oldSREG; } // #################### Output #################### /** Set the pin mode to output */ void setOutput() { oldSREG = SREG; cli(); DDR_HIGH; SREG = oldSREG; } /** Set the pin output to HIGH */ void setHigh() { oldSREG = SREG; cli(); PORT_HIGH; SREG = oldSREG; } /** Set the pin output to LOW */ void setLow() { oldSREG = SREG; cli(); PORT_LOW; SREG = oldSREG; } /** Set the pin mode to output and the pin output to HIGH */ void setOutputHigh() { oldSREG = SREG; cli(); DDR_HIGH; PORT_HIGH; SREG = oldSREG; } /** Set the pin mode to output and the pin output to LOW */ void setOutputLow() { oldSREG = SREG; cli(); DDR_HIGH; PORT_LOW; SREG = oldSREG; } // ################################# Utilities ################################# // #################### Toggle #################### /** Toggle the pin mode (OUTPUT -> INPUT, INPUT -> OUTPUT) */ void toggleMode() { oldSREG = SREG; cli(); DDR_TOGGLE; SREG = oldSREG; } /** Toggle the pin state (HIGH -> LOW, LOW -> HIGH) */ void toggleState() { oldSREG = SREG; cli(); PORT_TOGGLE; SREG = oldSREG; } private: uint8_t _numbers[8]; uint8_t _offset; uint8_t _ioffset; bool _valid; uint8_t oldSREG; volatile uint8_t *_PIN; volatile uint8_t *_PORT; volatile uint8_t *_DDR; };