/* "bit" and "mask" macros for 8-bit AVR microcontrollers
 * by Kavka from www.radiokot.ru/forum
 */


#ifndef _AVR_IO_MACROS_H
#define _AVR_IO_MACROS_H 1


/* single-bit macros
 * ----------------------------
 * IO_BIT_SET(EECR, EEMWE);
 * IO_BIT_SET(PORTA, PA0);
 * IO_BIT_SET(UCSRA, U2X);
 * IO_BIT_GET(PINA, PINA3) return 0x08 or 0x00
 * IO_BIT_GETBIT(PINA, PINA3) return 1 or 0
 */
#define IO_BIT_NEG(port, bitnum) port ^=  (1 << (bitnum))
#define IO_BIT_SET(port, bitnum) port |=  (1 << (bitnum))
#define IO_BIT_CLR(port, bitnum) port &= ~(1 << (bitnum))
#define IO_BIT_GET(port, bitnum) (port & (1 << (bitnum)))
#define IO_BIT_GETBIT(port, bitnum) ((port & (1 << (bitnum))) >> (bitnum))

/* mask macros
 * ----------------------------
 * IO_MASK_SET(DDRA, _BV(DDA0)|_BV(DDA1));
 * IO_MASK_SET(UCSRA, _BV(U2X));
 */
#define IO_MASK_NEG(port, mask) port ^=  (mask)
#define IO_MASK_SET(port, mask) port |=  (mask)
#define IO_MASK_CLR(port, mask) port &= ~(mask)
#define IO_MASK_GET(port, mask) (port & (mask))

#define GLUE(a, b)     a##b

/* 3-input single-bit macros
 * ----------------------------
 * PIN_BIT_SET_(PORT, A, PA0);
 * PIN_BIT_SET_(PIN , A, PA0);
 * PIN_BIT_SET_(DDR , A, PA0);
 */
#define PIN_BIT_NEG_(kind, port, bitnum) GLUE(kind, port) ^= (1 << (bitnum))
#define PIN_BIT_SET_(kind, port, bitnum) GLUE(kind, port) |= (1 << (bitnum))
#define PIN_BIT_CLR_(kind, port, bitnum) GLUE(kind, port) &= ~(1 << (bitnum))
#define PIN_BIT_GET_(kind, port, bitnum) (GLUE(kind, port) & (1 << (bitnum)))
#define PIN_BIT_GETBIT_(kind, port, bitnum) ((GLUE(kind, port) & (1 << (bitnum))) >> (bitnum))

/* mask macros
 * ----------------------------
 * PIN_MASK_SET(DDR,  A, _BV(0)|_BV(1));
 * PIN_MASK_SET(PORT, A, _BV(0));
 */
#define PIN_MASK_NEG(kind, port, mask) GLUE(kind, port) ^=  (mask)
#define PIN_MASK_SET(kind, port, mask) GLUE(kind, port) |=  (mask)
#define PIN_MASK_CLR(kind, port, mask) GLUE(kind, port) &= ~(mask)
#define PIN_MASK_GET(kind, port, mask) (GLUE(kind, port) & (mask))

/* 2-input macros for manipulation with state of general IO pins (leads) of chip
 * ----------------------------
 * PIN_INIT_AS_OUTPUT_(A, 0);
 * PIN_SET_(A, 0);
 */
#define PIN_INIT_AS_OUTPUT_(port, bitnum) PIN_BIT_SET_(DDR, port, bitnum)
#define PIN_INIT_AS_INPUT_(port, bitnum)  PIN_BIT_CLR_(DDR, port, bitnum)
#define PIN_PULLUP_ON_(port, bitnum)  PIN_BIT_SET_(PORT, port, bitnum)
#define PIN_PULLUP_OFF_(port, bitnum)  PIN_BIT_CLR_(PORT, port, bitnum)

#define PIN_NEG_(port, bitnum) PIN_BIT_NEG_(PORT, port, bitnum)
#define PIN_SET_(port, bitnum) PIN_BIT_SET_(PORT, port, bitnum)
#define PIN_CLR_(port, bitnum) PIN_BIT_CLR_(PORT, port, bitnum)
#define PIN_GET_(port, bitnum) PIN_BIT_GET_(PIN,  port, bitnum)
#define PIN_GETBIT_(port, bitnum) PIN_BIT_GETBIT_(PIN,  port, bitnum)

/* combined 1-input macros for manipulation with general IO pins (leads) of chip
 * this macros for "defined" pins
 * ----------------------------
 * #define LED1 B, 1
 * PIN_INIT_AS_OUTPUT(LED1);
 * PIN_SET(LED1); *
 */
#define PIN_INIT_AS_OUTPUT(portbitnum) PIN_INIT_AS_OUTPUT_(portbitnum)
#define PIN_INIT_AS_INPUT(portbitnum)  PIN_INIT_AS_INPUT_(portbitnum)
#define PIN_PULLUP_ON(portbitnum)  PIN_PULLUP_ON_(portbitnum)
#define PIN_PULLUP_OFF(portbitnum)  PIN_PULLUP_OFF_(portbitnum)

#define PIN_NEG(portbitnum) PIN_NEG_(portbitnum)
#define PIN_SET(portbitnum) PIN_SET_(portbitnum)
#define PIN_CLR(portbitnum) PIN_CLR_(portbitnum)
#define PIN_GET(portbitnum) PIN_GET_(portbitnum)
#define PIN_GETBIT(portbitnum) PIN_GETBIT_(portbitnum)

/* macros for extracting port symbol and bit number from "defined" pin
 * ----------------------------
 * #define LED1 B, 1
 * PIN_MASK_SET(DDR,  PIN_PORT(LED1), _BV(PIN_BIT(LED1)|_BV(5));
 */
#define PIN_PORT_(port, bitnum) port
#define PIN_PORT(portbitnum) PIN_PORT_(portbitnum)
#define PIN_BIT_(port, bitnum) bitnum
#define PIN_BIT(portbitnum) PIN_BIT_(portbitnum)

#endif /* avr_io_macros.h */
