It is currently Mon Aug 26, 2019 8:15 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 2 posts ] 
Author Message
 Post subject: HID USB Relay
PostPosted: Sun Dec 16, 2018 6:17 am 
Offline
User
User

Joined: Tue Mar 05, 2013 3:11 pm
Posts: 26
Bought a cheapo $5 USB Relay device from Ebay. It's a HID device, pretty straight forward.

Quote:
"1 Channel 5V USB Relay Module USB Computer Control USB Relay Switch Board"

Description:
- The module uses HID technology, foreign trade quality, without any driver, download the data with its own application, plug and play.
- Support WIN7, XP 32-bit, 64-bit system, easy to use.
- On-board square USB interface, stable connection.
- Using special relay driver chip ULN2803, relay work more stable.
- Military-level PCB production. (HAHA!)


Wrote some quick and dirty Sunday afternoon code for it...

Code:
EnableExplicit

; Generic USB HID Relay for Win32 - See Ebay
; reports as "dcttech.com"
; only tested on 1 channel unit.
; TODO: multi-unit / multi-relay support
; TODO: serial number setting / getting
; TODO: Modularize with a better API

; see inspiration on https://github.com/darrylb123/usbrelay
;                    http://vusb.wikidot.com/project:driver-less-usb-relays-hid-interface

