Full Version : Coneelly & Harrne Security System (AVR ASM)
avr >>HOME & TIME & TEMPERATURE PROJECTS >>Coneelly & Harrne Security System (AVR ASM)


Admin3- 04-18-2006
Security Entrance System by Abram Connelly & Matt Harren

Overview:

Our security system is a stand alone device that allows access to registered users identified by their magnetic cards.(For this project, "access" is represented by a lit LED, showing how the system could be used to control an external locking mechanism.)The system includes features such as:

Multiple accounts, including Administrator accounts (which can create, modify, or delete the other accounts). The account information is stored in non-volatile EEPROM memory, so that it is maintained even if the system is reset.
A "lock down" of the system when someone tries to gain access by repeatedly swiping incorrect cards.
A 20x4 LCD display to give the user feedback on the current state (such as "Access allowed." or "try swiping the card the other way.") and to prompt administrators for commands. All messages printed to the LCD are simultaneously transmitted to an RS232 port, so that all activity can be logged by a PC.

Design:

There are three basic modes of operation:


Normal Mode:

When a card is swiped, the system compares the number on the card to the list of numbers in the EEPROM database compare the number in its database. If a match is found, an the EEPROM lookup reveals that the account has not been disabled, the system prints a friendly message and lights the "access" LED for 4 seconds, representing the time that the door would be unlocked.

If the account number belongs to a system administrator number, then the administrator is prompted to enter a new mode via the keypad.

If more than three invalid attempts are made in a row, (i.e. presumably by a person who is not authorized for entrance) then an LED representing an alarm is activated, and the system goes into a lockdown mode.


Lockdown Mode:

While the system is in Lockdown mode, only administrators will be recognized. In addition to the ability to lock down after several failed attempts, this feature provides a convenient way for administrators to temporarily disable all non-administrator access, without having to modify each account individually,


Learn Mode:

This mode allows administrators to modify the database of magnetic card information. There are 4 levels of permission:

0:Delete account (account is deleted, and the space allocated to the account is freed)

1:Disable account (account is temporarily disabled, but remains in the database)

2:Normal permissions. (user may get access, unless the system is in lockdown mode.)

3:Administrator level permissions.


The administrator who puts the system in lockdown mode is prompted to swipe the card that will be modified, and can then choose any of the four permissions levels to assign to that card. If the card already exists in the database, it is overwritten with the new permissions level.

Hardware:
This system consists of an Atmel 8535 MCU and three other main components. The first is a magnetic card reader, which is used for authentication. The second is an LCD display, which will be used for messages to users. The third is a keypad which is used for by system administrators to configure and maintain the system.(See attached schematic.)In addition to these components, a UART connection allows real-time logging to the PC.

The LCD is a 20x4 display. The operation of this is almost identical to the ones we used in lab, except it has different base addresses for each line of displayable text. Here is a schematic of the hardware connections.

Card Reading:

The card reader has a 5-wire interface:

Red: +5v

Black: ground
Orange: Data

Brown: Clock

Green: Card Detect

Data and Card Detect are active low (data held low represents a logic '1') and data is read on the falling edge of the clock.

On typical magnetic cards, there are three tracks where information is stored. Most card readers (including this one) only read track 2. Furthermore, track 2 is where most useful information is stored, such as credit card numbers for credit cards, or Cornell ID numbers for Cornell cards.

Track 2 has a potential to store 40 characters, each character consisting of 5 bits, 4 for data, and 1 for odd parity. The least significant bit is transmitted first, with the parity bit transmitted last. Zero through nine represent decimal digits, the other 6 characters are for control. A start sentinel character (0b1011) indicates the start of the data block, and an end sentinel character (0b1111) indicate the end of the data block. If the start sentinel and end sentinel are not present in the data read, this indicates a bad read.

Because of limited EEPROM space, our system only looks at characters 9 through 14.These were chosen to correspond to the 6-digit ID number on CU IDs, but almost any credit card or ID card with a magnetic stripe can be used in the system, since these digits typically correspond to some relatively unique substring of the card number.


Software:

Our program was implemented as a state machine with 11 states. 7 of these states control the card reading, while the others perform lookups and writes to the database.

The database is stored in EEPROM, which gives it 512 bytes of space in the 8535.Each entry requires 8 bytes (6 characters of ID plus permission information), allowing a maximum of 64 users in the database.To add a new user, the system searches through the database to find the first open slot, or prints a message to the display if the database is full. Timer 0 is used for a 1 ms time base, which allowed us to add appropriate delays to our LCD and UART transmissions, and the Timer 1 ISR clears the display and turned off the access LED 4 seconds after each message is printed.


