Rev Author Line No. Line
615 kaklik 1 #include <avr/pgmspace.h>
2 #include <avr/interrupt.h>
3 #include <avr/signal.h>
4 #include <avr/sleep.h>
5  
6 #include "common.h"
7 #include "usart.h"
8 #include "twi_aap.h"
9 #include "eeprom.h"
10  
11 /*********
12 switch (TWOStatus) {
13 case TW_SR_SLA_ACK: //0x60
14 break;
15 case TW_SR_ARB_LOST_SLA_ACK: //0x68
16 break;
17 case TW_SR_GCALL_ACK: //0x70
18 break;
19 case TW_SR_ARB_LOST_GCALL_ACK: //0x78
20 break;
21 case TW_SR_DATA_ACK: //0x80
22 break;
23 case TW_SR_DATA_NACK: //0x88
24 break;
25 case TW_SR_GCALL_DATA_ACK: //0x90
26 break;
27 case TW_SR_GCALL_DATA_NACK: //0x98
28 break;
29 case TW_ST_LAST_DATA: //0xC8
30 case TW_SR_STOP: //0xA0
31 State = MS_Idle;
32 SETBIT(TWIControl,(1 << TWEA)); // turn address recognition back on
33 break;
34 default: // All non-handled states will basically terminate any processing
35 State = MS_Idle;
36 CLRBIT(TWIControl,(1 << TWEA)); // will return NACK, i.e. will pretend to be unaddressed
37 break;
38 }
39  
40 switch (TWOStatus) {
41 case TW_ST_SLA_ACK: //0xA8
42 break;
43 case TW_ST_ARB_LOST_SLA_ACK: //0xB0
44 break;
45 case TW_ST_DATA_ACK: //0xB8
46 break;
47 case TW_ST_DATA_NACK: //0xC0
48 break;
49 case TW_ST_ARB_LOST: //0x38 - let's hope it works
50 break;
51 case TW_ST_LAST_DATA: //0xC8
52 State = MS_Idle;
53 SETBIT(TWIControl,(1 << TWEA)); // turn address recognition back on
54 break;
55 default: // All non-handled states will basically terminate any processing
56 State = MS_Idle;
57 CLRBIT(TWIControl,(1 << TWEA)); // will return NACK, i.e. will pretend to be unaddressed
58 break;
59 }
60 **********/
61  
62 namespace TWI {
63 extern const sConfigRecord ConfigRecord PROGMEM __attribute__ ((weak)) = {UniqueIDUnassigned,DevClassUnassigned,DevUnassigned};
64  
65 // void TWI::UserInit() __attribute__ ((weak));
66 void TWI::HandleUserReceive() __attribute__ ((weak));
67 void TWI::HandleUserTransmit() __attribute__ ((weak));
68 void TWI::HandleUserState() __attribute__ ((weak));
69 static inline void TWI::HandleState_MS_Idle();
70 static inline void TWI::HandleState_MS_Addressed();
71 static inline void TWI::StateMachine();
72  
73 uint8_t ConfigCnt;
74 }
75  
76 void TWI::ResetTWITransmit() {
77 // Same as above, but also returns the statemachine to the idle state
78 State = MS_Idle;
79 LastCmd = TWI_AAPCmd_Reserved;
80 // In slave-transmitter mode it's not possible to reset the TWI.
81 // But at least we can transmit all '1'-s so we won't interfere with the bus.
82 #ifdef SERIAL_DBG
83 USART0::SendData('*');
84 #endif
85 TWDR = 0xff;
86 SETBIT(TWIControl,(1 << TWEA) | (1 << TWSTO));
87 }
88 void TWI::ResetTWIReceive() {
89 // Same as above, but also returns the statemachine to the idle state
90 State = MS_Idle;
91 LastCmd = TWI_AAPCmd_Reserved;
92 // In slave-transmitter mode it's not possible to reset the TWI.
93 // But at least we can transmit all '1'-s so we won't interfere with the bus.
94 #ifdef SERIAL_DBG
95 USART0::SendData('#');
96 #endif
97 TWDR = 0xff;
98 SETBIT(TWIControl,(1 << TWSTO));
99 CLRBIT(TWIControl,(1 << TWEA));
100 }
101 void TWI::ResetTWI() {
102 switch (TWIStatus) {
103 case TW_ST_LAST_DATA: //0xC8
104 case TW_SR_STOP:
105 case TW_ST_DATA_NACK:
106 case TW_SR_DATA_NACK:
107 case TW_SR_GCALL_DATA_NACK:
108 State = MS_Idle;
109 SETBIT(TWIControl,(1 << TWEA)); // turn address recognition back on
110 CLRBIT(TWIControl,(1 << TWSTO)); // even if we did so, stop aborting
111 break;
112 case TW_BUS_ERROR:
113 // This is the point where we re-enable the address recognition
114 ResetTWITransmit();
115 break;
116 default:
117 ResetTWIReceive();
118 break;
119 }
120 }
121  
122 /*void TWI::UserInit() {
123 }*/
124  
125 void TWI::HandleUserReceive() {
126 #ifdef SERIAL_DBG
127 USART0::SendData('r');
128 #endif
129 ResetTWI();
130 }
131  
132 void TWI::HandleUserTransmit() {
133 #ifdef SERIAL_DBG
134 USART0::SendData('t');
135 #endif
136 ResetTWI();
137 }
138  
139 void TWI::HandleUserState() {
140 }
141  
142  
143 static inline void TWI::HandleState_MS_Idle() {
144 switch (TWIStatus) {
145 case TW_SR_SLA_ACK:
146 LastCmd = TWI_AAPCmd_Reserved;
147 HandleUserReceive();
148 break;
149 case TW_SR_GCALL_ACK:
150 State = MS_Addressed;
151 break;
152 case TW_ST_SLA_ACK:
153 if ((TWIData & 0xfe) == GeneralCallAddr) {
154 // TWI_AAP read command: things depend on what the last (write) command was:
155 if (LastCmd == TWI_AAPCmd_GetConfig) {
156 // This is the read part of the GetUDID command: Send the byte count and change state
157 TWIPrevData = sizeof(ConfigRecord);
158 TWDR = TWIPrevData;
159 State = AAP_CmdGetConfig_SendConfig;
160 ConfigCnt = 0;
161 //SETBIT(TWIControl,(1 << TWEA)); // require ACK
162 } else {
163 //Unknown read command: ignore
164 ResetTWITransmit();
165 }
166 } else {
167 HandleUserTransmit();
168 }
169 break;
170 case TW_ST_LAST_DATA:
171 case TW_SR_STOP:
172 #ifdef SERIAL_DBG
173 USART0::SendData('.');
174 #endif
175 State = MS_Idle;
176 SETBIT(TWIControl,(1 << TWEA)); // turn address recognition back on
177 CLRBIT(TWIControl,(1 << TWSTO)); // even if we did so, stop aborting
178 break;
179 case TW_ST_DATA_ACK:
180 case TW_SR_DATA_ACK:
181 case TW_SR_GCALL_DATA_ACK:
182 ResetTWIReceive();
183 break;
184 case TW_BUS_ERROR:
185 case TW_ST_DATA_NACK:
186 case TW_SR_DATA_NACK:
187 case TW_SR_GCALL_DATA_NACK:
188 // This is the point where we re-enable the address recognition
189 ResetTWITransmit();
190 break;
191 default:
192 State = MS_Idle;
193 SETBIT(TWIControl,(1 << TWEA) | (1 << TWSTO)); // reset the TWI
194 break;
195 }
196 }
197  
198 static inline void TWI::HandleState_MS_Addressed() {
199 switch (TWIStatus) {
200 case TW_SR_GCALL_DATA_ACK:
201 switch(TWIData) {
202 case TWI_AAPCmd_ResetDevices:
203 LastCmd = TWIData;
204 State = MS_Idle;
205 SoftAddress = 0;
206 TWAR = SoftAddress | 1; // General call recognition and slave-receiver mode through address being 0
207 break;
208 case TWI_AAPCmd_ResetToPermAddress:
209 LastCmd = TWIData;
210 State = MS_Idle;
211 SoftAddress = EEPROM::GetByte(EEPROM_layout::TWI_SoftAddr_Ofs);
212 TWAR = SoftAddress | 1; // General call recognition and slave-receiver mode
213 if (SoftAddress != 0) {
214 // We have a valid address, do not respond to this command
215 LastCmd = TWI_AAPCmd_Reserved;
216 }
217 break;
218 case TWI_AAPCmd_GetConfig:
219 LastCmd = TWIData;
220 State = AAP_CmdGetConfig_GetAddress;
221 break;
222 case TWI_AAPCmd_AssignAddress:
223 LastCmd = TWIData;
224 ConfigCnt = 0;
225 State = AAP_CmdAssignAddress_GetUniqueID;
226 break;
227 default:
228 // unknown command - ignore the rest
229 ResetTWIReceive();
230 break;
231 }
232 break;
233 default:
234 ResetTWI();
235 break;
236 }
237 }
238  
239 static inline void TWI::StateMachine() {
240 TWIStatus = TWSR & TW_STATUS_MASK;
241 TWIControl = TWCR;
242 if (TWIStatus != TW_SR_STOP) {
243 TWIData = TWDR;
244 } else {
245 // Fast short-circuit for stop-bit detection
246 // This condition cannot use clock-stretching so we might miss the next start if we don't hurry
247 State = MS_Idle;
248 SETBIT(TWIControl,(1 << TWEA)); // turn address recognition back on
249 CLRBIT(TWIControl,(1 << TWSTO)); // even if we did so, stop aborting
250 SETBIT(TWIControl,(1 << TWINT));
251 TWCR = TWIControl;
252 return;
253 }
254  
255 #ifdef SERIAL_DBG
256 // DUMP state to serial port
257 USART0::SendData('s'); USART0::SendData(' '); USART0::SendHexData(TWIStatus); USART0::SendData(' ');
258 USART0::SendData('d'); USART0::SendData(' '); USART0::SendHexData(TWIData); USART0::SendData(' ');
259 USART0::SendData('S'); USART0::SendData(' '); USART0::SendHexData(State); USART0::SendData(' ');
260 USART0::SendData('L'); USART0::SendData(' '); USART0::SendHexData(LastCmd); USART0::SendData(' ');
261 USART0::SendData('A'); USART0::SendData(' '); USART0::SendHexData(SoftAddress); USART0::SendData('-');
262 #endif
263 switch (State) {
264 case MS_Idle:
265 HandleState_MS_Idle();
266 break;
267 case MS_Addressed:
268 HandleState_MS_Addressed();
269 break;
270  
271 case AAP_CmdGetConfig_GetAddress:
272 switch (TWIStatus) {
273 case TW_SR_GCALL_DATA_ACK:
274 State = MS_Idle;
275 SETBIT(TWIControl,(1 << TWEA) | (1 << TWSTO)); // reset the TWI
276 if (SoftAddress != TWIData) {
277 // We have a valid address, or was not addressed -> do not respond to this command
278 LastCmd = TWI_AAPCmd_Reserved;
279 }
280 break;
281 default:
282 ResetTWI();
283 break;
284 }
285 break;
286  
287 case AAP_CmdAssignAddress_GetUniqueID:
288 switch (TWIStatus) {
289 case TW_SR_GCALL_DATA_ACK:
290 if (TWIData == pgm_read_byte(ConfigRecord.UniqueID+ConfigCnt)) {
291 ++ConfigCnt;
292 if (ConfigCnt == UniqueID_Size) State = AAP_CmdAssignAddress_GetAddress;
293 } else {
294 // UDID is not ours, abort command
295 ResetTWIReceive();
296 }
297 break;
298 default:
299 ResetTWI();
300 break;
301 }
302 break;
303 case AAP_CmdAssignAddress_GetAddress:
304 switch (TWIStatus) {
305 case TW_SR_GCALL_DATA_ACK:
306 SoftAddress = TWIData & 0xfe;
307 if (TWIData & 0x01 == 1) {
308 EEPROM::SetByte(EEPROM_layout::TWI_SoftAddr_Ofs,SoftAddress);
309 }
310 State = MS_Idle;
311 TWAR = SoftAddress | 1; // General call recognition and normal operation
312 SETBIT(TWIControl,(1 << TWEA) | (1 << TWSTO)); // reset the TWI
313 LastCmd = TWI_AAPCmd_Reserved;
314 break;
315 default:
316 ResetTWI();
317 break;
318 }
319 break;
320  
321  
322  
323 // Read-oriented commands
324 case AAP_CmdGetConfig_SendConfig:
325 switch (TWIStatus) {
326 case TW_ST_DATA_ACK:
327 if (TWIData != TWIPrevData) {
328 // We've lost the arbitration
329 ResetTWITransmit();
330 break;
331 }
332 TWIPrevData = pgm_read_byte(((uint8_t*)(&ConfigRecord))+ConfigCnt);
333 TWDR = TWIPrevData;
334 ConfigCnt++;
335 //At the last byte, we require NACK
336 if (ConfigCnt == sizeof(ConfigRecord)) {
337 State = MS_Idle;
338 CLRBIT(TWIControl,(1 << TWEA)); // require NACK
339 } else {
340 State = AAP_CmdGetConfig_SendConfig;
341 SETBIT(TWIControl,(1 << TWEA)); // require ACK
342 }
343 break;
344  
345 default:
346 ResetTWI();
347 break;
348 }
349 break;
350  
351 // User commands
352 default:
353 HandleUserState();
354 break;
355 }
356 // re-enable the TWI interrupts
357 SETBIT(TWIControl,1 << TWINT);
358 #ifdef SERIAL_DBG
359 USART0::SendData('S'); USART0::SendData(' '); USART0::SendHexData(State); USART0::SendData(' ');
360 USART0::SendData('L'); USART0::SendData(' '); USART0::SendHexData(LastCmd); USART0::SendData(' ');
361 USART0::SendData('A'); USART0::SendData(' '); USART0::SendHexData(SoftAddress); USART0::SendData(' ');
362 USART0::SendData('C'); USART0::SendData(' '); USART0::SendHexData(TWIControl); USART0::SendData(0x0d); USART0::SendData(0x0a);
363 #endif
364 TWCR = TWIControl;
365 }
366  
367 SIGNAL(SIG_TWI) {TWI::StateMachine();}
368  
369 uint8_t TWI::State;
370 uint8_t TWI::LastCmd;
371 uint8_t TWI::SoftAddress;
372 uint8_t TWI::TWIStatus;
373 uint8_t TWI::TWIData;
374 uint8_t TWI::TWIPrevData;
375 uint8_t TWI::TWIControl;