//
// Date init       14.12.2004
//
// Revision date   $Date:: 19-02-09 18:51                                    $
//
// Filename        $Workfile:: d_lowspeed.r                                  $
//
// Version         $Revision:: 4                                             $
//
// Archive         $Archive:: /LMS2006/Sys01/Main_V02/Firmware/Source/d_lows $
//
// Platform        C
//

#ifdef    SAM7S256

#if       defined (PROTOTYPE_PCB_3) || (PROTOTYPE_PCB_4)

#define   CHANNEL_ONE_CLK				AT91C_PIO_PA23 /* PA23 is Clk */
#define   CHANNEL_ONE_DATA				AT91C_PIO_PA18 /* PA18 is Data */

#define   CHANNEL_TWO_CLK				AT91C_PIO_PA28 /* PA28 is Clk */
#define   CHANNEL_TWO_DATA				AT91C_PIO_PA19 /* PA19 is Data */

#define   CHANNEL_THREE_CLK				AT91C_PIO_PA29 /* PA29 is Clk */
#define   CHANNEL_THREE_DATA			AT91C_PIO_PA20 /* PA20 is Data */

#define   CHANNEL_FOUR_CLK				AT91C_PIO_PA30 /* PA30 is Clk */
#define   CHANNEL_FOUR_DATA				AT91C_PIO_PA2 /* PA2 is Data */

#else

#define   CHANNEL_ONE_CLK				AT91C_PIO_PA28 /* PA28 is Clk */
#define   CHANNEL_ONE_DATA				AT91C_PIO_PA20 /* PA20 is Data */

#endif

typedef   struct
{
  UWORD MaskBit;
  UBYTE ChannelState;
  UBYTE TxState;
  UBYTE RxState;
  UBYTE ReStartState;
  UBYTE TxByteCnt;
  UBYTE RxByteCnt;
  UBYTE *pComOutBuffer;
  UBYTE *pComInBuffer;
  UBYTE AckStatus;
  UBYTE RxBitCnt;
  UBYTE ReStartBit;
  UBYTE ComDeviceAddress;
  UBYTE RxWaitCnt;
  UBYTE ClkStatus;
}LOWSPEEDPARAMETERS;

static LOWSPEEDPARAMETERS LowSpeedData[4];

__ramdata
ULONG DATA_PINS[4] = {CHANNEL_ONE_DATA, CHANNEL_TWO_DATA, CHANNEL_THREE_DATA, CHANNEL_FOUR_DATA};
__ramdata
ULONG CLK_PINS[4] = {CHANNEL_ONE_CLK, CHANNEL_TWO_CLK, CHANNEL_THREE_CLK, CHANNEL_FOUR_CLK};

#define   LOWSPEED_CHANNEL1	 0
#define   LOWSPEED_CHANNEL2	 1
#define   LOWSPEED_CHANNEL3	 2
#define   LOWSPEED_CHANNEL4	 3
#define   NO_OF_LOWSPEED_COM_CHANNEL	4

#define   MASK_BIT_8		 0x80

#define   PIO_INQ            0x04

//Used for variable ChannelState
#define   LOWSPEED_IDLE		         0x00
#define   LOWSPEED_TX_STOP_BIT		 0x01
#define   LOWSPEED_TRANSMITTING      0x02
#define   LOWSPEED_RECEIVING		 0x04
#define   LOWSPEED_TEST_WAIT_STATE   0x08
#define   LOWSPEED_RESTART_CONDITION 0x10
#define   LOWSPEED_WAIT_BEFORE_RX    0x20

//Used for variable TxState
#define   TX_IDLE					 0x00
#define   TX_DATA_MORE_DATA			 0x01
#define   TX_DATA_CLK_HIGH           0x02
#define   TX_EVALUATE_ACK_CLK_HIGH   0x03
#define   TX_DATA_READ_ACK_CLK_LOW   0x04
#define   TX_DATA_CLK_LOW            0x05
#define   TX_ACK_EVALUATED_CLK_LOW   0x06

//Used for variable RxState
#define   RX_IDLE					 0x00
#define   RX_START_BIT_CLK_HIGH		 0x01
#define   RX_DATA_CLK_HIGH           0x02
#define   RX_ACK_TX_CLK_HIGH         0x03
#define   RX_DATA_CLK_LOW			 0x04
#define   RX_DONE_OR_NOT_CLK_LOW     0x05

