Remote Access Control


main.c

Go to the documentation of this file.
00001 // This file has been prepared for Doxygen automatic documentation generation.
00048 #include "common.h"
00049 #include "config.h"
00050 #include "aes.h"
00051 #include "cmac.h"
00052 #include "memory.h"
00053 #include "comms.h"
00054 #include "crc.h"
00055 
00056 
00057 
00059 #pragma vector = PCINT0_vect
00060 static __interrupt void pinChangeHandler(void)
00061 {
00062         COMMAND_CODE_TYPE lastButtonState;
00063         COMMAND_CODE_TYPE newButtonState;
00064         unsigned char equalCount = 0;
00065 
00066         lastButtonState = PINB & BUTTON_MASK;
00067         do {
00068                 __delay_cycles( 8000 ); // Allow for debounce and human slowness. Empirical value.
00069                 newButtonState = PINB & BUTTON_MASK;
00070                 if( newButtonState == lastButtonState ) {
00071                         ++equalCount;
00072                 } else {
00073                         equalCount = 0;
00074                         lastButtonState = newButtonState;
00075                 }
00076         } while( equalCount < 10 ); // 10 is empirical value.
00077 }
00078 
00079 
00080 
00081 #ifndef NOWDT
00083 #pragma vector = WDT_vect
00084 __interrupt void watchdogInterrupt(void)
00085 {
00086         // Do nothing. Just wake up.
00087 }
00088 #endif
00089 
00090 
00091 
00093 COMMAND_CODE_TYPE sleepAndGetCommand(void)
00094 {
00095         COMMAND_CODE_TYPE buttonState;
00096 
00097         // Enable Power Down Sleep Mode.
00098         MCUCR = (1<<SE) | (1<<SM1) | (0<<SM0);
00099 
00100         // Enable Pin Change Interrupt.
00101         __delay_cycles( 100 ); // Wait for RF TX ctrl pins to settle. Empirical value.
00102         GIFR |= (1<<PCIF);
00103         GIMSK |= (1<<PCIE);
00104 
00105         do {
00106 #ifndef NOWDT
00107                 // Restart watchdog if it timed out.
00108                 if( !(WDTCR & (1<<WDIE)) ) {
00109                         __watchdog_reset();
00110                         WDTCR |= (1<<WDIE);
00111                 }
00112 #endif
00113                 __sleep(); // Wait for Pin-Change Interrupt.
00114 
00115                 // Read pins and mask out unused inputs according pin change mask.
00116                 buttonState = PINB & BUTTON_MASK;
00117         } while( !buttonState );
00118 
00119         GIMSK &= ~(1<<PCIE); // Good practice to turn off interrupt.
00120 
00121         return buttonState;
00122 }
00123 
00124 
00125 
00126 
00128 void errorLoop( byte blinkCount )
00129 {
00130         // Initialize Watchdog Timer.
00131         __watchdog_reset();
00132         WDTCR = (1<<WDCE) | (1<<WDE);
00133         WDTCR = (1<<WDCE) | (1<<WDE) | (1<<WDP3) | (1<<WDP0);
00134         WDTCR |= (1<<WDTIF) | (1<<WDTIE);
00135 
00136         // Enable Power Down Sleep Mode.
00137         MCUCR = (1<<SE) | (1<<SM1) | (0<<SM0);
00138 
00139         // Start blinking.
00140         __enable_interrupt();
00141         DDRB = (1<<PB3);
00142         PORTB = (0<<PB3);
00143         for(;;) {
00144                 __sleep();
00145                 __watchdog_reset();
00146                 WDTCR |= (1<<WDTIE);
00147                 byte blinks;
00148                 for( blinks = 0; blinks < blinkCount; ++blinks ) {
00149                         PORTB = (1<<PB3);
00150                         __delay_cycles( (8000000/1000)*50 ); // 50ms
00151                         PORTB = (0<<PB3);
00152                         __delay_cycles( (8000000/1000)*50 ); // 50ms
00153                 }
00154         }
00155 }
00156 
00157 
00158 
00160 void transmitCommandMessage( COMMAND_CODE_TYPE command )
00161 {
00162         const byte preburst = 0xff;
00163         byte i;
00164 
00165         createMessage( command );
00166         startTransmission( &preburst, 1 );
00167         for( i = 0; i < PREBURST_BYTES-1; ++i ) {
00168                 waitForTransmission();
00169                 continueTransmission( &preburst, 1 );
00170         }
00171         waitForTransmission();
00172         continueTransmission( (const byte *)
00173                         &sharedBlock.messagePayload,
00174                         sizeof( struct MessagePayload ) );
00175         calcCMAC( (const byte *)
00176                         &sharedBlock.messagePayload.serialNo,
00177                         cryptoBlock );
00178         waitForTransmission();
00179         
00180         // Send MAC bytes and one extra byte to make sure all Manchester edges are recognized
00181         // at the receiver. Actually only one extra edge after the last MAC byte would be enough,
00182         // but it is more convenient to just add another byte in the transmission.
00183         cryptoBlock[ MAC_BYTES ] = 0x00; // Don't reveal more MAC bytes than necessary.
00184         continueTransmission( cryptoBlock, MAC_BYTES + 1 );
00185 
00186         startCounterUpdate();
00187         waitForTransmission();
00188         stopTransmission();
00189         waitForCounterUpdate();
00190 }
00191 
00192 
00193 
00195 void transmitTeachMessage( void )
00196 {
00197         const byte preburst = 0xff;
00198         byte i;
00199 
00200         calcKeySchedule( sharedKey );
00201         initCRC();
00202         startTransmission( &preburst, 1 );
00203         for( i = 0; i < PREBURST_BYTES-1; ++i ) {
00204                 waitForTransmission();
00205                 continueTransmission( &preburst, 1 );
00206         }
00207         waitForTransmission();
00208         continueTransmission( (const byte*)
00209                         &sharedBlock.messagePayload,
00210                         SERIAL_NO_BYTES + SEQ_COUNTER_BYTES + 1 );
00211         for( i = 0; i < SERIAL_NO_BYTES + SEQ_COUNTER_BYTES; ++i ) {
00212                 calcCRC( ((byte *) &sharedBlock.messagePayload.serialNo)[ i ] );
00213         }
00214         copyBytesFromEEPROM( cryptoBlock,
00215                         secretKey, BLOCK_SIZE );
00216         cipherLookup( cryptoBlock );
00217         waitForTransmission();
00218         continueTransmission( cryptoBlock, BLOCK_SIZE );
00219         for( i = 0; i < BLOCK_SIZE; ++i ) {
00220                 calcCRC( cryptoBlock[ i ] );
00221         }
00222 #if KEY_SIZE > BLOCK_SIZE
00223         copyBytesFromEEPROM( sharedBlock.cryptoBlock,
00224                         secretKey + BLOCK_SIZE,
00225                         KEY_SIZE - BLOCK_SIZE );
00226 #if KEY_SIZE < (2*BLOCK_SIZE)
00227 
00228         for( i = KEY_SIZE - BLOCK_SIZE; i < BLOCK_SIZE; ++i ) {
00229                 sharedBlock.cryptoBlock[ i ] = 0x00;
00230         }
00231 #endif
00232         cipherLookup( sharedBlock.cryptoBlock );
00233         waitForTransmission();
00234         continueTransmission( sharedBlock.cryptoBlock,
00235                         BLOCK_SIZE );
00236         for( i = 0; i < BLOCK_SIZE; ++i ) {
00237                 calcCRC( sharedBlock.cryptoBlock[ i ] );
00238         }
00239 #endif
00240 
00241         calcCRC( 0x00 );
00242         calcCRC( 0x00 );
00243         waitForTransmission();
00244         continueTransmission( CRCReg, 3 ); // Transmit one extra byte, see comment for MAC transmission in transmitCommandMessage(...).
00245         calcKeySchedule( secretKey );
00246         initializeMessage();
00247         waitForTransmission();
00248         stopTransmission();
00249 }
00250 
00251 
00252 
00254 void handleResetFlags( void )
00255 {
00256 #ifndef NOWDT
00257         static __no_init byte __eeprom watchdogResetCount; // Will be set to 0 or 0xff on first Power-up.
00258         if( watchdogResetCount == 0xff ) {
00259                 watchdogResetCount = 0x00;
00260         }
00261 #endif
00262 
00263         // Read and clear reset flags.
00264         byte resetFlags = MCUSR;
00265         MCUSR = 0x00;
00266 
00267         // Check for reset sources.
00268         if( resetFlags & ((1<<PORF)|(1<<EXTRF)) ) { // Power-on or External Reset?
00269 #ifndef NOWDT
00270                 watchdogResetCount = 0;
00271 #endif
00272         }
00273 #ifndef NOWDT
00274         if( resetFlags & (1<<WDRF) ) { // Watchdog Reset?
00275                 if( watchdogResetCount >= MAX_WATCHDOG_RESETS ) {
00276                         errorLoop( 2 );
00277                 } else {
00278                         ++watchdogResetCount;
00279                 }
00280         }
00281 #endif
00282 #ifndef NOBOD   
00283         if( resetFlags & (1<<BORF) ) { // Brown Out Reset?
00284                 errorLoop( 1 );
00285         }
00286 #endif
00287 }
00288 
00289 
00290 
00292 void setupPeripherals( void )
00293 {
00294 #ifndef NOWDT
00295         // Initialize Watchdog Timer.
00296         __watchdog_reset();
00297         WDTCR = (1<<WDCE) | (1<<WDE);
00298         WDTCR = (1<<WDCE) | (1<<WDE) | (1<<WDP3) | (1<<WDP0);
00299         WDTCR |= (1<<WDIF) | (1<<WDIE);
00300 #endif
00301 
00302         // Setup Pin-change input mask.
00303         PCMSK = BUTTON_MASK;
00304 
00305         // Setup IO ports.
00306         PORTB = (0<<PB0) |
00307                 (0<<PB1) |
00308                 (0<<PB2) |
00309                 (0<<PB3) |
00310                 (0<<PB4) |
00311                 (0<<PB5);
00312         DDRB |= (1<<PB4); // Transmitter Enable signal is output.
00313 
00314         // Turn off unused modules to save power/oomph.
00315         ACSR |= (1<<ACD);
00316         PRR = (1<<PRTIM1) | (1<<PRADC);
00317 
00318         // Enable Power Down Sleep Mode.
00319         MCUCR = (1<<SE) | (1<<SM1) | (0<<SM0);
00320 }
00321 
00322 
00323 
00324 void main(void)
00325 {
00326         handleResetFlags();
00327         setupPeripherals();
00328         initializeMessage();
00329         calcKeySchedule( secretKey );
00330         calcCMACSubkey( cryptoBlock );
00331         __enable_interrupt();
00332 
00333         for(;;) { // Loop for ever.
00334 
00335                 PORTB &= ~(1<<PB4); // Disable transmitter.
00336                 DDRB &= ~(1<<PB1); // PB1 back to input for button input.
00337 
00338                 COMMAND_CODE_TYPE command = sleepAndGetCommand();
00339 
00340                 PORTB |= (1<<PB4); // Enable transmitter.
00341                 DDRB |= (1<<PB1); // PB1 to output for both ASK and FSK.
00342 
00343                 // Allow time for transmitter to start up.
00344                 __delay_cycles( 8000000 / 1000 * 5 ); // 5ms, given in datasheet.
00345 
00346                 if( command != TEACH_COMMAND ) {
00347                         transmitCommandMessage( command );
00348                 } else {
00349                         transmitTeachMessage();
00350                 }
00351         }
00352 }
00353 
@DOC_TITLE@
Generated on Fri Aug 8 11:03:16 2008 for AVR411 Secure Rolling Code Algorithm (Transmitter) by doxygen 1.4.7