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 "timer.h"
00055 #include "crc.h"
00056 #include "radio.h"
00057 
00058 
00060 static volatile bool learnModeRequest = false;
00061 
00062 
00063 
00065 #pragma vector = LEARN_MODE_PCINT_VECT
00066 __interrupt void learnModeSwitchHandler(void)
00067 {
00068         // Only signal on falling edge.
00069         if( (LEARN_MODE_INPUT_REG & (1<<LEARN_MODE_INPUT_BIT)) == 0 ) {
00070                 learnModeRequest = true;
00071         }
00072 }
00073 
00074 
00075 
00077 #pragma vector = WDT_vect
00078 __interrupt void watchdogInterrupt(void)
00079 {
00080         // Do nothing. Just wake up.
00081 }
00082 
00083 
00084 
00086 void initCommand( void )
00087 {
00088         DDRC |= (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4);
00089         PORTC |= (0<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4);
00090 }
00091 
00092 
00093 
00095 void executeCommand( byte commandCode )
00096 {
00097         byte oldValue = PORTC;
00098         byte LEDMask = (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4);
00099         byte oldLEDs = oldValue & LEDMask;
00100 
00101         oldValue &= ~LEDMask;
00102 
00103         if( commandCode == (1<<1) ) {
00104                 PORTC = oldValue |
00105                                 ( ((oldLEDs << 1) | (oldLEDs >> 4)) & LEDMask );
00106         } else if( commandCode == (1<<2) ) {
00107                 PORTC = oldValue |
00108                                 ( ((oldLEDs >> 1) | (oldLEDs << 4)) & LEDMask );
00109         }
00110 }
00111 
00112 
00113 
00115 void setupLearnModeIO(void)
00116 {
00117         PCICR |= (1<<LEARN_MODE_PCINT_ENABLE_BIT);
00118         LEARN_MODE_PCINT_MASK_REG |= (1<<LEARN_MODE_PCINT_MASK_BIT);
00119         LEARN_MODE_INPUT_DDR &= ~(1<<LEARN_MODE_INPUT_BIT);
00120         LEARN_MODE_INPUT_PULLUP_REG |= (1<<LEARN_MODE_INPUT_BIT);
00121 
00122         LEARN_MODE_OUTPUT_DDR |= (1<<LEARN_MODE_OUTPUT_BIT);
00123         LEARN_MODE_OUTPUT_HIGH();
00124 }
00125 
00126 
00127 
00129 void learnMode(void)
00130 {
00131         LEARN_MODE_OUTPUT_LOW();
00132 
00133         startLongTimeout();
00134 
00135 #ifndef DONT_ERASE_TRANSMITTERS
00136         bool transmittersErasedYet = false;
00137         while( !longTimeout && (transmittersErasedYet == false || transmitterCount < MAX_TRANSMITTERS) ) {
00138 #else
00139         while( !longTimeout && transmitterCount < MAX_TRANSMITTERS) {
00140 #endif
00141                 // Restart watchdog if it timed out.
00142                 __watchdog_reset();
00143                 WDTCSR |= (1<<WDIE);
00144 
00145                 enableReception( sizeof( LearnMessage ) );
00146                 while( !messageComplete() && !receiverTimedOut() && !longTimeout ) {
00147                         // Restart watchdog if it timed out.
00148                         if( !(WDTCSR & (1<<WDIE)) ) {
00149                                 __watchdog_reset();
00150                                 WDTCSR |= (1<<WDIE);
00151                         }
00152                         __sleep();
00153                 }
00154 
00155                 if( messageComplete() ) {
00156                         initCRC();
00157                         byte i;
00158                         for( i = 0; i < sizeof( LearnMessage ); ++i ) {
00159                                 calcCRC( ( (byte *) &receiveBuffer.learnMessage )[ i ] );
00160                         }
00161                         if( (CRCReg[0] == 0) && (CRCReg[1] == 0) ) {
00162                                 LEARN_MODE_OUTPUT_HIGH();
00163                                 copyBytesFromEEPROM( tempKeyStorage, sharedKey, KEY_SIZE );
00164                                 prepareInvCipher( scheduleBuffer, tempKeyStorage );
00165                                 invCipher( receiveBuffer.learnMessage.secretKey,
00166                                                 scheduleBuffer );
00167 #if KEY_SIZE == 24 || KEY_SIZE == 32
00168                                 prepareInvCipher( scheduleBuffer, tempKeyStorage );
00169                                 invCipher( receiveBuffer.learnMessage.secretKey + BLOCK_SIZE,
00170                                                 scheduleBuffer );
00171 #endif
00172 #ifndef DONT_ERASE_TRANSMITTERS
00173                                 if( transmittersErasedYet == false ) {
00174                                         eraseTransmitters();
00175                                         transmittersErasedYet = true;
00176                                 }
00177 #endif
00178 
00179                                 transmitters[ transmitterCount ].serialNo =
00180                                         receiveBuffer.learnMessage.serialNo;
00181                                 transmitters[ transmitterCount ].lastCounterValue =
00182                                         receiveBuffer.learnMessage.lastCounterValue;
00183                                 copyBytesToEEPROM( transmitters[ transmitterCount ].secretKey,
00184                                                 receiveBuffer.learnMessage.secretKey, KEY_SIZE );
00185                                 ++transmitterCount;
00186                                 LEARN_MODE_OUTPUT_LOW();
00187 
00188                                 startLongTimeout();
00189                         }
00190                 }
00191         }
00192 
00193         stopTimer();
00194         LEARN_MODE_OUTPUT_HIGH();
00195 }
00196 
00197 
00198 
00199 
00200 
00202 void errorLoop( byte blinkCount )
00203 {
00204         // Initialize Watchdog Timer.
00205         __watchdog_reset();
00206         WDTCSR = (1<<WDCE) | (1<<WDE);
00207         WDTCSR = (1<<WDCE) | (1<<WDE) | (1<<WDP3) | (1<<WDP0);
00208         WDTCSR |= (1<<WDIF) | (1<<WDIE);
00209 
00210         // Enable Power Down Sleep Mode.
00211         SMCR = (0<<SM2) | (1<<SM1) | (0<<SM0) | (1<<SE);;
00212 
00213         // Start blinking.
00214         __enable_interrupt();
00215         LEARN_MODE_OUTPUT_DDR |= (1<<LEARN_MODE_OUTPUT_BIT);
00216         for(;;) {
00217                 __sleep();
00218                 __watchdog_reset();
00219                 WDTCSR |= (1<<WDIE);
00220                 byte blinks;
00221                 for( blinks = 0; blinks < blinkCount; ++blinks ) {
00222                         LEARN_MODE_OUTPUT_LOW();
00223                         __delay_cycles( (CPU_F/1000)*50 ); // 50ms
00224                         LEARN_MODE_OUTPUT_HIGH();
00225                         __delay_cycles( (CPU_F/1000)*50 ); // 50ms
00226                 }
00227         }
00228 }
00229 
00230 
00231 
00233 void handleResetFlags( void )
00234 {
00235         static __no_init byte __eeprom watchdogResetCount; // Will be set to 0 on first Power-up.
00236 
00237         // Read and clear reset flags.
00238         byte resetFlags = MCUSR;
00239         MCUSR = 0x00;
00240 
00241         // Check for reset sources.
00242         if( resetFlags & (1<<PORF) ) {
00243                 // Clear watchdog reset count on power on reset, e.g. battery change.
00244                 watchdogResetCount = 0;
00245         }
00246         if( resetFlags & (1<<WDRF) ) {
00247                 if( watchdogResetCount >= MAX_WATCHDOG_RESETS ) {
00248                         errorLoop( 1 );
00249                 } else {
00250                         ++watchdogResetCount;
00251                 }
00252         }
00253         // We don't handle Brown-out Resets specially.
00254 }
00255 
00256 
00257 
00259 void setupPeripherals( void )
00260 {
00261         // Initialize Watchdog Timer.
00262         __watchdog_reset();
00263         WDTCSR = (1<<WDCE) | (1<<WDE);
00264         WDTCSR = (1<<WDCE) | (1<<WDE) | (1<<WDP3) | (1<<WDP0);
00265         WDTCSR |= (1<<WDIF) | (1<<WDIE);
00266 
00267         // Turn off unused modules to save power/oomph.
00268         ACSR = (1<<ACD);
00269 // Disabling modules using PRR doesn't work with debugWIRE.
00270 //      PRR = (1<<PRTWI) | (1<<PRTIM2) | (1<<PRTIM0) | (0<<PRTIM1) |
00271 //              (1<<PRSPI) | (0<<PRUSART0) | (1<<PRADC);
00272 
00273         // Enable Idle Sleep Mode.
00274         SMCR = (0<<SM2) | (0<<SM1) | (0<<SM0) | (1<<SE);
00275 }
00276 
00277 
00278 
00279 void main( void )
00280 {
00281         handleResetFlags();
00282         __delay_cycles( 8000000 ); // Allow RF receiver to power up.
00283         if( !initReceiver() ) {
00284                 errorLoop( 3 );
00285         }
00286         setupPeripherals();
00287         setupLearnModeIO();
00288         initCommand();
00289         __enable_interrupt();
00290         
00291         for(;;) { // Loop forever.
00292                 // Wait for reception of serial number.
00293                 stopTimer(); // Save power while we wait for something to happen.
00294                 enableReception( sizeof( CommandMessage ) );
00295 
00296                 // Restart watchdog.
00297                 __watchdog_reset();
00298                 WDTCSR |= (1<<WDIE);
00299 
00300                 // Wait for reception, timeout or learn mode request.           
00301                 while( messageBytesReceived() < SERIAL_NO_BYTES &&
00302                                 !receiverTimedOut() &&
00303                                 !learnModeRequest) {
00304                         // If watchdog times out, restart it since there's nothing
00305                         // wrong now, and issue an OFF command to the RF receiver in
00306                         // case external RF noise woke it up.
00307                         if( !(WDTCSR & (1<<WDIE)) ) {
00308                                 __watchdog_reset();
00309                                 WDTCSR |= (1<<WDIE);
00310                                 rx_WriteOFF( false );
00311                         }
00312                         __sleep();
00313                 }
00314 
00315                 // Enter learn mode if button is pressed. Ignore any received messages.
00316                 if( learnModeRequest ) {
00317                         learnMode();
00318                         learnModeRequest = false;
00319                         continue;
00320                 }
00321 
00322                 if( receiverTimedOut() ) {
00323                         continue; // Restart loop on timeout.
00324                 }
00325 
00326                 // Search for transmitter serial number.
00327                 byte transmitterIdx = 0;
00328                 TransmitterInfo __eeprom * transmitter = transmitters;
00329                 bool found = false;
00330                 while( transmitterIdx < transmitterCount && !found) {
00331                         if( receiveBuffer.commandMessage.serialNo ==
00332                                         transmitter->serialNo ) {
00333                                 found = true;
00334                         } else {
00335                                 ++transmitterIdx;
00336                                 ++transmitter;
00337                         }
00338                 }
00339 
00340                 // Invalid serial numer => ignore rest of transmission and restart loop.
00341                 if( !found ) {
00342                         while( !messageComplete() && !receiverTimedOut() ) {
00343                                 __sleep();
00344                         }
00345 
00346                         continue;
00347                 }
00348                 
00349                 // Get transmitter's secret key from table.
00350                 copyBytesFromEEPROM( tempKeyStorage,
00351                                 transmitter->secretKey,
00352                                 KEY_SIZE );
00353 
00354                 // Calculate subkey for CMAC generation.
00355                 calcCMACSubkey( CMACSubkey, scheduleBuffer,
00356                                 tempKeyStorage );
00357 
00358                 // Wait for reception of counter value.
00359                 while( messageBytesReceived() <
00360                                 SERIAL_NO_BYTES + SEQ_COUNTER_BYTES &&
00361                                 !receiverTimedOut() ) {
00362                         __sleep();
00363                 }
00364 
00365                 if( receiverTimedOut() ) {
00366                         continue; // Restart loop on timeout.
00367                 }
00368 
00369                 // If counter value outside window, ignore rest of transmission and restart loop.
00370                 if( receiveBuffer.commandMessage.counterValue -
00371                                 (transmitter->lastCounterValue + 1) >=
00372                                 WINDOW_SIZE ) {
00373                         while( !messageComplete() && !receiverTimedOut() ) {
00374                                 __sleep();
00375                         }
00376 
00377                         continue;
00378                 }
00379 
00380                 // Wait for whole message except MAC.
00381                 while( messageBytesReceived() <
00382                                 SERIAL_NO_BYTES + SEQ_COUNTER_BYTES +
00383                                 COMMAND_CODE_BYTES &&
00384                                 !receiverTimedOut() ) {
00385                         __sleep();
00386                 }
00387 
00388                 if( receiverTimedOut() ) {
00389                         continue; // Restart loop on timeout.
00390                 }
00391 
00392                 // Calculate CMAC.
00393                 calcCMAC( (const byte *) &receiveBuffer.commandMessage.serialNo,
00394                                 CMACSubkey,
00395                                 scheduleBuffer,
00396                                 tempKeyStorage,
00397                                 cryptoBlock );
00398 
00399                 // Wait for whole message, ie. the CMAC value.
00400                 while( !messageComplete() && !receiverTimedOut() ) {
00401                         __sleep();
00402                 }
00403 
00404                 if( receiverTimedOut() ) {
00405                         continue; // Restart loop on timeout.
00406                 }
00407                 
00408                 // Compare generated CMAC with received CMAC.
00409                 byte MACIdx = 0;
00410                 bool stillMatches = true;
00411                 byte * generatedMAC = cryptoBlock;
00412                 byte * receivedMAC = receiveBuffer.commandMessage.MAC;
00413                 while( MACIdx < MAC_BYTES && stillMatches ) {
00414                         if( *generatedMAC++ != *receivedMAC++ ) {
00415                                 stillMatches = false;
00416                         }
00417                         ++MACIdx;
00418                 }
00419 
00420                 // If MAC is ok, execute command and update counter value for this transmitter.
00421                 if( stillMatches ) {
00422                         executeCommand( receiveBuffer.commandMessage.
00423                                         commandCode );
00424                         transmitter->lastCounterValue =
00425                                 receiveBuffer.commandMessage.counterValue;
00426                 }
00427         }
00428 }
@DOC_TITLE@
Generated on Fri Aug 8 11:03:47 2008 for AVR411 Secure Rolling Code Algorithm (Receiver) by doxygen 1.4.7