Results:

The system works reliably, and has no known bugs. Cards are almost always successfully read on the first try as long as they are held reasonably straight while swiping (swiping cards at an angle prevents the reader from reading the entire card number.)

If we were to add to the project, we would experiment with adding a card writer (our card reader can’t be used to write cards).Also, we would replace the access LED with an actual mechanical latching mechanism.


Project description:

Security system is a stand alone device that allows access to registered users identified by their magnetic cards.(For this project, “access” is represented by a lit LED, showing how the system could be used to control an external locking mechanism.)

Link: http://instruct1.cit.cornell.edu/courses/e...arren/index.htm

CODE

;********************************************
;
;   Security Entrance System
;
;   Abram Connelly and Matt Harren
;   EE 476   Spring '00
;
;********************************************

.nolist
.include "c:\avrtools\appnotes\8535def.inc"
.list

;portC for keyboard
;portD for magno card: d5 data, d6 clock, d7 card detect
;portA for lcd
;portB for LEDS
.equ READER =Pind

.def save =r1
.def RXready =r4
.def eepin =r5
.def char =r6
.def reload =r7
.def failedattempt =r8
.def buttnum =r9
.def lcdcharcnt =r10
.def lcdstat =r11
.def usertemp =r12

.def temp =r16
.def mainstate =r17
.def TXbusy =r18
.def RXchar =r19
.def bitnum =r20
.def TXflash =r21
.def flash =r21
.def perm =r21;permissions level of user
.def curnum =r22
.def newperm =r22;new permissions level of user, as selected by an administrator
.def tblpos =r23
.def mode =r24
.def key =r24;saved before use
.def timeout =r25
.def ssread =r26;start sentinel read yet?
;r28 thru r31 reserved for z and y.

;EEPROM access temps.  Saved before use
.def chrctr =r22
.def IDctr =r23
.def match =r24

;***********temporary
;.def charcnt =r18 ;Char position on the display
;.def chr =r19 ;a variable character to print

;********************


.equ baud96 =25
.equ asciizero ='0'
.equ Deleted =0;permissions levels.  Should be numbered by increasing power
.equ Disabled =1; (i.e. everyone with permission >= Access will get access)
.equ Access =2
.equ Admin =3
.equ maxIDs =60

;******lcd stuff
.equ lcdrs =Pa6
.equ lcdrw =Pa5
.equ lcde =Pa4

.equ lcdoutput =porta
.equ lcdinput =pina
.equ lcdcontrol =ddra

;******kb
.equ kboutput =portc
.equ kbinput =pinc
.equ kbcontrol =ddrc

;******states
.equ wait4clockHigh =3;wait for rising edge
.equ nocard  =4;if no card, print data, lookup  in EEPROM

.equ carddetect  =7;test card detect bit
.equ clock  =6;wait for falling edge of clock
.equ data  =5;test for the first '1'

.equ fullchar  =0;read a bit of data
.equ sstest  =1;test if already seen ss
.equ indb  =2;test if card is in database
.equ sysadmin  =8;test if the user is a sysadmin
.equ getNewPerm  =9;wait for administrator to specify new permissions label
.equ writeID  =10;add card to DB, or modify existing entry

;******modes
.equ normal  =1;normal, lockdown, and learn modes
.equ learn  =3
.equ lockdown  =2

;*******door etc.
.equ accessLED  =6;output pins on port B(active low)
.equ alarmLED  =7
.equ maxattempts =3

.macro lcdprintflash
 rcall lcdclr

 push zl
 push zh
 push flash
 ldi zl, low(@0<<1)
 ldi zh, high(@0<<1)
 ser flash
 rcall lcdputstring
 pop flash
 pop zh
 pop zl
.endmacro

.macro lcdprintram
 push zl
 push zh
 push flash
 ldi zl, low(@0)
 ldi zh, high(@0)
 clr flash
 rcall lcdputstring
 pop flash
 pop zh
 pop zl
.endmacro

.macro flashprint
 cli
 push zl
 push zh
 push txflash
 push txbusy
 push r0

;make sure to disable the timer1 isr in case
; it hasn't finished flashprintbrief
 in  temp, timsk
 andi temp, ~exp2(toie1)
 out timsk, temp

 sei
 ldi zl, low(@0<<1)
 ldi zh, high(@0<<1)
 ser flash
 rcall lcdputstring

 ldi zl, low(@0<<1)
 ldi zh, high(@0<<1)
 lpm
 out udr, r0
 ser txflash
 ser txbusy
 sbi ucr, udrie
 rcall txwait

 ldi zl, low(CRLF<<1)
 ldi zh, high(CRLF<<1)
 lpm
 out udr, r0
 ser txflash
 ser txbusy
 sbi ucr, udrie
 rcall txwait

 pop r0
 pop txbusy
 pop txflash
 pop zh
 pop zl
