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