Wednesday, July 25, 2012

TV IR Remote Controlled Robot

So this is my first AVR project which i thought is worth to share.
It is a simple Robot which is controlled by my TV remote.

How does It Work
IR Communication:
TV remotes uses Infra-red signals to communicate to TV. Remote have IR LED which sends IR signals. At receiving end (TV) has a IR receiver (normally TSOP 1738 sensor) to receive signals sent via remote. In Many remotes you can see IR LED on the front of the remote. Every button on Remote have a unique code which is stored in both TV and Remote memory. So whenever we press a button IR LED sends Code of the pressed Button to TV which then figure out code and take action accordingly.


TSOP 1738
This is the IR Receiver I have used in my project. It have 3 pins as shown below. OUT pin is the data pin which sends signals to Microcontroller. It is high by default that means when it has nothing to receive it will send 1 or +5v.




All buttons have individual code  
(... To be continue)

Complex Data Structure VBScript/QTP


VBScript data structures

Vbscript lacks support of complex data structures unlike other programming languages. This sometimes makes life a bit difficult. We need to code our own algorithms to achieve simple tasks like sorting of an array or reversing it.  .net has support for complex data structures which come with build-in functions for these simple tasks. So if we can use .net data structure then we can avoid reinvention of wheel for some of tasks. Well the good news is some of .net libraries are exposed to COM and can be used in vbscript.

Below are some examples:

  1. CreateObject("System.Collections.ArraytList")
  2. CreateObject("System.Collections.SortedList")
  3. CreateObject("System.Collections.Stack")
  4. CreateObject("System.Collections.Queue")
  5. CreateObject("ADODB.RecordSet")  'Disconnected RecordSet - this is not related to .net yet useful


ArrayList:

Set objArrayList = CreateObject("System.Collections.ArrayList")
objArrayList.Add 6
objArrayList.Add 8
objArrayList.Add 2
objArrayList.Add 4
objArrayList.Add 1
objArrayList.Add 5
objArrayList.Add 3
objArrayList.Add 3
objArrayList.Add 7

'unlike redefining array size (redim statement) every time before appening an element into an array,
' with arraylist you dont need to worry about that.

'Coverting ArrayList to legacy Array
Debug.Print Join(objArrayList.ToArray, ",")  ' output: 6,8,2,4,1,5,3,3,7

'will give u element at mentioned index
Debug.Print objArrayList(0)  ' output: 6

'this will give u size of arraylist                 
Debug.Print objArrayList.Count   ' output: 9

'this will tell u if an element exists or not. no need to iterate over all elements
Debug.Print objArrayList.contains(5) ' output: true

'this will sort elements. no need to write long algoritims
objArrayList.Sort
Debug.Print Join(objArrayList.ToArray, ",") ' output: 1,2,3,3,4,5,6,7,8

'this will reverse the order of all elements present
objArrayList.Reverse
Debug.Print Join(objArrayList.ToArray, ",") ' output: 8,7,6,5,4,3,3,2,1

'remove a specific element
objArrayList.Remove 8   'This will remove 8 from arraylist no matter on which index it is on

'remove element by index
objArrayList.RemoveAt 6   'This will remove element present at 6th index

'remove all elements
objArrayList.Clear


For VBScript Dictionary Objects we don’t need to redim while appending/removing elements; also an element can be directly searched without iterating through each of them. Both of these features are available with ArrayList as well but one of the most important dictionary feature ‘Key-Value pair’ is not present in ArrayList. SortedList is alternative if you want utilize power of both ArrayList and Dictionary.

SortedList :
SortedList is sorted Dictionary. Every time we add/remove a key value pair in dictionary, its automatically gets sorted by Key. Also you can also access elements based on its index (just like arrays) which makes this even more powerful.