.endmacro

.macro flashprintbrief
 push zl
 push zh
 push txflash
 push txbusy
 push r0

 ldi zl, low(@0<<1)
 ldi zh, high(@0<<1)
 ser flash
 rcall lcdputstring

 ldi zl, low(@0<<1)
 ldi zh, high(@0<<1)
 lpm
 out udr, r0
 ser txflash
 ser txbusy
 sbi ucr, udrie
 rcall txwait

 ldi zl, low(CRLF<<1)
 ldi zh, high(CRLF<<1)
 lpm
 out udr, r0
 ser txflash
 ser txbusy
 sbi ucr, udrie
 rcall txwait

 cli
 clr  temp
 out  tcnt1h, temp
 out  tcnt1l, temp
 in  temp, tifr
 ori temp, exp2(tov1)
 out tifr, temp
 in  temp, timsk
 ori temp, exp2(toie1)
 out timsk, temp
 sei

 pop r0
 pop txbusy
 pop txflash
 pop zh
 pop zl
.endmacro


.macro ramprint
 push zl
 push zh
 push txflash
 push txbusy
 ldi zl, low(@0)
 ldi zh, high(@0)
 ld r0, z
 out udr, r0
 clr txflash
 ser txbusy
 sbi ucr, udrie
 rcall txwait

 pop txbusy
 pop txflash
 pop zh
 pop zl
.endmacro

.MACRO getkey
 cli
 push temp
 push zl
 push zh
 push key
 push r0
 ldi temp, 0x0f
 out kbcontrol, temp
 ldi temp, 0xf0
 out kboutput, temp
 nop
 nop
 nop
 nop
 nop
 nop
 nop
 nop
 in temp, kbinput
 mov key, temp
 ldi temp, 0xf0
 out kbcontrol, temp
 ldi temp, 0x0f
 out kboutput, temp
 nop
 nop
 nop
 nop
 nop
 nop
 nop
 nop
 in temp, kbinput
 or key, temp

; ldi temp, 0xff
; out ddrb, temp
;  mov temp, key
;  com temp
;  out portb, key

 ldi zl, low(keytbl<<1)
 ldi zh, high(keytbl<<1)
 ldi temp, 0
tbllp:
 lpm
 cp key, r0
 breq tbldone
 inc temp
 cpi temp, 12
 breq tbldone
 adiw zl, 1
 rjmp tbllp
tbldone:
 mov @0, temp
 pop r0
 pop key
 pop zh
 pop zl
 pop temp
 sei
.ENDMACRO

.dseg
tempbuffer:  .byte 4
table:  .byte  100

.eseg
database: .db "384533", Admin, 0x0;Matt has permission "Admin"
;60 empty locations
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0

 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
 .db 0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0,    0,0,0,0, 0,0,0,0,     0,0,0,0, 0,0,0,0
numusers: .db 1


.cseg
.org $0000
 rjmp reset;reset
 reti ;irq0
 reti ;irq1
 reti ;timer2 compare
 reti ;timer2 overflow
 reti ;timer1 capt
 reti ;timer1a
 reti ;timer1b
 rjmp  timer1;timer1 overflow
 rjmp  timer0;timer0 overflow
 reti ;spi transfer complete
 rjmp RXdone;uart rx
 rjmp TXempty;udr empty
 rjmp TXdone;uart tx complete
 reti ;ADC complete
 reti  ;EEPROM ready
 reti ;analog comparitor

reset:
 ldi temp, low(ramend)
 out spl, temp
 ldi temp, high(ramend)
 out sph, temp

;initialize timer0 for 1mSec ticks
 ldi temp, 0b00000001;for 8535
 out timsk, temp
 ldi temp, 3
 out tccr0, temp
 ldi temp, 4
 out tccr1b, temp
 ldi temp, 256-62
 mov reload, temp
 out tcnt0, reload

;initialize portb
 ser temp
 out ddrb, temp
 out portb, temp;clear the LEDs

;initialize portc
;  clr temp
;  out ddrc, temp;all inputs
;  out portc, temp;no pullups

;initalize portd
 in temp, ddrd
 andi temp, 0b00011111
 out ddrd, temp;bits 5, 6, 7 inputs
 in temp, portd
 andi temp, 0b00011111
 out portd, temp;no pullups

