/********************************************************************************/
//  CAN2Flash Routinen for MB90F497
//  1.   can_init (ausserhalb dieses Files)  
//  2.   flash_main
//  alle Routinen wurden zu einer Funktion zusammengefasst um kein Stack zu benutzen.(mit goto :-)))
//  Uebertragene daten werden alternierende per can-msg invertiert um ev. dreher zu finden
//  es ist zu beachten da  alle Sectionen im Mirror-RAM liegen, und kein Platz mehr uebrig bleibt
//  um doppelbelegung zu vermeiden
//
//     ACHTUNG ! bei Code_Aenderung   ueberpruefen 
//
//  1. Overlap zwischen sectionen CODE_mcan und mcan_nofardata ?  falls ja dann anpassen
// 	   #pragma section DATA=mcan_nofardata,locate=0x1090
//  2. Sectionsgrenze 0x10FF fuer mcan_nofardata darf nicht  berschritten werden ?
//	
//  2. #defines SIZE_CODE_C2F im mcan.h ?
//
//  3. im mcan.lst zeile ~4308  "LINK 10" Eintrag  ueberpruefen  ?  dann ->
//     -> byte    dummy_buffer[10];     //_TODO  
//     -> MOVW A, #_dummy_buffer+10 
//	   Hintergrund: je nach compiler einstellung wird mit LINK speicher reserviert fuer variablen und
//	   der darf nicht  berschrieben werden  	
//
//  nach "_TODO" suchen und eintraege anpassen
// 
/*  address-sectionen
	00000900-0000097F  00000080  DATA  P RW-- 02 REL  DATA_mcan
	00000990-0000108E  000006FF  CODE  P RWXI 01 REL  CODE_mcan
	00001090-000010FF  00000070  DATA  N RW-- 00 ABS  mcan_nofardata
	00FFF000-00FFF6FF  00000700  CODE  P R-XI 01 REL  #CODE_mcan
*/
//  ACHTUG ! ES WIRD EMPFOHLEN DIESES FILE NICHT ANZUFASSEN -> sonst selber schuld :-)
//  03.12.2003  verzoegerung eingebaut beim ppcan-detect
/*
	last list-file:

	000007C0-000008FF  00000140  STACK P RW-- 02 REL  SSTACK
	00000900-0000097F  00000080  DATA  P RW-- 02 REL  DATA_mcan
	00000990-00001084  000006F5  CODE  P RWXI 01 REL  CODE_mcan
	00001096-000010FC  00000067  DATA  N RW-- 00 ABS  mcan_nofardata
*/
/********************************************************************************/

#pragma section CODE=CODE_mcan 
#pragma section DCLEAR=No_Init	// _far Variablen  nicht initialisieren; alle DCLEAR-Sections werden 
								// automatisch geloescht (siehe start.asm, 6.7)

// _TODO locate=0x1090 ?
#pragma section DATA=mcan_nofardata,locate=0x1096

#define _srvwdt_()    WDTC &= 0xFB  


#include "compiler.h"
#include "mb90495.h"
#include "mcan.h"
#include "comptime.h"
#include "main.h"


#define SETID(id) ((( (id) << 13) & 0xE000) | (( (id) >> 3) & 0xFF)) 
#define GETID(Value) (((Value << 3) & 0x7F8) | ((Value >> 13) & 0x007))

/********************************************************************************/

#define MAX_BUFFER 119
#define DEBUGPOINTER 0

// Version

#define MAIN_VERSIONMAIN _VERSION_MAIN_	
#define MAIN_VERSIONSUB _VERSION_SUB_	


// Bits in bStatus										
#define SET_STARTADDR	0x01
#define SET_CHECKSUM	0x02
#define SET_LENGTH		0x04
#define SET_ERASEOK		0x20
#define SET_CHECKSUMOK	0x40
#define SET_VERIFYOK	0x80

// Module ID

// ACHTUNG !!! dummy_buffer muss wenigstens so gross wie mit LINK reservierte bereich nach den flash_main sprung
// in nCAN.lst ~line 4308 nachschauen und ggf. korrigieren
// -> hier auch nicht vergessen : MOVW A, _dummy_buffer+0x10
u8_t    dummy_buffer[10];     //_TODO  
u8_t	b_dl_ModuleID;