'For this example i am maintain employee name and joining date where joining date is the key
Set objSortedList = CreateObject("System.Collections.SortedList")
objSortedList.Add CDate("1-jan-2012"), "Ajay"
objSortedList.Add CDate("3-Mar-2012"), "Amit"
objSortedList.Add CDate("20-dec-2011"), "Jay"
objSortedList.Add CDate("2-jan-2012"), "Vijay"
' All elements will be automatically sorted by Key (joining date in this case)

'Get Count of elements
Debug.Print objSortedList.Count 'output : 4

'access element by its key
Debug.Print objSortedList(CDate("1-Jan-2012")) 'output: Ajay

'accessing elements of dictionary by index
For i = 0 To objSortedList.Count - 1
    Debug.Print objSortedList.GetByIndex(i)
Next

'Check if Keys Exists                                                                                          
Debug.Print objSortedList.ContainsKey(CDate("1-jan-2012")) 'output: True

'Check if Value Exists
Debug.Print objSortedList.ContainsValue("Vijay") 'output: True

'Get Index by Key (zero based index)
Debug.Print objSortedList.IndexOfKey(CDate("1-jan-2012")) 'output: 1

'Get Index By Value
Debug.Print objSortedList.IndexOfValue("Vijay") 'output: 2

'Remove Element by Key
objSortedList.Remove CDate("1-jan-2012")

'Remove Element by Index
objSortedList.RemoveAt 0

'Remove all elements
objSortedList.Clear

 

Using Stack:

Set objStack = CreateObject("System.Collections.Stack")
'Adding elements in Stack
objStack.Push "Item_1"
objStack.Push "Item_2"
objStack.Push "Item_3"
objStack.Push "Item_4"

'Iterate through each element of Stack
For Each Item In objStack
    Debug.Print Item
Next
'Convert Stack to Array
Debug.Print Join(objStack.ToArray, ",") 'output: Item_4,Item_3,Item_2,Item_1

'Get Stack Element Count
Debug.Print objStack.Count  'output: 4

'Check if an element exists or not
Debug.Print objStack.Contains("Item_2") 'output: True

'Pop the last In element from Stack
Debug.Print objStack.Pop    'output: Item_4

'Get Last in element without popping it out
Debug.Print objStack.Peek   'output: Item_3
Debug.Print objStack.Pop    'output: Item_3
Debug.Print objStack.Pop    'output: Item_2

‘Remove all elements from Stack
objStack.Clear


Using Queue:

Set objQueue = CreateObject("System.Collections.Queue")

'Adding elements in Queue
objQueue.Enqueue "Work_Request_ID_11"
objQueue.Enqueue "Work_Request_ID_2"
objQueue.Enqueue "Work_Request_ID_4"
objQueue.Enqueue "Work_Request_ID_9"

'Iterate through each element of Queue
For Each Item In objQueue
    Debug.Print Item
Next

'Convert Queue to Array
Debug.Print Join(objQueue.ToArray, ",") 'output: Work_Request_ID_11,Work_Request_ID_2,Work_Request_ID_4,Work_Request_ID_9

'Get Queue Element Count
Debug.Print objQueue.Count  'output: 4

'Check if an element exists or not
Debug.Print objQueue.Contains("Work_Request_4") 'output: True

'Get the First In element from Queue
Debug.Print objQueue.Dequeue    'output: Work_Request_ID_11

'Get first in element without removing it
Debug.Print objQueue.Peek   'output: Work_Request_ID_2
Debug.Print objQueue.Dequeue    'output: Work_Request_ID_2
Debug.Print objQueue.Dequeue    'output: Work_Request_ID_4

'Clear Entire Queue
objQueue.Clear

Disconnected RecordSets:

Multi-Level Sorting and Filtering: If you are dealing with data which more than just key value pair and fits best in 2D array, and you also wanted to perform sorting and filtering on it, then disconnected recordsets is excellent option.
(Although this is not related to .net but is quite useful in these situations)

Let’s say if I have below 2D array