//Used for variable ReStart
#define   RESTART_STATE_IDLE		 0x00
#define   RESTART_STATE_ONE			 0x01
#define   RESTART_STATE_TWO			 0x02
#define   RESTART_STATE_THREE   	 0x03
#define   RESTART_STATE_FOUR		 0x04
#define   RESTART_STATE_FIVE		 0x05
#define   RESTART_STATE_SIX 		 0x06
#define   RESTART_STATE_SEVEN		 0x07

#define   LOWSpeedTxInit                {\
                                          LowSpeedData[LOWSPEED_CHANNEL1].ChannelState = 0;\
                                          LowSpeedData[LOWSPEED_CHANNEL2].ChannelState = 0;\
                                          LowSpeedData[LOWSPEED_CHANNEL3].ChannelState = 0;\
                                          LowSpeedData[LOWSPEED_CHANNEL4].ChannelState = 0;\
                                        }

#define   LOWSpeedTimerInit             {\
                                          *AT91C_PMC_PCER       = 0x400;					/* Enable clock for PWM, PID10*/\
										  *AT91C_PWMC_MR	    = 0x01;						/* CLKA is output from prescaler */\
										  *AT91C_PWMC_MR	   |= 0x600;					/* Prescaler MCK divided with 64 */\
										  *AT91C_PWMC_CH0_CMR   = 0x06;						/* Channel 0 uses MCK divided by 64 */\
										  *AT91C_PWMC_CH0_CMR  &= 0xFFFFFEFF;				/* Left alignment on periode */\
										  *AT91C_PWMC_CH0_CPRDR = 0x20;						/* Set to 39 => 52uSecondes interrupt */\
										  *AT91C_PWMC_IDR	    = AT91C_PWMC_CHID0;			/* Disable interrupt for PWM output channel 0 */\
										  *AT91C_AIC_IDCR       = 0x400;					/* Disable AIC intterupt on ID10 PWM */\
                                           AT91C_AIC_SVR[10]    = (unsigned int)LowSpeedPwmIrqHandler;\
                                           AT91C_AIC_SMR[10]    = 0x01;						/* Enable trigger on level */\
                                          *AT91C_AIC_ICCR       = 0x400;					/* Clear interrupt register PID10*/\
										  *AT91C_PWMC_IER		= AT91C_PWMC_CHID0;			/* Enable interrupt for PWM output channel 0 */\
										  *AT91C_AIC_IECR       = 0x400;					/* Enable interrupt from PWM */\
										}

#define   LOWSpeedExit

#define   ENABLEDebugOutput				{\
                                          *AT91C_PIOA_PER   = AT91C_PIO_PA29; /* Enable PIO on PA029 */\
                                          *AT91C_PIOA_OER   = AT91C_PIO_PA29; /* PA029 set to Output  */\
                                          *AT91C_PIOA_CODR	= 0x20000000;\
                                        }

#define   SETDebugOutputHigh			*AT91C_PIOA_SODR	= 0x20000000

#define   SETDebugOutputLow				*AT91C_PIOA_CODR	= 0x20000000


#define SETClkLow(ChannelNr)  {\
  *AT91C_PIOA_CODR	= CLK_PINS[ChannelNr];\
  LowSpeedData[ChannelNr].ClkStatus = 0;\
}

#define SETClkHigh(ChannelNr)  {\
  *AT91C_PIOA_SODR = CLK_PINS[ChannelNr];\
  LowSpeedData[ChannelNr].ClkStatus = 1;\
}

#define SETDataLow(ChannelNr)  {\
  *AT91C_PIOA_CODR = DATA_PINS[ChannelNr];\
}

#define SETDataHigh(ChannelNr)  {\
  *AT91C_PIOA_SODR = DATA_PINS[ChannelNr];\
}

#define SETDataToInput(ChannelNr)  {\
  *AT91C_PIOA_ODR  = DATA_PINS[ChannelNr];\
}


#define SETDataToOutput(ChannelNr)  {\
  *AT91C_PIOA_OER  = DATA_PINS[ChannelNr];\
}

#define GetClkPinLevel(ChannelNr) (*AT91C_PIOA_PDSR & CLK_PINS[ChannelNr])
#define GetDataPinLevel(ChannelNr)	(*AT91C_PIOA_PDSR & DATA_PINS[ChannelNr])