/*Globale variable fuer Copy-Routinen*/
volatile  u16_t c2f_counter;   
volatile  u16_t __far *c2f_src;
volatile  u16_t __far *c2f_des;


//******************************************************************************************************
/* ** 2stellige Versionskennung in 1 Byte packen:
     3 Bit fuer Main, 5 Bit fuer Sub (1.0 bis 7.31) ** */

#define PPCAN_VERSION2BYTE(main,sub) ((unsigned char)(((main) & 7) << 5) | ((sub) & 0x1f))
#define Invert_LED  PDR6_P61 = !PDR6_P61
#define LEDSTATUS   PDR6_P61

static u8_t 	One_Read_ret;
static u8_t 	One_Read_h;
static u8_t 	CAN__Read_ret;
static u8_t  	CAN__Write_jmp;
static u8_t		flash_wait_jmp;
static u32_t 	l_dl_Startadresse;
static u32_t 	l_dl_Blockgroesse;
static u32_t 	__far l_dl_Buffptr;

static u16_t 	w_dl_Checksum;
static u8_t 	b_dl_Status;//=0;		// Bits werden gesetzt wenn Wert per CAN definiert wird

static u8_t 	__far b_dl_buffer[MAX_BUFFER+5];
static u16_t 	w_dl_LocalChecksum;

static u16_t  	CAN__BUFF_ID ;
static u8_t 	CAN__BUFF_DATA[8];
static u8_t 	CAN__BUFF_LEN ;
static u8_t 	CAN__BUFF_RTR;
static u8_t  	RCR_Valid;

static u8_t   	read_idxptr;        //queue read pointer
static u8_t   	write_idxptr;       //queue write pointer
static u8_t   	q[0x11];   			//can-register queue 
static u8_t    data_invert;

static u16_t     ledhelp;

volatile static u16_t __far *flashptr;//(u16_t __far*)DEBUGPOINTER;

static 	u16_t __far *src; 
static	u16_t __far *dst;
static  u16_t  nbytes;
static u16_t i;

static u16_t __far* p;