EmpID
EmpName
EmpAge
JoiningDate
1
Ajay
27
5-Jan-2012
2
Vijay
28
5-Jan-2012
3
Jay
30
2-Mar-2012
4
Amit
26
20-Dec-2011

And you wanted to get employees who joined in 2012 and have age less than 30yrs, also you wanted to get data sorted on joining Date and if joining date is same then second level of sorting should be applied at Age (in decending order).
So output should look like

EmpID
EmpName
EmpAge
JoiningDate
2
Vijay
28
5-Jan-2012
1
Ajay
27
5-Jan-2012

Building this logic in plain Vbscript might be tedious and error prone, instead we can use a disconnected record set to first populate data and then filter and sort by using its internal function.

Const adDouble = 5
Const adVarChar = 200
Const adDate = 133

Set objRecordSet = CreateObject("ADODB.Recordset")

objRecordSet.Fields.Append "EmpID", adDouble
objRecordSet.Fields.Append "EmpName", adVarChar, 50
objRecordSet.Fields.Append "EmpAge", adDouble
objRecordSet.Fields.Append "JoiningDate", adDate

objRecordSet.Open

objRecordSet.AddNew Array("EmpID", "EmpName", "EmpAge", "JoiningDate"), Array(1, "Ajay", 27, CDate("5-Jan-2012"))
objRecordSet.AddNew Array("EmpID", "EmpName", "EmpAge", "JoiningDate"), Array(2, "Vijay", 28, CDate("5-Jan-2012"))
objRecordSet.AddNew Array("EmpID", "EmpName", "EmpAge", "JoiningDate"), Array(3, "jay", 30, CDate("2-Mar-2012"))
objRecordSet.AddNew Array("EmpID", "EmpName", "EmpAge", "JoiningDate"), Array(4, "Amit", 28, CDate("20-Dec-2011"))

objRecordSet.Filter = "JoiningDate>'1-jan-2012' and EmpAge<30"
objRecordSet.Sort = "JoiningDate, EmpAge DESC"
objRecordSet.MoveFirst

Do Until objRecordSet.EOF
    Debug.Print objRecordSet("EmpID").Value & " | " & objRecordSet("EmpName").Value & " | " & objRecordSet("EmpAge").Value
    objRecordSet.MoveNext
Loop

objRecordSet.Close

Label : QTP, vbscript, Array, Dictionary, RecordSet, ArrayList, Stack, Queue, SortedList, Sorting

Tuesday, May 22, 2012

vbscript gerp utility


DisplayLineNumber = False
ExactMatch = False
IgnoreCase = True

Set oFSO = CreateObject("Scripting.FileSystemObject")


if WScript.Arguments.Count = 0 Then
    Wscript.StdOut.Writeline "Incorrect arguments. syntax: egrep  [filename] [-n] [-x] [-cs]"
    Wscript.StdOut.Writeline "-n          : Display Line Number"
    Wscript.StdOut.Writeline "-x          : Exact Match"
    Wscript.StdOut.Writeline "-cs         : Case Sensitive. By Default it ignore Case"
    Wscript.StdOut.Writeline "Example: egrep @ EULA.txt" & vbNewLine & "Example: egrep /b.*@gmail.com EULA.txt -n -x -cs" & vbnewline & "Example: ipconfig | egrep ""IP Add"""

    Wscript.Quit
Else
    Pattern = WScript.Arguments.item(0)

    if WScript.Arguments.Count => 2 Then
 FileName = WScript.Arguments.item(1)
 if oFSO.FileExists(FileName) Then
  Set oInputStream = oFSO.OpenTextFile(FileName,1)
 Else
  Set oInputStream = Wscript.Stdin
 End if
    Else
 Set oInputStream = Wscript.Stdin
    End if

    For i = 0 to  (WScript.Arguments.Count - 1)
        Select Case Lcase(WScript.Arguments.item(i))
        Case "-n" DisplayLineNumber = True
        Case "-x" ExactMatch = True
        Case "-cs" IgnoreCase = False
        Case Else
        End Select

    Next


