//***************************************************************************************
// Header File Included Area
//***************************************************************************************
.include SACM_A1800_Constant.inc


//***************************************************************************************
// Function Call Publication Area
//***************************************************************************************
.public  _Event_Initial
.public F_Event_Initial

.public  _Event_ServiceLoop
.public F_Event_ServiceLoop

.public  _IO_Event_Enable
.public F_IO_Event_Enable

.public  _IO_Event_Disable
.public F_IO_Event_Disable

.public  _ISR_Event_Service
.public F_ISR_Event_Service

.public F_EventInit

.public F_IO_Event_End


//***************************************************************************************
// External RAM Declaration
//***************************************************************************************
.external R_SACM_A1800_Event_Flag
.external R_DutyArray
.external R_Event_Tag_Cunt


//***************************************************************************************
// External Function Declaration
//***************************************************************************************
.external F_SACM_A1800_Status
.external F_Event_Init_
.external F_USER_GetEvtData
.external F_USER_EvtProcess
.external F_USER_IoEvtStart
.external F_USER_IoEvtEnd


//***************************************************************************************
// External Table Declaration
//***************************************************************************************
.external T_IO_Event
.external D_IO_EVENT_NUM
.external D_SW_PWM_LEVEL	

//***************************************************************************************
// Contant Defintion Area
//***************************************************************************************
.define C_SW_PWM_EN_FLAG             15          // R_DutyArray bit15: 1 => S/W PWM: Disalbe, 0 => S/W PWM: Enable

//.define C_EXT_EVENT_FLAG             0x8000      // R_SACM_A1800_Event_Flag bit15: 1 => external event, 0 => internal event
												   // Move to Constant.inc

//
// R_Event_Ctrl definition
//
.define C_IO_EVENT_EN_FLAG           0x8000      // bit15: 1 => IO Event Enable, 0 => IO Event Disalbe
.define C_EVENT_HEADER_SHIFT_FLAG    0x4000      // bit14: 1 => event header on high byte, 0 => event header on low byte

.define C_PORT_DATA_IDX              0 
.define C_PORT_BUF_IDX               1
.define C_PORT_DIR_IDX               2
.define C_PORT_ATT_IDX               3

.define C_SW_PWM_LEVEL    128                    // PWM level selection (32/64/128/256)
//***************************************************************************************
// RAM Definition Area
//***************************************************************************************
.ram
OVERLAP_A1800_EVENT_BLOCK:	.section	.ORAM
.var R_EvtAddrL
.var R_EvtAddrH
.var R_DutyCounter
.var R_Processed_EventID
.var R_Event_Ctrl


//***************************************************************************************
// CODE Definition Area
//***************************************************************************************
.code
//*****************************************************************************
// Function    : F_Event_ServiceLoop
// Description : Change timer setting for change DA filter, called by library
// Destory     : 
// Parameter   : None
// Return      : None
// Note        : None
//*****************************************************************************
_Event_ServiceLoop:    .proc
F_Event_ServiceLoop:
  push R1, R3 to [sp];    

  R1 = [D_IO_EVENT_NUM]; 
  jz ?L_SACM_Event_ServiceLoop_End;              // If D_IO_EVENT_NUM == 0, go to ?L_SACM_Event_ServiceLoop_End
  
  call F_SACM_A1800_Status;
  R1 = R1 & C_SACM_A1800_PLAY;
  jz ?L_SACM_Event_ServiceLoop_End; 
  
  //
  // if R_Event_Tag_Cunt == R_Processed_EventID => jmp to ?L_SACM_EVENT_ServiceLoop_End
  // if R_Event_Tag_Cunt != R_Processed_EventID => Process event
  //
?L_Check_EventID:      
  R3 = [R_Event_Tag_Cunt];
  cmp R3, [R_Processed_EventID];
  je ?L_SACM_Event_ServiceLoop_End;    
  R1 = [R_Processed_EventID];  
  R1 += 1;
  [R_Processed_EventID] = R1;   
  call F_GetEvtNum;  
  call F_ProcessEvt;
  jmp ?L_Check_EventID; 

?L_SACM_Event_ServiceLoop_End:
  pop R1, R3 from [sp];
  retf;
  .endp

