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

- File: main.c
- Compiler: IAR EWAVR 4.11B
- Supported devices: ATtiny45/85
- AppNote: AVR411 - Secure Rolling Code Algorithm for Wireless Link

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().

    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 }

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@