Announcement

Collapse
No announcement yet.

How to get the time from an NTP server?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to get the time from an NTP server?

    Hi

    Has anybody realized a function to get the time from an NTP time server?

    Walter

  • #2
    Walter,
    I got this RCF-867 code based on Mike Doty's work.

    Code:
    [COLOR=#0000FF]#COMPILE EXE[/COLOR] [B][I][COLOR=#008080]'#Win 8.04#[/COLOR][/I][/B]
    [COLOR=#0000FF]#DIM ALL[/COLOR]
    [COLOR=#0000FF]#INCLUDE[/COLOR] [COLOR=#800040]"Win32Api.inc"[/COLOR]
     
    [COLOR=#8000FF]$TimeServer[/COLOR] = [COLOR=#800040]"time-a.timefreq.bldrdoc.gov"[/COLOR]
    [B][I][COLOR=#008080]'$TimeServer = "time-a.nist.gov"             '129.6.15.28 NIST, Gaithersburg, Maryland
    '$TimeServer = "time-b.nist.gov"             '129.6.15.29 NIST, Gaithersburg, Maryland
    '$TimeServer = "time-a.timefreq.bldrdoc.gov" '132.163.4.101 NIST, Boulder, Colorado
    '$TimeServer = "time-b.timefreq.bldrdoc.gov" '132.163.4.102 NIST, Boulder, Colorado
    '$TimeServer = "time-c.timefreq.bldrdoc.gov" '132.163.4.103 NIST, Boulder, Colorado
    '$TimeServer = "utcnist.colorado.edu"        '128.138.140.44 University of Colorado, Boulder
    '$TimeServer = "time.nist.gov"               '192.43.244.18 NCAR, Boulder, Colorado
    '$TimeServer = "time-nw.nist.gov"            '131.107.1.10 Microsoft, Redmond, Washington
    '$TimeServer = "nist1.datum.com"             '66.243.43.21 Datum, San Jose, California
    '$TimeServer = "nist1.aol-ca.truetime.com"   '207.200.81.113 TrueTime, AOL facility, Sunnyvale, California[/COLOR][/I][/B]
     
    [COLOR=#0000FF]TYPE[/COLOR] RFC867 [B][I][COLOR=#008080]'Example: "54488 08-01-23 03:55:27 00 0 0   0.0 UTC(NIST) *"[/COLOR][/I][/B]
      Julian  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]5[/COLOR]
      Space1  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Year    [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]2[/COLOR]
      Hyphen1 [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Month   [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]2[/COLOR]
      Hyphen2 [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Day     [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]2[/COLOR]
      Space2  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Hour    [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]2[/COLOR]
      Column1 [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Minute  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]2[/COLOR]
      Column2 [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Second  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]2[/COLOR]
      Space3  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      DST     [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]2[/COLOR]
      Space4  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      LeapSec [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Space5  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Health  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Space6  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Delay   [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]5[/COLOR]
      Space7  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      Label   [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]9[/COLOR]
      Space8  [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
      OTM     [COLOR=#0000FF]AS STRING[/COLOR] * [COLOR=#FF0000]1[/COLOR]
    [COLOR=#0000FF]END TYPE[/COLOR]
    [B][I][COLOR=#008080]'_____________________________________________________________________________[/COLOR][/I][/B]
     
    [COLOR=#0000FF]FUNCTION PBMAIN AS LONG[/COLOR]
     [COLOR=#0000FF]LOCAL[/COLOR] SysTimeUTC   [COLOR=#0000FF]AS[/COLOR] [COLOR=#009CFF][B]SYSTEMTIME[/B][/COLOR]
     [COLOR=#0000FF]LOCAL[/COLOR] SysTimeLocal [COLOR=#0000FF]AS[/COLOR] [COLOR=#009CFF][B]SYSTEMTIME[/B][/COLOR]
     [COLOR=#0000FF]LOCAL[/COLOR] ServerTime   [COLOR=#0000FF]AS[/COLOR] RFC867
     [COLOR=#0000FF]LOCAL[/COLOR] hFile        [COLOR=#0000FF]AS DWORD[/COLOR]
     [COLOR=#0000FF]LOCAL[/COLOR] sTime        [COLOR=#0000FF]AS STRING[/COLOR]
     [COLOR=#0000FF]LOCAL[/COLOR] sMessage     [COLOR=#0000FF]AS STRING[/COLOR]
     
     hFile = [COLOR=#0000FF]FREEFILE[/COLOR]
     [COLOR=#0000FF]TCP OPEN PORT[/COLOR] [COLOR=#FF0000]13[/COLOR] [COLOR=#0000FF]AT[/COLOR] [COLOR=#8000FF]$TimeServer[/COLOR] [COLOR=#0000FF]AS[/COLOR] hFile [COLOR=#0000FF]TIMEOUT[/COLOR] [COLOR=#FF0000]2000[/COLOR]
     [COLOR=#0000FF]IF ERR THEN[/COLOR]
       sMessage = [COLOR=#800040]"Error opening "[/COLOR] & [COLOR=#8000FF]$TimeServer[/COLOR]
     [COLOR=#0000FF]ELSE[/COLOR]
       [COLOR=#0000FF]TCP LINE INPUT[/COLOR] #hFile, sTime
       [COLOR=#0000FF]TCP LINE INPUT[/COLOR] #hFile, sTime
       [COLOR=#0000FF]TCP CLOSE[/COLOR] hFile
     
       [COLOR=#0000FF]TYPE SET[/COLOR] ServerTime = sTime
       sMessage = [COLOR=#800040]"Server"[/COLOR]  & [COLOR=#8000FF]$TAB[/COLOR] & [COLOR=#8000FF]$TimeServer[/COLOR]        & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"sTime"[/COLOR]   & [COLOR=#8000FF]$TAB[/COLOR] & sTime      & [COLOR=#8000FF]$CRLF[/COLOR] & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Year"[/COLOR]    & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Year    & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Month"[/COLOR]   & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Month   & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Day"[/COLOR]     & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Day     & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Hour"[/COLOR]    & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Hour    & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Minute"[/COLOR]  & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Minute  & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Second"[/COLOR]  & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Second  & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"DST"[/COLOR]     & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.DST     & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"LeapSec"[/COLOR] & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.LeapSec & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Health"[/COLOR]  & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Health  & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Delay"[/COLOR]   & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Delay   & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"Label"[/COLOR]   & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.Label   & [COLOR=#8000FF]$CRLF[/COLOR] & _
                  [COLOR=#800040]"OTM"[/COLOR]     & [COLOR=#8000FF]$TAB[/COLOR] & ServerTime.OTM     & [COLOR=#8000FF]$CRLF[/COLOR] & [COLOR=#8000FF]$CRLF[/COLOR]
     
       SysTimeUTC.wYear   = VAL(ServerTime.Year) + [COLOR=#FF0000]2000[/COLOR]
       SysTimeUTC.wMonth  = VAL(ServerTime.Month)
       SysTimeUTC.wDay    = VAL(ServerTime.Day)
       SysTimeUTC.wHour   = VAL(ServerTime.Hour)
       SysTimeUTC.wMinute = VAL(ServerTime.Minute)
       SysTimeUTC.wSecond = VAL(ServerTime.Second)
       SystemTimeToTzSpecificLocalTime(BYVAL [COLOR=#FF0000]0[/COLOR], SysTimeUTC, SysTimeLocal)
     
       sMessage = sMessage & [COLOR=#800040]"Local time conversion"[/COLOR] & [COLOR=#8000FF]$TAB[/COLOR] & _
                  FORMAT$(SysTimeLocal.wYear, [COLOR=#800040]"0000"[/COLOR]) & [COLOR=#800040]"-"[/COLOR] & FORMAT$(SysTimeLocal.wMonth,  [COLOR=#800040]"00"[/COLOR]) & [COLOR=#800040]"-"[/COLOR] & _
                  FORMAT$(SysTimeLocal.wDay,    [COLOR=#800040]"00"[/COLOR]) & [COLOR=#800040]" "[/COLOR] & FORMAT$(SysTimeLocal.wHour,   [COLOR=#800040]"00"[/COLOR]) & [COLOR=#800040]":"[/COLOR] & _
                  FORMAT$(SysTimeLocal.wMinute, [COLOR=#800040]"00"[/COLOR]) & [COLOR=#800040]":"[/COLOR] & FORMAT$(SysTimeLocal.wSecond, [COLOR=#800040]"00"[/COLOR])
     
     [COLOR=#0000FF]END[/COLOR] IF
     
     MessageBox([COLOR=#8000FF]%HWND_DESKTOP[/COLOR], BYVAL STRPTR(sMessage), [COLOR=#800040]"Time server"[/COLOR], [COLOR=#8000FF]%MB_ICONINFORMATION[/COLOR] OR [COLOR=#8000FF]%MB_OK[/COLOR])
     
    [COLOR=#0000FF]END[/COLOR] FUNCTION
    [B][I][COLOR=#008080]'_____________________________________________________________________________
    '
    '                              Daytime Protocol (RFC-867)
    '
    'This protocol is widely used by small computers running MS-DOS and similar operating systems.
    'The server listens on port 13, and responds to requests in either tcp/ip or udp/ip formats.
    'The standard does not specify an exact format for the Daytime Protocol,
    'but requires that the time is sent using standard ASCII characters.
    'NIST chose a time code format similar to the one used by its dial-up
    'Automated Computer Time Service (ACTS), as shown below:
    '
    '                JJJJJ YR-MO-DA HH:MM:SS TT L H msADV UTC(NIST) OTM
    '
    'JJJJJ    is the Modified Julian Date (MJD). The MJD has a starting point of midnight
    '         on November 17, 1858. You can obtain the MJD by subtracting exactly 2 400 000.5 days
    '         from the Julian Date, which is an integer day number obtained by counting days
    '         from the starting point of noon on 1 January 4713 B.C. (Julian Day zero).
    '
    'YR-MO-DA is the date. It shows the last two digits of the year, the month,
    '         and the current day of month.
    '
    'HH:MM:SS is the time in hours, minutes, and seconds. The time is always sent as
    '         Coordinated Universal Time (UTC). An offset needs to be applied to UTC to
    '         obtain local time. For example, Mountain Time in the U. S. is 7 hours behind
    '         UTC during Standard Time, and 6 hours behind UTC during Daylight Saving Time.
    '
    'TT       is a two digit code (00 to 99) that indicates whether the United States is
    '         on Standard Time (ST) or Daylight Saving Time (DST). It also indicates when ST or DST
    '         is approaching. This code is set to 00 when ST is in effect, or to 50 when DST
    '         is in effect. During the month in which the time change actually occurs,
    '         this number will decrement every day until the change occurs. For example,
    '         during the month of November, the U.S. changes from DST to ST. On November 1,
    '         the number will change from 50 to the actual number of days until the time change.
    '         It will decrement by 1 every day until the change occurs at 2 a.m. local time
    '         when the value is 1. Likewise, the spring change is at 2 a.m. local time when
    '         the value reaches 51.
    '
    'L        is a one-digit code that indicates whether a leap second will be added or subtracted
    '         at midnight on the last day of the current month. If the code is 0, no leap second
    '         will occur this month. If the code is 1, a positive leap second will be added at
    '         the end of the month. This means that the last minute of the month will contain
    '         61 seconds instead of 60. If the code is 2, a second will be deleted on the last
    '         day of the month. Leap seconds occur at a rate of about one per year.
    '         They are used to correct for irregularity in the earth's rotation.
    '         The correction is made just before midnight UTC (not local time).
    '
    'H        is a health digit that indicates the health of the server. If H = 0,
    '         the server is healthly. If H = 1, then the server is operating properly but
    '         its time may be in error by up to 5 seconds. This state should change to fully
    '         healthy within 10 minutes. If H = 2, then the server is operating properly but its
    '         time is known to be wrong by more than 5 seconds. If H = 3, then a hardware or
    '         software failure has occurred and the amount of the time error is unknown.
    '         If H = 4 the system is operating in a special maintenance mode and both its accuracy
    '         and its response time may be degraded. This value is not used for production servers
    '         except in special circumstances. The transmitted time will still be correct
    '         to within ±1 second in this mode.
    '
    'msADV    displays the number of milliseconds that NIST advances the time code to partially
    '         compensate for network delays. The advance is currently set to 50.0 milliseconds.
    '
    'label    UTC(NIST) is contained in every time code. It indicates that you are receiving
    '         Coordinated Universal Time (UTC) from the National Institute of Standards
    '         and Technology (NIST).
    '
    'OTM      (on-time marker) is an asterisk (*). The time values sent by the time code refer
    '         to the arrival time of the OTM. In other words, if the time code says
    '         it is 12:45:45, this means it is 12:45:45 when the OTM arrives.
    '_____________________________________________________________________________
    '[/COLOR][/I][/B]
    Last edited by Pierre Bellisle; 10 Sep 2016, 05:43 PM.

    Comment


    • #3
      Here is another variant of Mike Doty's work.

      If it has a command line, of anything, then it runs in silent mode. I did this because my XP box drifts something rotten and schedule the app to run every six hours. This is a bit naughty on a fixed time server list so the list is randomly shuffled first.

      The code includes suggestions by both Bob Scott and Clay Clear.

      The NIST time is adjusted by an 'average' 45ms to compensate for latency within the US. I live in the UK so I have removed that and added a latency adjustment myself.

      I have recently started using another app which taps into the time server at the National Physical Laboratory (NPL) here in the UK and corrections are down to a few milliseconds.

      Comparing the two apps the code below seems to be accurate to about 20-30 milliseconds which isn't bad considering where the servers are compared to where I live.

      Code:
      #COMPILE EXE
      #DIM ALL
      #REGISTER NONE
      #TOOLS OFF
      
      %NOMMIDS = 1
      %NOGDI = 1
      
      #INCLUDE "WIN32API.INC"
      '#INCLUDE "NIST-Time.inc"
      
      TYPE InputBuffer
        JJJJJ AS ASCIIZ * 6     ' Modified Julian Date
        year AS ASCIIZ * 3
        month AS ASCIIZ * 3
        day AS ASCIIZ * 3
        hour AS ASCIIZ * 3
        minute AS ASCIIZ * 3
        second AS ASCIIZ * 3
        TT AS ASCIIZ * 3        ' Regards US Standard or Daylight Saving Time
        L AS ASCIIZ * 2         ' To leap or not to leap, that is the question
        Health AS ASCIIZ * 2    ' = 0 for healthy, = 1 for < 5 secs error & should be OK within 10 minutes
                                ' = 2 for > 5 secs error & = 4 for unknown error
                                '
        msADV AS ASCIIZ * 6     ' millisecond advance for ACTS but not RFC-867
        sLabel AS STRING * 9    ' Should be UTC(NIST)
        dummy AS STRING * 1
        otm AS STRING * 1       ' On-time marker (*) - no cr/lf pair sent
      END TYPE
      
      UNION BufferUnion
        wholeStr AS STRING * 48
        section AS InputBuffer
      END UNION
      
      DECLARE FUNCTION FillArray( MyArray1( ) AS STRING, MyArray2( ) AS STRING ) AS LONG
      
      FUNCTION PBMAIN AS LONG
      LOCAL hSocket, NumberOfTimeServers, Count, dummy, success, Start, Finish AS LONG
      LOCAL wNistMilliseconds AS WORD
      DIM DataBuffer AS BufferUnion
      LOCAL qvTime AS QUAD
      DIM udtvTime AS SYSTEMTIME
      LOCAL mode AS STRING
      
        mode = COMMAND$ ' If anything found then run silent
      
        REDIM Site( 0 ) AS STRING
        REDIM SiteName( 0 ) AS STRING
      
        NumberOfTimeServers = FillArray( Site(), SiteName() )
      
        RANDOMIZE
        ' Shuffle the time servers to use
        FOR Count = 1 TO NumberOfTimeServers - 1
          dummy = RND( Count, NumberOfTimeServers )
          SWAP Site( Count ), Site( dummy )
          SWAP SiteName( Count ), SiteName( dummy )
        NEXT
      
        FOR Count = 1 TO NumberOfTimeServers
          ERRCLEAR
          hSocket = FREEFILE
          TCP OPEN PORT 13 AT Site( Count ) AS hSocket TIMEOUT 2000
          IF ERR = 0 THEN
      
            Start = TIMEGETTIME() ' ................................................................. [1]
            TCP LINE INPUT hSocket, DataBuffer.wholeStr
            TCP LINE INPUT hSocket, DataBuffer.wholeStr
            Finish = TIMEGETTIME() '................................................................. [2]
            TCP CLOSE hSocket
      
            IF VAL( DataBuffer.section.Health ) > 0 THEN EXIT IF
            ' We should have got the on-time marker - try another server
            IF DataBuffer.section.otm <> "*" THEN EXIT IF
      
            udtvTime.wYear = VAL( DataBuffer.section.year ) + 2000
            udtvTime.wMonth = VAL( DataBuffer.section.month )
            udtvTime.wDay = VAL( DataBuffer.section.day )
            udtvTime.wHour = VAL( DataBuffer.section.hour )
            udtvTime.wMinute = VAL( DataBuffer.section.minute )
            udtvTime.wSecond = VAL( DataBuffer.section.second )
            'wNistMilliseconds is the ms value to the next whole second
            wNistMilliseconds = VAL( DataBuffer.section.msADV ) ' Suggested by Bob Scott
      
            SYSTEMTIMETOFILETIME udtvTime, BYVAL VARPTR( qvTime ) '
            ' FILETIME routines used as opposed to VARIANTTIME routines as suggested by Clay Clear
      
            ' We are going to add latency which is the time estimated by ( [2] - [1] )/2
            ' and subtract 45ms which is the 'correction' for US users.
            qvTime = qvTime + ( (Finish - Start)/2 - wNistMilliseconds - 45 ) * 10000
            FILETIMETOSYSTEMTIME BYVAL VARPTR( qvTime ), udtvTime
            SETSYSTEMTIME udtvTime
            POSTMESSAGE %HWND_TOPMOST, %WM_TIMECHANGE, 0&, 0& ' POSTMESSAGE, another suggestion by Clay Clear
            success = %TRUE
            IF mode = "" THEN MSGBOX "Time set by " & SiteName( Count ) & " (# of servers tried:" & _
            STR$(Count) & ")" & $CRLF & $CRLF & "Estimated Latency:" & STR$((Finish - Start)\2) & "ms",,"NIST-Time"
            EXIT FOR
          END IF
        NEXT
        IF ISFALSE success THEN
          IF mode = "" THEN MSGBOX "Failed to get time" & $CRLF & $CRLF & "Error:" & STR$( ERR ),, "NIST-Time"
        END IF
      END FUNCTION
      
      FUNCTION FillArray( MyArray1( ) AS STRING, MyArray2( ) AS STRING ) AS LONG
      LOCAL x AS LONG
      
        REDIM MyArray1( 1 TO DATACOUNT/2 ) AS STRING
        REDIM MyArray2( 1 TO DATACOUNT/2 ) AS STRING
      
        FOR x = 1 TO DATACOUNT/2
          MyArray1( x ) = READ$( 2 * x - 1 ) ' giving 1, 3, 5, ..., DATACOUNT - 1
          MyArray2( x ) = READ$( 2 * x )     ' giving 2, 4, 6, ..., DATACOUNT
        NEXT
      
        FUNCTION = DATACOUNT/2
      
        DATA time-a.timefreq.bldrdoc.gov
        DATA "NIST, Boulder A, Colorado"
        DATA time-b.timefreq.bldrdoc.gov
        DATA "NIST, Boulder B, Colorado"
        DATA time-c.timefreq.bldrdoc.gov
        DATA "NIST, Boulder C, Colorado"
        DATA utcnist.colorado.edu
        DATA "University of Colorado, Boulder"
        DATA time.nist.gov
        DATA "NCAR, Boulder, Colorado"
        DATA time-nw.nist.gov
        DATA "Microsoft, Redmond, Washington"
        DATA nist1.symmetricom.com
        DATA "Symmetricom, San Jose, California"
        DATA nist1-dc.WiTime.net
        DATA "WiTime, Virginia"
        DATA nist1-ny.WiTime.net
        DATA "WiTime, New York City"
        DATA nist1-sj.WiTime.net
        DATA "WiTime, San Jose, California"
        DATA nist1.aol-ca.symmetricom.com
        DATA "Symmetricom, AOL facility, Sunnyvale, California"
        DATA nist1.aol-va.symmetricom.com
        DATA "Symmetricom, AOL facility, Virginia"
        DATA nist1.columbiacountyga.gov
        DATA "Columbia County, Georgia"
        DATA nist.expertsmi.com
        DATA "Monroe, Michigan"
      
      END FUNCTION
      Last edited by David Roberts; 23 Jan 2008, 05:04 AM. Reason: Misspelt one of the Symmetricom entries

      Comment


      • #4
        Thanks for the two solutions. Will save me a lot of time!

        Comment

        Working...
        X