//*****************************************************************************
// Function    : F_EventInit
// Description : None
// Destory     : 
// Parameter   : R1 = Low word of sound data addr
//               R2 = High word of sound data addr 
//               R3 = Low word of the speech length
//               R4 = High word of the speech length
// Return      : None
// Note        : None
//*****************************************************************************
F_EventInit:    .proc
  push R1, R5 to [sp];  

  call F_IO_Event_Start;              

  //
  // Initialize S/W PWM RAM
  //
  R5 = 0;
  [R_DutyCounter] = R5;    
  [R_Processed_EventID] = R5;    
  R5 = [R_SACM_A1800_Event_Flag];    
  R5 &= C_EXT_EVENT_FLAG;                        // Remain External Event Flag. Clear the others.
  [R_SACM_A1800_Event_Flag] = R5;     
 
  R5 = [R_SACM_A1800_Event_Flag];
  test R5, C_EXT_EVENT_FLAG;                              
  jz ?L_CalculateInEvtAddr;  
  
  //
  // Calculate the start address of the external event data
  //
//  R1 += 4;                                       // skip data lentgh: 4-bytes
//  R2 += 0, carry;      
//  R1 += R3;  
//  R2 += R4, carry;    
//  [R_EvtAddrL] = R1; 
//  [R_EvtAddrH] = R2;

  R2 += 4;                                       // skip data lentgh: 4-bytes
  R1 += 0, carry;      
  R2 += R3;  
  R1 += R4, carry;    
  [R_EvtAddrL] = R2; 
  [R_EvtAddrH] = R1;
  
  pop R1, R5 from [sp];  
  retf;    

  //
  // Calculate the start address of the internal event data
  //
?L_CalculateInEvtAddr:  
//  R2 = R2 lsr 4;                                 // Added by Allen on 20150408
//  R2 = R2 lsr 4;                                 // Added by Allen on 20150408
//  R2 = R2 lsr 2;                                 // Added by Allen on 20150408
//  R1 += 2;                                       // Skip data lentgh: 2-words
//  R2 += 0, carry;
//  R4 = R4 lsr 1;
//  R1 += R3 lsr 1;  
//  R2 += R4, carry;
//  [R_EvtAddrL] = R2;
//  [R_EvtAddrH] = R1;  
  push R3 to [sp];
  R1 = R1 lsr 4;                                 // 
  R1 = R1 lsr 4;                                 //
  R1 = R1 lsr 2;                                 //
  R2 += 2;                                       // Skip data lentgh: 2-words
  R1 += 0, carry;
  R5 = R4;
  R4 = R4 lsr 1;
  R3 = R3 ror 1;
  TEST R5, 0x01;
  jz ?conti
  R3 |=0x8000;
?conti:  
  R2 += R3;
  R1 += R4, carry; 
  [R_EvtAddrL] = R2;
  [R_EvtAddrH] = R1;  
  pop R3 from [sp]; 
   
  test R3, 0x0001;
  jnz ?L_SetEvtAddrSftFlag;  
  R1 = [R_Event_Ctrl];
  R1 &= ~C_EVENT_HEADER_SHIFT_FLAG;  
  [R_Event_Ctrl] = R1;                           // EVENT_HEADER_SHIFT_FLAG = '0' => event header on low byte          
  
  pop R1, R5 from [sp];
  retf;    
  
?L_SetEvtAddrSftFlag:   
  R1 = [R_Event_Ctrl];
  R1 |= C_EVENT_HEADER_SHIFT_FLAG;  
  [R_Event_Ctrl] = R1;                           // EVENT_HEADER_SHIFT_FLAG = '1' => event header on high byte
  
  pop R1, R5 from [sp];
  retf
  .endp 

//*****************************************************************************
// Function    : F_GetEvtNum
// Description : None
// Destory     : 
// Parameter   : None
// Return      : R1: Event Number
// Note        : None
//*****************************************************************************
F_GetEvtNum:    .proc
  push R2, R3 to [sp];

  R1 = [R_EvtAddrL];
  R2 = [R_EvtAddrH]; 

  //
  // Get event number
  // - Bit13: External Event Flag = '1' => Get external event and store to R1
  // - Bit13: External Event Flag = '0' => Get internal event and store to R1
  //
  R3 = [R_SACM_A1800_Event_Flag];
  test R3, C_EXT_EVENT_FLAG;               
  jz ?L_GetInEvtNum;
  call F_USER_GetEvtData;                        // Get external event number and store to R1
  jmp ?L_EvtHeaderOnLowByte;  
?L_GetInEvtNum:
  DS = R2;                                       // Added by Allen on 20150408
  //R1 = [R1];                                   // Masked by Allen on 20150408
  R1 = D:[R1];                                   // Added by Allen on 20150408
  R2 = [R_Event_Ctrl];
  test R2, C_EVENT_HEADER_SHIFT_FLAG;
  jnz ?L_EvtHeaderOnHighByte
