' ' Access a GEOMEM62 Smart Card using the Proton SMART Development board. ' ' For use with the Crownhill Proton+ Compiler version 3.2.5.5 onwards. ' ' Original Code Concept by G.Cavarra 17/04/2007 ' Re-Written and Optimised by L.Johnson 29/05/2007 ' ' Connect Pins 13(RC2) and 14(RC3) together on the PICmicro for use with this code. ' This allows the PICmicro's PWM module to provide the 5MHz clock required by the card ' '------------------------------------------------------------------------------ ' Declarations '------------------------------------------------------------------------------ DEVICE = 16F876 ' PICmicro used in the PROTON SMART OPTIMISER_LEVEL = 6 ' Tighten the code generated REMINDERS = OFF ' Disable reminders in the program Declare XTAL = 20 ' We're using a 20MHZ crystal Declare HSERIAL_BAUD = 57600 ' Set the baud rate to 57600 Declare HSERIAL_RCSTA = %10010000 ' Enable serial port and continuous receive Declare HSERIAL_TXSTA = %00100100 ' Enable transmit and asynchronous mode Declare HSERIAL_CLEAR = ON ' Enable Error clearing on received characters Declare SERIAL_DATA 9 ' Set Serin and Serout data bits to 8 + parity Declare SERIAL_PARITY = EVEN ' Even Parity used for Serin and Serout '------------------------------------------------------------------------------ ' Variables '------------------------------------------------------------------------------ Dim AsyncData as Byte Dim BitCount as Byte Dim Temp as Byte Dim Parity as Byte Dim SB1 as Byte ' Card Status byte 1 Dim SB2 as Byte ' Card Status byte 2 Dim Length as Byte Dim Index as Byte Dim IndexII as Byte Dim Ta as Bit ' Interface character bits in ATR Dim Tb as Bit Dim Tc as Bit Dim Td as Bit Dim ResetOk as Bit Dim Countr as Byte Dim FileToAccess as Word ' File of interest within the card Dim Ri as Byte Dim Bte as Byte Dim PIN1[5] as Byte ' PIN 1 Container Dim PIN2[5] as Byte ' PIN 2 Container Dim Buffer1[256] as Byte '------------------------------------------------------------------------------ ' Port assignments '------------------------------------------------------------------------------ Symbol CardVcc = PORTA.5 ' Supplies the card with 5 Volts Symbol CardIn = PORTA.4 ' CARD in sensor switch (normally closed) symbol CardClk = PORTC.3 ' Card's CLK line Symbol CardIo = PORTC.4 ' Card's IO line Symbol CardRst = PORTA.3 ' Card's RESET line '------------------------------------------------------------------------------ ' Start of code '------------------------------------------------------------------------------ Goto Main ' Jump over the subroutines to the main program loop '------------------------------------------------------------------------------ ' Get Byte from card & Return with it in AsyncData ' ' Input : None ' Output : Variable "AsyncData" holds the byte read from the card ' Notes : The parity bit (bit-9) is ignored for this application ' GetData: Serin CardIo,$36,1000,TimeOut,[AsyncData] ' True data, 9600 baud baud using 20Mhz TimeOut: Return '------------------------------------------------------------------------------ ' Send Byte in AsyncData to the card ' ' Input : Variable "AsyncData" Holds the value to send to the card ' Output : None ' Notes : Data is sent 9 bits with EVEN parity ' : Calling "SendFFData" will send the value $FF ' SendFFData: AsyncData = $FF SendData: Temp = AsyncData ' Calculate Parity and place in bit-0 of Variable "Parity" Swapf Temp,W ' /\ Xorwf Temp,W ' | Movwf Parity ' | Rrf Parity,F ' | Rrf Parity,F ' | Xorwf Parity,F ' | Inc Parity ' \/ Rrf Parity,F ' Parity bit is now in bit 0 ( even ) High CardIo Clear CardIo ' Send the Start bit Delayus 72 ' Bit time For 9600 baud BitCount = 0 Repeat CardIo = Getbit AsyncData,BitCount ' Send the 8 Data bits Delayus 67 Inc BitCount Until BitCount > 7 CardIo = Parity.0 ' Send the 9th Parity bit Delayus 71 Set CardIo ' Send the Stop Bit Delayus 70 Input CardIo Return '------------------------------------------------------------------------------ ' Select the card file ' ' Input : Variable "FileToAccess" holds the address of the file to access ' Output : Variables "SB1" and "SB2" hold the response from the card ' Notes : None ' SelectFile: AsyncData = $EE : Gosub SendData AsyncData = $A4 : Gosub SendData AsyncData = $00 : Gosub SendData AsyncData = $00 : Gosub SendData AsyncData = $02 : Gosub SendData Gosub GetData ' Get card command Return ( $A4 ) While AsyncData = $60 ' Check For NULL - V4.09 Gosub GetData Wend Delayms 2 ' ' Select File ID ' AsyncData = FileToAccess.HighByte : Gosub SendData AsyncData = FileToAccess.LowByte : Gosub SendData ' ' Get card status bytes ' Gosub GetData SB1 = AsyncData ' Get Status byte 1 Gosub GetData SB2 = AsyncData ' Get Status byte 2 If SB1 = $9F Then Length = SB2 Endif Delayms 5 ' Wait approx 5mS between commands Return '------------------------------------------------------------------------------ ' Send Read Binary command to card ' ' Input : Variable "Length" holds the amount of bytes to send to the card ' Output : Variables "SB1" and "SB2" hold the response from the card ' Notes : None ' ReadBinary: AsyncData = $EE : Gosub SendData AsyncData = $B0 : Gosub SendData AsyncData = $00 : Gosub SendData ' EE address high Byte AsyncData = $00 : Gosub SendData ' EE address low Byte AsyncData = Length : Gosub SendData ' ' Get returned bytes ' Gosub GetData ' Instruction Return ' ' Read the File into Buffer1 ' Ri = 0 Repeat Gosub GetData Buffer1[Ri] = AsyncData Inc Ri Until Ri >= Length Gosub GetData SB1 = AsyncData ' Get Status byte 1 Gosub GetData SB2 = AsyncData ' Get Status byte 2 Return '------------------------------------------------------------------------------ ' Update file with binary data ' ' Input : Buffer1 holds the data to write to the file ' Output : Variables "SB1" and "SB2" hold the response from the card ' Notes : None ' UpdateBinary: AsyncData = $EE : Gosub SendData AsyncData = $D6 : Gosub SendData AsyncData = $00 : Gosub SendData ' EE address high Byte AsyncData = $00 : Gosub SendData ' EE address low Byte AsyncData = Length : Gosub SendData Gosub GetData ' Get card command Return ( $D6 or $29) Bte = AsyncData Delayms 2 Index = 0 Repeat AsyncData = Buffer1[Index] Gosub SendData If Bte = $29 Then Gosub GetData Bte = AsyncData Delayms 2 Endif Inc Index Until Index >= Length Gosub GetData SB1 = AsyncData ' Get Status byte 1 Gosub GetData SB2 = AsyncData ' Get Status byte 2 Delayms 10 Return '------------------------------------------------------------------------------ ' Verify PIN 1 ' ' Input : Byte array "PIN1" holds the 4 PIN characters ' Output : Variables "SB1" and "SB2" hold the response from the card ' Notes : None ' VerifyPin1: AsyncData = $EE : Gosub SendData AsyncData = $20 : Gosub SendData AsyncData = $00 : Gosub SendData AsyncData = $01 : Gosub SendData ' PIN 1 AsyncData = $08 : Gosub SendData ' ' Get returned bytes ' Gosub GetData ' Instruction Return If AsyncData = $98 Then EndPin1 Delayms 2 Index = 0 Repeat ' Send the PIN to the card AsyncData = PIN1[Index] Gosub SendData Inc Index Until Index > 3 Gosub SendFFData ' Send 4 bytes of $FF Gosub SendFFData Gosub SendFFData Gosub SendFFData Gosub GetData ' Get the response from the card EndPin1: SB1 = AsyncData ' Status byte 1 Gosub GetData SB2 = AsyncData ' Status byte 2 Return '------------------------------------------------------------------------------ ' Verify PIN 2 ' ' Input : Byte array "PIN2" holds the 4 PIN characters ' Output : Variables "SB1" and "SB2" hold the response from the card ' Notes : None ' VerifyPin2: AsyncData = $EE : Gosub SendData AsyncData = $20 : Gosub SendData AsyncData = $00 : Gosub SendData AsyncData = $02 : Gosub SendData ' PIN 2 AsyncData = $08 : Gosub SendData ' ' Get returned bytes ' Gosub GetData ' Instruction Return If AsyncData = $98 Then EndPin2 Delayms 2 Index = 0 Repeat ' Send the PIN to the card AsyncData = PIN2[Index] Gosub SendData Inc Index Until Index > 3 Gosub SendFFData ' Send 4 bytes of $FF Gosub SendFFData Gosub SendFFData Gosub SendFFData Gosub GetData ' Get the response from the card EndPin2: SB1 = AsyncData ' Status byte 1 Gosub GetData SB2 = AsyncData ' Status byte 2 Return '------------------------------------------------------------------------------ ' Reset the card, try 3 times max, each active high or active low ' ' Input : None ' Output : Bit Variable "ResetOk" is cleared if a fault occured ' Notes : None ' ResetCard: ResetOk = 0 Countr = 3 Repeat Dec Countr Low CardRst ' Active Low Reset Gosub GetATR If ResetOk = 1 Then Break Delayms 200 ' Delay between resets High CardRst ' Active High Reset Gosub GetATR If ResetOk = 1 Then Break Delayms 200 ' Delay between resets Until Countr = 0 Return '------------------------------------------------------------------------------ ' Receive and interpret the card's ATR ' ' Input : None ' Output : Bit variable "ResetOk" is cleared if a problem occured ' : Variable "Length" Holds the amount of values in the ATR ' Notes : None ' WARNINGS = OFF BYTE_MATH = ON ' Tighten the math operations GetATR: Length = 0 Gosub GetData If AsyncData = $3B Then ' Normal ATR - T0 ResetOk = 1 ' Set Reset Ok Endif If ResetOk = 0 Then Return Buffer1[0] = AsyncData ' Possibly inverted Gosub GetData Buffer1[1] = AsyncData ' Get length in low nibble Ta = (AsyncData & $10) >> 4 ' Interface character TA Tb = (AsyncData & $20) >> 5 ' Interface character TB Tc = (AsyncData & $40) >> 6 ' Interface character TC Td = (AsyncData & $80) >> 7 ' Interface character TD Length = AsyncData & $0F Length = Length + Ta Length = Length + Tb Length = Length + Tc Length = Length + Td Length = Length + 1 Index = 2 ' Read in remaining Bytes Repeat Gosub GetData Buffer1[Index] = AsyncData Inc Index Until Index > Length Delayms 500 Return BYTE_MATH = OFF WARNINGS = ON '------------------------------------------------------------------------------ ' Display the MAIN MEMORY via RS232 ' ' Input : Byte Array "Buffer1" holds the data to display ' Output : None ' Notes : Dispays both HEX and ASCII values ' DisplayMemory: Hrsout 13,13,"MEMORY:",13 For Index = 0 to 255 Step 16 Hrsout HEX2 Index , ": " IndexII = 0 ' Display HEX Repeat Hrsout HEX2 Buffer1[Index + IndexII] If IndexII < 15 Then Hrsout "," Inc IndexII Until IndexII > 15 Hrsout " | " IndexII = 0 ' Display ASCII Repeat Temp = Buffer1[Index + IndexII] Select Temp Case 32 To 127 ' Make sure only valid ASCII is displayed Hrsout Temp Case Else Hrsout "." EndSelect Inc IndexII Until IndexII > 15 Hrsout 13 Next Return '------------------------------------------------------------------------------ ' Entry point of main program '------------------------------------------------------------------------------ Main: Delayms 200 ' Wait for things to stabilise Clear ' Clear all RAM ALL_DIGITAL = TRUE ' Set all ports to digital mode PORTB_PULLUPS = OFF ' Turn ON PortB internal Pull-up Resistors ' ' Setup the PWM module for a card clock of 5MHz ' Input PORTC ' Hold the Clock line as an input until setup PR2 = 0 CCPR1L = 0 CCP1CON = %00101100 ' Set for PWM mode T2CON = %00000100 Output PORTC.2 ' Turn ON the Clock ' ' Main program loop ' While 1 = 1 ' Create an infinite loop ' ' Wait For the card to be inserted into the socket before continuing ' Low CardVcc ' Disable the card's VCC (5 Volts) Hrsout "GeoMem\rPlease Insert Card\r" While CardIn = 0 : Wend ' Wait For card insertion High CardVcc ' Enable the card's VCC (5 Volts) Delayms 100 ' Wait For the card to fully power up ' ' Reset the card ' Hrsout "CARD RESET\r" Gosub ResetCard If ResetOk = 1 Then Hrsout "Card reset OK\r" Else Hrsout "Card Reset Error!\r" Stop ' <<< STOP here if the reset was not succesful Endif ' ' Read and display the ATR ' Hrsout "\rATR : " Index = 0 Repeat Hrsout HEX2 Buffer1[Index]," " Inc Index Until Index > Length Hrsout 13 ' ' Select file $9F00 ' FileToAccess = $9F00 Gosub SelectFile Hrsout "\rSelect file Return: ",HEX2 SB1,HEX2 SB2 ' ' Send PIN 2 For write access ' Str PIN2 = "5678" Gosub VerifyPin2 Hrsout "\rVerify PIN2 Return: ",HEX2 SB1,HEX2 SB2 ' ' Write to the card ' Str Buffer1 = "GeoMem62 WRITE String" ' Data to write to the card Length = 21 ' The amount of data to write to the card Gosub UpdateBinary Hrsout "\rUpdate binary Return: ",HEX2 SB1,HEX2 SB2 ' ' Send PIN 1 For read access ' Str PIN1 = "1234" Gosub VerifyPin1 Hrsout "\rVerify PIN1 Return: ",HEX2 SB1,HEX2 SB2 ' ' Read the card ' Length = 255 ' Read 255 bytes Gosub ReadBinary Hrsout "\rRead binary Return: ",HEX2 SB1,HEX2 SB2 ' ' Display the card's memory ' Gosub DisplayMemory ' ' Wait For the card to be removed before proceeding ' While CardIn = 1 : Delayms 10 : Wend Wend