#define   ENABLEPWMTimerForLowCom       {\
                                          *AT91C_PWMC_ENA		= AT91C_PWMC_CHID0;			/* Enable PWM output channel 0 */\
										}

#define    DISABLEPWMTimerForLowCom		{\
                                          *AT91C_PWMC_DIS	 = AT91C_PWMC_CHID0;			/* Disable PWM output channel 0 */\
										}
										
#define    OLD_DISABLEPWMTimerForLowCom	{\
										  *AT91C_PWMC_DIS	 = AT91C_PWMC_CHID0;			/* Disable PWM output channel 0 */\
                                          *AT91C_PWMC_IDR	 = AT91C_PWMC_CHID0;			/* Disable interrupt from PWM output channel 0 */\
										  *AT91C_AIC_IDCR    = 0x400;						/* Disable Irq from PID10 */\
                                          *AT91C_AIC_ICCR    = 0x400;						/* Clear interrupt register PID10*/\
                                          *AT91C_PMC_PCDR    = 0x400;						/* Disable clock for PWM, PID10*/\
										}

__ramfunc void LowSpeedPwmIrqHandler(void)
{
  ULONG TestVar;
  ULONG PinStatus;
  UBYTE ChannelNr;

  TestVar = *AT91C_PWMC_ISR;
  TestVar = TestVar;
  PinStatus = *AT91C_PIOA_PDSR;

  for (ChannelNr = 0; ChannelNr < NO_OF_LOWSPEED_COM_CHANNEL; ChannelNr++)
  {
    if (((LowSpeedData[ChannelNr].ClkStatus == 1) && (PinStatus & CLK_PINS[ChannelNr])) || (((LowSpeedData[ChannelNr].ClkStatus == 0) && (!(PinStatus & CLK_PINS[ChannelNr])))))
    {
      switch(LowSpeedData[ChannelNr].ChannelState)
      {
        case LOWSPEED_IDLE:
        {
        }
        break;

        case LOWSPEED_TX_STOP_BIT:
        {
          SETDataHigh(ChannelNr);
          LowSpeedData[ChannelNr].ChannelState = LOWSPEED_IDLE;                                     //Now we have send a STOP sequence, disable this channel
        }
        break;

        case LOWSPEED_TRANSMITTING:
        {
          switch(LowSpeedData[ChannelNr].TxState)
          {
            case TX_DATA_MORE_DATA:
            {
              PinStatus |= CLK_PINS[ChannelNr];
              LowSpeedData[ChannelNr].TxState = TX_DATA_CLK_HIGH;
            }
            break;

            case TX_DATA_CLK_HIGH:
            {
              SETClkLow(ChannelNr);
              if (LowSpeedData[ChannelNr].MaskBit == 0)     				                           //Is Byte Done, then we need a ack from receiver
            {
              SETDataToInput(ChannelNr);                                                             //Set datapin to input
              LowSpeedData[ChannelNr].TxState = TX_DATA_READ_ACK_CLK_LOW;
            }
            else
            {
              if (*LowSpeedData[ChannelNr].pComOutBuffer & LowSpeedData[ChannelNr].MaskBit)          //Setup data pin in relation to the data
              {
	            SETDataHigh(ChannelNr);       						                               //Set data output high
              }
	          else
              {
	            SETDataLow(ChannelNr);                                                               //Set data output low
              }
              LowSpeedData[ChannelNr].TxState = TX_DATA_CLK_LOW;
            }
          }
          break;

          case TX_EVALUATE_ACK_CLK_HIGH:
          {
            SETClkLow(ChannelNr);
            if (LowSpeedData[ChannelNr].AckStatus == 1)	
	        {
	          LowSpeedData[ChannelNr].TxByteCnt--;
	          if (LowSpeedData[ChannelNr].TxByteCnt > 0)	        		    			   //Here initialise to send next byte
	          {
	            LowSpeedData[ChannelNr].MaskBit = MASK_BIT_8;
	            LowSpeedData[ChannelNr].pComOutBuffer++;
	          }
	          LowSpeedData[ChannelNr].TxState = TX_ACK_EVALUATED_CLK_LOW;                    //Received ack, now make a stop sequence or send next byte
	        }
	        else
	        { //Data communication error !
	          LowSpeedData[ChannelNr].TxByteCnt = 0;
	          SETClkHigh(ChannelNr);
              LowSpeedData[ChannelNr].ChannelState = LOWSPEED_TX_STOP_BIT;                     //Received ack, now make a stop sequence or send next byte.
	        }
          }
          break;

          case TX_DATA_READ_ACK_CLK_LOW:
          {
            if (!(PinStatus & DATA_PINS[ChannelNr]))
	        {
	          LowSpeedData[ChannelNr].AckStatus = 1;										//Read ack signal from receiver
	        }	        	        	
	        SETDataToOutput(ChannelNr);
	        SETDataLow(ChannelNr);
	        LowSpeedData[ChannelNr].TxState = TX_EVALUATE_ACK_CLK_HIGH;
	        SETClkHigh(ChannelNr);
          }
          break;

          case TX_DATA_CLK_LOW:
          {
            LowSpeedData[ChannelNr].MaskBit = LowSpeedData[ChannelNr].MaskBit >> 1;			//Get ready for the next bit which should be clk out next time
            SETClkHigh(ChannelNr);															//Clk goes high = The reciever reads the data
            LowSpeedData[ChannelNr].TxState = TX_DATA_CLK_HIGH;
          }
          break;

          case TX_ACK_EVALUATED_CLK_LOW:
          {
            if (LowSpeedData[ChannelNr].MaskBit != 0)
            {
              LowSpeedData[ChannelNr].TxState = TX_DATA_MORE_DATA;
            }
            else
            {
              if (LowSpeedData[ChannelNr].ReStartBit != 0)
              {
                LowSpeedData[ChannelNr].ChannelState = LOWSPEED_RESTART_CONDITION;
                LowSpeedData[ChannelNr].ReStartState = RESTART_STATE_ONE;
                SETDataLow(ChannelNr);
                SETClkHigh(ChannelNr);                                                         //Clk goes high = The reciever reads the data
              }
              else
              {
                if (LowSpeedData[ChannelNr].RxByteCnt != 0)
                {
                  LowSpeedData[ChannelNr].ChannelState = LOWSPEED_WAIT_BEFORE_RX;
                }
                else
                {
                  LowSpeedData[ChannelNr].ChannelState = LOWSPEED_TX_STOP_BIT;
                  SETClkHigh(ChannelNr);                                                         //Clk goes high = The reciever reads the data
                }
              }
              LowSpeedData[ChannelNr].TxState = TX_IDLE;
            }
          }
          break;
        }
      }
      break;

      case LOWSPEED_RESTART_CONDITION:
      {
        switch(LowSpeedData[ChannelNr].ReStartState)
        {
          case RESTART_STATE_ONE:
          {
            LowSpeedData[ChannelNr].ReStartState = RESTART_STATE_TWO;
          }
          break;

          case RESTART_STATE_TWO:
          {
            SETDataHigh(ChannelNr);
            LowSpeedData[ChannelNr].ReStartState = RESTART_STATE_THREE;
          }
          break;

          case RESTART_STATE_THREE:
          {
            SETClkLow(ChannelNr);
            LowSpeedData[ChannelNr].ReStartState = RESTART_STATE_FOUR;
          }
          break;

          case RESTART_STATE_FOUR:
          {
            SETClkHigh(ChannelNr);
            LowSpeedData[ChannelNr].ReStartState = RESTART_STATE_FIVE;
          }
          break;

          case RESTART_STATE_FIVE:
          {
            SETDataLow(ChannelNr);
            LowSpeedData[ChannelNr].ReStartState = RESTART_STATE_SIX;
          }
          break;

          case RESTART_STATE_SIX:
          {
            LowSpeedData[ChannelNr].ReStartState = RESTART_STATE_SEVEN;
          }
          break;

          case RESTART_STATE_SEVEN:
          {
            SETClkLow(ChannelNr);
            LowSpeedData[ChannelNr].ReStartState = RESTART_STATE_IDLE;
            LowSpeedData[ChannelNr].ReStartBit = 0;
            LowSpeedData[ChannelNr].pComOutBuffer = &LowSpeedData[ChannelNr].ComDeviceAddress;
            *LowSpeedData[ChannelNr].pComOutBuffer += 0x01;
			LowSpeedData[ChannelNr].ChannelState = LOWSPEED_TRANSMITTING;
			LowSpeedData[ChannelNr].MaskBit = MASK_BIT_8;
			LowSpeedData[ChannelNr].TxByteCnt = 0x01;
			LowSpeedData[ChannelNr].TxState = TX_DATA_CLK_HIGH;
			LowSpeedData[ChannelNr].AckStatus = 0;
          }
          break;
        }
      }
      break;

      case LOWSPEED_WAIT_BEFORE_RX:
      {
        LowSpeedData[ChannelNr].RxWaitCnt++;
        if (LowSpeedData[ChannelNr].RxWaitCnt > 5)
        {
          LowSpeedData[ChannelNr].ChannelState = LOWSPEED_RECEIVING;
          SETDataToInput(ChannelNr);
        }
      }
      break;

      case LOWSPEED_RECEIVING:
      {
        switch(LowSpeedData[ChannelNr].RxState)
        {
          case RX_START_BIT_CLK_HIGH:
          {
            SETClkLow(ChannelNr);
            LowSpeedData[ChannelNr].RxState = RX_DATA_CLK_LOW;
          }
          break;

          case RX_DATA_CLK_HIGH:
          {
            LowSpeedData[ChannelNr].RxBitCnt++;
            if(PinStatus & DATA_PINS[ChannelNr])
            {
              *LowSpeedData[ChannelNr].pComInBuffer |= 0x01;
            }
            SETClkLow(ChannelNr);
            if (LowSpeedData[ChannelNr].RxBitCnt < 8)
            {
              *LowSpeedData[ChannelNr].pComInBuffer = *LowSpeedData[ChannelNr].pComInBuffer << 1;
            }
            else
            {
              if (LowSpeedData[ChannelNr].RxByteCnt > 1)
              {
                SETDataToOutput(ChannelNr);
                SETDataLow(ChannelNr);
              }
            }
            LowSpeedData[ChannelNr].RxState = RX_DATA_CLK_LOW;
          }
          break;

          case RX_ACK_TX_CLK_HIGH:
          {
            SETClkLow(ChannelNr);
            SETDataToInput(ChannelNr);
            LowSpeedData[ChannelNr].pComInBuffer++;
		    LowSpeedData[ChannelNr].RxByteCnt--;
		    LowSpeedData[ChannelNr].RxBitCnt = 0;
	        LowSpeedData[ChannelNr].RxState = RX_DONE_OR_NOT_CLK_LOW;
          }
          break;

          case RX_DATA_CLK_LOW:
          {
            SETClkHigh(ChannelNr);
            if (LowSpeedData[ChannelNr].RxBitCnt == 8)
            {
              LowSpeedData[ChannelNr].RxState = RX_ACK_TX_CLK_HIGH;
            }
            else
            {
              LowSpeedData[ChannelNr].RxState = RX_DATA_CLK_HIGH;
            }
          }
          break;

          case RX_DONE_OR_NOT_CLK_LOW:
          {
            if (LowSpeedData[ChannelNr].RxByteCnt == 0)
            {
              LowSpeedData[ChannelNr].ChannelState = LOWSPEED_IDLE;
              LowSpeedData[ChannelNr].RxState = RX_IDLE;
              SETClkHigh(ChannelNr);
            }
            else
            {
              LowSpeedData[ChannelNr].RxState = RX_START_BIT_CLK_HIGH;
            }
          }
          break;
        }
      }
      break;

      default:
      break;
      }
    }
    else
    {

      if (LOWSPEED_IDLE != LowSpeedData[ChannelNr].ChannelState)
      {
        //Data communication error !
        LowSpeedData[ChannelNr].TxByteCnt = 0;
        SETClkHigh(ChannelNr);
        LowSpeedData[ChannelNr].ChannelState = LOWSPEED_TX_STOP_BIT;
      }
    }
  }
}

