/* Infrared Communication Last updated 1.11.01 */ #include "H8.h" #include "RCX_Interrupts.h" #include "SCI.h" #include "Timers.h" #include "IOPorts.h" #ifndef IR_H_DEFINED #define IR_H_DEFINED /* Infrared communication based on the serial communication interface and Timer 1. */ #define LongRange P4DR &= ~bit0 #define ShortRange P4DR |= bit0 #define Header 0x55 #define FF 0xff #define Zero 0x00 enum Tstate_t { Idle, HeaderSent, FFSent, ZeroSent, b3Sent, b2Sent, b1Sent, b0Sent, checkSent }; typedef enum Tstate_t Tstate; static volatile Tstate TransmitState; static struct { byte b3, b2, b1, b0; byte check; } TransmitBuffer; enum Rstate_t { LookingForHeader, HeaderReceived, FFReceived, ZeroReceived, b3Received, b2Received, b1Received, b0Received }; typedef enum Rstate_t Rstate; static volatile Rstate ReceiveState; static struct { byte empty; byte b3, b2, b1, b0; word TimeStamp; } ReceiveBuffer; /* Error = bit5 + bit4 + bit3 >> 3. Error = 0 means reception of data byte ok. Otherwise the errorvalue can be interpreted according to: bit3 , parity error, bit4 , frame error, bit5 , overrun error. */ static byte Error; void TXI ( void ) /* Transmit Data Register Ready for next byte */ { switch ( TransmitState ) { case Idle: break; case HeaderSent: SCI_TDR = FF; SCI_SSR &= ~bit7; /* clear TDRE */ TransmitState = FFSent; break; case FFSent: SCI_TDR = Zero; SCI_SSR &= ~bit7; /* clear TDRE */ TransmitState = ZeroSent; break; case ZeroSent: SCI_TDR = TransmitBuffer.b3; SCI_SSR &= ~bit7; /* clear TDRE */ TransmitState = b3Sent; break; case b3Sent: SCI_TDR = TransmitBuffer.b2; SCI_SSR &= ~bit7; /* clear TDRE */ TransmitState = b2Sent; break; case b2Sent: SCI_TDR = TransmitBuffer.b1; SCI_SSR &= ~bit7; /* clear TDRE */ TransmitState = b1Sent; break; case b1Sent: SCI_TDR = TransmitBuffer.b0; SCI_SSR &= ~bit7; /* clear TDRE */ TransmitState = b0Sent; break; case b0Sent: SCI_TDR = TransmitBuffer.check; SCI_SSR &= ~bit7; /* clear TDRE */ TransmitState = checkSent; break; case checkSent: SCI_SCR_Saved &= ~bit7; /* Disable TXI */ break; } } void TEI ( void ) /* Last byte of message transmitted */ { TransmitState = Idle; SCI_SCR_Saved &= ~ bit2 ; /* Disable TEIE */ } static byte b, b3, b2, b1, b0, checktemp; static word time; void RXI ( void ) /* Receive Data Register Full */ { b = SCI_RDR; SCI_SSR &= ~bit6; /* clear Receive Data Register Full flag */ switch ( ReceiveState ) { case LookingForHeader: if ( b == Header ) { /* time = ; */ ReceiveState = HeaderReceived; } break; case HeaderReceived: if ( b == FF ) ReceiveState = FFReceived; else ReceiveState = LookingForHeader; break; case FFReceived: if ( b == Zero ) ReceiveState = ZeroReceived; else ReceiveState = LookingForHeader; break; case ZeroReceived: b3 = b; checktemp = b; ReceiveState = b3Received; break; case b3Received: b2 = b; checktemp ^= b; ReceiveState = b2Received; break; case b2Received: b1 = b; checktemp ^= b; ReceiveState = b1Received; break; case b1Received: b0 = b; checktemp ^= b; ReceiveState = b0Received; break; case b0Received: if ( b == checktemp ) { ReceiveBuffer.empty = FALSE; ReceiveBuffer.b3 = b3; ReceiveBuffer.b2 = b2; ReceiveBuffer.b1 = b1; ReceiveBuffer.b0 = b0; ReceiveBuffer.TimeStamp = time; } ReceiveState = LookingForHeader; break; } } void ERI ( void ) /* Overrun, Frame or Parity Error */ { Error = ( SCI_SSR & ( bit5 | bit4 | bit3 ) ) >> 3; /* Clear Receive Data Register Full and error flags */ SCI_SSR &= ~( bit6 | bit5 | bit4 | bit3 ); TransmitState = Idle; ReceiveState = LookingForHeader; SCI_SCR_Saved &= ~bit7; /* Disable TXI */ SCI_SCR_Saved &= ~bit2; /* Disable TEIE */ } /* Interrupt handlers */ #define SaveRegisters asm("push r0"); \ asm("push r1"); \ asm("push r2"); \ asm("push r3"); \ asm("push r4"); \ asm("push r5") #define RestoreRegisters asm("pop r5"); \ asm("pop r4"); \ asm("pop r3"); \ asm("pop r2"); \ asm("pop r1"); \ asm("pop r0") void TXIHandler ( void ) { SaveRegisters; DisableSCI; Enable; TXI(); Disable; EnableSCI; RestoreRegisters; } void TEIHandler ( void ) { SaveRegisters; DisableSCI; Enable; TEI(); Disable; EnableSCI; RestoreRegisters; } void RXIHandler ( void ) { SaveRegisters; DisableSCI; Enable; RXI(); Disable; EnableSCI; RestoreRegisters; } void ERIHandler ( void ) { SaveRegisters; DisableSCI; Enable; ERI(); Disable; EnableSCI; RestoreRegisters; } /* Interrupt based transmit and receive routines */ #define Await( B ) { i = 0; \ while ( ! ( B ) ) { \ Enable; \ Nop; \ BusyPauseMS(20); \ i++; \ if ( i > 4 ) return FALSE; \ Disable; \ } \ } /* Transmit a word on the Infrared Transmitter */ byte IRTransmit ( word m1, word m0 ) { byte result; uint16 i; Disable; /* Await IR idle */ Await( ( TransmitState == Idle ) && ( ReceiveState == LookingForHeader ) ); /* Turn on long range */ LongRange; /* Enter word into TransmitBuffer */ TransmitBuffer.b3 = ( (m1>>8) & 0x00ff ); TransmitBuffer.b2 = ( m1 & 0x00ff ); TransmitBuffer.check = ( (m1>>8) & 0x00ff ) ^ ( m1 & 0x00ff ); TransmitBuffer.b1 = ( (m0>>8) & 0x00ff ); TransmitBuffer.b0 = ( m0 & 0x00ff ); TransmitBuffer.check^= ( (m0>>8) & 0x00ff ) ^ ( m0 & 0x00ff ); /* Transmit first byte of message and reset Error */ SCI_TDR = Header; SCI_SSR &= ~bit7; /* Clear TDRE flag and hence TEND flag */ SCI_SCR |= ( bit7 | bit2 ); /* Enable TXI and TEI */ TransmitState = HeaderSent; Error = 0; /* Await IR idle */ Await( ( TransmitState == Idle ) && ( ReceiveState == LookingForHeader ) ); /* Turn on short range */ ShortRange; /* Set result according to Error and words in ReceiveBuffer */ ReceiveBuffer.empty = TRUE; if ( Error != 0 ) result = FALSE; else result = ( m1 == ( ( ReceiveBuffer.b3 << 8 ) + ReceiveBuffer.b2 ) ) && ( m0 == ( ( ReceiveBuffer.b1 << 8 ) + ReceiveBuffer.b0 ) ); Enable; return result; } /* Receive from the Infrared Receiver, returns the word received or a 0 if no word has been received. Also returned is a timestamp. */ byte IRReceive ( word * m1, word * m0, word * Time ) { byte result; Disable; if ( ReceiveBuffer.empty ) { result = FALSE; } else { result = TRUE; ReceiveBuffer.empty = TRUE; * m1 = ( ReceiveBuffer.b3 << 8 ) + ReceiveBuffer.b2; * m0 = ( ReceiveBuffer.b1 << 8 ) + ReceiveBuffer.b0; * Time = ReceiveBuffer.TimeStamp; } Enable; return result; } /* Transmit and receive based on busy waiting */ void IRBusyTransmit( byte b ) { /* Figure 11-5, page 182 */ while ( ! ( SCI_SSR & bit7 ) ) ; SCI_TDR = b; SCI_SSR &= ~bit7; /* clear Transmit Data Register Empty */ } byte IRBusyReceive( void ) { /* Figure 11-7, page 184 */ /* Wait for Receive Register Full or error during reception */ while ( ( ! ( SCI_SSR & bit6 ) ) && ( ! ( SCI_SSR & ( bit4 | bit3 ) ) ) ) ; Error = ( SCI_SSR & ( bit5 | bit4 | bit3 ) ) >> 3; /* clear error bits and Receive Data Register Full */ SCI_SSR &= ~( bit6 | bit5 | bit4 | bit3 ); return ( SCI_RDR ); } void IREnableInterrupts( void ) { TXI_Interrupt_Handler = TXIHandler; TEI_Interrupt_Handler = TEIHandler; RXI_Interrupt_Handler = RXIHandler; ERI_Interrupt_Handler = ERIHandler; SCI_SCR |= bit6; /* Enable RXI */ } void IRDisableInterrupts( void ) { SCI_SCR &= ~( bit7 | bit6 | bit2 ); /* Disable all interrupts */ } void IRInit( void ) { TransmitState = Idle; ReceiveState = LookingForHeader; ReceiveBuffer.empty = TRUE; Error = 0; /* Initialize Timer 1 */ T1_TCR = ( bit3 | bit0 ); /* Timer cleared on compare-match A, internal clock rate 0.5 usec */ T1_TCSR = ( bit1 | bit0 ); /* Toggle on compare-match A, Port 6, pin 7 set to output */ T1_TCORA = 26; /* Toggle every 26*0.5=13 usec, freq. 38.5 kHz */ /* Initialize Port4, pin 0 as output and set it to short range */ P4DDR_ROM |= bit0; P4DDR = P4DDR_ROM; ShortRange; /* Initialize SCI , Figure 11-4, page 181 */ /* Disable interrupts, disable transmit and receive, internal clock and clock signal not output */ SCI_SCR = 0; /* Asynchronous communication, 8 bit data, odd parity, one stop bit, internal clock source = 16 MHz */ SCI_SMR = ( bit5 | bit4 ); /* Bit rate 2400 bit/sec, Table 11-3, page 174 */ SCI_BRR = 207; /* Enable transmit and receive */ SCI_SCR |= ( bit5 | bit4 ); } void IRClose( void ) { /* Disable interrupts and transmit/receive */ SCI_SCR = 0; /* Disable Timer 1 carrier and IR long range*/ } #endif /* IR_H_DEFINED */