;initialize for rx isr
 clr rxready
 clr rxchar

;initialize for tx isr
 clr txbusy
 ldi  temp, 0b10111000
 out ucr, temp
 ldi temp, baud96
 out ubrr, temp

;general initialization;
 ldi bitnum, 1
 ldi mainstate, carddetect
 ldi mode, normal
 ldi curnum, 0
 ldi tblpos, 0
 ldi ssread, 0;ss not seen yet

 sei

;lcd initialize
 rcall lcdinit
 rcall lcdclr
 
 rcall lcdclr
 flashprintbrief teststring

 ldi zl, low(table)
 ldi zh, high(table)


 ldi timeout, 100
 rcall delay

;************************************
; State dispatch
;************************************
main:
;  in temp, portb
;  mov temp, mainstate
;  com temp
;  out portb, temp

 cpi mainstate, carddetect
 breq carddetectCode
 cpi mainstate, clock
 breq clockCode
 cpi mainstate, wait4clockhigh
 breq wait4clockhighCode
 cpi mainstate, sstest
 breq sstestCode
 cpi mainstate, data
 breq dataCode
 cpi mainstate, fullchar
 breq fullcharCode
 cpi mainstate, noCard
 breq noCardCode
 cpi mainstate, getNewPerm
 brne skipgetNewPerm
 rjmp getNewPermCode
skipgetNewPerm:
 cpi mainstate, indb
 brne skipindb
 rjmp  indbCode
skipindb:
 cpi mainstate, sysadmin
 brne skipsysad
 rjmp  sysAdminCode
skipsysad:
 cpi mainstate, writeID
 brne spin
 rjmp  writeIDCode

spin:
;  ldi temp, 0x55
;  out portb, temp
;  mov temp, mainstate
;  com temp
;  out portb, temp
;  rjmp spin
 rjmp Reset;bad state;  reset

;*****

carddetectCode:
 ldi mainstate, clock;if card is detected, goto clock
;  ldi mainstate, 0xf5 ;if card is detected, goto clock
 sbic READER, carddetect; else goto nocard
 ldi mainstate, nocard;(card is detected when carddetect is low)
 rjmp main

;*****

clockCode:
 sbic  reader, carddetect
 rjmp reallywrong
 sbis READER, clock ;wait till clock goes low (active)
 ldi mainstate, sstest; then go to sstest
 rjmp main
reallywrong:
 ldi mainstate, nocard
 rjmp main

;*****

sstestCode:
 ldi mainstate, data
 cpi ssread, 0
 breq  main ;if ss not seen, goto data

 ldi mainstate, fullchar
 sbis READER, data;if data line is low, (bit is '1')
 or curnum, bitnum; set bit 'bitnum' high
 lsl bitnum  
 rjmp main

;*****

fullcharCode:
 ldi mainstate, wait4clockhigh
 cpi bitnum, 0b00100000
 brne main

;read 5 chars?  store and clear
 cpi curnum, 31; curnum = end Sentinel?
 brne notend
 rjmp main

notend:
 andi curnum, 0x0f
 subi curnum, -('0')
 st z+, curnum
 clr curnum
 ldi bitnum, 1
 rjmp main

;*****

wait4clockhighCode:
 sbic READER, clock
 ldi  mainstate, carddetect
 rjmp main

;*****

dataCode:
 ldi mainstate, wait4clockhigh
 sbic READER, data
 rjmp main

 ldi curnum, 1
 ldi bitnum, 2
 ldi ssread, 1
 rjmp main

;*****

nocardCode:
 ldi mainstate, carddetect
 cpi ssread, 1
;  brne endnocard2;jump back 3 lines, then jump to main
 breq ssskip
 rjmp endnocard
ssskip:
 clr ssread
 ldi mainstate, indb
 cpi mode, learn
 breq dolearn
 rjmp continue
dolearn:
;learn mode
 rcall lcdclr
 flashprint learnopt1
 flashprint learnopt2
 flashprint learnopt3
 flashprint learnopt4
 ldi mainstate, getNewPerm
 ldi mode, normal

continue:
 ldi zl, low(table+15)
 ldi zh, high(table+15)

 ldi temp, 0x0d
 st z+, temp
 ldi temp, 0x0a
 st z+, temp
 clr temp
 st z+, temp

 ldi zl, low(table)
 ldi zh, high(table)
 ld r0, z+ ;read first char to check for start senitel
 adiw zl, 8  ;start printing at z+9, to skip the ss and the first 8 chars of data
 clr txflash
 mov temp, r0
 ld r0, z ;load first character being printed

 cpi temp, 0x3b;  ;first character = start sentinel?
 breq  ok

 ldi mainstate, carddetect;bad read, print an error and go back to carddetect

 rcall lcdclr
 flashprintbrief error
 rjmp skipnocard

