aboutsummaryrefslogtreecommitdiff
path: root/src/ioport.c
blob: 3cc940656ada0fb8b109d8942a40704242b6a96f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <ioport.h>
#ifdef CONFIG_IOPORTS
#ifdef CONFIG_PCINT

struct PCIW {
	uint8_t flags;
	uint8_t mask;
	void (*change) (uint8_t group, uint8_t mask);
};

// Exploiting implementation of libc malloc
#define PCIW_LEN(INPCIW) (*((uint16_t *) INPCIW - 1) / sizeof(struct PCIW) - 1)

#if (defined MCUSUPPORT_PCINT0 && defined MCUSUPPORT_PCINT1 && defined MCUSUPPORT_PCINT2)
#define PCI_COUNT 3
#elif (defined MCUSUPPORT_PCINT0 && defined MCUSUPPORT_PCINT1 || \
		defined MCUSUPPORT_PCINT1 && defined MCUSUPPORT_PCINT2 || \
		defined MCUSUPPORT_PCINT2 && defined MCUSUPPORT_PCINT0)
#define PCI_COUNT 2
#elif (defined MCUSUPPORT_PCINT0 || defined MCUSUPPORT_PCINT1 || defined MCUSUPPORT_PCINT2)
#define PCI_COUNT 1
#else
#define PCI_COUNT 0
#endif

#define GROUP2INDEX(GRP) (GRP - MCUSUPPORT_PCINT0)

static struct PCIW *pciw[PCI_COUNT];
static uint8_t pci_state[PCI_COUNT];
static void pci(int8_t group, int8_t pinmax) {
	int8_t i, y;
	int8_t index = GROUP2INDEX(group);
	int8_t len = (int8_t) PCIW_LEN(pciw[index]);
	// WARN Is possible that PCINT0 is not corresponding with B group and so on?
	uint8_t state = IOE_IO_PIN(group);
	for (i = len; i >= 0; i--) {
		uint8_t stA = state & pciw[index][i].mask;
		uint8_t stB = pci_state[index] & pciw[index][i].mask;
		if (((~stA & stB) && pciw[index][i].flags & IOE_IO_RISING) ||
			((stA & ~stB) && pciw[index][i].flags & IOE_IO_FALLING)) {
			pciw[index][i].change(IOE_IO_B, mask);
		}
	}
	pci_state[index] = state;
}

void io_change_sethook(uint8_t group, uint8_t mask, uint8_t edge,
					   void (*change) (uint8_t group, uint8_t mask)) {
	int8_t index = (int8_t) GROUP2INDEX(group);
	int8_t len = (int8_t) PCIW_LEN(pciw[index]);
	pciw[index] = realloc(pciw[index], len + 1);
	pciw[index][len].flags = edge;
	pciw[index][len].mask = mask;
	pciw[index][len].change = change;
	switch (group) {
#ifdef MCUSUPPORT_PCINT0 // TODO this wont work with attiny4313 and meaby others
	case IO_B:
		PCICR |= (1<<0);
		PCMSK0 |= mask;
		break;
#endif
#ifdef MCUSUPPORT_PCINT1
	case IO_C:
		PCICR |= (1<<1);
		PCMSK1 |= mask;
		break;
#endif
#ifdef MCUSUPPORT_PCINT2
	case IO_D:
		PCICR |= (1<<2);
		PCMSK2 |= mask;
		break
#endif
	}
}

void io_change_remhook(void (*change) (uint8_t group, uint8_t mask)) {
	int8_t i, y;
	int8_t len;
	for (i = PCI_COUNT - 1; i >= 0; i--) {
		len = (int8_t)PCIW_LEN(pciw[index]);
		for (y = len - 1; y >= 0; y--) {
			if (pciw[i][y].change == change) {

			}
		}
	}
}

void io_change_clearhooks(void) {
	// TODO
}

// WARN This will work only if C is only defined on MCU with also B defined.
#ifdef MCUSUPPORT_PCINT0
ISR(PCINT0_vect, ISR_BLOCK) {
	pci(IO_B, MCUSUPPORT_PCINT0);
}
#endif /* MCUSUPPORT_PCINT0 */

#ifdef MCUSUPPORT_PCINT1
ISR(PCINT1_vect, ISR_BLOCK) {
	pci(IO_C, MCUSUPPORT_PCINT1);
}
#endif /* MCUSUPPORT_PCINT1 */

#ifdef MCUSUPPORT_PCINT2
ISR(PCINT2_vect, ISR_BLOCK) {
	pci(IO_D, MCUSUPPORT_PCINT2);
}
#endif /* MCUSUPPORT_PCINT2 */

#endif /* CONFIG_PCINT */
#endif /* CONFIG_IOPORTS */