End if




Dim StrLine, LineCount

if Pattern = "*" Then : Pattern = ".*" : End If

Set oRegX = New RegExp

oRegX.Pattern = Pattern
oRegX.IgnoreCase = IgnoreCase
oRegX.Global = True

LineCount = 0

Do Until oInputStream.AtEndOfStream
        StrLine = oInputStream.ReadLine
 TextToPrint = ""
        LineCount = LineCount + 1
        Set oMatches = oRegX.Execute(StrLine)

        if oRegX.Test(StrLine) Then
            Set oMatches = oRegX.Execute(StrLine)
            if ExactMatch then
                For each oMatch in oMatches
                    TextToPrint = TextToPrint & oMatch.Value
                Next
            else
                TextToPrint = StrLine
            end if
            
            If DisplayLineNumber Then
                TextToPrint = LineCount & "::" & TextToPrint
            End if
            Wscript.StdOut.WriteLine TextToPrint

        End if

Loop

'================ BAT ===============

@echo off
Set CurrentDirectory=%~dp0
cscript //nologo %CurrentDirectory%egrepvbs.vbs %1 %2 %3 %4
Save bat file in a folder present in path variable

Sunday, April 15, 2012

Some Imp function

Function getTimeStamp()
    sHour = CStr(String(2 - Len(Hour(Now)), "0") & Hour(Now))
    sMin = CStr(String(2 - Len(Minute(Now)), "0") & Minute(Now))
    sSecond = CStr(String(2 - Len(Second(Now)), "0") & Second(Now))
    sMillSecond = CStr(Right(Replace(Timer, ".", ""), 2))
    getTimeStamp = Day(Now) & MonthName(Month(Now), True) & Year(Now) & "_" & sHour & sMin & sSecond & sMillSecond
End Function

Wednesday, February 1, 2012

Using Classes in QTP/VBScript

Using Classes in QTP

QTP works on VBscript which is a scripting language not a programming language but it still supports “Class” concept in a limited manner. It does not support inheritance (which I believe is a major drawback) but you can leverage encapsulation and beautify your code.
Reasons to use Classes in QTP/VBscript:
1.       Achieve Encapsulation
2.       Create logical structure/packaging of functions
3.       Make code more readable
4.       Passing variables make easy

Achieve Encapsulation:

Some time we end up creating some variables global variables which can be accessed through multiple functions. Creating a Public Variable at function library level means that it can be modified by any of the function, even to those functions which should be modifying it. You can restrict it by creating it Private at class level.

Logical Structure/packaging and better readability:

Say example, I have a bunch of functions which does reporting, lying in function library. We log at different places like adding a node at XML , marking a row pass in Excel , adding a step at QC and saving screen print in Word. So my function library looks like this:

‘Reporting functions
‘-----------------------XML functions starts ----------------------------------------------------
Sub CreateXML(FilePath)
End Sub

Sub AddNodeToXML(NodeName,NodeText,ParentXPath)
End Sub

Sub SaveXML(FilePath)
End Sub
‘-----------------------XML functions ends----------------------------------------------------
‘-----------------------Excel functions starts ----------------------------------------------------
Sub CreateExcel(FilePath)
End Sub

Sub MarkTestCasePassInExcel(TestCaseName)
End Sub

Sub SaveExcel(FilePath)
End Sub
‘-----------------------Excel functions starts ----------------------------------------------------
‘-----------------------QC functions starts ----------------------------------------------------
Sub AddStepToQC(StepStatus, StepName, StepDescription,StepExpected,StepAtual)
End Sub

Sub DeleteStepFromQC(StepID)
End Sub
‘-----------------------QC functions Ends----------------------------------------------------
‘-----------------------Word functions starts ----------------------------------------------------
Sub CreateWord(FilePath)
End Sub

