Remote Access Control


main.c File Reference


Detailed Description

Main application source file.

This file contains the setup and main control code for the Remote Keyless Entry application.

Author:
Atmel Corporation: http://www.atmel.com
Support email: avr@atmel.com
Name
Revision
1193
Date
2006-10-31 14:21:08 +0100 (ti, 31 okt 2006)

Copyright (c) 2006, Atmel Corporation All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. The name of ATMEL may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Definition in file main.c.

#include "common.h"
#include "config.h"
#include "aes.h"
#include "cmac.h"
#include "memory.h"
#include "comms.h"
#include "timer.h"
#include "crc.h"
#include "radio.h"

Include dependency graph for main.c:

Go to the source code of this file.

Functions

void errorLoop (byte blinkCount)
void executeCommand (byte commandCode)
void handleResetFlags (void)
void initCommand (void)
void learnMode (void)
__interrupt void learnModeSwitchHandler (void)
void main (void)
void setupLearnModeIO (void)
void setupPeripherals (void)
__interrupt void watchdogInterrupt (void)

Variables

static volatile bool learnModeRequest = false


Function Documentation

void errorLoop ( byte  blinkCount  ) 

Loop forever, blinking a LED.

Definition at line 202 of file main.c.

References CPU_F, LEARN_MODE_OUTPUT_BIT, LEARN_MODE_OUTPUT_DDR, LEARN_MODE_OUTPUT_HIGH, and LEARN_MODE_OUTPUT_LOW.

Referenced by handleResetFlags(), and main().

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 }

void executeCommand ( byte  commandCode  ) 

Perform desired operation based on the given command code.

Definition at line 95 of file main.c.

Referenced by main().

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 }

void handleResetFlags ( void   ) 

Read reset flags and act accordingly.

Definition at line 233 of file main.c.

References errorLoop(), and MAX_WATCHDOG_RESETS.

Referenced by main().

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 }

Here is the call graph for this function:

void initCommand ( void   ) 

Initialize IO-pins used by the 'executeCommand' function.

Definition at line 86 of file main.c.

Referenced by main().

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 }

void learnMode ( void   ) 

Enter learn mode loop, exit when long timeout expires.

Definition at line 129 of file main.c.

References BLOCK_SIZE, calcCRC(), copyBytesFromEEPROM(), copyBytesToEEPROM(), CRCReg, enableReception(), eraseTransmitters(), initCRC(), invCipher(), KEY_SIZE, LearnMessage::lastCounterValue, TransmitterInfo::lastCounterValue, LEARN_MODE_OUTPUT_HIGH, LEARN_MODE_OUTPUT_LOW, ReceiveBuffer::learnMessage, longTimeout, MAX_TRANSMITTERS, messageComplete(), prepareInvCipher(), receiveBuffer, receiverTimedOut(), scheduleBuffer, LearnMessage::secretKey, LearnMessage::serialNo, TransmitterInfo::serialNo, sharedKey, startLongTimeout(), stopTimer(), tempKeyStorage, and transmitters().

Referenced by main().

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 }

Here is the call graph for this function:

__interrupt void learnModeSwitchHandler ( void   ) 

ISR called when learn mode input pin changes.

Definition at line 66 of file main.c.

References LEARN_MODE_INPUT_BIT, LEARN_MODE_INPUT_REG, and learnModeRequest.

00067 {
00068         // Only signal on falling edge.
00069         if( (LEARN_MODE_INPUT_REG & (1<<LEARN_MODE_INPUT_BIT)) == 0 ) {
00070                 learnModeRequest = true;
00071         }
00072 }

void main ( void   ) 

Definition at line 279 of file main.c.

References calcCMAC(), calcCMACSubkey(), CMACSubkey, COMMAND_CODE_BYTES, ReceiveBuffer::commandMessage, copyBytesFromEEPROM(), CommandMessage::counterValue, cryptoBlock, enableReception(), errorLoop(), executeCommand(), handleResetFlags(), initCommand(), initReceiver(), KEY_SIZE, learnMode(), learnModeRequest, CommandMessage::MAC, MAC_BYTES, messageBytesReceived(), messageComplete(), receiveBuffer, receiverTimedOut(), rx_WriteOFF(), scheduleBuffer, SEQ_COUNTER_BYTES, SERIAL_NO_BYTES, CommandMessage::serialNo, setupLearnModeIO(), setupPeripherals(), stopTimer(), tempKeyStorage, transmitters(), and WINDOW_SIZE.

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 }

Here is the call graph for this function:

void setupLearnModeIO ( void   ) 

Initialize IO-pins and Pin-change interrupt used by learn mode switch and LED.

Definition at line 115 of file main.c.

References LEARN_MODE_INPUT_BIT, LEARN_MODE_INPUT_DDR, LEARN_MODE_INPUT_PULLUP_REG, LEARN_MODE_OUTPUT_BIT, LEARN_MODE_OUTPUT_DDR, LEARN_MODE_OUTPUT_HIGH, LEARN_MODE_PCINT_ENABLE_BIT, LEARN_MODE_PCINT_MASK_BIT, and LEARN_MODE_PCINT_MASK_REG.

Referenced by main().

void setupPeripherals ( void   ) 

Initial setup of misc. peripherals in the AVR.

Definition at line 259 of file main.c.

Referenced by main().

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 }

__interrupt void watchdogInterrupt ( void   ) 

ISR called when watchdog times out with interrupts enabled.

Definition at line 78 of file main.c.

00079 {
00080         // Do nothing. Just wake up.
00081 }


Variable Documentation

volatile bool learnModeRequest = false [static]

Set to true by interrupt handler when learn mode swith is activated.

Definition at line 60 of file main.c.

Referenced by learnModeSwitchHandler(), and main().

@DOC_TITLE@
Generated on Fri Aug 8 11:04:03 2008 for AVR411 Secure Rolling Code Algorithm (Receiver) by doxygen 1.4.7