Project Fabrication

Reader evaluation, Hardware and software development, Enclosure design, testing

Different activities incorporated for implementing the project are listed below:

  1. Evaluation of Reader to be use
  2. Deciding on controller and peripherals to be use and studying them
  3. Software development
  4. Designing and making the electronic circuit
  5. Firmware development
  6. Designing an enclosure for the product



1. Reader Evaluation

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


Reader Images

OEM of these reader is company by name Smarti, protocols for communicating with reader have been documented in below document

Reader Protocol Document

I will be using below mentioned command for communicating will the reader over serial


Have documented the command and their responses in below document

Reader command and response

For testing and configuring the reader have developed below utility

Utility exe can be downloaded through below link

Smart card reader configuration utility

Reader 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 :

  • To program the reader
  • To read the version number
  • To check reader LEDs and Buzzer

  • Below video shows how utility can be used to configure and check the reader





    2. Controller and Peripheral Selection and evaluation


    Selection of controller

    Below are the minimum specs required in the controller

  • Serial ports : 2 number - for reader and software
  • On chip flash : For storing access bank and logs
  • I2C bus : For interfacing RTC
  • GPIOs : Minimum 5 - For driving peripherals
  • On board TCP/IP provision : Currently software is developed over RS 232 later the number of devices increases would required to have centralize software which will required either RS 485 or TCP/IP. Have selected TCP-IP over RS 485 because RS 485 is not real time as it works in pooling fashion and also it would be required to have Rs 485 converter at PC end.
  • 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 document

    Main features of LM 3S 6965

  • LM 3S6965 is TI Stellaris series 32 bit ARM Cortex M3 microcontroller.
  • 38 interrupts with 8 priority levels
  • Serial Wire JTAG Debug Port.
  • Optimized for single-cycle flash usage
  • 256 KB flash
  • 64 KB SRAM
  • Supports 4 Timers, 6 PWM
  • Ethernet MAC+PHY
  • 3 UART, 2 I2C and 1 SSI
  • 4 10 bit ADC
  • 42 GPIO pins. etc
  • For more details about the micro controller please refer below datasheet of LM3S6965

    Datasheet - LM 3S6965

    For current application we will be using:

  • 2 no. of UART for Reader and software communication
  • I2C bus for communicating with RTC
  • GPIOs for controlling output and indications
  • Before actual board was design and fabricated I started my development work on 6965 Evaluation board.

    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-Readme
    6965 Eval board-Detailed Manual

    Before 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 Programmer

    Below steps are required to be followed for programming the MAC address:

  • Open the LM Flash Programmer and select the Configuration tab.
  • In the Quickset menu, select LM3S6965 Ethernet Evaluation Board from the drop down box.For programming the MAC address go to the Other Utilities tab. Select MAC Address Mode. Enter the MAC address correctly and avoid duplication. For example, a MAC address will be of the form as shown below and has to be entered as shown.
  • Click on the Commit MAC Address option. Now, to program the MAC address, click on Program MAC Address button. Switch off the power to the board and then turn it ON. This will complete the MAC ad-dress programming step. Once programmed the MAC address cannot be changed.


  • LM flash programmer can also be used for programming the board. For programming the board using LM flash programmer follow below mentioned steps:

  • Go to the Program Tab and select the file to program using the Browse selection button.
  • Click on Program and wait for programming to complete. After programming is complete, it will show Verify Complete Passed at the bottom as shown in the below figure.
  • RTC - bq32000

    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:

  • Automatic Switchover to Backup Supply
  • 8-Pin SOIC Package
  • I2C Interface Supports Serial Clock up to 400 kHz
  • Requires external 32.768-kHz Crystal and battery/SuperCap
  • Trickel charge for supercap
  • Below is the datasheet of BQ 32000 crystal

    BQ 32000 datasheet


    I2C 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_1

    A 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




    3. Software development

    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

  • i. For establising connection.
  • ii. For uploading data.
  • iii. For downloading data.
  • 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

    Software development using Microsoft Visual studio

  • Have started by installing microsoft visual studio on my machine. It is a license software and requires license to start with.
  • Step 1: Is to start by selecting new template. Of the available template select Windows form application.
  • Step 2: Name your project and select okay then a blank form will appare on the screen. On left side there is a list of all tools available and on right side project list and properties of each tool.
  • Step 3: Drag and drop the items required for your project from left. As I was requiring serial port have added it.
  • Step 4: As Serial port is the backbone of my software started by writing a sample code for testing serial interface.
  • 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.

  • Step 5: Deciding on protocols for communication between board and software.
  • Again had started by writing it on paper

    Communication Protocol

    1. For connection
      • Tab will be provided for selecting the baud rate and COM port
      • A test command("CC") will be send on selected COM port at selected baud rate, if device is connected on the COM port and baud rate is correct it will respond saying Connection okay("CCOK").
    2. For upload
      • Provision to upload card number
        Command : "UC+8digit_card_no.+expiry_date DDMMYYYY"
        Reply : "UCOK" if okay and "UCERR" in case of error
      • Provision to set date and time
        Command : "SD+DDMMYYYYhhmmss"
        Reply : "SDOK" if okay and "SDERR" in case of error
    3. For download
      • Provision to read date and time from controller
        Command : "GD"
        Reply : "GD+DDMMYYhhmmss"
      • Provision to download logs
        Command : "GL"
        Reply : "GL+logs"
        Each log will have below structure --> Event_ID + YYMMDDhhmmss + 8digit_card_no.
        Each log will be comma separated.
        eg. GL117061520392500000000,417061520402500000000,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512345678,217061520392512344678,317061520392512344678,317061520392512344678,317061520392512344678
  • Step 6: GUI design and Protocol implementation.
  • 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"





    4. Electronic circuit design

    Designing the Circuit Diagram using Eagle

    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 Eagle

    It 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 autorouting

    layout

    DRC Errors

    layout

    Adding jumper whereever removal of cross section not posible. Final layout

    layout

    Removing the ground plane

    layout



    5. Firmware Development

    I 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 library

    Below 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:


    A. Communicating with software over serial :

    Serial Implementation

    1. Initializing controller Serial port and setting serial parameters like baud rate as 9600, data bit as 8, parity as none and enabling serial interrupt.
    2. // 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 );
    3. #defines for Serial communication. Buffer sizes should be defined larger than the data you are expecting to receive. Timeout is unit to clear the data incase entire data is not received.
    4. #define RX_BUFFER_SIZE_2 100 #define TX_BUFFER_SIZE_2 5000 #define TX_TIMEOUT_2 1 #define RX_TIMEOUT_2 1
    5. Writing Driver functions for serial
    6. -------------------------------------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; } }
    7. Writing serial interrupt handler function - This function is used to fill the data into receive buffer and when entire data is received set data receive flag as true.
    8. 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; } }
    9. Writing application level function for processing the data received and sending response back
    10. 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

    B. Flash implementation


    6965 has 256KB of internal flash. I am using the same flash for storing Employee data and logs.

    1. Defining structure for storing employee data and logs.
    2. 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.

    3. #defines
    4. #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.

    5. Different driver function for Event bank : These are majorly used for locating the write pointer and to write logs in cyclic fashion
    6. 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); }
    7. Different driver level function for employee bank : They functions are used while adding a employee into employees. So these function search for empty space. If it is not available scans all pages and clear and rewrite the page having maximum number of deleted enteries
    8. 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); }
    9. Event bank Application functions : This function is used for reading and sending the events
    10. 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++; } } }
    11. Employee bank Application functions : These function are used to find the count, delete the entire bank, Add or delete a particular entry.
    12. 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 }

    C. I2C implemention : For communicating with RTC

    1. Initializing controller I2C and setting it as master.
    2. 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); }
    3. Defining a structure to date and time values
    4. 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;
    5. #defines for RTC
    6. #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
    7. Writing Driver functions for reading data from rtc
    8. 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)); }
    9. Writing driver function for writing data into RTC.
    10. 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); } } }
    11. Writing application level function which will read date time from RTC and return it
    12. 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; } }
    13. Writing apllication level function for setting RTC Date time
    14. 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.

    D. Communicating with Reader over serial


    1. Initializing controller Serial port and setting serial parameters like baud rate as 38400, data bit as 8, parity as none and enabling serial interrupt.
    2. 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 ); }
    3. #defines for Serial communication. Buffer sizes should be defined larger than the data you are expecting to receive. Timeout is unit to clear the data incase entire data is not received.
    4. #define RX_BUFFER_SIZE_0 100 #define TX_BUFFER_SIZE_0 100 #define TX_TIMEOUT_0 1 #define RX_TIMEOUT_0 1
    5. Writing Driver functions for serial
    6. -------------------------------------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; } }
    7. Writing serial interrupt handler function - This function is used to fill the data into receive buffer and when entire data is received set data receive flag as true.
    8. /*-----------------------------------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; } }
    9. Writing application level function for converting card number received from reader
    10. /*--------------------------------------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; } }
    11. Driver function for communicating with reader
    12. 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); } } } /*----------------------------------------------------------------------------------------------- */

      E. Driving peripherals : SSR

      /*------------------------------------------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); }



    6. Product design

    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:

      Outer Connections :
    1. 12 V input power : 2 Core
    2. Serial connection to PC : 3 core
    3. 230 V output via SSR : 2 core
      Inner connection :
    1. From reader to PCB : 4 core
    2. From PCB to SSR : 2 core

    So I decided to make the outer cover in 2 parts

  • Base : To mount SSR and PCB
  • Top : To mount Reader

  • I started by documenting the dimension and then making it using solid works

    Bottom base

    Top cover

    Assembled job


    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


    Marking for connecing External AC device


    Marking for connecting 12 V input power and PC


    Dimention were verified by placing SSR and PCB inside the 3 D printed base.



    Top cover



    Mounting reader on top cover



    Final Assembled Product






    Output files

  • Software .exe file
  • Software code
  • Controller board Schematic
  • Controller board layout
  • Peripherial board Schematic
  • Peripherial board layout
  • Firmware
  • Outer facia : Base
  • Outer facia : Base
  • Outer facia : Assembly