Sub AddTextToTestProof(Text)
End Sub

Sub SaveScreenShotToTestProof()
End Sub

Sub SaveTestProof(FilePath)
End Sub
‘-----------------------Word functions Ends ----------------------------------------------------

Lets “Class-ify” it

‘Reporting functions
‘-----------------------XML Class starts ----------------------------------------------------
Class XMLReporting
                Sub Create(FilePath)
                End Sub

                Sub AddNode(NodeName,NodeText,ParentXPath)
                End Sub

                Sub Save(FilePath)
                End Sub
End Class
‘-----------------------XML Class ends----------------------------------------------------
‘-----------------------Excel Class starts ----------------------------------------------------
Class XLReporting
                Sub Create(FilePath)
                End Sub

                Sub MarkTestCasePass(TestCaseName)
                End Sub

                Sub Save(FilePath)
                End Sub
End Class
‘-----------------------Excel Class starts ----------------------------------------------------
‘-----------------------QC Class starts ----------------------------------------------------
Class QCFunctions
                Sub AddStep(StepStatus, StepName, StepDescription,StepExpected,StepAtual)
                End Sub

                Sub DeleteStep(StepID)
                End Sub
End Class
‘-----------------------QC Class Ends----------------------------------------------------
‘-----------------------Word Class starts ----------------------------------------------------
Class TestProof
                Sub Create(FilePath)
                End Sub

                Sub AddText(Text)
                End Sub

                Sub SaveScreenShot()
                End Sub

                Sub Save(FilePath)
                End Sub
End Class
‘-----------------------Word Class Ends ----------------------------------------------------

This Code looks more structured then the previous one and is more readable
Function Calls will Look Like This
Set XML = New XMLReporting
XML.Create “C:\Temp.xml”
XML.AddNode “Step”, “Loan Booked”, “.//”

The one I have implemented in my project looks like this
‘Previous Call
QCUploadAttachmentToCurrentTestInstance “C:\Temp.xml”
QCDownloadAttachmentFromTestPlanFolder  “Subject\TestFolder\TestData.xls”

‘Now it looks like
QC.Upload.ToCurentTest “C:\Temp.xml”
QC.Download.FromTestPlan “Subject\TestFolder\TestData.xls”

Data Passing:

If you wanted to pass a new argument to a function which is called from multiple places, then you have to do a lot of rework changing every call of that function. However in order to deal with this we use work around like
a.       Making some variable Public so that it can be used inside function
b.      Passing multiple comma separated values in a single argument
c.       Passing an array
d.      Passing dictionary object

Another workaround can be passing Custom defined data structure.
Let’s consider that you are testing mortgage calculator functionality. Calculator takes some details of applicant and displays eligibility criteria of Mortgage loan. You are replicating calculation logic in your automation script in order to validate the eligibility criteria displayed on application.

‘Code Snippet 1
ApplicantName = "John"
ApplicantAge = 30
ApplicantIncome = 100  'Poor Chap
ApplicantAddress = "CyberWorld"

Eligiblity = CalculateEligibilityCriteria(ApplicantName, ApplicantAge, ApplicantIncome, ApplicantAddress)

Function CalculateEligibilityCriteria (Name, Age, AnualIncome, Address)
                'Calculate Eligibilty and Return Value
End Function

‘Code Snippet 2
Class ApplicantDetails
                Public Name
                Public Age
                Public AnualIncome
                Public Address
End Class


Set Applicant = New ApplicantDetails

Applicant.Name = "John"
Applicant.Age = 30
Applicant.Income = 100 'Poor Chap
Applicant.Address = "CyberWorld"

Eligiblity = CalculateEligibilityCriteria(Applicant)

Function CalculateEligibilityCriteria (objApplicant)
                'Calculate Eligibility and Return Value
End Function

Using Class to pass custom data structure makes it more readable and more flexible to accommodate changes