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

Date
  2006-11-08 09:50:32 +0100 (on, 08 nov 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 "crc.h"`

Include dependency graph for main.c:

Go to the source code of this file.

## Functions
void | errorLoop (byte blinkCount)
void | handleResetFlags (void)
void | main (void)
static __interrupt void | pinChangeHandler (void)
void | setupPeripherals (void)
COMMAND_CODE_TYPE | sleepAndGetCommand (void)
void | transmitCommandMessage (COMMAND_CODE_TYPE command)
void | transmitTeachMessage (void)

## Function Documentation

void errorLoop | ( | byte | blinkCount | ) |

Loop forever, blinking a LED.

Definition at line 128 of file main.c.

Referenced by handleResetFlags().

    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 }

void handleResetFlags | ( | void |  | ) |

Read reset flags and act accordingly.

Definition at line 254 of file main.c.

References errorLoop(), and MAX_WATCHDOG_RESETS.

Referenced by main().

    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 }

Here is the call graph for this function:

void main | ( | void |  | ) |

Definition at line 324 of file main.c.

References calcCMACSubkey(), calcKeySchedule(), COMMAND_CODE_TYPE, cryptoBlock, handleResetFlags(), initializeMessage(), setupPeripherals(), sleepAndGetCommand(), TEACH_COMMAND, transmitCommandMessage(), and transmitTeachMessage().

    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 }

Here is the call graph for this function:

static __interrupt void pinChangeHandler | ( | void |  | ) | `[static]`

ISR called when a button is pressed.

Definition at line 60 of file main.c.

References BUTTON_MASK, and COMMAND_CODE_TYPE.

    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 }

void setupPeripherals | ( | void |  | ) |

Initial setup of misc. peripherals in the AVR.

Definition at line 292 of file main.c.

References BUTTON_MASK.

Referenced by main().

    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 }

COMMAND_CODE_TYPE sleepAndGetCommand | ( | void |  | ) |

Sleep and wait for button to be pressed.

Definition at line 93 of file main.c.

References BUTTON_MASK, and COMMAND_CODE_TYPE.

Referenced by main().

    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 }

void transmitCommandMessage | ( | COMMAND_CODE_TYPE | command | ) |

Construct and transmit and ordinary command message.

Definition at line 160 of file main.c.

References calcCMAC(), continueTransmission(), createMessage(), cryptoBlock, MAC_BYTES, SharedBlock::messagePayload, PREBURST_BYTES, MessagePayload::serialNo, sharedBlock, startCounterUpdate(), startTransmission(), stopTransmission(), waitForCounterUpdate(), and waitForTransmission().

Referenced by main().

    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 }

Here is the call graph for this function:

void transmitTeachMessage | ( | void |  | ) |

Construct and transmit a message with serial number, encrypted key etc.

Definition at line 195 of file main.c.

References BLOCK_SIZE, calcCRC(), calcKeySchedule(), cipherLookup(), continueTransmission(), copyBytesFromEEPROM(), CRCReg, SharedBlock::cryptoBlock, cryptoBlock, initCRC(), initializeMessage(), KEY_SIZE, SharedBlock::messagePayload, PREBURST_BYTES, SEQ_COUNTER_BYTES, SERIAL_NO_BYTES, MessagePayload::serialNo, sharedBlock, startTransmission(), stopTransmission(), and waitForTransmission().

Referenced by main().

    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 }

Here is the call graph for this function:

@DOC_TITLE@