| 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@