| Remote Access Control | |||||
This file contains the setup and main control code for the Remote Keyless Entry application.
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 |
| 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 | ) |
| 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 | ) |
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().
Generated on Fri Aug 8 11:04:03 2008 for AVR411 Secure Rolling Code Algorithm (Receiver) by 1.4.7
|