XIncludeFile "hid_module.pbi"  ; found in google with no credits sorry :( ... posted below,

#RELAY_ON=$ff
#RELAY_OFF=$fd
#RELAY_CMD_SET_SERIAL=$fa

Global *relaydevice

Procedure Operate_Relay(*hid_device, relay.a, state.a);{
  Protected res.l                                      ; 
  Protected *b = AllocateMemory(9)
  PokeB(*b, $00)
  PokeB(*b+1, state)
  PokeB(*b+2, relay) 
  res = hid::SetFeature(*hid_device, *b, 9)
  If (res < 0)
    Debug ("Unable to WriteDevice() Error: " + Str(res));
  EndIf
  ProcedureReturn res;
EndProcedure


Procedure Init_Relays(vendor_id.l = $16c0, product_id.l = $05df)
  Protected relay_device_available
  Protected Test=HID::TestDevice(product_id, vendor_id)
  If Test
    HID::CloseDevice(*relaydevice)
    *relaydevice=HID::OpenDevice(product_id, vendor_id, -1, 0)
    Debug "Relay: Device Opened"
    Debug "Manufacturer: "+hid::GetManufacturerString(*relaydevice)
    Debug "Product: "+hid::GetProductString(*relaydevice)
    Debug "Serial: "+hid::GetSerialNumberString(*relaydevice)
    relay_device_available = 1
  Else
    Debug "Relay: No Device"     
    relay_device_available = 0
  EndIf
  ProcedureReturn relay_device_available
EndProcedure


Procedure Done_Relay(*relaydevice)
  hid::CloseDevice(*relaydevice) 
EndProcedure


HID::HID_Init()
If Init_Relays()

; simple test toggles relay 1 at 1hz.
Repeat
  Sleep_(1000)
  Operate_Relay(*relaydevice,1,#RELAY_ON)  ; not zero indexed, wasted some time trying relay 0 :)
  Sleep_(1000)
  Operate_Relay(*relaydevice,1,#RELAY_OFF)
ForEver

Else
  Debug "No device found."
EndIf




And the required HID Module...
Tried to translate some of the strings from Russian, with strange results.


Code:

DeclareModule HID

;-DeclareModule

Structure HID_CAPS
  Usage.w
  UsagePage.w
  InputReportByteLength.w
  OutputReportByteLength.w
  FeatureReportByteLength.w
  Reserved.w[17]
  NumberLinkCollectionNodes.w
  NumberInputButtonCaps.w
  NumberInputValueCaps.w
  NumberInputDataIndices.w
  NumberOutputButtonCaps.w
  NumberOutputValueCaps.w
  NumberOutputDataIndices.w
  NumberFeatureButtonCaps.w
  NumberFeatureValueCaps.w
  NumberFeatureDataIndices.w
EndStructure

Structure HID_Sub_DeviceInfo
  VendorID.u
  ProductID.u
  VersionNumber.u
  NumInputBuffers.u
  InputReportByteLength.u
  OutputReportByteLength.u
  FeatureReportByteLength.u
  Manufacturer.s
  Product.s
  SerialNumber.s
EndStructure

Structure HID_DeviceInfo
  CountDevice.w              ; The number of the HID devices
  DeviceInfo.HID_Sub_DeviceInfo[258]
EndStructure


Structure HID_Attributes
  VID.u
  PID.u
  VersionNumber.u
EndStructure


Declare HID_Init()
Declare HID_End()
Declare OpenDevice(PID.u, VID.u, VersionNumber.w=-1, Index.u=0)
Declare CloseDevice(hDevice)
Declare TestDevice(PID.u, VID.u, VersionNumber.w=-1, Index.u=0)
Declare DeviceInfo(*Info.HID_DeviceInfo)
Declare ReadDevice(hDevice, *Buffer, Len)
Declare WriteDevice(hDevice, *Buffer, Len)
Declare GetFeature(hDevice, *Buffer, Len)
Declare SetFeature(hDevice, *Buffer, Len)
Declare GetInputReport(hDevice, *Buffer, Len)
Declare SetOutputReport(hDevice, *Buffer, Len)
Declare GetCaps(hDevice, *Capabilities.HID_CAPS)
 ; Assignment for the lack of facilities, the PID, the VID and the number of the universe.
Declare GetAttributes(hDevice, *DeviceInfo.HID_Attributes)
Declare GetNumInputBuffers(hDevice)
Declare.s GetManufacturerString(hDevice)
Declare.s GetProductString(hDevice)
Declare.s GetSerialNumberString(hDevice)
Declare.s GetIndexedString(hDevice, Index)

EndDeclareModule




Module HID


Structure HIDD_ATTRIBUTES
  Size.l
  VendorID.u
  ProductID.u
  VersionNumber.w
EndStructure

Structure PSP_DEVICE_INTERFACE_DETAIL_DATA
  cbSize.l
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    DevicePath.l
  CompilerElse
    DevicePath.c
  CompilerEndIf
EndStructure

CompilerIf Defined(SP_DEVICE_INTERFACE_DATA, #PB_Structure)=0
  Structure SP_DEVICE_INTERFACE_DATA
    cbSize.l
    InterfaceClassGuid.GUID
    Flags.l
    Reserved.l
  EndStructure
CompilerEndIf

EnableExplicit
Define.i

Prototype pGetHidGuid(*HidGuid.GUID)
Prototype pGetAttributes(*HidDeviceObject, *Attributes.HIDD_ATTRIBUTES)
Prototype pGetPreparsedData(*HidDeviceObject, *PreparsedData)
Prototype pGetCaps(*PreparsedData, *Capabilities.HID_CAPS)
Prototype pFreePreparsedData(PreparsedData)
Prototype pGetNumInputBuffers(HidHandle, *NumInputBuffers)
Prototype pGetManufacturerString(HidHandle, *Buffer, Len)
Prototype pGetProductString(HidHandle, *Buffer, Len)
Prototype pGetSerialNumberString(HidHandle, *Buffer, Len)
Prototype pGetIndexedString(HidHandle, Index, *Buffer, Len)
Prototype pGetFeature(HidHandle, *Buffer, Len)
Prototype pSetFeature(HidHandle, *Buffer, Len)
Prototype pGetInputReport(HidHandle, *Buffer, Len)
Prototype pSetOutputReport(HidHandle, *Buffer, Len)
Prototype pSetupDiEnumDeviceInterfaces(*DeviceInfoSet, DeviceInfoData, *InterfaceClassGuid.GUID,
                                       MemberIndex, *DeviceInterfaceData.SP_DEVICE_INTERFACE_DATA)
Prototype pSetupDiGetDeviceInterfaceDetail(*DeviceInfoSet, *DeviceInterfaceData.SP_DEVICE_INTERFACE_DATA,
                                           DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize,
                                           *RequiredSize, *DeviceInfoData)

Define hid_Lib, Setupapi_Lib, OS_Version

Procedure HID_Init()
  Shared hid_Lib, Setupapi_Lib, OS_Version
  Static __HID_INIT = 0
 
  If __HID_INIT
    ProcedureReturn ; run once only
  Else   
    __HID_INIT = 1
  EndIf
 
  OS_Version = OSVersion()
 
  hid_Lib=LoadLibrary_("hid.dll")
  Setupapi_Lib=LoadLibrary_("setupapi.dll")
 
  Global fGetHidGuid.pGetHidGuid=GetProcAddress_(hid_Lib, ?GetHidGuid)
  Global fGetAttributes.pGetAttributes=GetProcAddress_(hid_Lib, ?GetAttributes)
  Global fGetPreparsedData.pGetPreparsedData=GetProcAddress_(hid_Lib, ?GetPreparsedData)
  Global fFreePreparsedData.pFreePreparsedData=GetProcAddress_(hid_Lib, ?FreePreparsedData)
  Global fGetCaps.pGetCaps=GetProcAddress_(hid_Lib, ?GetCaps)
  Global fGetInputReport.pGetInputReport=GetProcAddress_(hid_Lib, ?GetInputReport)
  Global fSetOutputReport.pSetOutputReport=GetProcAddress_(hid_Lib, ?SetOutputReport)
  Global fGetFeature.pGetFeature=GetProcAddress_(hid_Lib, ?GetFeature)
  Global fSetFeature.pSetFeature=GetProcAddress_(hid_Lib, ?SetFeature)
  Global fGetNumInputBuffers.pGetNumInputBuffers=GetProcAddress_(hid_Lib, ?GetNumInputBuffers)
  Global fGetManufacturerString.pGetManufacturerString=GetProcAddress_(hid_Lib, ?GetManufacturerString)
  Global fGetProductString.pGetProductString=GetProcAddress_(hid_Lib, ?GetProductString)
  Global fGetSerialNumberString.pGetSerialNumberString=GetProcAddress_(hid_Lib, ?GetSerialNumberString)
  Global fGetIndexedString.pGetIndexedString=GetProcAddress_(hid_Lib, ?GetIndexedString)
  Global fSetupDiEnumDeviceInterfaces.pSetupDiEnumDeviceInterfaces=GetProcAddress_(Setupapi_Lib,
                                                                                   ?SetupDiEnumDeviceInterfaces)
  Global fSetupDiGetDeviceInterfaceDetail.pSetupDiGetDeviceInterfaceDetail=GetProcAddress_(Setupapi_Lib,
                                                                                           ?Setup_InterfaceDetail)
 
  DataSection
   
    GetHidGuid:
    ! db "HidD_GetHidGuid", 0, 0
   
    GetAttributes:
    ! db "HidD_GetAttributes", 0, 0
   
    GetPreparsedData:
    ! db "HidD_GetPreparsedData", 0, 0
   
    FreePreparsedData:
    ! db "HidD_FreePreparsedData", 0, 0
   
    GetCaps:
    ! db "HidP_GetCaps", 0, 0
   
    GetInputReport:
    ! db "HidD_GetInputReport", 0, 0
   
    SetOutputReport:
    ! db "HidD_SetOutputReport", 0, 0
   
    GetFeature:
    ! db "HidD_GetFeature", 0, 0
   
    SetFeature:
    ! db "HidD_SetFeature", 0, 0
   
    GetNumInputBuffers:
    ! db "HidD_GetNumInputBuffers", 0, 0
   
    GetManufacturerString:
    ! db "HidD_GetManufacturerString", 0, 0
   
    GetProductString:
    ! db "HidD_GetProductString", 0, 0
   
    GetSerialNumberString:
    ! db "HidD_GetSerialNumberString", 0, 0
   
    GetIndexedString:
    ! db "HidD_GetIndexedString", 0, 0
   
    SetupDiEnumDeviceInterfaces:
    ! db "SetupDiEnumDeviceInterfaces", 0, 0
   
    Setup_InterfaceDetail:
    CompilerIf #PB_Compiler_Unicode=0
      ! db "SetupDiGetDeviceInterfaceDetailA", 0, 0
    CompilerElse
      ! db "SetupDiGetDeviceInterfaceDetailW", 0, 0
    CompilerEndIf
   
  EndDataSection
 
EndProcedure


Procedure HID_End()
  Shared hid_Lib, Setupapi_Lib
  If hid_Lib
    FreeLibrary_(hid_Lib)
  EndIf
  If Setupapi_Lib
    FreeLibrary_(Setupapi_Lib)
  EndIf
EndProcedure


Procedure FunctInfo(hDevice, *Info.HID_DeviceInfo)
  Protected Attributes.HIDD_ATTRIBUTES, i
  Protected HIDP_CAPS.HID_CAPS
   
  Attributes\Size = SizeOf(HIDD_ATTRIBUTES)
 
  If fGetAttributes(hDevice, @Attributes)
   
    i = *Info\CountDevice
    *Info\CountDevice+1
   
    *Info\DeviceInfo[i]\VendorID        = Attributes\VendorID
    *Info\DeviceInfo[i]\ProductID       = Attributes\ProductID
    *Info\DeviceInfo[i]\VersionNumber   = Attributes\VersionNumber
   
    *Info\DeviceInfo[i]\Manufacturer    = GetManufacturerString(hDevice)
    *Info\DeviceInfo[i]\Product         = GetProductString(hDevice)
    *Info\DeviceInfo[i]\SerialNumber    = GetSerialNumberString(hDevice)
    *Info\DeviceInfo[i]\NumInputBuffers = GetNumInputBuffers(hDevice)
    GetCaps(hDevice, @HIDP_CAPS)
    *Info\DeviceInfo[i]\InputReportByteLength   = HIDP_CAPS\InputReportByteLength
    *Info\DeviceInfo[i]\OutputReportByteLength  = HIDP_CAPS\OutputReportByteLength
    *Info\DeviceInfo[i]\FeatureReportByteLength = HIDP_CAPS\FeatureReportByteLength
   
  EndIf
 
EndProcedure

; Preparing the HID for the installation
Procedure Open_HID_Device(PID.u, VID.u, VersionNumber.w=-1, Index.u=0, *Funct=0, *Info.HID_DeviceInfo=0)
  Protected HidGuid.Guid
  Protected devInfoData.SP_DEVICE_INTERFACE_DATA
  Protected Attributes.HIDD_ATTRIBUTES, Security.SECURITY_ATTRIBUTES
  Protected *detailData.PSP_DEVICE_INTERFACE_DETAIL_DATA
  Protected Length.l, CurrentIndex.w, hDevInfo
  Protected i, Result, DevicePath.s
  Protected Required, hDevice
 
  If fGetHidGuid=0 Or fSetupDiEnumDeviceInterfaces=0 Or
     fSetupDiGetDeviceInterfaceDetail=0 Or fGetAttributes=0
    ProcedureReturn 0
  EndIf
 
  devInfoData\cbSize = SizeOf(SP_DEVICE_INTERFACE_DATA)
 
  Security\nLength=SizeOf(SECURITY_ATTRIBUTES)
  Security\bInheritHandle=1
  Security\lpSecurityDescriptor = 0
 
  fGetHidGuid(@HidGuid)
 
  hDevInfo=SetupDiGetClassDevs_(@HidGuid,0,0, #DIGCF_PRESENT|#DIGCF_DEVICEINTERFACE)
  If hDevInfo=0
    ProcedureReturn 0
  EndIf
 
 
  For i=0 To 255
   
    Result=fSetupDiEnumDeviceInterfaces(hDevInfo, 0, @HidGuid, i, @devInfoData)
    If Result
      Result = fSetupDiGetDeviceInterfaceDetail(hDevInfo, @devInfoData, 0, 0,@Length, 0)
      *detailData=AllocateMemory(Length)
      *detailData\cbSize=SizeOf(PSP_DEVICE_INTERFACE_DETAIL_DATA)
      Result = fSetupDiGetDeviceInterfaceDetail(hDevInfo, @devInfoData, *detailData, Length+1, @Required, 0)
     
      DevicePath.s=PeekS(@*detailData\DevicePath)
      FreeMemory(*detailData)
     
      hDevice=CreateFile_(@DevicePath, #GENERIC_READ|#GENERIC_WRITE,
                          #FILE_SHARE_READ|#FILE_SHARE_WRITE, @Security, #OPEN_EXISTING, 0, 0)
     
      If hDevice<>#INVALID_HANDLE_VALUE
       
        If *Funct And *Info
         
          CallFunctionFast(*Funct, hDevice, *Info)
          CloseHandle_(hDevice)
         
        Else
         
          Attributes\Size = SizeOf(HIDD_ATTRIBUTES)
          Result = fGetAttributes(hDevice, @Attributes)
         
          If Attributes\ProductID=PID And Attributes\VendorID=VID And
             (Attributes\VersionNumber=VersionNumber Or VersionNumber=-1 )
            If CurrentIndex=Index
              SetupDiDestroyDeviceInfoList_(hDevInfo)
              ProcedureReturn hDevice
            Else
              CurrentIndex+1
              CloseHandle_(hDevice)
            EndIf
          Else
            CloseHandle_(hDevice)
          EndIf
         
        EndIf
       
      EndIf
    Else
      Break
    EndIf
  Next i
 
  SetupDiDestroyDeviceInfoList_(hDevInfo)
  ProcedureReturn 0
EndProcedure

Procedure OpenDevice(PID.u, VID.u, VersionNumber.w=-1, Index.u=0)
  ProcedureReturn Open_HID_Device(PID, VID, VersionNumber, Index, 0, 0)
EndProcedure

Procedure CloseDevice(hDevice) ; Çàêðûòèå HID óñòðîéñòâà.
  If hDevice
    ProcedureReturn CloseHandle_(hDevice)
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure TestDevice(PID.u, VID.u, VersionNumber.w=-1, Index.u=0)
  Protected hHid.i, Result
 
  hHid=OpenDevice(PID, VID, VersionNumber, Index)
  If hHid
    CloseDevice(hHid)
    Result=#True
  Else
    Result=#False
  EndIf
 
  ProcedureReturn Result
EndProcedure

Procedure DeviceInfo(*Info.HID_DeviceInfo)
  If *Info
    ClearStructure(*Info, HID_DeviceInfo)
    Open_HID_Device(0, 0, 0, 0, @FunctInfo(), *Info)
    ProcedureReturn Bool(*Info\CountDevice>0)
  EndIf
EndProcedure

Procedure ReadDevice(hDevice, *Buffer, Len) ; ×òåíèå äàííûõ èç HID óñòðîéñòâà
  Protected Written.l=0
 
  If hDevice=0 Or *Buffer=0 Or Len<=0
    ProcedureReturn 0
  EndIf
 
  ReadFile_(hDevice, *Buffer, Len, @Written, 0)
  ProcedureReturn Written
EndProcedure

Procedure WriteDevice(hDevice, *Buffer, Len) ; Çàïèñü äàííûõ â HID óñòðîéñòâî
  Protected Written.l=0
 
  If hDevice=0 Or *Buffer=0 Or Len<=0
    ProcedureReturn 0
  EndIf
 
  WriteFile_(hDevice, *Buffer, Len, @Written,  0)
  ProcedureReturn Written
EndProcedure


Procedure GetFeature(hDevice, *Buffer, Len)
  If hDevice And *Buffer And Len>0 And fGetFeature
    ProcedureReturn fGetFeature(hDevice, *Buffer, Len)
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure SetFeature(hDevice, *Buffer, Len)
  If hDevice And *Buffer And Len>0 And fSetFeature
    ProcedureReturn fSetFeature(hDevice, *Buffer, Len)
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

 ; Consumption of a fresh fire. THE WINDOWS PLEASE TAKE PARTNERSHIP   ?
Procedure GetInputReport(hDevice, *Buffer, Len)
  Shared OS_Version
  If hDevice And *buffer And Len>0 And
     OS_Version>=#PB_OS_Windows_XP And fGetInputReport
    ProcedureReturn fGetInputReport(hDevice, *Buffer, Len)
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

 ; Çàïèñü â óñòðîéñòâî âûõîäíîãî ðåïîðòà. ÂÍÈÌÀÍÈÅ ôóíêöèÿ ïîÿâèëàñü òîëüêî â WinXP
Procedure SetOutputReport(hDevice, *Buffer, Len)
  Shared OS_Version
  If hDevice And *buffer And Len>0 And
     OS_Version>=#PB_OS_Windows_XP And fSetOutputReport
    ProcedureReturn fSetOutputReport(hDevice, *Buffer, Len)
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure GetCaps(hDevice, *Capabilities.HID_CAPS) ; Óçíà¸ì ðàçìåðû áóôåðîâ è äð. èíôîðìàöèþ îá óñòðîéñòâå
  Protected result=0, PreparsedData
  If hDevice And fGetPreparsedData And
     fGetCaps And fFreePreparsedData
   
    If fGetPreparsedData(hDevice, @PreparsedData)
      fGetCaps(PreparsedData, *Capabilities)
      fFreePreparsedData(PreparsedData)
      result=1
    EndIf 
   
  EndIf
  ProcedureReturn result
EndProcedure

 ; Óçíà¸ì ïî õåíäëó óñòðîéñòâà, åãî PID, VID è íîìåð âåðñèè.
Procedure GetAttributes(hDevice, *DeviceInfo.HID_Attributes)
  Protected Info.HIDD_ATTRIBUTES, Result=#False
 
  If hDevice And *DeviceInfo And fGetAttributes
    Info\Size = SizeOf(HIDD_ATTRIBUTES)
    If fGetAttributes(hDevice, @Info)
      CopyMemory(@Info+OffsetOf(HIDD_ATTRIBUTES\VendorID), *DeviceInfo, SizeOf(HID_Attributes))
      Result=#True
    EndIf
  EndIf
 
  ProcedureReturn Result
EndProcedure

Procedure GetNumInputBuffers(hDevice)
  Protected NumInputBuffers=0
  If hDevice And fGetNumInputBuffers
    fGetNumInputBuffers(hDevice, @NumInputBuffers)
  EndIf
  ProcedureReturn NumInputBuffers
EndProcedure

Procedure.s GetManufacturerString(hDevice) ; Ïîëó÷àåì èäåíòèôèêàòîð èçãîòîâèòåëÿ
  Protected Result.s="", *mem
  If hDevice And fGetManufacturerString
    *mem=AllocateMemory(256)
    If *mem
      If fGetManufacturerString(hDevice, *mem, 252)
        Result=PeekS(*mem,-1,#PB_Unicode)
      EndIf
      FreeMemory(*mem)
    EndIf
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure.s GetProductString(hDevice) ; Ïîëó÷àåì èäåíòèôèêàòîð ïðîäóêòà
  Protected Result.s="", *mem
  If hDevice And fGetProductString
    *mem=AllocateMemory(256)
    If *mem
      If fGetProductString(hDevice, *mem, 252)
        Result=PeekS(*mem,-1,#PB_Unicode)
      EndIf
      FreeMemory(*mem)
    EndIf
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure.s GetSerialNumberString(hDevice) ; The beginning of the serial number of the project
  Protected Result.s="", *mem
  If hDevice And fGetSerialNumberString
    *mem=AllocateMemory(256)
    If *mem
      If fGetSerialNumberString(hDevice, *mem, 252)
        Result=PeekS(*mem,-1,#PB_Unicode)
      EndIf
      FreeMemory(*mem)
    EndIf
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure.s GetIndexedString(hDevice, Index) ; The differences between the scenes and the source of the structure
  Protected Result.s="", *mem
  If hDevice And fGetIndexedString
    *mem=AllocateMemory(256)
    If *mem
      If fGetIndexedString(hDevice, Index, *mem, 252)
        Result=PeekS(*mem,-1,#PB_Unicode)
      EndIf
      FreeMemory(*mem)
    EndIf
  EndIf
  ProcedureReturn Result
EndProcedure

EndModule


Top
 Profile  
Reply with quote  
 Post subject: Re: HID USB Relay
PostPosted: Mon Dec 17, 2018 12:45 am 
Offline
Enthusiast
Enthusiast

Joined: Mon Jan 20, 2014 6:32 pm
Posts: 240
Very nice thanks for posting.

Also take a look at this lib from infratec maybe help a bit it is also very nice:

viewtopic.php?f=12&t=71365

_________________
WARNING: I dont know what I am doing! I just put stuff here and there and sometimes like magic it works. So please improve on my code and post your changes so I can learn more. TIA


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye