welcome: please sign in

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.
  • [laden | anzeigen] (2017-06-12 18:26:24, 11.6 KB) [[attachment:pmc.c]]
  • [laden | anzeigen] (2017-06-12 18:26:24, 1.0 KB) [[attachment:pmc.config.h]]
  • [laden | anzeigen] (2017-06-12 18:26:24, 6.0 KB) [[attachment:pmc.h]]
  • [laden | anzeigen] (2017-06-12 18:26:24, 5.3 KB) [[attachment:uart.zip]]
 Alle Dateien | Ausgewählte Dateien: löschen verschieben auf Seite kopieren auf Seite

Sie dürfen keine Anhänge an diese Seite anhängen!