;  ser txflash  ;if not, print error message from flash
;  ldi zl, low(error<<1)
;  ldi zh, high(error<<1)
;  lpm

ok:

 ramprint table

;  out udr, r0
;  ser txbusy
;  sbi ucr, udrie
;  rcall txwait

skipnocard:
 clr curnum
 ldi bitnum, 1
 ldi zl, low(table)
 ldi zh, high(table)
endnocard:
 rjmp main

;*****

getNewPermCode:
 getKey  buttnum
 mov temp, buttnum
 cpi temp, 12
 breq exitGNP
 cpi temp, 4
 brsh invalid
 mov newperm, temp
 ldi mainstate, writeID
 rjmp exitGNP
invalid:
 rcall lcdclr
 flashprintbrief badchoice
exitGNP:
 rjmp main

;*****

;Writes the ID at table+9 to the database, with permsission newperm
writeIDcode:
 ldi temp, low(numusers);eear = numusers
 out eearl, temp
 ldi temp, high(numusers)
 out eearh, temp
 sbi eecr, EERE;read the permissions byte
 in usertemp, eedr; store the permissions in perm

 ldi zl, low(table)
 ldi zh, high(table)
 adiw zl, 9
 rcall getperm
 cpi perm, 1
 brge rewrite ;person is already in database;  rewrite with new perm

 mov temp, usertemp
 cpi temp, maxIDs
 brlt write
 flashprintbrief toomany
 rjmp exitwriteID

write:
 ldi zl, low(table)
 ldi zh, high(table)
 adiw zl, 15 ;store newperm at table+15
 st z+,  newperm
 clr temp
 st z+, temp
 subi zl, 8
 sbc zh, temp
 rcall writeEEPROM;write ID at Z to database, with the permission
 inc usertemp
 rjmp exitwrite

rewrite:
 cli
 out eedr, newperm
 sbi eecr, EEMWE;enable writes
 sbi eecr, EEWE;begin writing
 sei
EEspin2:
 sbic eecr, EEWE
 rjmp EEspin2

 cpi newperm, 0
 brne exitwrite
 dec usertemp;an account is being deleted

exitwrite:
 rcall lcdclr
 flashprint id
 ramprint (table+9)
 lcdprintram (table+9)
 flashprint written
 ldi zl, low(tempbuffer)
 ldi zh, high(tempbuffer)
 clr temp
 subi newperm, -'0'
 st z+, newperm
 st z, temp
 ramprint tempbuffer
 lcdprintram tempbuffer
 flashprintbrief Null

 ldi temp, low(numusers);eear = numusers
 out eearl, temp
 ldi temp, high(numusers)
 out eearh, temp
 out eedr, usertemp
 sbi eecr, EEMWE;enable writes
 sbi eecr, EEWE;write the new number of users
EEspin3:
 sbic eecr, EEWE
 rjmp EEspin3

exitwriteID:
 ldi mode, normal
 ldi mainstate, carddetect
 ldi zl, low(table)
 ldi zh, high(table)
 rjmp main

;*****

sysAdminCode:
 getKey  buttnum
 mov temp, buttnum
;  com temp
;  out portb, temp
;  com temp

 cpi temp, 4
 brge sysnobutt
 cpi temp, 0
 brne getmode
sysnobutt:
 rjmp main
getmode:
 ldi mainstate, carddetect
 cpi temp, 1
 brne no1
 ldi mode, normal
 sbi portb, alarmLED
 rcall lcdclr
 flashprintbrief normalmsg
 rjmp sysnobutt
No1:
 cpi temp, 2
 brne no2
 ldi mode, lockdown
 sbi portb, accessLED
 rcall lcdclr
 flashprintbrief lockmsg
 rjmp sysnobutt
No2:
 cpi temp, 3
 brne no3
 ldi mode, learn
 rcall lcdclr
 flashprint learnmsg
No3:

;sysnobutt:
 rjmp main
 
;*****

indbCode:
 ldi zl, low(table)
 ldi zh, high(table)
 adiw zl, 9

 ld r0, z
 out udr, r0
 clr txflash
 ser txbusy
 sbi ucr, udrie
 rcall txwait

 ldi zl, low(table)
 ldi zh, high(table)
 adiw zl, 9

 rcall getperm

 ldi zl, low(table)
 ldi zh, high(table)
 adiw zl, 9
 clr temp
 st z, temp

 cpi perm, 0x3
 breq printsys
 rjmp L1
printsys:
 rcall lcdclr
 flashprint sysopt1
 flashprint sysopt2
 flashprint sysopt3
 flashprint sysopt4
 ldi mainstate, sysadmin
 clr failedattempt
 rjmp exit
L1:
 ldi mainstate, carddetect
 cpi mode, lockdown
 brne notlocked
 rcall lcdclr
 flashprintbrief locked
 rjmp exit
notlocked:
 cpi perm, 0x2
 brne L2
 clr  failedattempt

 rcall lcdclr
 cbi Portb, accessLED ;cleared in 4s by the timer1 ISR
 flashprintbrief accessmsg
;  cli
;  cbi Portb, accessLED
;  clr  temp
;  out  tcnt1h, temp
;  ldi temp, 1
;  out  tcnt1l, temp
;  in  temp, tifr
;  ori temp, exp2(tov1)
;  out tifr, temp
;  in  temp, timsk
;  ori temp, exp2(toie1)
;  out timsk, temp
;  sei
 rjmp exit
L2:
 inc failedattempt
 ldi mainstate, carddetect

 rcall lcdclr
 flashprintbrief noaccessmsg
 mov temp, failedattempt
 cpi temp, maxattempts
 brne  exit
 cbi Portb, alarmLED
 sbi Portb, accessLED
 ldi mode, lockdown
 rcall lcdclr
 flashprint alarmmsg

;  ser txflash  
;  ldi zl, low(noaccessmsg<<1)
;  ldi zh, high(noaccessmsg<<1)
;  lpm
;  out udr, r0
;  ser txbusy
;  sbi ucr, udrie
;  rcall txwait

exit:
 ldi zl, low(table)
 ldi zh, high(table)

;  com perm
;  out portb, perm
 rjmp  main



;****************************
;    UART Routines
;****************************
 
txwait:
 tst txbusy
 brne txwait
 ret

txempty:
 in save, sreg
 tst txflash
 breq txram
 adiw zl, 1
 lpm
 rjmp txfls
txram:
 adiw zl, 1
 ld r0, z
txfls:
 tst r0
 breq txend
 out udr, r0
 rjmp txexit

txend:
 clr txbusy
 cbi ucr, udrie
txexit:
 out sreg, save
 reti

txdone:
 in  save, sreg
 out sreg, save
 reti


rxdone:
 in save, sreg
 push temp
 in rxchar, udr
 ser temp
 mov  rxready, temp
 pop temp
 out sreg, save
 reti


;****************************
;    EEPROM Routines
;****************************

;writes 8 chars starting at z in RAM to y in eeprom, (6 ID numbers followed by permission level and 0(filler))
writeEEPROM:
 cli
 push yl
 push yh
 push chrctr
 push temp

 rcall findempty
 out eearl, yl
 out eearh, yh
 ldi chrctr, 8

writeChar:
 ld temp, z+
 out eedr, temp
 sbi eecr, EEMWE;enable writes
 sbi eecr, EEWE;begin writing
EEspin:
 sbic eecr, EEWE
 rjmp EEspin
 adiw yl, 1
 out eearl, yl;increment the address
 out eearh, yh
 dec chrctr
 brne writeChar

 pop temp
 pop chrctr
 pop yh
 pop yl
 sei
 ret

;finds the location of an empty location in the database, returns pointer in y
;returns -1 on failure
findempty:
 push IDctr

 ldi yl, low(database);y = database
 ldi yh, high(database)
 ldi IDctr, maxIDs;look at at most maxIDs IDs
 adiw yl, 6 ;look at the permissions (stored 6 characters after the start of the field)

loopempty:
 out eearl, yl
 out eearh, yh
 sbi eecr, EERE;read a char
 in temp, eedr
 cpi temp, 0 ;if temp = 0, this location is empty  
 breq foundone

 adiw yl, 8
 dec IDctr  
 brne loopempty

 ser yh ;failure
 ser yl
 rjmp exitfind

foundone:
 subi yl, 6 ;subtract 6 from y to point to the start of the field
 sbc yh, temp

exitfind:
 pop IDctr
 ret


;reads EEPROM, looking for an ID matching z thru z+5 in RAM
;if found, returns the permission in perm and the address of the permissions byte in EEAR.
;if not found, returns -1 as the permission
getperm:
 push yl
 push yh
 push chrctr
 push IDctr
 push char
 push match
 push zl
 push zh

 ldi perm, -1;default to "no match found"
 ldi temp, low(database);eear = y = database
 mov yl, temp
 out eearl, yl
 ldi temp, high(database)
 mov yh, temp
 out eearh, yh
 ldi chrctr, 6
 ldi IDctr, maxIDs;look at at most maxIDs IDs
 ser match