#define ENABLETxPins(ChannelNumber)  {\
  ULONG Tmp = CLK_PINS[ChannelNumber] | DATA_PINS[ChannelNumber];\
  *AT91C_PIOA_PER   = Tmp; /* Enable PIO */\
  *AT91C_PIOA_PPUDR = Tmp; /* Disable Pull-up resistor  */\
  *AT91C_PIOA_ODR   = Tmp; /* PIO set to Input  */\
}

#define TxData(ChannelNumber, Status, DataOutBuffer, NumberOfByte) {\
  if ((GetDataPinLevel(ChannelNumber) && GetClkPinLevel(ChannelNumber)) && (LowSpeedData[ChannelNumber].ChannelState == LOWSPEED_IDLE))\
  {\
    ULONG Tmp = CLK_PINS[ChannelNumber] | DATA_PINS[ChannelNumber];\
    *AT91C_PIOA_PER   = Tmp; /* Enable PIO */\
    *AT91C_PIOA_OER   = Tmp; /* POI set to Output  */\
    *AT91C_PIOA_PPUDR = Tmp; /* Disable Pull-up resistor  */\
    SETClkHigh(ChannelNumber);\
    SETDataLow(ChannelNumber);\
    LowSpeedData[ChannelNumber].ClkStatus = 1;\
    LowSpeedData[ChannelNumber].pComOutBuffer = DataOutBuffer;\
    LowSpeedData[ChannelNumber].ComDeviceAddress = *LowSpeedData[ChannelNumber].pComOutBuffer;\
    LowSpeedData[ChannelNumber].MaskBit = MASK_BIT_8;\
    LowSpeedData[ChannelNumber].TxByteCnt = NumberOfByte;\
    LowSpeedData[ChannelNumber].TxState = TX_DATA_CLK_HIGH;\
    LowSpeedData[ChannelNumber].AckStatus = 0;\
    LowSpeedData[ChannelNumber].ChannelState = LOWSPEED_TRANSMITTING;\
    Status = 1;\
  }\
  else\
  {\
    Status = 0;\
  }\
}

