'I2CIO.VBS - this file started out as a simple test of calling the ASCOM chooser from WSH script 'It has since mutated into more - a complete i2c data logger 'You can find the original code at the bottom of the file. 'Mike HArrison '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Some handy global variables '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Dim TabStop Dim NewLine Dim gCurrentLogFileName Dim readingNumber Dim excelApp Const logFilePrefix ="compass" Const logFileSuffix = ".log" Const TestDrive = "C" Const TestFilePath = "C:\Test" '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Constants returned by Drive.DriveType '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Const DriveTypeRemovable = 1 Const DriveTypeFixed = 2 Const DriveTypeNetwork = 3 Const DriveTypeCDROM = 4 Const DriveTypeRAMDisk = 5 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Constants returned by File.Attributes '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Const FileAttrNormal = 0 Const FileAttrReadOnly = 1 Const FileAttrHidden = 2 Const FileAttrSystem = 4 Const FileAttrVolume = 8 Const FileAttrDirectory = 16 Const FileAttrArchive = 32 Const FileAttrAlias = 64 Const FileAttrCompressed = 128 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Constants for opening files '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Const ForReading = 1 Const ForWriting = 2 Const ForAppending = 8 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Function OctetToHexStr (arrbytOctet) ' Function to convert OctetString (byte array) to Hex string. ' Code from Richard Mueller, a MS MVP in Scripting and ADSI Dim k OctetToHexStr = "" For k = 1 To Lenb (arrbytOctet) OctetToHexStr = OctetToHexStr & Right("0" & Hex(Ascb(Midb(arrbytOctet, k, 1))), 2) Next End Function ' This WSH script places some data (including a formula) into ' an Excel spreadsheet, formats the spreadsheet, and saves it. Public function openExcelLog( filename ) Dim xapp Dim workbook Dim worksheet set xapp = WScript.CreateObject("Excel.Application") xapp.Visible = False ' Make a new Excel workbook: set workbook = xapp.Workbooks.Add set worksheet = workbook.Worksheets("sheet1") workbook.SaveAs(filename) set openExcelLog = xapp End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public function logToExcelog( ordinal, row , byRef measurements ) Dim workbook Dim worksheet Dim k set workbook = xapp.Workbooks("workbook") set worksheet = workbook.Worksheets("sheet1") worksheet.row = row worksheet.column = 0 worksheet.cell = ordinal for count = 1 to uBound( measurements) worksheet.column = count worksheet.cell = measurements(count-1) next set logToExcelLog = nextRow end function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public function closeExcelLog( ) workbook.SaveAs(filename) 'Use xapp.Quit if you want to quit Excel. excelApp.Quit End Function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Function calcJD( refDate ) 'creates t and jdy0 dim y, m, d, t y = Year(refDate) m = Month(refDate) d = Day(refDate) t = hour(refDate)*14400 + minute(refDate)*60 + second(refDate) if m <= 2 then y = y - 1 m = m + 12 end if Dim a, b, jdg, jdyo jdyo = 0 a = Int(y/100) b = 2 - a + Int(a/4) d = d + t/86400 'mikes mod to change from hours to seconds jdg = Int(365.25*(y+4716))+Int(30.6001*(m+1))+d+b-1524.5 jdyo = CDBL(jdg+0.5) - 0.5 ' Julian day 0h UT - modified by MH from CInt() calcJD = jdyo end Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '/* MSCommlib stuff seems to work if you use the object methods as properties. */ 'Trying this in jscript leads to problems writing binary data due to the lack of 'ability to write byte array to the output stream. 'the attempt to use the jsafearray was to get around this limit. 'Result was the move to vbs to handle the data more easily Public Function getComms( commPortID, settingString ) dim oComms set oComms = CreateObject("MSCommLib.MSComm") If IsNull(oComms) or NOT IsObject( oComms ) Then WScript.Echo "Undefined/null comms object returned" oComms = Nothing exit function Else 'oComms.AboutBox() WScript.Echo "MS comms lib found OK " oComms.CommPort = commPortID WScript.Echo "Comm port allocated : " & CStr ( oComms.CommPort ) '//Tell the control to read entire buffer when Input is used. oComms.InputLen = 0 oComms.InputMode = 1 oComms.RThreshold = 0 'must be non-zero to enable receive by commEvent '//Connect to the port oComms.PortOpen = True 'oComms.HandShaking = 2 oComms.Settings = settingString '"19200,n,8,1" WScript.Echo "Comm port opened ? : " & Cstr( oComms.PortOpen ) End If set getComms = oComms End function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'Function to find current logfile based on now date & create as necessary Public Function getCurrentLogFile( ) Dim localPath, logFile, nowDate, timestamp Dim dateStrings localPath = getHomePath() 'WScript.Echo "current working directory is : " & localPath nowDate = now timestamp = FormatDateTime( nowDate, 1 ) 'WScript.Echo timestamp dateStrings = split( timestamp, " ", 3 ) timestamp = datestrings(2) & left( datestrings(1),3) & datestrings(0) 'WScript.Echo timestamp set logFile = createLogFile ( timestamp, localPath ) set getCurrentLogFile = logFile End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Function getLogFile( logFileName ) Dim objFSO, objLogFile Set objFSO = CreateObject ("Scripting.FileSystemObject") ' create a file system object path = objFSO.GetAbsolutePathName ("c:") ' get the path to this directory Set objLogFile = objFSO.OpenTextFile( path & "\\" & logFileName, ForAppending, True) WScript.Echo "Creating file for logging : " & path & "\" & logFileName set getLogFile = objLogFile End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'Function returns string path of folder the script is currently sitting in 'Need to append'\' to make a full path to any child folder. Public Function getHomePath() Dim WshShell, localPath Set WshShell = WScript.CreateObject("WScript.Shell") WScript.Echo WshShell.CurrentDirectory getHomePath = WshShell.CurrentDirectory set WshShell = nothing End Function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'This function creates a new logfile based on the name stub and filepath provided 'The file is opened in append, text mode Public Function createLogFile ( logFileStub, logFilePath ) Dim oFSO, logFileName, localPath, logFile set oFSO = CreateObject ("Scripting.FileSystemObject") localPath = logFilePath & "\" & logFilePrefix & logFileStub & logFileSuffix WScript.Echo "Requested filepath for new logfile is : " & localPath set logFile = oFSO.OpenTextFile( localPath, ForAppending, True ) gCurrentLogFileName = localPath set createLogFile = logFile set oFSO = nothing End Function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' public sub usage WScript.Echo "I2CIO.vbs : cscript i2cio.vbs " end sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '// ASCOM-specific stuff Public Function testAscom() Dim driverName driverName = "" Dim oChooser set oChooser = CreateObject("DriverHelper.Chooser") if( IsNull( oChooser ) OR NOT IsObject( oChooser ) )Then WScript.Echo "Undefined/null/empty Chooser object returned" WScript.Exit(1) else driverName = oChooser.Choose("ScopeSim.Telescope") WScript.Echo( driverName ) End IF Dim oADriver set oADriver = CreateObject( driverName ) if( IsNull( oADriver ) OR NOT IsObject( oADriver ) ) Then WScript.Echo "Undefined/null/empty ASCOM driver object returned" WScript.Exit(1) else Wscript.DisconnectObject oADriver End If WScript.Echo "system execution completed with status : " + "Success" End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public function getCentreTime( startTime ) endTime = CDbl( calcJD(now) ) centreTime = ( endTime - startTime)/2 + startTime getCentreTime= centreTime end Function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'This function calculates the average of the last 0....N datapoints in an array of 0...n data points 'inArr is the array itself, count is the current size of the dataset in the array,span is the length of the array Public Function getAverage( ByRef inArr, span, count ) 'WScript.Echo "getAverage args: " & span & " " & count dim answer, i answer = 0.0 if ( count < span ) then for i=0 to count -1 answer = answer + inArr(i) next answer = answer / count else for i=0 to span -1 answer = answer + inArr(i) next answer = answer / span End If getAverage = answer End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'This function gets the compass data in a block into a supplied array 'We supply the array to fill by ref so we don't have to return it. 'The time we return is the centre time of the acquisition Public Function getRemoteI2CCompassData( byRef dataArray, avgSpan, oComms ) Dim startTime, endTime Dim dataIndex, dataCount, average dataIndex = 0 dataCount = 0 do while ( dataCount < avgSpan ) 'This string tells the remote i2c listener on the other side of the radio interface 'which device on the bus to interrogate ( 0xc0 ) 'and which sub register to read ( 0x02 ) and how many bytes to read ( 0x02 ) 'max resulting buffer size is 76 bytes oComms.Output = Chr( &H55 ) & chr( &Hc1 ) & chr( &h02 ) & Chr( &H02 ) 'wait for obligatory half-sec timeout or response from remote device. startTime = Timer DO while startTime > ( Timer - 0.5 ) AND oComms.InBufferCount <2 WScript.sleep( 100 ) 'WScript.Echo "looping " & CStr( Timer ) Loop ' Check for data - missing data is possible and causes quantum drops in the average of the data If oComms.InBufferCount >= 2 Then dataIn = oComms.Input dataString = OctetToHexStr(dataIn) Wscript.Echo "compass raw data: " & dataString measurement = CSng( "&H" & dataString )/10 dataArray( dataIndex ) = measurement dataIndex = ( dataIndex + 1 ) mod avgSpan dataCount = dataCount + 1 End If loop average = getAverage ( dataArray, avgSpan, dataCount ) getRemoteI2CCompassData = average End Function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'This function gets the compass data in a block into a supplied array 'We supply the array to fill by ref so we don't have to return it. 'The time we return is the centre time of the acquisition Public Function getRemoteI2CBatteryData( oComms ) Dim startTime, endTime, voltage 'This function is internal to remote I2C/serial radio receiver and so behaves differently ' from external devices to that receiver. Ie address is different and there are always at least four bytes ' argument, even if ignored. ' internal battery - register 03 WORD ) ' plus two bytes command padding 'max resulting buffer size is 76 bytes - expect 2 bytes/WORD oComms.Output = Chr( &H5a ) & chr( &H03 ) & chr( &h00 ) & chr( &h00 ) 'wait for obligatory half-sec timeout or response from remote device. startTime = Timer Do while ( Timer - startTime < 0.5 ) AND oComms.InBufferCount <2 WScript.sleep( 100 ) 'WScript.Echo "looping " & CStr( Timer ) Loop ' Check for data - missing data is possible and causes drops in the average of the data If oComms.InBufferCount >= 2 Then dataIn = oComms.Input voltageString = OctetToHexStr(dataIn) WScript.Echo "log battry raw data: " & voltageString voltage = Cdbl("&H" & voltageString ) /4198.0 End If getRemoteI2CBatteryData = voltage End Function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'This function gets the remote data in a block into a supplied array 'We supply the array to fill by ref so we don't have to return it. 'makes the assumption thatthe data is in bytes ( ie not float or double or complex ) Public Function writeRemoteI2CDevice( outArray, dataCount, remoteAddress, remoteRegister,oComms ) Dim startTime, endTime, result, dataIndex Dim i , j, outputString, returnByte result = false dataIndex=0 'This string tells the serial i2c device on the usb interface 'which device on the bus to interrogate 'max resulting buffer size is 76 bytes - expect 2 bytes 'USB forward command address, Device Address, register, number of bytes, data 'line below works 'outputString = Chr( &H55 ) & chr( &HD0 ) & chr( &H0 ) & chr( &H1 ) & chr( outArray(0) ) 'loop over the data and spit it out outputString = Chr( &H55 ) & chr( remoteAddress ) & chr( remoteRegister ) & chr( datacount ) 'loop over the data and spit it out for i = 0 to dataCount-1 outputString = outputString & chr(outArray(i)) next 'Wscript.Echo "writeDevice : " & outputString oComms.Output=outputString 'wait for obligatory half-sec timeout or response from remote device. startTime = Timer Do while ( Timer - startTime < 0.5 ) AND ( oComms.InBufferCount < 1 ) WScript.sleep( 100 ) Loop If oComms.InBufferCount >= 1 then returnByte = oComms.input 'WScript.Echo " TypeOf ( returnByte) is :" & TypeName ( returnByte) blat = CInt ( "&H" & octettohexstr( returnByte) ) if blat <> &H0 then result = true End if writeRemoteI2CDevice = result End Function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'This function reads the data from the remote i2c device into a supplied array 'You must supply a remote device address with the lsb set ( read bit ) 'We supply the array to fill by ref so we don't have to return it. 'return strings of hex characters Public Function getRemoteI2CBlockData( byRef dataArray, datumSize, dataCount, remoteAddress, remoteRegister,oComms ) Dim startTime, endTime, result, i, j, temp Dim dataIndex Dim datum() redim datum( datumSize ) result = false dataIndex=0 arraySize = datumsize*datacount 'This string tells the serial i2c device on the usb interface 'which device on the bus to interrogate ( internal battery - command 03 ) 'plus two bytes padding 'max resulting buffer size is 76 bytes - expect 2 bytes if arraySize >= 76 then getRemoteI2CBlockData = false exit function Else 'wscript.Echo "expected data array size :" & arraySize End if oComms.Output = Chr( &H55 ) & chr( remoteAddress ) & chr( remoteRegister ) & chr( arraySize ) 'wait for obligatory half-sec timeout or response from remote device. startTime = Timer Do while ( Timer - startTime < 0.5 ) AND oComms.InBufferCount < arraySize WScript.sleep( 100 ) Loop ' Check for data - missing data is possible and causes drops in the average of the data If oComms.InBufferCount >= (arraySize) Then result = true dataIn = oComms.Input WScript.Echo "raw data: " & OctetToHexStr(dataIn) for i=0 to dataCount-1 temp=0 for j= 0 to datumSize-1 datum(j) = Right("0" & Hex(Ascb(MidB( dataIn, 1+(i*datumSize+j), 1))), 2) temp = temp * 256 + CInt( "&H" & datum(j) ) next dataArray(i) = temp WScript.Echo "raw datum: " & CInt( temp ) next else WScript.Echo "failure reading from remote device :" & remoteAddress & ", register: " & remoteRegister & ", # of bytes : " & (datumsize * dataCount) result = false End If getRemoteI2CBlockData = result End Function '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '0------------------------ 'Start of main script Const avgSpan = 9 dim dataArr( ) Dim outData() dim logFile, logEntry dim commPortId , oComms Dim average, measurement, dataCount, dataIndex Dim startTime, endTime, dataTime, dataIn , resultValid Dim measurementStartTime, measurementEndTime, centreTime Dim j Dim voltage dataCount = 0 dataIndex = 0 redim dataArr( avgSpan ) If WScript.Arguments.count < 2 Then call usage WScript.quit(-1) Else commPortID = WScript.Arguments.Item(0) logFile = WScript.Arguments.Item(1) End If set logFile = getCurrentLogFile( ) set oComms = getComms( commPortID, "19200,n,8,1" ) 'voltage=getremoteI2CBatteryData( ocomms ) 'WScript.Echo "Battery starting voltage is : "& voltage startTime = 0 do while True endTime = Timer resultValid = false if endTime - startTime < 0 Then logFile.Close set logFile = getCurrentLogFile() WScript.Echo " log file rolled over to new log file : " & gCurrentLogFileName End If measurementStartTime = CDbl( calcJD( now ) ) 'Compass redim dataArr(2) datumSize=2 dataCount = 1 'Read from compass - tested OK for raw data, return data is corrupted resultValid = getRemoteI2CBlockData( dataArr, datumSize, dataCount, &Hc1, 2, oComms ) 'Battery 'redim dataArr(1) 'voltage=getremoteI2CBatteryData( ocomms ) 'dataIn = getRemoteI2CCompassData( dataArr, avgSpan, oComms ) 'Bolometer 'Write new pointing location to IR bolometer - tested OK 'redim dataArr(1) 'datumSize = 1 'dataCount = 9 'outData(0) = readingNumber mod 32 'resultValid = writeRemoteI2CDevice( outData, 1, &Hd0, 0, oComms ) 'if ( resultValid ) then 'Read from IR sensor, beginning at reg 0 - tested OK 'resultValid = getRemoteI2CBlockData( dataArr, datumSize, dataCount, &Hd1, 1, oComms ) 'else ' WScript.Echo "failed to write to device for device setup" 'end if 'WScript.Echo "Reading Index: " & readingNumber centreTime = getCentreTime( measurementStartTime ) logEntry = FormatNumber( centreTime, 7 , -1, 0, 0 ) '& FormatNumber ( dataArr(0), 4, -1, 0, 0 ) & ", " for i=0 to dataCount -1 step 1 logEntry = logEntry & ", " & FormatNumber ( dataArr(i)/10, 4, -1, 0, 0 ) next logFile.WriteLine logEntry WScript.Echo logEntry startTime = Timer WScript.Sleep ( 1000 ) readingNumber = readingNumber + 1 Loop logFile.Close Wscript.DisconnectObject oComms WScript.Quit(0)