?L_EvtHeaderOnLowByte:    
  R1 &= 0x00FF;
  R1 = R1 lsr 2;                                 // R1 = event number
  R3 = [R_SACM_A1800_Event_Flag];
  test R3, C_EXT_EVENT_FLAG;                              
  jnz ?L_IncEvtAddr;  
  jmp ?L_GetEvtNum_End;
?L_EvtHeaderOnHighByte: 
  R1 = R1 lsr 4;
  R1 = R1 lsr 4;  
  R1 = R1 lsr 2;                                 // R1 = event number

  //
  // Event address = Event address + 1
  //
?L_IncEvtAddr:
  R2 = [R_EvtAddrL];
  R3 = [R_EvtAddrH];
  R2 += 1;
  R3 += 0, carry;
  [R_EvtAddrL] = R2;
  [R_EvtAddrH] = R3;

?L_GetEvtNum_End:
  pop R2, R3 from [sp];
  retf
  .endp

//*****************************************************************************
// Function    : F_GetEvtData
// Description : None
// Destory     : None
// Return      : R1 = SubIndex:MainIndex
// Note        : None
//*****************************************************************************
F_GetEvtData:    .proc
  push R2, R3 to [sp];
  R1 = [R_EvtAddrL]; 
  R2 = [R_EvtAddrH];

  R3 = [R_SACM_A1800_Event_Flag];
  test R3, C_EXT_EVENT_FLAG;                              
  jz ?L_GetInEvtData;
  
  //
  // Get external event data and store to R1
  //  
  call F_USER_GetEvtData;                        // R1 = Sub_Index(8-bits):Main_index(8-bits)  
  R2 = [R_EvtAddrH];
  R3 = [R_EvtAddrL];
  R3 += 2;
  R2 += 0, carry;  
  [R_EvtAddrH] = R2;
  [R_EvtAddrL] = R3;  
  pop R2, R3 from [sp];
  retf;  

  //
  // Get internal event data and store to R1
  //
?L_GetInEvtData:    
  R3 = [R_Event_Ctrl];
  test R3, C_EVENT_HEADER_SHIFT_FLAG;
  jnz ?L_EvtHeaderOnHighByte
?L_EvtHeaderOnLowByte:   
  DS = R2;                                       // Added by Allen on 20150408
  //R3 = [R1++];                                 // Masked by Allen on 20150408
  R3 = D:[R1++];                                 // Added by Allen on 20150408
  //R1 = [R1];                                   // Masked by Allen on 20150408
  R1 = D:[R1]                                    // Added by Allen on 20150408
  R1 = R1 lsl 4;
  R1 = R1 lsl 4;
  R3 = R3 lsr 4;
  R3 = R3 lsr 4;
  R1 |= R3;                                      // R1 = Sub_Index(8-bits):Main_index(8-bits)  
  jmp ?L_IncEvtAddr;  
?L_EvtHeaderOnHighByte: 
  DS = R2;                                       // Added by Allen on 20150408 
  //R1 = [R1];                                   // R1 = Sub_Index(8-bits):Main_index(8-bits). Masked by Allen on 20150408          
  R1 = D:[R1];                                   // R1 = Sub_Index(8-bits):Main_index(8-bits). Added by Allen on 20150408
?L_IncEvtAddr:
  R2 = [R_EvtAddrH];
  R3 = [R_EvtAddrL];
  R3 += 1;
  R2 += 0, carry;  
  [R_EvtAddrH] = R2;
  [R_EvtAddrL] = R3;

  pop R2, R3 from [sp];
  retf
  .endp

//*****************************************************************************
// Function    : F_ProcessEvt
// Description : None
// Destory     : 
// Parameter   : R1 = Event Number
// Return      : None
// Note        : None
//*****************************************************************************
F_ProcessEvt:    .proc  
  push R1, R3 to [sp];  

?L_GetEvtData:
  push R1 to [sp];                              // push Event Number
  
  call F_GetEvtData;                            // Get event data, R1 = SubIndex(8-bits):MainIndex(8-bits)    

  R2 = R1 & 0x00FF;
  cmp R2, 0x0080;
  jb ?L_UserEvtProcess;                         // User Event:  00h~7Fh  
  
  R3 = [R_Event_Ctrl];  
  jpl ?L_NextEvt;
  
  cmp R2, 0x00A0;  
  jb ?L_IOEventProcess;                         // IO Event:    80h~9Fh
  cmp R2, 0x00F0;
  je ?L_IOEventStart;                           // Event start: F0h
  cmp R2, 0x00F1;
  je ?L_IOEventEnd;                             // Event end:   F1h  
  jmp ?L_IOEventStart;                          // If the others events happened, go to ?L_IOEventStart

