Reader evaluation, Hardware and software development, Enclosure design, testing
Different activities incorporated for implementing the project are listed below:
In Godrej we are using Smart card reader which reads data stored inside 1KB Mifare(ISO14443)Smarts cards.
There were 4 options available in readers as seen in below image
CSN is 4 byte card serial number. So basically using this reader we can either read CSN number or the data written inside the card using sector keys.
Reader communicates the data to controller either on serial(RS-232) or wiegand(Three lines D0,D1,GND)
As in our case data is written inside the cards so I am using sector read mode and for communicating to controller I have selected RS 232 interface as being bi-direction addition wires are not required for controlling reader led and buzzer which would been required if using wiegand
OEM of these reader is company by name Smarti, protocols for communicating with reader have been documented in below document
Reader Protocol DocumentI will be using below mentioned command for communicating will the reader over serial
Note : After configuring the reader into any mode it is required to power cycle the reader.
Have documented the command and their responses in below document
Reader command and responseFor testing and configuring the reader have developed below utility
Utility exe can be downloaded through below link
Smart card reader configuration utilityReader requires 12 Volt supply for operation and can be connected to PC/Laptop over serial port or by using USB to serial converter
You need to select the COM over which reader get connected then utility can be used to :
Below video shows how utility can be used to configure and check the reader
Below are the minimum specs required in the controller
These requirement were not met by ATtiny45, so decided to use LM3S6965 as it meets all above mentioned requirement and was being used by one of my collegue and was available with us.
LM 3S6965 code can be easily ported to TIVA series microcontroller the successor of LM 3S6965. Below document explain in details on step by step procedure for migration.
Migrating from stellaris to Tiva documentMain features of LM 3S 6965
For more details about the micro controller please refer below datasheet of LM3S6965
Datasheet - LM 3S6965For current application we will be using:
Before actual board was design and fabricated I started my development work on 6965 Evaluation board.
The Stellaris LM3S6965 Evaluation Kit for Ethernet provides a low-cost way to start designing Ethernet applications with Stellaris microcontrollers. The LM3S6965 Evaluation Board (EVB) can function as either a complete evaluation target, or as a debugger interface to any external Stellaris device. The included USB cable is all that is needed to provide power and communication to the host PC.
The Stellaris LM3S6965 Evaluation Kit can operate as an In-Circuit Debugger Interface (ICDI). ICDI acts as a USB to the JTAG/SWD adaptor, allowing debugging of any external target boar that uses a Stellaris microcontroller.
For further details about Eval board you may refer below documents:
6965 Eval board-ReadmeBefore proceeding with developing and programming code, it is required to program the MAC id into the controller. LM flash programmer utility can be used for same.
Utility can be downloaded using below link
LM Flash ProgrammerBelow steps are required to be followed for programming the MAC address:
LM flash programmer can also be used for programming the board. For programming the board using LM flash programmer follow below mentioned steps:
As in my project I intended to track the uses of the machine by an individual it was required to use an accurate rtc
So had decided to use bq 32000 real time clock from TI
Main features of RTC are listed below:
Below is the datasheet of BQ 32000 crystal
BQ 32000 datasheetI2C interface with microcontroller
The I2C interface allows control and monitoring of the RTC by a microcontroller. I2C is a two-wire serial interface. The bus consists of a data line (SDA) and a clock line (SCL) with off-chip pullup resistors. When the bus is idle both SDA and SCL lines are pulled high.
rtc_1A master device, usually a microcontroller or a digital signal processor, controls the bus. The master is responsible for generating the SCL signal and device addresses. The master also generates specific conditions that indicate the START and STOP of data transfer. A slave device receives and/or transmits data on the bus under control of the master device. BQ32000 operates only as a slave device.
I2C communication is initiated by a master sending a start condition, a high-to-low transition on the SDA I/O while SCL is held high. After the start condition, the device address byte is sent, most-significant bit (MSB) first, including the data direction bit (R/W). After receiving a valid address byte, this device responds with an acknowledge, a low on the SDA I/O during the high of the acknowledge-related clock pulse. This device responds to the I2C slave address 11010000b for write commands and slave address 11010001b for read commands.
Further details are available in data sheet
Software is required for communicating with the controlling. Software will be communicating with the controller over RS 232 interface.
Software will be divided into 3 sections
Before starting with actual implementation of software have made rough sketches of same using paper pen.
Have decided to use VB language for software development and .Net framework as found it to be convinient for my application
This test code detect the available COM ports and shows them in drop box list
Second dropdown provides the list of baud rates which we want to use for communication
Using button 1 we can open the port and button 2 was used to send data written onto text box on selected COM port at selected baud rate. For testing whatever data listen on serial is shown in output window. For testing purpose have shorted RX and TX of my laptop serial port so if every thing is working okay should be able to see the data I am sending on debug output window.
Again had started by writing it on paper
Started with new project by name Amol_FAB_BOMBAY_PROJECT
Have created a module where I am going to define all the commands and there replies. The reason was so I will be able to modify it easy in future. Also if there are multiple form each form is able to access these values.
Designing forms and writting backend code.
Tab 1 : This form will be used for establishing connection with the controller board. Using drop down user has to select the COM port and baud rate and then click on connect button. If connection is successful Connection success message will be displayed else Error in connection message will be displayed.
Tab 2 : Here user has to enter card number(max 8 digit) and then select expiry date for the card.
Later click onUpload card button. If card is uploaded successfully Success dialogue box will pop up else
error dialogue box.
Using Get Date/Time button we can read the date/time set inside the controller. It will get displayed
in Date and Time boxes. If we wish set the date click on set date/time button. When this button is
pressed PC date and time is sync with the controller.
Tab 3 : It is used for downloading log from the controller. When user click on Get Log button, logs from controller are read and shown on display grid. Also the logs gets stored into text file at location were software exe is kept.
As the activity of downloading the log takes longer time "Please wait message is shown to inform user to wait."
Pre defined time out is added for all commands. Whenever there is no response from the controller. Software display a dialogue box saying "Error connecting to device"
It starts with the microcontroller. As I was using a new IC I had a task of drawing it pinout and PCB layout. Instead of doing it I downloaded it from snapEDA. This site has millions of parts readily available for download
Before proceding this site asks you to register. Once you sign up using your valid email id you can access the resources available on site.
Using the search option search for desired part. In my case it was LM 3S6965
Select your desired part from the list
Then click on download footprint and symbol.
Once the library file for desired part is downloaded save it in eagle library folder.
Then the library will be visible in list of libraries.
For using the component we have to activate the library. A green dot come in front of library
Selecting the components
Selecting the frame for circuit digram
Final circuit diagram - Page 1 : Microcontroller, regulator, crystal etc
Final circuit diagram - Page 2 : RTC, MAX 232 , serial connectors.
Preparing layout using EagleIt was a very though task to prepare the layout on single layer board as there are many power and ground connections in 6965.
We can enter the layout mode by clicking on sch/lay toggle button
Select approx PCB size Start placing the components starting with microcontroller, power IC Placing all components on PCB ensuring minimal track overlap. Adding ground polygon Adding DRC parameters Doing autoroutingI am using Keil complier for writing the code
Stellaris has provided lot of example code and library files for reference. It can be downloaded from below link
Sellarisware driver libraryBelow is the Startup file : We have set Stack size, Heap size as per requirement, Also have to provide external declarations for the interrupt handlers used by the application and change there name in vector table. I have also modified the the code to get reset if Non maskable interrupt, fault interrupt or unhandled interrupt occurs to avoid the code getting hang.
Below is my Startup.S file
; <<< Use Configuration Wizard in Context Menu >>>
;******************************************************************************
;
; startup_rvmdk.S - Startup code for use with Keil's uVision.
;
; Copyright (c) 2008-2010 Texas Instruments Incorporated. All rights reserved.
; Software License Agreement
;
; Texas Instruments (TI) is supplying this software for use solely and
; exclusively on TI's microcontroller products. The software is owned by
; TI and/or its suppliers, and is protected under applicable copyright
; laws. You may not combine this software with "viral" open-source
; software in order to form a larger program.
;
; THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
; NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
; NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
; A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
; CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
; DAMAGES, FOR ANY REASON WHATSOEVER.
;
; This is part of revision 5570 of the EK-LM3S6965 Firmware Package.
;
;******************************************************************************
;******************************************************************************
;
; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
;******************************************************************************
Stack EQU 0x00001500
;******************************************************************************
;
; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
;******************************************************************************
Heap EQU 0x00000000
;******************************************************************************
;
; Allocate space for the stack.
;
;******************************************************************************
AREA STACK, NOINIT, READWRITE, ALIGN=3
StackMem
SPACE Stack
__initial_sp
;******************************************************************************
;
; Allocate space for the heap.
;
;******************************************************************************
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
HeapMem
SPACE Heap
__heap_limit
;******************************************************************************
;
; Indicate that the code in this file preserves 8-byte alignment of the stack.
;
;******************************************************************************
PRESERVE8
;******************************************************************************
;
; Place code into the reset code section.
;
;******************************************************************************
AREA RESET, CODE, READONLY
THUMB
;******************************************************************************
;
; External declarations for the interrupt handlers used by the application.
;
;******************************************************************************
EXTERN lwIPEthernetIntHandler
EXTERN SysTickIntHandler
EXTERN UART0IntHandler
EXTERN UART1IntHandler
EXTERN UART2IntHandler
EXTERN Timer0IntHandler
EXTERN Timer1IntHandler
EXTERN BusFaultHandler
EXTERN NmiSR
EXTERN FaultISR
EXTERN GPIOcIntHandler
EXTERN GPIObIntHandler
EXTERN IntDefaultHandler
EXTERN WatchdogIntHandler
;******************************************************************************
;
; The vector table.
;
;******************************************************************************
EXPORT __Vectors
__Vectors
DCD StackMem + Stack ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NmiSR ; NMI Handler
DCD FaultISR ; Hard Fault Handler
DCD IntDefaultHandler ; The MPU fault handler
DCD BusFaultHandler ; The bus fault handler
DCD IntDefaultHandler ; The usage fault handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD IntDefaultHandler ; SVCall handler
DCD IntDefaultHandler ; Debug monitor handler
DCD 0 ; Reserved
DCD IntDefaultHandler ; The PendSV handler
DCD SysTickIntHandler ; The SysTick handler
DCD IntDefaultHandler ; GPIO Port A
DCD GPIObIntHandler ; GPIO Port B
DCD GPIOcIntHandler ; GPIO Port C
DCD IntDefaultHandler ; GPIO Port D
DCD IntDefaultHandler ; GPIO Port E
DCD UART0IntHandler ; UART0 Rx and Tx
DCD UART1IntHandler ; UART1 Rx and Tx
DCD IntDefaultHandler ; SSI0 Rx and Tx
DCD IntDefaultHandler ; I2C0 Master and Slave
DCD IntDefaultHandler ; PWM Fault
DCD IntDefaultHandler ; PWM Generator 0
DCD IntDefaultHandler ; PWM Generator 1
DCD IntDefaultHandler ; PWM Generator 2
DCD IntDefaultHandler ; Quadrature Encoder 0
DCD IntDefaultHandler ; ADC Sequence 0
DCD IntDefaultHandler ; ADC Sequence 1
DCD IntDefaultHandler ; ADC Sequence 2
DCD IntDefaultHandler ; ADC Sequence 3
DCD WatchdogIntHandler ; Watchdog timer
DCD Timer0IntHandler ; Timer 0 subtimer A
DCD Timer0IntHandler ; Timer 0 subtimer B
DCD IntDefaultHandler ; Timer 1 subtimer A
DCD IntDefaultHandler ; Timer 1 subtimer B
DCD IntDefaultHandler ; Timer 2 subtimer A
DCD IntDefaultHandler ; Timer 2 subtimer B
DCD IntDefaultHandler ; Analog Comparator 0
DCD IntDefaultHandler ; Analog Comparator 1
DCD IntDefaultHandler ; Analog Comparator 2
DCD IntDefaultHandler ; System Control (PLL, OSC, BO)
DCD IntDefaultHandler ; FLASH Control
DCD IntDefaultHandler ; GPIO Port F
DCD IntDefaultHandler ; GPIO Port G
DCD IntDefaultHandler ; GPIO Port H
DCD UART2IntHandler ; UART2 Rx and Tx
DCD IntDefaultHandler ; SSI1 Rx and Tx
DCD IntDefaultHandler ; Timer 3 subtimer A
DCD IntDefaultHandler ; Timer 3 subtimer B
DCD IntDefaultHandler ; I2C1 Master and Slave
DCD IntDefaultHandler ; Quadrature Encoder 1
DCD IntDefaultHandler ; CAN0
DCD IntDefaultHandler ; CAN1
DCD IntDefaultHandler ; CAN2
DCD lwIPEthernetIntHandler ; Ethernet
DCD IntDefaultHandler ; Hibernate
;******************************************************************************
;
; This is the code that gets called when the processor first starts execution
; following a reset event.
;
;******************************************************************************
EXPORT Reset_Handler
Reset_Handler
;
; Call the C library enty point that handles startup. This will copy
; the .data section initializers from flash to SRAM and zero fill the
; .bss section.
;
IMPORT __main
B __main
;******************************************************************************
;
; This is the code that gets called when the processor receives a NMI. This
; simply enters an infinite loop, preserving the system state for examination
; by a debugger.
;
;******************************************************************************
;NmiSR
; B NmiSR
;******************************************************************************
;
; This is the code that gets called when the processor receives a fault
; interrupt. This simply enters an infinite loop, preserving the system state
; for examination by a debugger.
;
;******************************************************************************
;FaultISR
; B FaultISR
;******************************************************************************
;
; This is the code that gets called when the processor receives an unexpected
; interrupt. This simply enters an infinite loop, preserving the system state
; for examination by a debugger.
;
;******************************************************************************
;IntDefaultHandler
; B IntDefaultHandler
;******************************************************************************
;
; Make sure the end of this section is aligned.
;
;******************************************************************************
ALIGN
;******************************************************************************
;
; Some code in the normal code section for initializing the heap and stack.
;
;******************************************************************************
AREA |.text|, CODE, READONLY
;******************************************************************************
;
; The function expected of the C library startup code for defining the stack
; and heap memory locations. For the C library version of the startup code,
; provide this function so that the C library initialization code can find out
; the location of the stack and heap.
;
;******************************************************************************
IF :DEF: __MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, =HeapMem
LDR R1, =(StackMem + Stack)
LDR R2, =(HeapMem + Heap)
LDR R3, =StackMem
BX LR
ENDIF
;******************************************************************************
;
; Make sure the end of this section is aligned.
;
;******************************************************************************
ALIGN
;******************************************************************************
;
; Tell the assembler that we're done.
;
;******************************************************************************
END
Firmware development can be divided into below mentioned sub parts:
// Enable the peripherals
SysCtlPeripheralEnable( SYSCTL_PERIPH_UART2 );
SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOG );
// Set GPIO G0 and G1 as UART pins.
GPIOPinTypeUART( GPIO_PORTG_BASE, Serial2_Rx | Serial2_Tx );
// Configure the UART for 9600, 8-N-1 operation.
UARTConfigSetExpClk( UART2_BASE, SysCtlClockGet(), 9600,
( UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE ) );
//Set the UART FIFO Level
UARTFIFOLevelSet( UART2_BASE, UART_FIFO_TX1_8,UART_FIFO_RX1_8 );
// Enable the UART interrupt.
IntEnable( INT_UART2 );
UARTIntEnable( UART2_BASE, UART_INT_RX | UART_INT_RT );
#define RX_BUFFER_SIZE_2 100
#define TX_BUFFER_SIZE_2 5000
#define TX_TIMEOUT_2 1
#define RX_TIMEOUT_2 1
-------------------------------------CLEAR UART 2 TX BUFFER------------------------------------
void clear_uart_2_tx_buffer()
{
unsigned int i;
tx_timeout_counter_2=0;
for (i=0;i < TX_BUFFER_SIZE_2;i++)
{
tx_buffer_2[i] = 0;
}
}
-------------------------------------CLEAR UART 2 RX BUFFER------------------------------------
void clear_uart_2_rx_buffer()
{
unsigned int i;
rx_count_2 = 0;
rx_start_2 = false;
rx_command_ready_2 =false;
rx_timeout_counter_2=0;
for (i=0;i < RX_BUFFER_SIZE_2;i++)
{
rx_buffer_2[i] = 0;
}
}
void UART2IntHandler(void)
{
unsigned long ulStatus;
tBoolean rx_interrupt = false;
tBoolean tx_interrupt = false;
unsigned char received_char = 0;
// Get the interrrupt status.
ulStatus = UARTIntStatus( UART2_BASE, true );
if( UART_INT_RX )
{
rx_interrupt = true;
}
if( UART_INT_TX )
{
tx_interrupt = true;
}
// Clear the asserted interrupts. Clearing an interrupt takes time.
UARTIntClear( UART2_BASE, ulStatus );
if(rx_interrupt == true)
{
received_char = UARTCharGetNonBlocking( UART2_BASE );
if (rx_command_ready_2 == false) //Ensuring that previous data has been processed
{
rx_buffer_2[rx_count_2++] = received_char;
rx_start_2 = true;
if(rx_count_2 == 2)
{
if((rx_buffer_2[0] == 'C') && (rx_buffer_2[1] == 'O'))
{
rx_command_ready_2 = true;
rx_start_2 = false;
cmd_no = 1;
}
if((rx_buffer_2[0] == 'G') && (rx_buffer_2[1] == 'D'))
{
rx_command_ready_2 = true;
rx_start_2 = false;
cmd_no = 4;
}
if((rx_buffer_2[0] == 'G') && (rx_buffer_2[1] == 'L'))
{
rx_command_ready_2 = true;
rx_start_2 = false;
cmd_no = 5;
}
}
if(rx_count_2 == 18)
{
if(rx_buffer_2[0] == 'U' && rx_buffer_2[1] == 'C')
{
rx_command_ready_2 = true;
rx_start_2 = false;
cmd_no = 2;
}
}
if(rx_count_2 == 16)
{
if(rx_buffer_2[0] == 'S' && rx_buffer_2[1] == 'D')
{
rx_command_ready_2 = true;
rx_start_2 = false;
cmd_no = 3;
}
}
if(rx_count_2 > 18)
{
clear_uart_2_rx_buffer();
cmd_no = 0;
}
}
rx_interrupt = false;
}
if(tx_interrupt==true)
{
tx_interrupt=false;
}
}
void process_serial_command_2(void)
{
unsigned int i,length = 0;
// long temp_read_pointer;
unsigned char checksum = 0;
long err_flag;
if(rx_command_ready_2 == true)
{
switch (cmd_no)
{
case 1:
tx_buffer_2[0] = 'C';
tx_buffer_2[1] = 'O';
tx_buffer_2[2] = 'O';
tx_buffer_2[3] = 'K';
for(i = 0 ; i < 4 ; i++)
{
UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
}
break;
case 2:
ascii_to_digit(2,2,18);
err_flag = InsertDelTimeZone(rx_buffer_2);
if(err_flag == 0) //SUCCESS;
{
tx_buffer_2[0] = 'U';
tx_buffer_2[1] = 'C';
tx_buffer_2[2] = 'O';
tx_buffer_2[3] = 'K';
for(i = 0 ; i < 4 ; i++)
{
UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
}
}
else if(err_flag == -1) //FAILURE;
{
tx_buffer_2[0] = 'U';
tx_buffer_2[1] = 'C';
tx_buffer_2[2] = 'E';
tx_buffer_2[3] = 'R';
tx_buffer_2[3] = 'R';
for(i = 0 ; i < 5 ; i++)
{
UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
}
}
else if(err_flag == -2) //MEMORY_FULL;
{
tx_buffer_2[0] = 'U';
tx_buffer_2[1] = 'C';
tx_buffer_2[2] = 'E';
tx_buffer_2[3] = 'R';
tx_buffer_2[3] = 'R';
for(i = 0 ; i < 5 ; i++)
{
UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
}
}
break;
case 3:
ascii_to_digit(2,2,16);
new_present_time.date = (rx_buffer_2[2] * 10);
new_present_time.date = (new_present_time.date + rx_buffer_2[3]);
new_present_time.month = (rx_buffer_2[4] * 10);
new_present_time.month = (new_present_time.month + rx_buffer_2[5]);
new_present_time.year = (rx_buffer_2[8] * 10);
new_present_time.year = (new_present_time.year + rx_buffer_2[9]);
new_present_time.hour = (rx_buffer_2[10] * 10);
new_present_time.hour = (new_present_time.hour + rx_buffer_2[11]);
new_present_time.min = (rx_buffer_2[12] * 10);
new_present_time.min = (new_present_time.min + rx_buffer_2[13]);
new_present_time.sec = (rx_buffer_2[14] * 10);
new_present_time.sec = (new_present_time.sec + rx_buffer_2[15]);
err_flag = set_Current_Date_Time(&new_present_time);
insert_attendence_log(DateTime_Set,0,0);
if(err_flag == 0) //SUCCESS;
{
tx_buffer_2[0] = 'S';
tx_buffer_2[1] = 'D';
tx_buffer_2[2] = 'O';
tx_buffer_2[3] = 'K';
for(i = 0 ; i < 4 ; i++)
{
UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
}
}
else if(err_flag == -1) //FAILURE;
{
tx_buffer_2[0] = 'S';
tx_buffer_2[1] = 'D';
tx_buffer_2[2] = 'E';
tx_buffer_2[3] = 'R';
tx_buffer_2[3] = 'R';
for(i = 0 ; i < 5 ; i++)
{
UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
}
}
break;
case 4:
tx_buffer_2[0] = 'G';
tx_buffer_2[1] = 'D';
sprintf(tx_buffer_2+2,"%02d",date_time_variable.date);
sprintf(tx_buffer_2+4,"%02d",date_time_variable.month);
sprintf(tx_buffer_2+6,"%02d",date_time_variable.year);
sprintf(tx_buffer_2+8,"%02d",date_time_variable.hour);
sprintf(tx_buffer_2+10,"%02d",date_time_variable.min);
sprintf(tx_buffer_2+12,"%02d",date_time_variable.sec);
for(i = 0 ; i < 14 ; i++)
{
UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
}
break;
case 5:
tx_buffer_2[0] = 'G';
tx_buffer_2[1] = 'L';
SendAllEvent();
for(i = 0 ; i < 3000 ; i++)
{
if(tx_buffer_2[i] == 0)
{}
else
{
length++;
}
}
for(i = 0 ; i < length ; i++) //2690
{
UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
mili_sec(5);
}
break;
default:
break;
}
clear_uart_2_rx_buffer();
rx_command_ready_2 = false;
}
}
Have written driver files for serial UART2 for PC communication
Board can be connected to software using 3 wires Rx, Tx and GND
6965 has 256KB of internal flash. I am using the same flash for storing Employee data and logs.
typedef struct
{
unsigned long empid;
unsigned char exp_date; //card expiry date,month and year
unsigned char exp_month;
unsigned char exp_year;
unsigned char reserve;
unsigned short int nextrec;
// structure padding
unsigned char reserved[6];
}employee_rec;
typedef struct
{
unsigned char event;
unsigned char source;
unsigned char year;
unsigned char month;
unsigned char date;
unsigned char hour;
unsigned char min;
unsigned char sec;
unsigned long empid;
unsigned char read_status;
unsigned char reserved[3];
// structure padding
}event_rec;
This structure has to be kept in multiple of 8.
Nextrec in employee is used for jumping to next location if employee data is reinserted
. So it helps in fast searching.
#define PARAM_1B_PAGES ((sizeof(param_1b)*MAX_PARAM_1B)/PAGE_SIZE)+1
#define PARAM_1B_REC_PER_PAGE PAGE_SIZE/sizeof(param_1b)
#define PARAM_4B_PAGES ((sizeof(param_4b)*MAX_PARAM_4B)/PAGE_SIZE)+1
#define PARAM_4B_REC_PER_PAGE PAGE_SIZE/sizeof(param_4b)
#define EVENT_PAGES ((sizeof(event_rec)*MAX_EVENT_REC)/PAGE_SIZE)+1
#define EVENT_REC_PER_PAGE PAGE_SIZE/sizeof(event_rec)
#define EMPLOYEE_PAGES ((sizeof(employee_rec)*MAX_EMPLOYEE)/PAGE_SIZE)+1
#define EMPLOYEE_REC_PER_PAGE PAGE_SIZE/sizeof(employee_rec)
#define PARAM_1B_START (param_1b *)0x00019400
#define PARAM_4B_START (param_4b *)((unsigned long)(PARAM_1B_START) + ((PARAM_1B_PAGES)*PAGE_SIZE) + BUFFER)
#define EVENT_START (event_rec *)((unsigned long)(PARAM_4B_START) + ((PARAM_4B_PAGES)*PAGE_SIZE) + BUFFER)
#define EMPLOYEE_START (employee_rec *)((unsigned long)(EVENT_START) + ((EVENT_PAGES)*PAGE_SIZE) + BU
Param are used for storing various 1 byte and 4 byte data which is required to be stored and retained in non volatile flash.
int read_attd_log_complete(void)
{
event_rec cur_rec;
int writeerr;
memset(&cur_rec,0xff,sizeof(event_rec));
writeerr = -1; /* error by default */
if(read_pointer != write_pointer)
{
/* record modification is required */
memcpy(&cur_rec,read_pointer,sizeof(event_rec));
if(cur_rec.event != 0xff)
{
cur_rec.read_status = 0x00;
writeerr = FlashProgram((unsigned long *)&cur_rec,(unsigned long )read_pointer,sizeof(event_rec));
}
if((unsigned long)((unsigned long)read_pointer + sizeof(event_rec)) == (unsigned long)((unsigned long)EVENT_START + sizeof(event_rec)* MAX_EVENT_REC))
{
read_pointer = EVENT_START;
}
else
{
read_pointer++;
}
}
return (writeerr);
}
event_rec* read_attd_log(void)
{
event_rec *ret;
if(read_pointer != write_pointer)
{
if(read_pointer->event == 0xff || read_pointer->read_status == 0x00)
{
init_attd_pointers();
}
if(read_pointer == write_pointer)
{
ret = NULL;
}else
{
ret = read_pointer;
}
}
else
{
ret = NULL;
}
return(ret);
}
long init_attd_pointers(void)
{
event_rec *search;
int count;
unsigned char read_found = 0,write_found = 0,temp_read = 0;
event_log_count = 0;
search = EVENT_START;
for(count = 1; count <= MAX_EVENT_REC; count++)
{
/*Write Pointer */
if(write_found == 0)
{
if(search->event == 0xff)
{
write_pointer = search;
write_found = 1;
}
else
{
event_log_count++;
}
if(count == MAX_EVENT_REC && write_found == 0)/*Memory corrput case */
{
//clear_all_logs();
read_pointer = EVENT_START;
write_pointer = EVENT_START;
read_found = 1;
write_found = 1;
}
}
/*Read pointer */
if(read_found == 0)
{
/*Flash has overflowed once */
if(g_sParameters.attd_flash_cycle_complete == 1)
{
if(temp_read == 0)
{
if(search->event != 0xff)
{
if(search->read_status == 0xff)
{
temp_read = 3;
}
else if(search->read_status == 0x00)
{
temp_read = 1;
}else
{
temp_read = 0;
}
}
else if(search->event == 0xff)
{
temp_read = 2;
}else
{
temp_read = 0;
}
}
else if(temp_read == 1)
{
if(search->event == 0xff)
{
read_pointer = search;
read_found = 1;
}else
{
}
if(search->event != 0xff)
{
if(search->read_status == 0xff)
{
read_pointer = search;
read_found = 1;
}else
{
}
}else
{
}
}
else if(temp_read == 2)
{
if(count == EVENT_REC_PER_PAGE+1)
{
if(search->event == 0xff)/*Memory corrupt case */
{
//clear_all_logs();
read_pointer = EVENT_START;
write_pointer = EVENT_START;
read_found = 1;
write_found = 1;
}
else
{
/*Search read pointer normally */
if(search->read_status == 0xff)
{
read_pointer = search;
read_found = 1;
}
else if(search->read_status == 0x00)
{
temp_read = 1;
}else
{
}
}
}else
{
}
}
else if(temp_read == 3)
{
if(search->event == 0xff)
{
temp_read = 4;
}else
{
}
}
else if(temp_read == 4)
{
if(search->event != 0xff)
{
if(search->read_status == 0xff)
{
read_pointer = search;
read_found = 1;
}
else if(search->read_status == 0x00)
{
temp_read = 5;
}else
{
}
}else
{
}
}
else if(temp_read == 5)
{
if(search->event != 0xff && search->read_status == 0xff)
{
read_pointer = search;
read_found = 1;
}else
{
}
}else
{
}
}
else/*Flash has not been full yet */
{
if(temp_read == 0)
{
if(search->event != 0xff)
{
if(search->read_status == 0xff)
{
read_pointer = search;
read_found = 1;
}
else if(search->read_status == 0x00)
{
temp_read = 1;
}else
{
}
}else if(search->event == 0xff)/*Normal case when all the flash is blank */
{ /*or Unusual case if valid read or unread records are found after first page */
temp_read = 2;
}else
{
}
}
else if(temp_read == 1)/*Some read log is found and searches for a unread log */
{
if(search->event == 0xff)
{
read_pointer = search;
read_found = 1;
}
else if(search->event != 0xff)
{
if(search->read_status == 0xff)
{
read_pointer = search;
read_found = 1;
}else
{
}
}
}
else if(temp_read == 2)
{
if(count == EVENT_REC_PER_PAGE+1)
{
if(search->event == 0xff)
{
read_pointer = EVENT_START;
read_found = 1;
}
else
{
/*Search read pointer normally */
if(search->read_status == 0xff)
{
read_pointer = search;
read_found = 1;
}
else if(search->read_status == 0x00)
{
temp_read = 1;
}
}
}else
{
}
}else
{
}
}
}else
{
}
search++;
if ((count % (EVENT_REC_PER_PAGE)) == 0) /* count starts with 1 */
{
if(write_found == 0)
{
latest_pagewrite_start = search;
event_log_count = 0;
}else
{
}
}else
{
}
if((read_found == 1) && (write_found == 1))
{
break;
}else
{
}
}
return 1;
}
long add_attendence_rec(event_rec* pbuffer)
{
event_rec cur_rec,prev_rec,*temp_addr;
long writeerr;
unsigned long address = 0;
writeerr = -1; /* error by default */
memset(&cur_rec,0xff,sizeof(event_rec));
memset(&prev_rec,0xff,sizeof(event_rec));
if(write_pointer == EVENT_START)
{
if(g_sParameters.attd_flash_cycle_complete)
{
temp_addr = (event_rec*)((unsigned long)EVENT_START + ((EVENT_PAGES-1)*PAGE_SIZE)-sizeof(event_rec));
memcpy(&prev_rec,temp_addr,sizeof(event_rec));
memcpy(&cur_rec,write_pointer,sizeof(event_rec));
if(cur_rec.event != 0xff || prev_rec.event == 0xff)
{
init_attd_pointers();
}
}
}
else
{
memcpy(&prev_rec,write_pointer-1,sizeof(event_rec));
memcpy(&cur_rec,write_pointer,sizeof(event_rec));
if(cur_rec.event != 0xff || prev_rec.event == 0xff)
{
init_attd_pointers();
}
}
if(event_log_count == ((EVENT_REC_PER_PAGE)-1))
{
if((unsigned long)((unsigned long)write_pointer+sizeof(event_rec)) == (unsigned long)((unsigned long)EVENT_START + sizeof(event_rec)* MAX_EVENT_REC))
{
address = (unsigned long)EVENT_START;
writeerr = FlashErase(address);
writeerr = FlashProgram((unsigned long *)pbuffer, (unsigned long)write_pointer, sizeof(event_rec));
write_pointer = EVENT_START;
latest_pagewrite_start = write_pointer;
event_log_count = 0;
if(g_sParameters.attd_flash_cycle_complete == 0)
{
g_sParameters.attd_flash_cycle_complete = 1;
SaveParam1b(ATTD_FLASH_ID);
}
}
else
{
address = (unsigned long)((unsigned long)latest_pagewrite_start + PAGE_SIZE);
writeerr = FlashErase(address);
writeerr = FlashProgram((unsigned long *)pbuffer, (unsigned long)write_pointer, sizeof(event_rec));
write_pointer++;
latest_pagewrite_start = write_pointer;
event_log_count = 0;
}
if((read_pointer >= write_pointer) && ((unsigned long)read_pointer < (unsigned long)((unsigned long)write_pointer+PAGE_SIZE)))
{
read_pointer = (event_rec*)((unsigned long)write_pointer+PAGE_SIZE);
}
}
else
{
writeerr = FlashProgram((unsigned long *)pbuffer, (unsigned long)write_pointer, sizeof(event_rec));
write_pointer++;
event_log_count++; /*take care what happens when it becomes greater than 32 */
}
return(writeerr);
}
These function are required as in flash we can't erase byte but having to erase entire page of 1KB and flash has fixed number of read write cycles.
int update_bankstatus_employee(void)
{
int count,pageno,free_pageno;
employee_rec *cur_rec;
employee_current_page.free = 0;
employee_current_page.deleted = 0;
employee_current_page.active = 0;
employee_maxfree_page.free = 0;
employee_maxfree_page.deleted = 0;
employee_maxfree_page.active = 0;
free_pageno = 0;
pageno = 0;
cur_rec = EMPLOYEE_START;
for(count = 1; count <= MAX_EMPLOYEE; count++)
{
if (cur_rec->empid != 0xffffffff)
{
if (cur_rec->nextrec != 0xffff)
{
employee_current_page.deleted++;
}else
{
employee_current_page.active++;
}
}else
{
employee_current_page.free++;
}
cur_rec++;
if ((count % (TIMEZONE_REC_PER_PAGE)) == 0) // count starts with 1
{
if (employee_current_page.deleted > employee_maxfree_page.deleted)
{
employee_maxfree_page.free = employee_current_page.free;
employee_maxfree_page.deleted = employee_current_page.deleted;
employee_maxfree_page.active = employee_current_page.active;
free_pageno = pageno;
}
employee_current_page.free = 0;
employee_current_page.deleted = 0;
employee_current_page.active = 0;
pageno++;
}
}
if (employee_current_page.deleted > employee_maxfree_page.deleted)
{
employee_maxfree_page.free = employee_current_page.free;
employee_maxfree_page.deleted = employee_current_page.deleted;
employee_maxfree_page.active = employee_current_page.active;
free_pageno = pageno;
}
return (free_pageno);
}
employee_rec * defragment_timezone(void)
{
int count, pageno;
employee_rec *cur_rec;
unsigned char temp_page[PAGE_SIZE];
unsigned char *temp_page_start;
//temp_page = (unsigned char *)malloc(PAGE_SIZE);
temp_page_start = temp_page;
memset(temp_page,0xff,PAGE_SIZE);
pageno = update_bankstatus_employee();
cur_rec = NULL;
if (employee_maxfree_page.deleted > 0)
{
cur_rec = (employee_rec *)((unsigned long)TIMEZONE_START + (pageno * PAGE_SIZE));
for(count = 1; count <= TIMEZONE_REC_PER_PAGE; count++)
{
if (cur_rec->nextrec == 0xffff)
{
memcpy(temp_page_start,(unsigned char *)cur_rec,sizeof(employee_rec));
}else
{
memset(temp_page_start,0xff,sizeof(employee_rec));
}
cur_rec++;
temp_page_start += sizeof(employee_rec);
}
cur_rec = (employee_rec *)((unsigned long)TIMEZONE_START + (pageno * PAGE_SIZE));
FlashErase((unsigned long )cur_rec);
FlashProgram((unsigned long *)temp_page,(unsigned long)cur_rec,PAGE_SIZE);
cur_rec = (employee_rec *)((unsigned long)TIMEZONE_START + (pageno * PAGE_SIZE));
for(count = 1; count <= TIMEZONE_REC_PER_PAGE; count++)
{
if ((cur_rec->empid == 0xffffffff) && (cur_rec->nextrec == 0xffff))
{
break;
}
cur_rec++;
}
if (count > TIMEZONE_REC_PER_PAGE)
{
cur_rec = NULL;
}
}
// free(temp_page);
return(cur_rec);
}
employee_rec * get_free_employee(void)
{
employee_rec *search;
int count, found;
search = TIMEZONE_START;
found = -1;
for (count = 1; count <= MAX_EMPLOYEE; count++)
{
if (search->empid == 0xffffffff && search->nextrec == 0xffff)
{
found = count;
break;
}
search++;
}
if (found < 0)
{
search = defragment_timezone();
}
return(search);
}
employee_rec * check_employee(employee_rec *pbuffer)
{
int found;
int count,prev_count;
employee_rec *reference,*prev_reference;
reference = TIMEZONE_START;
found = -1;
for(count = 1; count <= MAX_EMPLOYEE; count++)
{
if (reference->empid == pbuffer->empid)
{
if(reference->nextrec == 0xffff)
{
found = count;
break;
}
else if(reference->nextrec != 0x0000)
{
prev_count = count;
prev_reference = reference;
count = (reference->nextrec);
reference = (employee_rec*)((unsigned long)(TIMEZONE_START) + ((reference->nextrec)*sizeof(employee_rec)));
if(reference->empid != pbuffer->empid)
{
count = prev_count;
reference = prev_reference;
reference++;
}
}
else
{
reference++;
}
}
else
{
reference++;
}
if(reference > (employee_rec*)((unsigned long)(TIMEZONE_START) +((MAX_EMPLOYEE)*sizeof(employee_rec))))
{
break;
}
}
if (found < 0)
{
reference = NULL;
}
return(reference);
}
long add_employee(employee_rec *pbuffer)
{
int compare;
long writeerr;
employee_rec *newrec ;
employee_rec *tmprec ;
employee_rec *temp_rec;
unsigned long *temp_char;
unsigned char temp_page[PAGE_SIZE]; // temprary page of 1K
int pageno, offset;
temp_rec = (employee_rec *) malloc(sizeof(employee_rec));
//temp_page = (unsigned long *)((unsigned char *)malloc(PAGE_SIZE));
offset = sizeof(employee_rec);
writeerr = -1; // error by default
newrec = check_employee(pbuffer);
if (newrec != NULL)
{
if (pbuffer->nextrec != 0xffff)// delete exisiting record
{
// update existing record
writeerr = FlashProgram((unsigned long *)pbuffer,(unsigned long)newrec,sizeof(employee_rec));
}else
{
// record found in bank
compare = memcmp(pbuffer,newrec,sizeof(employee_rec));
if (compare != 0)
{
// record modification is required
memcpy(temp_rec , newrec , sizeof(employee_rec));
tmprec = newrec;
newrec = get_free_employee();
if (newrec != NULL)
{
temp_rec->nextrec = ((unsigned long)newrec - (unsigned long)TIMEZONE_START)/sizeof(employee_rec);
writeerr = FlashProgram((unsigned long *)temp_rec,(unsigned long )tmprec,sizeof(employee_rec));
writeerr = FlashProgram((unsigned long *)pbuffer,(unsigned long)newrec,sizeof(employee_rec));
}else
{
// copy entire page in ram
// modify contents of struct required
// erase page
// write page back to memory from ram
newrec = tmprec;
pageno = ((unsigned long)newrec - (unsigned long)TIMEZONE_START)/PAGE_SIZE;
temp_char = (unsigned long *)((unsigned long)TIMEZONE_START + (pageno * PAGE_SIZE));
offset = (unsigned long)newrec - (unsigned long)temp_char;
memcpy((unsigned char *)temp_page,(unsigned char *)temp_char,PAGE_SIZE);
newrec = (employee_rec *)((unsigned long)temp_page + offset);
memcpy(newrec,pbuffer,sizeof(employee_rec));
writeerr = FlashErase((unsigned long)tmprec);
writeerr = FlashProgram((unsigned long *)temp_page,(unsigned long)temp_char,PAGE_SIZE);
}
}else
{
// matching record already exists
writeerr = 0;// return (0);
}
}
}else
{
if (pbuffer->nextrec == 0xffff)
{
// no record found in bank
newrec = get_free_employee();
if (newrec != NULL)
{
writeerr = FlashProgram((unsigned long *)pbuffer, (unsigned long)newrec, sizeof(employee_rec));
}else
{
writeerr = -2; // buffer full
}
}else
{
writeerr = 0;// no record found to delete
}
}
free(temp_rec);
//free(temp_page);
return(writeerr);
}
void SendAllEvent()
{
event_rec *reference;
unsigned long count = 0x00000000;
unsigned int byte_no,i;
unsigned char checksum;
reference = EVENT_START + count; /// Incrementing reference as to point to start location
count = count + 1;
byte_no = 2;
for(; count <= MAX_EVENT_REC; count++)
{
if (reference->event == 0xFF)
{
reference++;
}
else
{
sprintf(tx_buffer_2+byte_no,"%01d",reference->event);
sprintf(tx_buffer_2+byte_no+1,"%02d",reference->year);
sprintf(tx_buffer_2+byte_no+3,"%02d",reference->month);
sprintf(tx_buffer_2+byte_no+5,"%02d",reference->date);
sprintf(tx_buffer_2+byte_no+7,"%02d",reference->hour);
sprintf(tx_buffer_2+byte_no+9,"%02d",reference->min);
sprintf(tx_buffer_2+byte_no+11,"%02d",reference->sec);;
sprintf(tx_buffer_2+byte_no+13,"%08d",reference->empid);
if(count == MAX_EVENT_REC)
{}
else
{
tx_buffer_2[byte_no+21] = ',';
}
byte_no += 22;
reference++;
}
}
}
unsigned char SendTimeZoneCount(void)
{
time_zone_rec *reference;
unsigned int i,count;
reference = TIMEZONE_START;
count = 0;
for(i = 1; i <= MAX_TIME_ZONE; i++)
{
if (reference->empid != 0xffffffff)
{
if(reference->nextrec == 0xffff)
{
count++;
}
}
reference++;
}
return(count);
}
/*----------------------------------------------------------------------------------------------- */
long InsertDelTimeZone(unsigned char* tcp_rcv)
{
time_zone_rec time_zone_temp;
long adderr;
unsigned char i;
time_zone_temp.empid = 0;
time_zone_temp.empid = (tcp_rcv[2] * 10000000);
time_zone_temp.empid = time_zone_temp.empid + (tcp_rcv[3] * 1000000);
time_zone_temp.empid = time_zone_temp.empid + (tcp_rcv[4] * 100000);
time_zone_temp.empid = time_zone_temp.empid + (tcp_rcv[5] * 10000) ;
time_zone_temp.empid = time_zone_temp.empid + (tcp_rcv[6] * 1000) ;
time_zone_temp.empid = time_zone_temp.empid + (tcp_rcv[7] * 100);
time_zone_temp.empid = time_zone_temp.empid + (tcp_rcv[8] * 10) ;
time_zone_temp.empid = time_zone_temp.empid + (tcp_rcv[9]) ;
time_zone_temp.exp_date = (tcp_rcv[10] * 10) ;
time_zone_temp.exp_date = time_zone_temp.exp_date + (tcp_rcv[11]) ;
time_zone_temp.exp_month =(tcp_rcv[12] * 10) ;
time_zone_temp.exp_month = time_zone_temp.exp_month + (tcp_rcv[13]) ;
time_zone_temp.exp_year = (tcp_rcv[16] * 10) ;
time_zone_temp.exp_year = time_zone_temp.exp_year + (tcp_rcv[17]) ;
insert_attendence_log(Access_bank_upload,0,time_zone_temp.empid);
if(tcp_rcv[1] == 'C')
{
time_zone_temp.nextrec = 0xffff;
}
else if (tcp_rcv[1] == 'D') ///For deleting record
{
time_zone_temp.nextrec = 0x0000;
adderr = add_time_zone(&time_zone_temp);
return(adderr);
}
for(i=0;i<=5;i++)
{
time_zone_temp.reserved[i] = 0x00;
}
time_zone_temp.reserve = 0x00;
adderr = add_time_zone(&time_zone_temp);
return(adderr);
}
/*----------------------------------------------------------------------------------------------- */
long DelAllTimeZone(void)
{
long ret_val = -1;
unsigned long totalpages;
unsigned long address;
totalpages = (TIMEZONE_PAGES);
address = (unsigned long )TIMEZONE_START;
while(totalpages--)
{
ret_val = FlashErase(address);
address += PAGE_SIZE;
}
return(ret_val);//-1 = Error, 0 = Success
}
void I2C0_init()
{
GPIOPinTypeGPIOOutput( GPIO_PORTB_BASE, (I2C0SCL| I2C0SDA) );
mili_sec(50);
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3 | GPIO_PIN_2);
I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false);
}
typedef struct
{
unsigned char date;
unsigned char month;
unsigned char year;
unsigned char hour;
unsigned char min;
unsigned char sec;
unsigned char bufferdate[8];
unsigned char buffertime[8];
}date_time;
#define RTC_ADDR 0x68
#define SECOND 0x00
#define MINUTE 0x01
#define HOUR 0x02
#define DAY 0x03
#define DATE 0x04
#define MONTH 0x05
#define YEAR 0x06
unsigned char rtc_Read(unsigned char slave_addr, unsigned char Reg)
{
int i;
i2c_timeout_counter = 0;
I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,slave_addr , false);
I2CMasterDataPut(I2C0_MASTER_BASE, Reg);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);
while(I2CMasterBusy(I2C0_MASTER_BASE) && (i2c_timeout_counter < 2));
if(i2c_timeout_counter >= 2)
{
I2C0_init();
for(i = 0; i<3; i++)
{
long_beep(500,2);
}
}
i2c_timeout_counter = 0;
I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, slave_addr , true);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
while(I2CMasterBusy(I2C0_MASTER_BASE) && (i2c_timeout_counter < 2));
if(i2c_timeout_counter >= 2)
{
I2C0_init();
for(i = 0; i<3; i++)
{
long_beep(500,2);
}
}
return(I2CMasterDataGet(I2C0_MASTER_BASE));
}
void rtc_Write(unsigned char slave_addr, unsigned char Reg, unsigned char value )
{
int i;
i2c_timeout_counter = 0;
I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, slave_addr , false);
I2CMasterDataPut(I2C0_MASTER_BASE, Reg);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);
while(I2CMasterBusy(I2C0_MASTER_BASE) && (i2c_timeout_counter < 2));
if(i2c_timeout_counter >= 2)
{
I2C0_init();
for(i = 0; i<3; i++)
{
long_beep(500,2);
}
}
i2c_timeout_counter = 0;
I2CMasterDataPut(I2C0_MASTER_BASE, value);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
while(I2CMasterBusy(I2C0_MASTER_BASE) && (i2c_timeout_counter < 2));
if(i2c_timeout_counter >= 2)
{
I2C0_init();
for(i = 0; i<3; i++)
{
long_beep(500,2);
}
}
}
date_time* get_Current_Date_Time()
{
// int i=0;
current_time.sec = bcd_to_hex(rtc_Read(RTC_ADDR, SECOND ) & 0x7F);
current_time.min = bcd_to_hex(rtc_Read(RTC_ADDR, MINUTE ) & 0x7F);
current_time.hour = bcd_to_hex(rtc_Read(RTC_ADDR, HOUR ) & 0x3F);
current_time.date = bcd_to_hex(rtc_Read(RTC_ADDR, DATE ) & 0x3F);
current_time.month = bcd_to_hex(rtc_Read(RTC_ADDR, MONTH ) & 0x1F);
current_time.year = bcd_to_hex(rtc_Read(RTC_ADDR, YEAR ) & 0xFF);
current_day = bcd_to_hex(rtc_Read(RTC_ADDR, DAY ) & 0x07);
if( (current_time.year<=100) && (current_time.date>=1) &&
(current_time.date<=31) && (current_time.month>=1) &&
(current_time.month<=12) && (current_time.hour<=23) &&
(current_time.min<=59) && (current_time.sec<=59) )
{
return ¤t_time;
}
else
{
I2C0_init();
return 0;
}
}
long set_Current_Date_Time(date_time* new_Date_Time )
{
if(validate_datetime(new_Date_Time))
{
if((new_Date_Time->year != date_time_variable.year) || (new_Date_Time->month != date_time_variable.month) ||(new_Date_Time->date != date_time_variable.date) ||(new_Date_Time->hour != date_time_variable.hour) ||(new_Date_Time->min != date_time_variable.min) )
{
rtc_Write (RTC_ADDR , SECOND , hex_to_bcd(new_Date_Time->sec) );
rtc_Write (RTC_ADDR , MINUTE , hex_to_bcd(new_Date_Time->min) );
rtc_Write (RTC_ADDR , HOUR , hex_to_bcd(new_Date_Time->hour) );
rtc_Write (RTC_ADDR , DATE , hex_to_bcd(new_Date_Time->date) );
rtc_Write (RTC_ADDR , MONTH , hex_to_bcd(new_Date_Time->month) );
rtc_Write (RTC_ADDR , YEAR , hex_to_bcd(new_Date_Time->year) );
}
return(0);
}
return(-1);
}
Have written driver files for RTC bq32000 which can be used if any one wish to use this RTC in future.
void init_UART0(void)
{
// Enable the peripherals used by this example.
SysCtlPeripheralEnable( SYSCTL_PERIPH_UART0 );
SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOA );
// Set GPIO A0 and A1 as UART pins.
GPIOPinTypeUART( GPIO_PORTA_BASE, Serial1_Rx | Serial1_Tx );
// Configure the UART for 9600, 8-N-1 operation.
UARTConfigSetExpClk( UART0_BASE, SysCtlClockGet(), 38400,
( UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE ) );
//Set the UART FIFO Level
UARTFIFOLevelSet( UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8 );
// Enable the UART interrupt.
IntEnable( INT_UART0 );
UARTIntEnable( UART0_BASE, UART_INT_RX | UART_INT_RT );
}
#define RX_BUFFER_SIZE_0 100
#define TX_BUFFER_SIZE_0 100
#define TX_TIMEOUT_0 1
#define RX_TIMEOUT_0 1
-------------------------------------CLEAR UART 0 TX BUFFER------------------------------------
void clear_uart_0_tx_buffer()
{
unsigned int i;
tx_timeout_counter_0=0;
for (i=0;i < TX_BUFFER_SIZE_0;i++)
{
tx_buffer_0[i] = 0;
}
}
-------------------------------------CLEAR UART 0 RX BUFFER------------------------------------
void clear_uart_0_rx_buffer()
{
unsigned int i;
rx_count_0 = 0;
rx_start_0 = false;
rx_command_ready_0 =false;
rx_timeout_counter_0=0;
for (i=0;i < RX_BUFFER_SIZE_0;i++)
{
rx_buffer_0[i] = 0;
}
}
/*-----------------------------------UART 0 INTERRUPT HANDLER------------------------------------ */
void UART0IntHandler(void)
{
unsigned long ulStatus;
tBoolean rx_interrupt = false;
tBoolean tx_interrupt = false;
unsigned char received_char = 0;
// Get the interrrupt status.
ulStatus = UARTIntStatus( UART0_BASE, true );
if( UART_INT_RX )
{
rx_interrupt = true;
}
if( UART_INT_TX )
{
tx_interrupt = true;
}
// Clear the asserted interrupts. Clearing an interrupt takes time.
UARTIntClear( UART0_BASE, ulStatus );
if(rx_interrupt == true)
{
received_char = UARTCharGetNonBlocking( UART0_BASE );
if (rx_command_ready_0 == false) //Ensuring that previous data has been processed
{
if((rx_count_0 == 0) && (received_char == 0x23))
{
rx_buffer_0[rx_count_0++] = received_char;
rx_start_0 = true;
}
else if(rx_start_0 == true)
{
rx_buffer_0[rx_count_0++] = received_char;
if((rx_buffer_0[45] == 0x0A) && (rx_count_0 == 46))
{
rx_command_ready_0 = true;
rx_start_0 = false;
}
else if(rx_count_0 < 45 && received_char == 0x0A)
{
clear_uart_0_rx_buffer();
}
}
else
{
clear_uart_0_rx_buffer();
}
}
rx_interrupt = false;
}
if(tx_interrupt==true)
{
tx_interrupt=false;
}
}
/*--------------------------------------PROCESS UART 0 DATA-------------------------------------- */
void process_serial_command_0(void)
{
unsigned int i;
// long temp_read_pointer;
unsigned char checksum = 0;
if(rx_command_ready_0 == true)
{
ascii_to_digit(1,13,32);
for (i = 13 ; i < 44 ; i++ )
{
if (i == 35) // At 35th location lies the checksum - Checksum was inserted in between to support innovation centre cards
{
i++;
}
else
{
checksum += ( rx_buffer_0[i++] << 4 );
checksum += rx_buffer_0[i];
}
}
if(checksum == ( rx_buffer_0[35] << 4 ) + (rx_buffer_0[36]))
{
if (rx_count_0 == 46 && rx_buffer_0[45] == 0x0A)
{
ac_salcode_5 = (rx_buffer_0[13]);
ac_salcode_5 = ( ac_salcode_5 << 4 ) + (rx_buffer_0[14]);
ac_salcode_5 = ( ac_salcode_5 << 4 ) + (rx_buffer_0[15]);
ac_salcode_5 = ( ac_salcode_5 << 4 ) + (rx_buffer_0[16]);
ac_salcode_5 = ( ac_salcode_5 << 4 ) + (rx_buffer_0[17]);
ac_salcode_5 = ( ac_salcode_5 << 4 ) + (rx_buffer_0[18]);
ac_salcode_5 = ( ac_salcode_5 << 4 ) + (rx_buffer_0[19]);
ac_salcode_5 = ( ac_salcode_5 << 4 ) + (rx_buffer_0[20]);
card_issue_number_serial_1 = (rx_buffer_0[21]);
card_issue_number_serial_1 = ( card_issue_number_serial_1 << 4 ) + (rx_buffer_0[22]);
alphanumeric_flag_serial_1 = (rx_buffer_0[29]);
alphanumeric_flag_serial_1 = ( alphanumeric_flag_serial_1 << 4 ) + (rx_buffer_0[30]);
ac_empid_5 = (rx_buffer_0[37] );
ac_empid_5 = ( ac_empid_5 << 4 ) + (rx_buffer_0[38]);
ac_empid_5 = ( ac_empid_5 << 4 ) + (rx_buffer_0[39]);
ac_empid_5 = ( ac_empid_5 << 4 ) + (rx_buffer_0[40]);
ac_empid_5 = ( ac_empid_5 << 4 ) + (rx_buffer_0[41]);
ac_empid_5 = ( ac_empid_5 << 4 ) + (rx_buffer_0[42]);
ac_empid_5 = ( ac_empid_5 << 4 ) + (rx_buffer_0[43]);
ac_empid_5 = ( ac_empid_5 << 4 ) + (rx_buffer_0[44]);
if(true)
{
card_on_serial_1 = true;
card_on_serial_1_counter = 0;
clear_uart_0_rx_buffer(); // clear as data has been processed
// process_card_access(ac_salcode_5, ac_empid_5 , SERIAL1, card_issue_number_serial_1, alphanumeric_flag_serial_1 );
process_card_serial(ac_salcode_5);
// temp_ac_empid_5 = ac_empid_5;
}
else
{
if (ac_empid_5 == 0x00)
{
lcd_print_msg(LCD_MODULE_ADDRESS_0x36, PRINT_SWIPE_AGAIN); // Swipe Again
smarti_change_colour_with_beep_command(READER1,RED_COLOUR,DOUBLE_BEEP);
clear_uart_0_rx_buffer();
}
else
{
// process_card_access(ac_salcode_5, ac_empid_5 , SERIAL1_DOUBLE , card_issue_number_serial_1, alphanumeric_flag_serial_1 );
process_card_serial(ac_salcode_5);
clear_uart_0_rx_buffer(); // clear as card is swiped again
}
}
}
else
{
lcd_print_msg(LCD_MODULE_ADDRESS_0x36, PRINT_SWIPE_AGAIN); // Swipe Again
smarti_change_colour_with_beep_command(READER1,RED_COLOUR,DOUBLE_BEEP);
clear_uart_0_rx_buffer();
}
}
else
{
lcd_print_msg(LCD_MODULE_ADDRESS_0x36, PRINT_SWIPE_AGAIN); // Swipe Again
smarti_change_colour_with_beep_command(READER1,RED_COLOUR,DOUBLE_BEEP);
clear_uart_0_rx_buffer();
}
rx_command_ready_0 = false;
}
}
header file
// smarti_func.h - Common types and macros.
// Created by Amol Wadkar on 27/05/2017
#ifndef __SMARTI_FUNC_H__
#define __SMARTI_FUNC_H__
/*----------------------------------------------------------------------------------------------- */
//*******************************#defines*************************************************
#define SMARTI_BAUD_RATE 38400
#define SMARTI_START_BYTE 0x24
#define SMARTI_END_BYTE 0x0D
#define SMARTI_SLAVE_NUMBER 0x31
#define SMARTI_KEYA 0x30
#define SMARTI_KEYB 0x31
#define SMARTI_REQUEST_ONLY_IDLE_CARD 0x30
#define SMARTI_REQUEST_ALL_CARDS 0x31
#define READER1 0x01
#define READER2 0x02
#define RED_COLOUR 0x30
#define GREEN_COLOUR 0x31
#define NO_BEEP 0x30
#define SINGLE_BEEP 0x31
#define DOUBLE_BEEP 0x32
#define ERROR_BEEP 0x33
// Different Smart i commands
#define SMARTI_CMD_VERSION_NUM 0x56
#define SMARTI_CMD_REQUEST_CARD 0x53
#define SMARTI_CMD_CARD_CSN 0x54
#define SMARTI_CMD_SELECT_CARD 0x49
#define SMARTI_CMD_AUTHENTICATE_CARD 0x55
#define SMARTI_CMD_READ_CARD 0x52
#define SMARTI_CMD_WRITE_CARD 0x57
#define SMARTI_CMD_INCREMENT_DATA 0x4F
#define SMARTI_CMD_DECREMENT_DATA 0x51
#define SMARTI_CMD_WRITE_KEY 0x4A
#define SMARTI_CMD_REQUEST_SELECT_AUTHENTICATE 0x5A
#define SMARTI_CMD_AUTHENTICATE_READ_CARD 0x58
#define SMARTI_CMD_AUTHENTICATE_WRITE_CARD 0x59
#define SMARTI_CMD_AUTHENTICATE_READ512_CARD 0x4E
#define SMARTI_CMD_AUTHENTICATE_INCREMENT_DATA 0x4B
#define SMARTI_CMD_AUTHENTICATE_DECREMENT_DATA 0x4C
#define SMARTI_CMD_POLL_CARD 0x50
#define SMARTI_CMD_BUZZER_CONTROL 0x47
#define SMARTI_CMD_BUZZER_BEEP_SOUND_CONTROL 0x4D
#define SMARTI_CMD_CHANGE_COLOUR_WITH_BEEP 0x6F
#define SMARTI_CMD_HALT 0x48
//Different Poll request
#define SMARTI_STOP_POLL 0x30
#define SMARTI_JUST_POLL_FOR_CARD_PRESENCE 0x31
#define SMARTI_POLL_AND_AUTH_CARD 0x32
#define SMARTI_POLL_AUTH_READ_CARD 0x33
#define SMARTI_POLL_READ_512_BYTES 0x35
// Reader Status
#define SMARTI_READER_IDLE 0x01
#define SMARTI_READER_AWAITING_POLLING_REPLY 0x02
#define SMARTI_READER_POLLING 0x03
#define SMARTI_READER_AWAITING_HALT_REPLY 0x04
#define SMARTI_READER_HALT 0x05
#define SMARTI_READER_AWAITING_CNG_COLOUR_REPLY 0x06
//*******************************Extern Variables******************************************
extern unsigned char smarti_reader1_status,smarti_reader2_status,smarti_reader1_poll_timeout_counter;
//*******************************Extern Functions******************************************
extern void process_smarti_reader(unsigned char reader_num);
extern void smarti_poll_command(unsigned char reader_num,unsigned char poll_sub_cmd);
extern void ascii_to_digit(unsigned char reader_num,unsigned char start, unsigned char count);
extern void smarti_change_colour_with_beep_command(unsigned char reader_num,unsigned char colour_type, unsigned char beep_type );
extern void smarti_halt_command(unsigned char reader_num);
#endif
Code file
/*********************************************************************************************************
smarti_func.c - This file contains function used to communicate with SMART i reader
(c) Copyright Godrej Security Solution
*********************************************************************************************************/
/*********************************************************************************************************
File description here
Filename : tcp_func.c
Version : V1.1
Last Modified : 27-06-17
Programmer(s) initials : 1. Amol Wadkar
All major MACROS used in this file are define in smarti_func.h
----------------------------------------------------------------------------------------------------- */
/*******************************************************************************************************
INCLUDE (HEADER) FILES
*******************************************************************************************************/
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/timer.h"
#include "uart0.h"
#include "uart2.h"
#include "smarti_func.h"
/*----------------------------------------------------------------------------------------------- */
/******************************************************************************************************
GLOBAL VARIABLES
******************************************************************************************************/
unsigned char smarti_reader1_status = SMARTI_READER_IDLE,smarti_reader2_status = SMARTI_READER_IDLE, smarti_reader1_poll_timeout_counter = 0;
/*----------------------------------------------------------------------------------------------- */
/******************************************************************************************************
FUNCTION PROTOTYPES
*******************************************************************************************************/
void process_smarti_reader(unsigned char reader_num);
void ascii_to_digit(unsigned char reader_num,unsigned char start, unsigned char count);
void smarti_version_read(unsigned char reader_num);
void smarti_poll_command(unsigned char reader_num,unsigned char poll_sub_cmd);
void smarti_change_colour_with_beep_command(unsigned char reader_num,unsigned char colour_type, unsigned char beep_type );
void smarti_halt_command(unsigned char reader_num);
/*----------------------------------------------------------------------------------------------- */
/******************************************************************************************************
FUNCTION DEFINITIONS
*******************************************************************************************************/
// Smarti reader main function
void process_smarti_reader(unsigned char reader_num)
{
if(reader_num == 1)
{
if (smarti_reader1_status == SMARTI_READER_IDLE)
{
smarti_reader1_poll_timeout_counter = 0;
smarti_poll_command(READER1,SMARTI_POLL_AUTH_READ_CARD);
smarti_reader1_status = SMARTI_READER_AWAITING_POLLING_REPLY;
}
} }
// Version Command
void ascii_to_digit(unsigned char reader_num,unsigned char start, unsigned char count)
{
unsigned char j;
if(reader_num == 1)
{
for( j = 0; j < count; j++ ) ///Ascii to digit
{
if( ( rx_buffer_0[start+j] >= 0x30 ) && ( rx_buffer_0[start+j] <= 0x39 ) )
{
rx_buffer_0[start+j] = rx_buffer_0[start+j] - 0x30;
}
else if( ( rx_buffer_0[start+j] >= 0x41 ) && ( rx_buffer_0[start+j] <= 0x46 ) )
{
switch( rx_buffer_0[start+j] )
{
case 0x41:
rx_buffer_0[start+j] = 0x0A;
break;
case 0x42:
rx_buffer_0[start+j] = 0x0B;
break;
case 0x43:
rx_buffer_0[start+j] = 0x0C;
break;
case 0x44:
rx_buffer_0[start+j] = 0x0D;
break;
case 0x45:
rx_buffer_0[start+j] = 0x0E;
break;
case 0x46:
rx_buffer_0[start+j] = 0x0F;
break;
default:
break;
}
}
}
}
else if(reader_num == 2)
{
for( j = 0; j < count; j++ ) ///Ascii to digit
{
if( ( rx_buffer_2[start+j] >= 0x30 ) && ( rx_buffer_2[start+j] <= 0x39 ) )
{
rx_buffer_2[start+j] = rx_buffer_2[start+j] - 0x30;
}
else if( ( rx_buffer_2[start+j] >= 0x41 ) && ( rx_buffer_2[start+j] <= 0x46 ) )
{
switch( rx_buffer_2[start+j] )
{
case 0x41:
rx_buffer_2[start+j] = 0x0A;
break;
case 0x42:
rx_buffer_2[start+j] = 0x0B;
break;
case 0x43:
rx_buffer_2[start+j] = 0x0C;
break;
case 0x44:
rx_buffer_2[start+j] = 0x0D;
break;
case 0x45:
rx_buffer_2[start+j] = 0x0E;
break;
case 0x46:
rx_buffer_2[start+j] = 0x0F;
break;
default:
break;
}
}
}
}
}
// Version Command
void smarti_version_read(unsigned char reader_num)
{
if(reader_num == 1)
{
tx_buffer_0[0] = SMARTI_START_BYTE;
tx_buffer_0[1] = SMARTI_SLAVE_NUMBER;
tx_buffer_0[2] = SMARTI_CMD_VERSION_NUM;
tx_buffer_0[3] = SMARTI_END_BYTE;
}
}
void smarti_poll_command(unsigned char reader_num,unsigned char poll_sub_cmd)
{
unsigned char i;
if(reader_num == 1)
{
tx_buffer_0[0] = SMARTI_START_BYTE;
tx_buffer_0[1] = SMARTI_SLAVE_NUMBER;
tx_buffer_0[2] = SMARTI_CMD_POLL_CARD;
tx_buffer_0[3] = SMARTI_POLL_AUTH_READ_CARD;
tx_buffer_0[4] = SMARTI_REQUEST_ONLY_IDLE_CARD;
tx_buffer_0[5] = SMARTI_KEYA;
tx_buffer_0[6] = 0x30; //Sector to be used for key authentication = 0x0A
tx_buffer_0[7] = 0x30;//0x41;
tx_buffer_0[8] = 0x32; //Block number to be read = 0x28
tx_buffer_0[9] = 0x38;
tx_buffer_0[10] = SMARTI_END_BYTE;
for(i = 0 ; i < 11 ; i++)
{
UARTCharPutNonBlocking(UART0_BASE, tx_buffer_0[i]);
mili_sec(5);
}
}
}
void smarti_change_colour_with_beep_command(unsigned char reader_num,unsigned char colour_type, unsigned char beep_type )
{
unsigned char i;
if(reader_num == 1)
{
tx_buffer_0[0] = SMARTI_START_BYTE;
tx_buffer_0[1] = SMARTI_SLAVE_NUMBER;
tx_buffer_0[2] = SMARTI_CMD_CHANGE_COLOUR_WITH_BEEP;
tx_buffer_0[3] = 0x30;
tx_buffer_0[4] = SMARTI_SLAVE_NUMBER;
tx_buffer_0[5] = 0x30;
tx_buffer_0[6] = colour_type;
if(beep_type == 0x30)
{
tx_buffer_0[7] = SMARTI_END_BYTE;
for(i = 0 ; i < 8 ; i++)
{
UARTCharPutNonBlocking(UART0_BASE, tx_buffer_0[i]);
// mili_sec(5);
}
}
else
{
tx_buffer_0[7] = 0x30;
tx_buffer_0[8] = beep_type;
tx_buffer_0[9] = 0x30;
tx_buffer_0[10] = 0x30;
tx_buffer_0[11] = SMARTI_END_BYTE;
for(i = 0 ; i < 12 ; i++)
{
UARTCharPutNonBlocking(UART0_BASE, tx_buffer_0[i]);
// mili_sec(5);
}
}
}
else if(reader_num == 2)
{
tx_buffer_2[0] = SMARTI_START_BYTE;
tx_buffer_2[1] = SMARTI_SLAVE_NUMBER;
tx_buffer_2[2] = SMARTI_CMD_CHANGE_COLOUR_WITH_BEEP;
tx_buffer_2[3] = 0x30;
tx_buffer_2[4] = SMARTI_SLAVE_NUMBER;
tx_buffer_2[5] = 0x30;
tx_buffer_2[6] = colour_type;
if(beep_type == 0x30)
{
tx_buffer_2[7] = SMARTI_END_BYTE;
for(i = 0 ; i < 8 ; i++)
{
// UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
// mili_sec(5);
}
}
else
{
tx_buffer_2[7] = 0x30;
tx_buffer_2[8] = beep_type;
tx_buffer_2[9] = 0x30;
tx_buffer_2[10] = 0x30;
tx_buffer_2[11] = SMARTI_END_BYTE;
for(i = 0 ; i < 12 ; i++)
{
// UARTCharPutNonBlocking(UART2_BASE, tx_buffer_2[i]);
// mili_sec(5);
}
}
}
}
void smarti_halt_command(unsigned char reader_num)
{
unsigned char i;
if(reader_num == 1)
{
tx_buffer_0[0] = SMARTI_START_BYTE;
tx_buffer_0[1] = SMARTI_SLAVE_NUMBER;
tx_buffer_0[2] = SMARTI_CMD_HALT;
tx_buffer_0[3] = SMARTI_END_BYTE;
for(i = 0 ; i < 4 ; i++)
{
UARTCharPutNonBlocking(UART0_BASE, tx_buffer_0[i]);
mili_sec(5);
}
}
}
/*----------------------------------------------------------------------------------------------- */
/*------------------------------------------RELAY 1 OFF------------------------------------------ */
void turn_off_relay_1(void)
{
GPIOPinWrite( GPIO_PORTF_BASE, Relay1, 0x00 );
}
/*------------------------------------------RELAY 2 ON------------------------------------------- */
void turn_on_relay_2(void)
{
GPIOPinWrite( GPIO_PORTF_BASE, Relay2, Relay2 );
relay2_on_counter = 0;
relay2_on_flag = true;
access_granted_2 = true; //Added on 26/5/15
door_2_counter = 0;
// insert_event_log(RELAY2_TRIP);
}
Components involved are electronic PCB,SSR module and reader. So wanted to design a outer body over which these components can be mounted.
Connection coming to the board:
So I decided to make the outer cover in 2 parts
I started by documenting the dimension and then making it using solid works
After 3 D printing I realise the wall thickness of 5 mm was very thick and not required so I redesign the module reducing the wall thickness.
Base
Top
Assembled Job
Later I 3 D printed the design
Base
Dimention were verified by placing SSR and PCB inside the 3 D printed base.
Top cover
Mounting reader on top cover
Final Assembled Product