Dateianhang 'pmc.c'
Herunterladen 1 // This file has been prepared for Doxygen automatic documentation generation.
2 /** \file ********************************************************************
3 *
4 * Implementation of PoorMansCan Stack
5 *
6 * \date 1.4.2012
7 * \author : Dominic Rathje (dominic.rathje@uni-ulm.de)
8 * \version 1.2
9 * \note
10 * - Supported devices : any AVR CPU
11 *
12 *
13 *****************************************************************************/
14
15 #define _PMC_C_ 1
16
17 #include <avr/io.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include "pmc.h"
21
22 //global variables
23 volatile PMC_MODE pmc_mode; ///< status of the state machine
24 volatile uint8_t pmc_error; ///< error code
25 volatile uint8_t pmc_tick; ///< time tick. This is used to generate delay between the last received data an the beginning of an transmission. It should be increased every 500µs by timer interrupt.
26 volatile uint8_t pmc_timeout; ///< timeout counter. This is used to trigger an timout while waiting for sth. It.should be increased every 500µs by timer interrupt.
27 volatile uint8_t pmc_crc_errorcount; ///< CRC Error Counter.
28 uint8_t pmc_random_delay; ///< Random Delay before a Message is sent.
29
30 struct pmc_buffer pmc_rx_buffer[PMC_RX_BUFFERS];
31 struct pmc_buffer pmc_tx_buffer[PMC_TX_BUFFERS];
32
33 volatile uint8_t pmc_rx_head=0, pmc_rx_tail=0;
34 volatile uint8_t pmc_tx_head=0, pmc_tx_tail=0;
35
36 volatile uint8_t pmc_rx_counter=0;
37
38 volatile uint8_t pmc_rx_int_head=0; ///< head index used in RX ISR
39 volatile uint8_t pmc_rx_int_tail=0; ///< tail index used in RX ISR
40 volatile uint8_t *pmc_rx_int_buffer=NULL; ///< buffer pointer used in RX ISR
41
42 uint8_t (*pmc_filter)(uint8_t data);
43
44 const uint8_t pmc_crc_table[256] = {
45 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
46 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
47 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
48 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
49 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
50 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
51 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
52 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
53 140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
54 17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
55 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
56 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
57 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
58 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
59 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
60 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};
61
62 void pmc_init(uint8_t (*filter)(uint8_t data)){
63
64 pmc_mode = PMC_MODE_IDLE;
65 pmc_error = 0;
66 pmc_tick = 0;
67 pmc_timeout = 0;
68 pmc_crc_errorcount = 0;
69 pmc_mpcm_en();
70
71 pmc_rx_head=0;
72 pmc_rx_tail=0;
73 pmc_tx_head=0;
74 pmc_tx_tail=0;
75
76 pmc_rx_counter=0;
77 pmc_rx_int_head=0;
78 pmc_rx_int_tail=0;
79
80 pmc_filter = filter;
81
82 }
83
84 uint8_t pmc_process(void) {
85 switch(pmc_mode) {
86 case PMC_MODE_IDLE:
87
88 //if there is data to be transmitted
89 if( (pmc_tx_tail != pmc_tx_head)) {
90
91
92 // switch mode to TX_REQUEST
93 pmc_mode = PMC_MODE_TX_REQUEST;
94
95 // disable mpcm to listen on the bus
96 pmc_mpcm_dis();
97
98 }
99
100 break;
101
102 case PMC_MODE_TX_REQUEST:
103
104
105 // wait for tick>2+random
106 if(pmc_tick> 2 + pmc_random_delay) {
107
108 // switch mode to TX
109 pmc_mode = PMC_MODE_TX;
110
111 //set index and buffer variables for ISR
112 pmc_rx_int_buffer = pmc_tx_buffer[pmc_tx_tail].buffer;
113 pmc_rx_int_head = pmc_tx_buffer[pmc_tx_tail].head;
114 pmc_rx_int_tail = pmc_tx_buffer[pmc_tx_tail].tail;
115
116 //sendid
117 pmc_sendid(pmc_rx_int_buffer[pmc_rx_int_tail]);
118 }
119
120 break;
121
122 case PMC_MODE_RX_CTRL:
123 case PMC_MODE_RX_DATA:
124
125 //timeout: if pmc_tick>100 -> reset
126 if(pmc_tick>100) {
127 pmc_rx_buffer[pmc_rx_head].head=0;
128 pmc_mpcm_en();
129 pmc_mode=PMC_MODE_IDLE;
130 }
131 break;
132
133 case PMC_MODE_TX:
134
135 //timeout: if pmc_tick>100 -> reset
136 if(pmc_tick>10) {
137 pmc_mode=PMC_MODE_ERROR;
138 pmc_error=PMC_ERROR_TX_DATA_INVALID;
139 }
140 break;
141
142 case PMC_MODE_ERROR:
143 switch(pmc_error) {
144
145 case PMC_ERROR_RX_BUFFER_FULL:
146 pmc_error = 0;
147 pmc_mode = PMC_MODE_IDLE;
148 return PMC_ERROR_RX_BUFFER_FULL;
149
150 case PMC_ERROR_RX_CRC_FAILED:
151 if(pmc_crc_errorcount < 100) {
152 pmc_crc_errorcount+=10;
153 pmc_error = 0;
154 pmc_mode = PMC_MODE_IDLE;
155 return PMC_ERROR_RX_CRC_FAILED;
156 } else {
157 return PMC_ERROR_LINK_BAD;
158 }
159 break;
160
161 case PMC_ERROR_TX_DATA_INVALID:
162
163 //set delay to wait before an error frame is sent
164 pmc_tick = 0;
165 pmc_random_delay += pmc_random();
166
167 //reset tail index, so that the message will be transmitted again.
168 pmc_tx_buffer[pmc_tx_tail].tail = 0;
169
170 //send error frame (id=0) and wait until this was recognized by pmc_rx_int
171 //which will change mode to PMC_MODE_WAIT
172 while(pmc_mode == PMC_MODE_ERROR) {
173 if(pmc_tick>pmc_random_delay) {
174 pmc_sendid(0);
175 pmc_random_delay += pmc_random();
176 pmc_tick = 0;
177 }
178 }
179
180
181 //set mode to PMC_MODE_ERROR in order to send a second error frame
182 pmc_mode = PMC_MODE_ERROR;
183
184 //set delay to wait before an error frame is sent
185 pmc_tick = 0;
186 pmc_random_delay = pmc_random();
187
188
189 //send a second error frame
190 while(pmc_mode == PMC_MODE_ERROR) {
191 if(pmc_tick>pmc_random_delay) {
192 pmc_sendid(0);
193 pmc_random_delay += pmc_random();
194 pmc_tick = 0;
195 }
196 }
197
198
199 //reset state machine
200 pmc_tick = 0;
201 pmc_error = 0;
202
203 break;
204
205 case PMC_ERROR_TX_SEND_FAILED:
206 //this error must not occur. so we stop work here and rest in this endless loop.
207 break;
208
209 }
210 break;
211
212 case PMC_MODE_WAIT:
213 if(pmc_tick > 10) {
214 pmc_tick=0;
215 pmc_mode = PMC_MODE_IDLE;
216 }
217
218 }
219
220 return pmc_error;
221
222 }
223
224 void pmc_rx_int(uint8_t mark, uint8_t data) {
225
226 extern volatile uint8_t pmc_rx_counter;
227 extern struct pmc_buffer pmc_rx_buffer[PMC_RX_BUFFERS];
228 //extern struct pmc_buffer pmc_tx_buffer[PMC_TX_BUFFERS];
229 extern volatile uint8_t pmc_rx_head, pmc_rx_tail;
230 extern volatile uint8_t pmc_tx_tail;
231 extern volatile PMC_MODE pmc_mode;
232 extern volatile uint8_t pmc_error;
233 extern volatile uint8_t pmc_tick;
234
235 extern volatile uint8_t pmc_rx_int_head;
236 extern volatile uint8_t pmc_rx_int_tail;
237 extern volatile uint8_t *pmc_rx_int_buffer;
238
239 pmc_tick=0;
240
241 if(mark==1 && data==0) {
242 pmc_rx_buffer[pmc_rx_head].head=0;
243 pmc_mpcm_en();
244 pmc_mode=PMC_MODE_WAIT;
245 pmc_tick = 0;
246 return;
247 }
248
249
250 switch(pmc_mode) {
251 case PMC_MODE_IDLE:
252 case PMC_MODE_TX_REQUEST:
253
254 if(mark) {
255 if( pmc_filter(data) ) {
256 if(pmc_rx_head != ((pmc_rx_tail-1)&(PMC_RX_BUFFERS-1)) ) {
257 pmc_mpcm_dis();
258 pmc_mode=PMC_MODE_RX_CTRL;
259
260 //copy data to buffer
261 pmc_rx_int_head = 0;
262 pmc_rx_int_buffer = pmc_rx_buffer[pmc_rx_head].buffer;
263 pmc_rx_int_buffer[pmc_rx_int_head++] = data;
264
265
266 } else {
267 pmc_mode=PMC_MODE_ERROR;
268 pmc_error=PMC_ERROR_RX_BUFFER_FULL;
269 }
270
271 }
272 }
273 break;
274
275 case PMC_MODE_RX_CTRL:
276 //init counter (number of databytes + number of CRC bytes)
277 pmc_rx_counter=(data & 0x0F)+1;
278
279 //copy data to buffer
280 pmc_rx_int_buffer[pmc_rx_int_head++] = data;
281
282 pmc_mode = PMC_MODE_RX_DATA;
283
284 break;
285
286 case PMC_MODE_RX_DATA:
287 //copy data to buffer
288 pmc_rx_int_buffer[pmc_rx_int_head++] = data;
289
290 //dec counter
291 pmc_rx_counter--;
292
293 //if last byte, counter==0, MODE_IDLE, enable MPCM,
294 if(pmc_rx_counter==0) {
295 pmc_mpcm_en();
296 pmc_mode=PMC_MODE_IDLE;
297
298 // write head and tail pointer
299 pmc_rx_buffer[pmc_rx_head].head=pmc_rx_int_head;
300 pmc_rx_buffer[pmc_rx_head].tail=0;
301
302 //increase buffer index, to tell the world that this buffer contains valid data
303 pmc_rx_head++;
304 pmc_rx_head &= (PMC_RX_BUFFERS-1);
305 }
306 break;
307
308 case PMC_MODE_TX:
309 //check if the received byte equals the send byte
310 //increase tail index
311 if( data != pmc_rx_int_buffer[pmc_rx_int_tail++]) {
312 pmc_mode=PMC_MODE_ERROR;
313 pmc_error=PMC_ERROR_TX_DATA_INVALID;
314 break;
315 }
316
317 //check if there is any data left to send
318 if(pmc_rx_int_tail == pmc_rx_int_head) {
319
320 #ifdef PMC_LOOPBACK
321 if(pmc_rx_head != ((pmc_rx_tail-1)&(PMC_RX_BUFFERS-1)) ) {
322 //copy data from tx butter to rx buffer
323 memcpy((void *)pmc_rx_buffer[pmc_rx_head].buffer,(const void *)pmc_rx_int_buffer,pmc_rx_int_head+1) ;
324 pmc_rx_buffer[pmc_rx_head].head=pmc_rx_int_head;
325 pmc_rx_buffer[pmc_rx_head].tail=0;
326 pmc_rx_head++;
327 pmc_rx_head &= (PMC_RX_BUFFERS-1);
328 }
329 #endif
330
331 pmc_tx_tail++;
332 pmc_tx_tail &= (PMC_TX_BUFFERS-1);
333 pmc_mpcm_en();
334 pmc_mode=PMC_MODE_IDLE;
335 break;
336 }
337
338 //send the next byte
339 if(pmc_senddata(pmc_rx_int_buffer[pmc_rx_int_tail])==0) {
340 pmc_mode=PMC_MODE_ERROR;
341 pmc_error=PMC_ERROR_TX_SEND_FAILED;
342 }
343 break;
344
345 default:
346 break;
347
348 }
349 }
350
351 uint8_t pmc_send_message_wait(uint8_t id, uint8_t subid, uint8_t datalength, uint8_t *data) {
352 if(pmc_send_message(id,subid,datalength,data)==0) {
353 return 0;
354 }
355
356 while(pmc_tx_head != pmc_tx_tail) {
357 pmc_process();
358 }
359 return 1;
360 }
361
362 uint8_t pmc_send_message(uint8_t id, uint8_t subid, uint8_t datalength, uint8_t *data) {
363
364
365 uint8_t crc;
366 uint8_t tmp;
367
368 //check for space in buffer and wait if necessary.
369 pmc_timeout=0;
370 while(pmc_tx_head == ((pmc_tx_tail-1)&(PMC_TX_BUFFERS-1)) ) {
371 if(pmc_timeout>100) {
372 return 0;
373 }
374 }
375 //validate parameters
376 if(datalength>15 || subid>15) {
377 return 0;
378 }
379
380
381 //initialize crc value
382 crc=0;
383
384 uint8_t *buffer;
385 uint8_t head=0;
386
387 buffer = pmc_tx_buffer[pmc_tx_head].buffer;
388
389 //move data to tx buffer and calculate crc
390 buffer[head++]=id;
391 crc = pmc_crc_update(crc,id);
392
393 tmp = (subid<<4) | datalength;
394 buffer[head++]=tmp;
395 crc = pmc_crc_update(crc,tmp);
396
397 for(;datalength>0;datalength--) {
398 buffer[head++]=*data;
399 crc = pmc_crc_update(crc,*data);
400 data++;
401 }
402
403 //copy crc to buffer
404 buffer[head++]=crc;
405
406
407
408 // write head and tail pointer
409 pmc_tx_buffer[pmc_tx_head].head=head;
410 pmc_tx_buffer[pmc_tx_head].tail=0;
411
412
413 //increase head index. this will trigger an tx request.
414 pmc_tx_head++;
415 pmc_tx_head &= (PMC_TX_BUFFERS-1);
416
417
418 //reset pmc_tick
419 pmc_tick=0;
420
421 //set delay
422 pmc_random_delay = pmc_random();
423
424 return 1;
425 }
426
427 uint8_t pmc_get_message(uint8_t *id, uint8_t *subid, uint8_t *datalength, uint8_t *data) {
428
429 uint8_t crc=0;
430 uint8_t tmp;
431
432 if(pmc_rx_head == pmc_rx_tail) {
433 return 0;
434 }
435
436 uint8_t *buffer;
437 uint8_t tail, head;
438 buffer = pmc_rx_buffer[pmc_rx_tail].buffer;
439 tail = 0;
440 head = pmc_rx_buffer[pmc_rx_tail].head;
441
442 // check crc
443 while(tail != head) {
444 crc = pmc_crc_update(crc,buffer[tail++]);
445 }
446
447 if(crc) {
448 pmc_error = PMC_ERROR_RX_CRC_FAILED;
449 pmc_mode = PMC_MODE_ERROR;
450 pmc_rx_tail++;
451 pmc_rx_tail &= (PMC_RX_BUFFERS-1);
452 return 0;
453 }
454
455 if(pmc_crc_errorcount) pmc_crc_errorcount--;
456
457 // copy data to destination
458 tail=0;
459 *id = buffer[tail++];
460 tmp = buffer[tail++];
461 *subid = (tmp>>4) & 0x0F;
462 *datalength = tmp & 0x0F;
463
464 head=head-1;
465 while(tail != head) {
466 *data = buffer[tail++];
467 data++;
468 }
469
470
471 // mark buffer as empty
472 pmc_rx_tail++;
473 pmc_rx_tail &= (PMC_RX_BUFFERS-1);
474
475 return 1;
476 }
477
478 void pmc_flush_rx_buffer(void) {
479
480 pmc_rx_tail = pmc_rx_head;
481
482 }
Gespeicherte Dateianhänge
Um Dateianhänge in eine Seite einzufügen sollte unbedingt eine Angabe wie attachment:dateiname benutzt werden, wie sie auch in der folgenden Liste der Dateien erscheint. Es sollte niemals die URL des Verweises ("laden") kopiert werden, da sich diese jederzeit ändern kann und damit der Verweis auf die Datei brechen würde.Sie dürfen keine Anhänge an diese Seite anhängen!