readChar:
 sbi eecr, EERE;read a char
 in char, eedr;char = character from EEPROM
 ld temp, z+;temp = character from RAM
 cpse temp, char;if they are the same, ok
 clr  match ; else no match  

 adiw yl, 1
 out eearl, yl;increment the address
 out eearh, yh
 dec chrctr
 brne readChar

 cpi match, 0;if a match was found
 brne  success ; we're done

 dec IDctr ;no match found?  decide if we should continue testing
 breq exitget ; if IDctr = 0, give up

 ;otherwise, look at the next ID
 ldi chrctr, 6;restore chrctr
 clr  temp
;  pop zh
;  pop zl
;  push  zl
;  push  zh
 subi zl, 6 ;restore Z
 sbc zh, temp

 adiw yl, 2 ; increment y by 2 to account for the 2 bytes of overhead per ID
 out eearl, yl
 out eearh, yh
 ser  match
 rjmp readChar

success:
 sbi eecr, EERE;read the permissions byte
 in perm, eedr; store the permissions in perm

exitget:
 pop zh
 pop zl
 pop match
 pop char
 pop IDctr
 pop chrctr
 pop yh
 pop yl
 ret

;****************************
;    Timer Routines
;****************************

; subroutine waits for time equal to value in register timeout
;the register 'timeout' should be loaded before the call
delay:
 tst timeout
 brne delay
 ret


timer0:
 in save, SREG
 out  TCNT0, Reload; keeps clock ticking at 1 mSec

 dec  timeout ;subtract another mSec

 out SREG, save
 reti  ;back to backgound tasks

timer1:
 in save, SREG
 push save
 push temp

 in  temp, timsk
 andi temp, ~exp2(toie1)
 out timsk, temp
 sbi portb, accessLED
 
 sei
 rcall lcdclr

 cpi mode, lockdown
 breq tim1lockmsg
 flashprint prompt
 rjmp timer1exit
tim1lockmsg:
 flashprint lockmsg
timer1exit:

 pop  temp
 pop save
 out SREG, save
 reti  ;back to backgound tasks


;****************************
;    LCD Routines
;****************************

;load zl/h with null terminated message
;  flash set, its in flash
;  flash clear, its in dseg
lcdputstring:

 tst flash
 breq lcdputram
 lpm;r0
 rjmp skippy
lcdputram:
 ld r0, z

skippy:
 mov temp, r0
 cpi temp, 32
 brlt lpsexit

 mov temp, lcdcharcnt
 cpi temp, 20
 brne checknext
 ldi temp, 0xc0
 rcall lcdcmd

checknext:
 cpi temp, 40
 brne checknext2
 ldi temp, 0x94
 rcall lcdcmd
 
checknext2:
 cpi temp, 60
 brne writeit
 ldi temp, 0xd4
 rcall lcdcmd
 
writeit:
 mov temp, lcdcharcnt
 cpi temp, 80
 brne reallywrite
 rcall lcdclr
 clr temp
 mov lcdcharcnt, temp
reallywrite:
 mov temp, r0
 rcall lcdput
 adiw zl, 1
 inc lcdcharcnt
 rjmp lcdputstring
lpsexit:
 ret

;================================================

; Clear entire LCD and delay for a bit

lcdclr:

push temp
ldi temp,1 ;Clear LCD command

rcall lcdcmd


ldi timeout,3;Delay 3 mS for clear command

rcall delay

clr  temp
mov lcdcharcnt, temp


pop temp
ret


;================================================

; Initialize LCD module

lcdinit:

cbi PORTB,0 ;Turn on LED 0

ldi temp,0 ;Setup port pins

out lcdoutput,temp;Pull all pins low

ldi temp,0xff;All pins are outputs

out lcdcontrol,temp

ldi timeout,15;Wait at least 15 mS at power up

rcall delay

; LCD specs call for 3 repetitions as follows:
;first rep

ldi temp,3 ;Function set

out lcdoutput,temp;to 8-bit mode
nop  ;nop is data setup time

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde


ldi timeout,15;Wait at least 15 mS

rcall delay

;second rep

ldi temp,3 ;Function set

out lcdoutput,temp
nop

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde


ldi timeout,15;Wait at least 15 ms

rcall delay

;third rep

ldi temp,3 ;Function set