#define RxData(ChannelNumber, DataInBuffer, RxBytes) {\
											           LowSpeedData[ChannelNumber].pComInBuffer = DataInBuffer;\
									                   LowSpeedData[ChannelNumber].RxBitCnt = 0;\
												       LowSpeedData[ChannelNumber].RxByteCnt = RxBytes;\
									                   LowSpeedData[ChannelNumber].RxState = RX_DATA_CLK_LOW;\
									                   LowSpeedData[ChannelNumber].ReStartBit = 1;\
									                   LowSpeedData[ChannelNumber].RxWaitCnt = 0;\
											         }
											
											
#define STATUSTxCom(ChannelNumber, Status)     {\
											     if (LowSpeedData[ChannelNumber].ChannelState != 0)\
											     {\
											       if ((LowSpeedData[ChannelNumber].TxByteCnt == 0) && (LowSpeedData[ChannelNumber].ChannelState != LOWSPEED_RESTART_CONDITION))\
											       {\
											         if (LowSpeedData[ChannelNumber].MaskBit == 0)\
											         {\
											           if (LowSpeedData[ChannelNumber].AckStatus == 1)\
											           {\
													     Status = 0x01;  /* TX SUCCESS  */\
											           }\
											           else\
											           {\
                                                                                                     Status = 0xFF; /* TX ERROR */\
											           }\
											         }\
											         else\
											         {\
											           Status = 0;\
											         }\
											       }\
											       else\
											       {\
											         Status = 0;\
											       }\
											     }\
											     else\
											     {\
											       if (LowSpeedData[ChannelNumber].RxByteCnt == 0)\
											       {\
											         if (LowSpeedData[ChannelNumber].AckStatus == 1)\
											         {\
													   Status = 0x01;  /* TX SUCCESS  */\
											         }\
											         else\
											         {\
											           Status = 0xFF; /* TX ERROR */\
											         }\
											       }\
											       else\
											       {\
											         Status = 0xFF; /* TX ERROR */\
											       }\
											     }\
											   }
											
#define STATUSRxCom(ChannelNumber, Status)     {\
                                                 if (LowSpeedData[ChannelNumber].ChannelState == LOWSPEED_IDLE)\
											     {\
											       if (LowSpeedData[ChannelNumber].RxByteCnt == 0)\
											       {\
											         Status = 0x01;  /* RX SUCCESS  */\
											       }\
											       else\
											       {\
											         Status = 0xFF; /* RX ERROR */\
											       }\
											     }\
											     else\
											     {\
											       Status = 0;\
											     }\
                                               }


#endif

#ifdef    PCWIN

#endif
