twi: Stripped down TWI module to fix compile
[simavr] / simavr / sim / sim_twi.c
1 /*
2         sim_twi.c
3
4         Internal TWI/i2c slave/master subsystem
5         
6         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
7
8         This file is part of simavr.
9
10         simavr is free software: you can redistribute it and/or modify
11         it under the terms of the GNU General Public License as published by
12         the Free Software Foundation, either version 3 of the License, or
13         (at your option) any later version.
14
15         simavr is distributed in the hope that it will be useful,
16         but WITHOUT ANY WARRANTY; without even the implied warranty of
17         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18         GNU General Public License for more details.
19
20         You should have received a copy of the GNU General Public License
21         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include "sim_twi.h"
28
29 static void twi_bus_master_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
30 {
31         twi_bus_t * bus = (twi_bus_t *)param;
32         switch (irq->irq) {
33                 case TWI_MASTER_STOP:
34                         bus->peer = NULL;
35                         break;
36                 case TWI_MASTER_START:
37                         bus->peer = NULL;
38                         bus->ack = 0;
39                         break;
40                 case TWI_MASTER_MISO:
41                         bus->ack = 0;
42                         break;
43                 case TWI_MASTER_MOSI:
44                         bus->ack = 0;
45                         break;
46                 case TWI_MASTER_ACK:
47                         if (!bus->peer) {
48                         }
49                         break;
50         }
51 }
52
53 static void twi_bus_slave_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
54 {
55         twi_slave_t * slave = (twi_slave_t*)param;
56         twi_bus_t * bus = slave->bus;
57         switch (irq->irq) {
58                 case TWI_SLAVE_MISO:
59                         bus->latch = value;
60                         break;
61                 case TWI_SLAVE_ACK:
62                         if (!bus->peer) {
63                                 bus->peer = slave;
64                                 printf("twi bus: slave %x selected\n", slave->address);
65                         }
66                         bus->ack = 0x80 | (value & 1);
67                         break;
68         }
69 }
70
71 static void twi_slave_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
72 {
73         twi_slave_t * slave = (twi_slave_t*)param;
74         switch (irq->irq) {
75                 case TWI_MASTER_STOP:
76                         if (slave->match) {
77                                 // we were target
78                         }
79                         slave->match = 0;
80                         break;
81                 case TWI_MASTER_START:
82                         if ((value & 0xfe) == (slave->address & 0xfe)) {
83                                 if (slave->match) {
84                                         // restart
85                                 }
86                                 slave->match = 1;
87                                 avr_raise_irq(slave->irq + TWI_SLAVE_ACK, 1);
88                         }
89                         break;
90                 case TWI_MASTER_MISO:
91                         break;
92                 case TWI_MASTER_MOSI:
93                         break;
94                 case TWI_MASTER_ACK:
95                         break;
96         }
97 }
98
99 void twi_bus_init(twi_bus_t * bus)
100 {
101         memset(bus, 0, sizeof(twi_bus_t));
102         avr_init_irq(bus->irq, 0, TWI_MASTER_STATE_COUNT);
103         for (int i = 0; i < TWI_MASTER_STATE_COUNT; i++)
104                 avr_irq_register_notify(bus->irq + i, twi_bus_master_irq_notify, bus);
105 }
106
107 void twi_bus_attach(twi_bus_t * bus, twi_slave_t * slave)
108 {
109         twi_slave_detach(slave);
110         slave->bus = bus;
111         slave->next = bus->slave;
112         bus->slave = slave;
113         
114         for (int i = 0; i < TWI_SLAVE_STATE_COUNT; i++)
115                 avr_irq_register_notify(slave->irq + i, twi_bus_slave_irq_notify, slave);
116         for (int i = 0; i < TWI_MASTER_STATE_COUNT; i++)
117                 avr_irq_register_notify(bus->irq + i, twi_slave_irq_notify, slave);
118 }
119
120 int twi_bus_start(twi_bus_t * bus, uint8_t address)
121 {
122         avr_raise_irq(bus->irq + TWI_MASTER_START, address);
123         return bus->peer != NULL ? 1 : 0;
124 }
125
126 void twi_bus_stop(twi_bus_t * bus)
127 {
128         avr_raise_irq(bus->irq + TWI_MASTER_STOP, 0);
129 }
130
131
132 void twi_slave_init(twi_slave_t * slave, uint8_t address, void * param)
133 {
134         memset(slave, 0, sizeof(twi_slave_t));
135         slave->address = address;
136 //      slave->param = param;
137 }
138
139 void twi_slave_detach(twi_slave_t * slave)
140 {
141         if (!slave || !slave->bus)
142                 return;
143         twi_slave_t *s = slave->bus->slave;
144         while (s) {
145                 if (s->next == slave) {
146                         // clear that, too
147                         if (slave->bus->peer == slave)
148                                 slave->bus->peer = NULL;
149                                 
150                         s->next = slave->next;
151                         slave->next = NULL;
152                         slave->bus = NULL;
153                         return;
154                 }
155                 s = s->next;
156         }
157 }
158