out lcdoutput,temp
nop

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde

ldi timeout,15;Wait at least 15 ms

rcall delay

;Now change to 4-wire interface mode

ldi temp,2 ;Function set, 4 wire databus

out lcdoutput,temp
nop

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde


; Finally, at this point,

; the normal 4 wire command routine (lcdcmd) can be used


ldi temp,0b00100000;Function set, 4 wire, 1 line, 5x7 font

rcall lcdcmd


ldi temp,0b00001100;Display on, no cursor, no blink

rcall lcdcmd


ldi temp,0b00000110;Address increment, no scrolling

rcall lcdcmd

sbi PORTB,0 ;Turn off LED 0

ret


;============================================

; Wait for LCD to go unbusy

lcdwait:

cbi PORTB,1 ;Turn on LED 1

ldi temp,0xF0;Make 4 data lines inputs

out lcdcontrol,temp

sbi lcdoutput,lcdrw;Set r/w pin to read

cbi lcdoutput,lcdrs;Set register select to command

waitloop:

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde

in lcdstat,lcdinput;Read busy flag

;Read, and ignore lower nibble

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde


sbrc lcdstat,3;Loop until done

rjmp waitloop

sbi PORTB,1 ;Turn off LED 1


ret


;=============================================

; Send command in temp to LCD

lcdcmd:

push temp ;Save character

rcall lcdwait


ldi temp,0xFF;Make all port D pins outputs

out lcdcontrol,temp

pop temp ;Get character back

push temp ;Save another copy

swap temp ;Get upper nibble

andi temp,0x0F;Strip off upper bits

out lcdoutput,temp;Put on port
nop  ;wait for data setup time

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde


pop temp ;Recall character

andi temp,0x0F;Strip off upper bits

out lcdoutput,temp;Put on port
nop

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde


ret


;=============================================

; Send character data in temp to LCD

lcdput:

push temp ;Save character

rcall lcdwait



ldi temp,0xFF;Make all port D pins outputs

out lcdcontrol,temp


pop temp ;Get character back

push temp ;Save another copy

swap temp ;Get upper nibble

andi temp,0x0F;Strip off upper bits

out lcdoutput,temp;Put on port

sbi lcdoutput,lcdrs;Register select set for data
nop

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde


pop temp ;Recall character

andi temp,0x0F;Strip off upper bits

out lcdoutput,temp;Put on port

sbi lcdoutput,lcdrs;Register select set for data
nop

sbi lcdoutput,lcde;Toggle enable line
nop

cbi lcdoutput,lcde


ret


;**************************************
;    Constants
;**************************************

keytbl: .db 0b11010111, 0b11101110, 0b11011110, 0b10111110
.db 0b11101101, 0b11011101, 0b10111101, 0b11101011
.db 0b11011011, 0b10111011, 0b11100111, 0b10110111
; 0 1 2 3
; 4 5 6 7
; 8 9 * # ('*' = 10, '#' = 11)



; Strings are <= 20 chars long, to fit on the LCD.

teststring: .db " Ready", 0x00
accessmsg: .db "Access allowed.     "
 .db "Have a nice day!    ", 0x00
noaccessmsg:.db " Access denied.     ", 0x00
error: .db "Unable to read card."
 .db "Try swiping the     "
 .db "other way.          ", 0x00
sysopt1: .db "What's up, doc?     ", 0x00
sysopt2: .db "1 Normal mode.      ", 0x00
sysopt3: .db "2 Lockdown mode.    ", 0x00
sysopt4: .db "3 Learn mode.       ", 0x00
locked: .db "System is locked.   "
 .db "Go away.            ", 0x00
lockmsg: .db "System is locked.   ", 0x00
normalmsg: .db "System is back in   "
 .db "normal mode.        ", 0x00
learnmsg: .db "Swipe the card to   "
 .db "add or modify.      ", 0x00
id:  .db "ID ", 0x00
written: .db " written    "
 .db "with permission ", 0x00
CRLF:  .db 0x0d, 0x0a, 0x00
Null:  .db 0x00
learnopt1: .db "0: Delete account   ", 0x00
learnopt2: .db "1: Disable account  ", 0x00
learnopt3: .db "2: Give normal perm.", 0x00
learnopt4: .db "3: Give admin perm. ", 0x00
badchoice: .db "Umm... that wasn't  "
 .db "one of the choices  ", 0x00
alarmmsg: .db "Alarm set.          ", 0x00
prompt: .db "Please swipe card.  ", 0x00
toomany: .db "Too many users.     "
 .db "Write failed.       ", 0x00








Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.