?L_UserEvtProcess:
  call F_USER_EvtProcess;
  jmp ?L_NextEvt;
  
?L_IOEventProcess:
  call F_IOEventProcess;
  jmp ?L_NextEvt;

?L_IOEventStart:  
  call F_IO_Event_Start;  
  jmp ?L_NextEvt;

?L_IOEventEnd:
  call F_IO_Event_End;  

?L_NextEvt:
  pop R1 from [sp];                              // pop Event Number
  R1 -= 1;  
  jnz ?L_GetEvtData;

?L_ChangeEvtAddrSftFlag:    
  R1 = [R_Event_Ctrl];
  R1 ^= C_EVENT_HEADER_SHIFT_FLAG;  
  [R_Event_Ctrl] = R1;

?L_ProcessEvt_End:
  pop R1, R3 from [sp];  
  retf
  .endp  

//*****************************************************************************
// Function    : F_IOEventProcess
// Description : None
// Destory     : 
// Parameter   : R1 = SubIndex:MainIndex 
// Return      : None
// Note        : None
//*****************************************************************************    
F_IOEventProcess:    .proc
  push R1, R3 to [sp];

  R2 = R1 & 0x007F;
  cmp R2, [D_IO_EVENT_NUM];
  jae ?L_IOEventProcessEnd; 

  R2 = R1 lsr 4;
  R2 = R2 lsr 4;
  
  R3 = [D_SW_PWM_LEVEL];
  cmp R3, 128;
  ja ?L_StoreDutyTo_R_DutyArray;  
  cmp R3, 64;
  ja ?L_DutyDiv_2;
  cmp R3, 32;
  ja ?L_DutyDiv_4;
  cmp R3, 0;
  jae ?L_DutyDiv_8; 
  
?L_DutyDiv_2: 
  R2 = R2 lsr 1
  jmp ?L_StoreDutyTo_R_DutyArray; 

?L_DutyDiv_4:
  R2 = R2 lsr 2
  jmp ?L_StoreDutyTo_R_DutyArray; 

?L_DutyDiv_8:
  R2 = R2 lsr 3 
   
  //
  // Store Duty to R_DutyArray
  //
?L_StoreDutyTo_R_DutyArray:
  R1 &= 0x007F;
  R3 = R_DutyArray;
  R3 += R1; 
  [R3] = R2;  

?L_IOEventProcessEnd:
  pop R1, R3 from [sp];
  retf
  .endp    
    
//*****************************************************************************
// Function    : F_Event_Initial
// Description : None
// Destory     : 
// Parameter   : None
// Return      : None
// Note        : None
//***************************************************************************** 
_Event_Initial:    .proc
F_Event_Initial:    
  push R1, R5 to [sp];  

  R1 = 0;
  [R_Processed_EventID] = R1;  

  //
  // Initialize R_DutyArray
  // - Disalbe S/W PWM
  // - Duty = 0;
  // 
  R1 = [D_IO_EVENT_NUM];  
  jz ?L_Event_Initial_End;  
  R2 = R_DutyArray;  
  R3 = 0x8000;
?L_Init_SWPWM_RAM_Loop:     
  [R2++] = R3; 
  R1 -= 1;
  jnz ?L_Init_SWPWM_RAM_Loop; 

  R1 = C_IO_EVENT_EN_FLAG;
  [R_Event_Ctrl] = R1;                           // Default IO Event Enable Flag = '1' => IO Event: Enable     

  call F_Event_Init_;                            // Callback Function, Design by user. This function in the SACM_xxx_User.asm

?L_Event_Initial_End:
  pop R1, R5 from [sp]; 
  retf
  .endp    

//*****************************************************************************
// Function    : F_ISR_Event_Service
// Description : None
// Destory     : 
// Parameter   : None
// Return      : None
// Note        : None
//*****************************************************************************   
_ISR_Event_Service:    .proc
F_ISR_Event_Service:
  push R1, BP to [sp];

  R1 = [D_IO_EVENT_NUM];
  jz ?L_ISR_Event_Service_End;
  
  R1 = [R_DutyCounter];
  R1 += 1;
  [R_DutyCounter] = R1;
  CMP R1, [D_SW_PWM_LEVEL];
  jb ?L_SW_PWM_Process;
  [R_DutyCounter] = R1 - R1;
  