__nosavereg void __far mCAN_flash_main(void)
{

//  Hilfsvariablen fuer Parameteruebergabe

/**** Initialisierung ****/

	#pragma asm
		    MOVW A, #_dummy_buffer+10         ; _TODO LINK RW3 auf ende von dummy_buffer zeigen ev. anpassen
	    	MOVW RW3,A	    	
	#pragma endasm
	    	
 /*       	MOVW RW0, #mcan_nofardata 			;speicher initialisieren mit null 
    loop:  	MOVW @RW0,#0000            
           	INCW RW0
           	INCW RW0
           	CWBNE RW0,#0x10FE,loop
	#pragma endasm
*/    	
	
	read_idxptr=0;   
	write_idxptr=0;
	q[0]=0;
	b_dl_Status=0;	
	RCR_Valid =0;
	data_invert =0;

	ledhelp=1;
	b_dl_ModuleID=31-(PDR3>>3); 
    
	//while(1)
	for(;;)
	{
	   _srvwdt_();

		goto CAN__Read;
CAN__Read_jmp_1:
		if (CAN__Read_ret==0)
		{
				
			switch(CAN__BUFF_ID)
			{
				case 0x7E7:
					if((CAN__BUFF_DATA[0]==0x80) && (CAN__BUFF_DATA[1]==0x00) && (CAN__BUFF_DATA[2]==0x06))
					{
					    // 0xC000 | typ<<6 | id  -> hardawre typ 
						ledhelp = 0x5FF * b_dl_ModuleID;
						while(--ledhelp);
						CAN__BUFF_DATA[0]= 0xCF;
						CAN__BUFF_DATA[1]= 0xC0 | 	b_dl_ModuleID; // Module id
						CAN__BUFF_DATA[3]= ((__COMPILETIME_DAY__ / 10) << 4) | (__COMPILETIME_DAY__ % 10) ;
						CAN__BUFF_DATA[4]= ((__COMPILETIME_MONTH__ / 10) << 4) | (__COMPILETIME_MONTH__ % 10) ;
						CAN__BUFF_DATA[5]=  (((__COMPILETIME_YEAR__ % 100) / 10) << 4)| ((__COMPILETIME_YEAR__ % 100) % 10) ;
						CAN__BUFF_DATA[6]= PPCAN_VERSION2BYTE(_MAIN_,_SUB_);
						CAN__BUFF_DATA[7]= 0x00;
						CAN__BUFF_LEN=8;
						CAN__Write_jmp = 1;
						goto CAN__Write;//();
					}
				   	else
					{
						if(CAN__BUFF_LEN == 8)
						{
							//Add_Data();						
							if((l_dl_Buffptr < MAX_BUFFER) ) // || ( buffptr > (wBlockgroesse-8) ) )
							{ 
							static u8_t n,m;
						
								for(n=0,m=2;n<6;n++,m++)
								{
									b_dl_buffer[l_dl_Buffptr] = CAN__BUFF_DATA[m]^data_invert;
									w_dl_LocalChecksum+= CAN__BUFF_DATA[m]^data_invert;

									l_dl_Buffptr++;
									if(l_dl_Buffptr >= l_dl_Blockgroesse) break; 
								}
								data_invert^=0xFF;
							}
						}else if(CAN__BUFF_LEN == 7)
						{
							//if(ID_Check())
							if((CAN__BUFF_DATA[2]==b_dl_ModuleID) || (CAN__BUFF_DATA[2]==0xFF))
							  goto	Eval_Command;//();
						}
					}
					
Eval_Command_jmp_1:				
CAN__Write_jmp_1:
	
				break;
			} //swich
		}
		else
		{
		  
		  _srvwdt_() ;

			if(ledhelp--==0 )
			{
				if(LEDSTATUS) ledhelp=5000;
				else ledhelp=64000;
				Invert_LED;
			}	 
		  
		  
		}  //if read ok
		
	} //while
	
	/* ** end flash_main(void) ** */
/******************************************************************************/
/* ************ void __far flash_wait(u32_t offset) ***************** */
//int __far flash_wait_jmp; -> siehe oben
//u32_t flash_wait_offset; -> siehe oben
flash_wait :
	{
    volatile static	u16_t d,t;
//s.oben	volatile static u16_t __far *flashptr;//(u16_t __far*)DEBUGPOINTER;
	    t=1;
	    flashptr=0;
		while(t)
		{
			d=flashptr[/*flash_wait_offset*/0xFF0000/2] & 0x4040;
			t=d^(flashptr[/*flash_wait_offset*/0xFF0000/2] & 0x4040);
		 	_srvwdt_() ;
		}
		
//	flash_wait_offset=0;     // hier auf null um nicht jedes mal neu
		
	if (flash_wait_jmp==1)
		goto flash_wait_jmp_1;
	else if (flash_wait_jmp ==2)
		goto flash_wait_jmp_2;
	else if (flash_wait_jmp ==3)
		goto flash_wait_jmp_3;
	else if (flash_wait_jmp ==4)
		goto flash_wait_jmp_4;	 
	} 
/******************************************************************************/
/* ***	int __far flash_write(u32_t offset, u8_t *buf, u16_t nbytes) ***/
//l_dl_Startadresse,(char*)b_dl_buffer,l_dl_Blockgroesse);
flash_write :
	{
//s.oben	static	u16_t __far *flashptr; 
//			static 	u16_t __far *src; 
//			static	u16_t __far *dst;
//s.oben	static  u16_t  nbytes;
	
	flashptr= 0;//DEBUGPOINTER;
	flashptr[0] = 0xF0F0;

	nbytes = l_dl_Blockgroesse;
	nbytes>>=1;

	dst = (u16_t __far*)(/*DEBUGPOINTER +*/ l_dl_Startadresse);   
	src = (u16_t __far*)/*buf*/b_dl_buffer;

	while (nbytes != 0) 
	{
	
	#pragma asm	
		MOVN	A,#0
		MOV		@RW3-1,A
		SETB	I:0xAE:5
	#pragma endasm
	
		_srvwdt_() ;
		flashptr[0xFFAAAA/2] = 0xAAAA;      
		flashptr[0xFF5554/2] = 0x5555;      
		flashptr[0xFFAAAA/2] = 0xA0A0;	
	
		*dst++ = *src++;
		
		flash_wait_jmp = 1;
		goto flash_wait;//(0);
flash_wait_jmp_1:
		nbytes --;
	}
	flashptr[0xFF0000] = 0xF0F0;
	flash_wait_jmp = 2;
	goto flash_wait;//(0);
flash_wait_jmp_2:

	//return (char __far*)src - buf;
	goto flash_write_jmp_1;	
	}
/******************************************************************************/
/* ****** u8_t __far One_Read(u8_t h ) ****** */
//__far u8_t One_Read_ret; -> siehe oben 
//__far u8_t One_Read_h; -> siehe oben
One_Read:
	{           
  
		if((RCR & (0x01<</*BitMask[*/One_Read_h)) !=0 )	// dann liegen Daten/RTR vor
		{
			
			CAN__BUFF_LEN = DLCR(One_Read_h);
   			CAN__BUFF_ID  = GETID(IDR(One_Read_h));
					     			          				
      				if(RRTRR & (0x01<</*BitMask[*/One_Read_h))	// wenn remoteframe
      				{
      					CAN__BUFF_RTR = 1;
      					RRTRR &= ~(0x01<</*BitMaskInv[*/One_Read_h);	// !!!!!
      				}
      				else		// sonst datenframe
      				{
      					CAN__BUFF_RTR = 0;
	      				*(int*)(CAN__BUFF_DATA+0) = DTR_WORD(One_Read_h,0);
    	  				*(int*)(CAN__BUFF_DATA+2) = DTR_WORD(One_Read_h,1);
						*(int*)(CAN__BUFF_DATA+4) = DTR_WORD(One_Read_h,2);
						*(int*)(CAN__BUFF_DATA+6) = DTR_WORD(One_Read_h,3);						
					}

      				if(ROVRR )//& BitMask[h])
      				{
	      				ROVRR =0; 
	      			    One_Read_ret = CAN_ERR_QOVERRUN;
	      			    goto One_Read_jmp_1;//return;
      				}  			
                	       		
      			RCR  = RCR &  ~(0x01<</*BitMaskInv[*/One_Read_h);//BitMaskInv[One_Read_h];  	// Box wurde gelesen   			
      			while((RCR & (0x01<</*BitMask[*/One_Read_h)) !=0 ){};	//warten bis gel scht 				      		      	
         	
         	//    BVALR |= BitMask[h];  	    // Message Buffer entsperren
    		//    while ((BVALR & BitMask[h]) == 0 ){};   
			One_Read_ret = CAN_ERR_OK;
   			goto One_Read_jmp_1;//return CAN_ERR_OK;
    	}
	    else
	    {	
	       One_Read_ret = CAN_ERR_QRCVEMPTY;
	       goto One_Read_jmp_1;//return CAN_ERR_QRCVEMPTY;   // keiene can-msg da
	    }   
	}
/******************************************************************************/
/* ****** u8_t __far CAN__Read(void) ****** */
//__far u8_t CAN__Read_ret; -> siehe oben
CAN__Read:
{
//static u8_t ret;	
	
           CAN__Read_ret=CAN_ERR_QRCVEMPTY;	     
                          	
        	if (q[read_idxptr]!=0 ) //  also bit gesettz
        	{
        	 static u8_t b;
        	 static u8_t ii;
                
                b=0x01;
                ii=0;
           		while (!(b &q[read_idxptr])) {b<<=1;ii++;} 
                
				//if (b & q[read_idxptr])
				{
				//ret =  One_Read(i);         
				One_Read_h = ii;
				goto One_Read;
One_Read_jmp_1:
				CAN__Read_ret =  One_Read_ret;
				q[read_idxptr] &= ~b;                   //bitl schen                	                      
                RCR_Valid &= ~b; 
                }
                
       	 	}
       	
        	if (read_idxptr != write_idxptr)       // read_pointer wird inc erst wenn alle msg gelesen
        	{         	 	
       	 		if(q[read_idxptr]==0 ) //  also keine bit gesettz
            	{ 
           			read_idxptr++;
           			read_idxptr&=0x0F;
         		}  // inc rd_ptr
        	}           
             
       	   	if (RCR & ~RCR_Valid)//~q[write_idxptr]) // bitzuwachs
        	{       	
        	 static u8_t t;
        	             
           		if (((write_idxptr+1)&0x0F) != read_idxptr) //  ueberlauf abfangen
           		{
           	  		write_idxptr++; 
           	  		write_idxptr&=0x0F;
           	  		
           	  		t = RCR;
           	  		q[write_idxptr] = t & ~RCR_Valid;//RCR & ~t;
           	  		RCR_Valid = t;
           	  		
                 	//BVALR &= ~q[write_idxptr];             // Message Buffer sperren     			
     	 	        //while (BVALR & q[write_idxptr] ){PDR2_P24=!PDR2_P24;};    // Warten bis Box gesperrt ist
                    //PDR2_P24=0;
                }
        		else
        		  CAN__Read_ret = CAN_ERR_QOVERRUN;
        	}      	           
        
    //return ret;        
    goto CAN__Read_jmp_1;
}           
	
/* ****** void __far CAN__Write(void) ******  */
//__far  int CAN__Write_jmp; -> siehe oben

CAN__Write:
	{
	//static int ret;
	if((RCR & 0x80) ==0 )	// dann liegen keine Daten/RTR vor
	{
	BVALR_BVAL7	 = 0;		// message buffer  invalid
    while (BVALR_BVAL7){}
   
		// pruefen ob Buffer 7 frei 
		if( (TREQR_TREQ7 == 0) ) 
		{
			//set frame format for messagebuffer 0
			RFWTR_RFWT7  = 0;		// no wait for remote requeset
			TRTRR_TRTR7	 = 0;		// data frame transfer
			IDER_IDE7	 = 0;		// 11bit indentifier
			IDR(7)       = SETID(CAN__BUFF_ID);
	
			//AMSR_AMS7	 = 0;		// full bit compare
		    //TIER_TIE7 	 = 1;   keine irq
		
			DLCR(7)		  = CAN__BUFF_LEN;		// data length
			DTR_WORD(7,0) = *(int*)(CAN__BUFF_DATA+0);
			DTR_WORD(7,1) = *(int*)(CAN__BUFF_DATA+2);		
			DTR_WORD(7,2) = *(int*)(CAN__BUFF_DATA+4);
			DTR_WORD(7,3) = *(int*)(CAN__BUFF_DATA+6);
	
	  		TREQR_TREQ7 = 1;		// transmition request

		}

		BVALR_BVAL7	 = 1;			// message buffer  invalid
		while (TREQR_TREQ7);         // warten bis gesendet 
	}

	if (CAN__Write_jmp == 1)
	  goto CAN__Write_jmp_1;
	else 
	  goto CAN__Write_jmp_2; 
	} 	
	
/* ****** void __far Eval_Command() ******  */
Eval_Command:
{

	switch(CAN__BUFF_DATA[3])
	{
		case 0: // Status abfragen

			/* *** void __far SendStatus() *** */
			{
				if(w_dl_LocalChecksum==w_dl_Checksum) 
				   b_dl_Status |=SET_CHECKSUMOK;
				else 
				   b_dl_Status &=~SET_CHECKSUMOK;
				CAN__BUFF_ID = 0x7E7;
				CAN__BUFF_LEN= 6;
				CAN__BUFF_DATA[0] = 0x7f;
				CAN__BUFF_DATA[1] = 0xff;
				CAN__BUFF_DATA[2] = b_dl_ModuleID;	
				CAN__BUFF_DATA[3] = 4;	// Hardware-Typ   MicoMod
				CAN__BUFF_DATA[4] = 4;	// Flash-Typ      MB90F497
				CAN__BUFF_DATA[5] = b_dl_Status;
				CAN__Write_jmp=2;
				goto CAN__Write;//();
			}									
CAN__Write_jmp_2:
		break;
		case 1: // Startadresse setzen
				l_dl_Startadresse=  ((u32_t) CAN__BUFF_DATA[4]<<16)+
									((u32_t) CAN__BUFF_DATA[5]<<8)+
									((u32_t) CAN__BUFF_DATA[6]<<0);
				b_dl_Status|= SET_STARTADDR;
				b_dl_Status&=~(SET_VERIFYOK | SET_ERASEOK | SET_CHECKSUM );
				w_dl_LocalChecksum = 0;
				l_dl_Buffptr = 0;
				data_invert  = 0;  
		break;
		case 2: // Blockgroesse
				l_dl_Blockgroesse=  ((u32_t) CAN__BUFF_DATA[4]<<16)+
									((u32_t) CAN__BUFF_DATA[5]<<8)+
									((u32_t) CAN__BUFF_DATA[6]<<0);
				b_dl_Status |= SET_LENGTH;
		break;
		case 3: // Checksumme 
				w_dl_Checksum = 256*(u16_t)CAN__BUFF_DATA[4]+CAN__BUFF_DATA[5];
				b_dl_Status|= SET_CHECKSUM;
				
		break;

		case 4: // Erase Sektor
 			flashptr = 0;// (u16_t *) DEBUGPOINTER;
			if(CAN__BUFF_DATA[4]==0x55)
			{

					#pragma asm	
						MOVN	A,#0
						MOV		@RW3-1,A
						SETB	I:0xAE:5
					#pragma endasm

					flashptr[0xFFAAAA/2] = 0xAAAA;       /* unlock 1 */
				  	flashptr[0xFF5554/2] = 0x5555;       /* unlock 2 */
					flashptr[0xFFAAAA/2] = 0x8080;
					flashptr[0xFFAAAA/2] = 0xAAAA;
					flashptr[0xFF5554/2] = 0x5555;
	
					flashptr[l_dl_Startadresse/2]=0x30;
					flash_wait_jmp = 3;
					goto flash_wait;//(offset);
flash_wait_jmp_3:
					flashptr[0xFF0000] = 0xF0F0;   /* assume reset device to read mode */
					flash_wait_jmp = 4;
					goto flash_wait;//(0);
flash_wait_jmp_4:
					b_dl_Status|= SET_ERASEOK;
					for(i=0;i<l_dl_Blockgroesse/2;i++)
					{
						if(flashptr[l_dl_Startadresse/2+i]!=0xffff) b_dl_Status &=~SET_ERASEOK;
						_srvwdt_() ;
					}			
			}
		break;
		case 5: // Flash schreiben
					if( ((b_dl_Status&(SET_STARTADDR | SET_LENGTH | SET_CHECKSUM))==(SET_STARTADDR | SET_LENGTH | SET_CHECKSUM)) && 
					(CAN__BUFF_DATA[4]==0x55) )
					{
						//flash_write(l_dl_Startadresse,(char*)b_dl_buffer,l_dl_Blockgroesse);
						goto flash_write;
flash_write_jmp_1:
						b_dl_Status &=~(SET_CHECKSUM | SET_STARTADDR | SET_LENGTH | SET_VERIFYOK);	// Adresse, Checksum, L nge und Verify ung ltig machen
					}
		break;
		case 6: // Verify
					flashptr = 0;//(/*DEBUGPOINTER+*/l_dl_Startadresse);
					b_dl_Status|=SET_VERIFYOK;
					{
						p=(u16_t __far*)b_dl_buffer;
						for(i=0; i<l_dl_Blockgroesse/2; i++)
						{
							if( p[i] != flashptr[l_dl_Startadresse/2+i]) b_dl_Status&=~SET_VERIFYOK;
						   _srvwdt_() ;
						}
					} 
		break;		
		case 15: // Reset
					if(CAN__BUFF_DATA[4]==0x55)
					//while(1);//_trap_(0);                //reset
					for(;;);
		break;
	}
	goto Eval_Command_jmp_1;
	}
}