?L_SW_PWM_Process:  
  R1 = 0;
  R2 = T_IO_Event;
  
?L_SW_PWM_ProcessLoop:
  R3 = R_DutyArray;
  R3 += R1;
  R3 = [R3];
  jmi ?L_Next_PWM;      // Check if the designated I/O of SW PWM is disabled. Bit15 = '1' => S/W PWM:Disable, Bit15 = '0' => S/W PWM:Enable 
  jz ?L_PWM_Low; 
  cmp R3, [R_DutyCounter];
  jb ?L_PWM_Low; 
  
  //
  // Set S/W PWM IO to output high
  //   
?L_PWM_High:     
  R3 = [R2++];
  R5 = [R2++];
  R4 = [R5 + C_PORT_BUF_IDX];
  setb R4, R3;
  [R5 + C_PORT_BUF_IDX] = R4;   
  jmp ?L_Next_PWM; 

  //
  // Set S/W PWM IO to output low
  // 
?L_PWM_Low:   
  R3 = [R2++];
  R5 = [R2++];
  R4 = [R5 + C_PORT_BUF_IDX];
  clrb R4, R3;
  [R5 + C_PORT_BUF_IDX] = R4;  
  
?L_Next_PWM:
  R1 += 1;
  cmp R1, [D_IO_EVENT_NUM]; 
  jb ?L_SW_PWM_ProcessLoop;

?L_ISR_Event_Service_End:
  pop R1, BP from [sp];
  retf
  .endp    
  
//*****************************************************************************
// Function    : F_IO_Event_Start
// Description : None
// Destory     : 
// Parameter   : None
// Return      : None
// Note        : None
//*****************************************************************************    
F_IO_Event_Start:    .proc
  push R1, BP to [sp];
  
  R1 = [D_IO_EVENT_NUM];
  jz ?L_IO_Event_Start_End;

  //
  // Disable S/W PWM
  //
  R1 = 0;  
?L_EvtEndSettingLoop:   
  R2 = R_DutyArray;
  R2 += R1;
  setb [R2], C_SW_PWM_EN_FLAG;  
   
  R1 += 1;
  cmp R1, [D_IO_EVENT_NUM];
  jb ?L_EvtEndSettingLoop 

  call F_USER_IoEvtStart;                        // Callback Function, Design by user. This function in the SACM_xxx_User.asm

?L_IO_Event_Start_End:
  pop R1, BP from [sp]; 
  retf
  .endp  

//*****************************************************************************
// Function    : F_IO_Event_End
// Description : None
// Destory     : 
// Parameter   : None
// Return      : None
// Note        : None
//*****************************************************************************    
F_IO_Event_End:    .proc    
  push R1, BP to [sp];

  R1 = [D_IO_EVENT_NUM];
  jz ?L_IO_Event_End; 
  //
  // Disable S/W PWM
  //
  R1 = 0;  
?L_EvtEndSettingLoop:   
  R2 = R_DutyArray;
  R2 += R1;
  setb [R2], C_SW_PWM_EN_FLAG;  
   
  R1 += 1;
  cmp R1, [D_IO_EVENT_NUM];
  jb ?L_EvtEndSettingLoop 

  call F_USER_IoEvtEnd;                          // Callback Function, Design by user. This function in the SACM_xxx_User.asm

?L_IO_Event_End:
  pop R1, BP from [sp];  
  retf
  .endp    
        
//*****************************************************************************
// Function    : F_IO_Event_Enable
// Description : None
// Destory     : 
// Parameter   : None
// Return      : None
// Note        : None
//*****************************************************************************    
_IO_Event_Enable:    .proc   
F_IO_Event_Enable:
  push R1 to [sp];
       
  R1 = [R_Event_Ctrl];
  R1 |= C_IO_EVENT_EN_FLAG;
  [R_Event_Ctrl] = R1;
       
  pop R1 from [sp];   
  retf;
  .endp
  
//*****************************************************************************
// Function    : F_IO_Event_Disable
// Description : None
// Destory     : 
// Parameter   : None
// Return      : None
// Note        : None
//*****************************************************************************    
_IO_Event_Disable:    .proc   
F_IO_Event_Disable:
  push R1 to [sp];
       
  R1 = [R_Event_Ctrl];
  R1 &= ~C_IO_EVENT_EN_FLAG;
  [R_Event_Ctrl] = R1;
       
  pop R1 from [sp];   
  retf;
  .endp  