;
; Part of the flukecom system, see comments in flukecom.asp for information
; on how this is used and what is required 
;

; globals
long 	currbaud		; current baud rate

include "flukecom.h"

proc main
	integer reterror
	string retstr

	call init_pcplus
	call write_user with versionstr
	call grab_meter with &reterror,&retstr
	if reterror
		call write_user with "ERROR: can't find meter, aborting"
		execute "flukexit"
	endif
	call write_user with &retstr
	execute "flukecom"
endproc

; initialize the script

proc init_pcplus
	set aspdebug on
	set display off
	set rxdata on
	set keys on
	set softflow off	; off handshake to prevent echoing to screen
	set duplex full		; to prevent echoing to screen
	set msg_crlf off	; prevent default cr/lf to double space screen
	set cr cr		; prevent multiple cr to double space screen
	set fgets_crlf off	; prevent fgets from grabbing cr
	set parity none
	set stopbits 1
	set databits 8
endproc

; this routine cycles to the next acceptable baud rate and leaves
; the value in the global currbaud.
; return is normally zero with the exception of when a complete cycle
; has been completed (returned to 1200), then 1

proc cycle_baud
	intparm reterror

	reterror = 0
	if currbaud == 19200
		currbaud = 1200
		return
	endif
	if currbaud == 1200
		currbaud = 9600
		return
	endif
	if currbaud == 9600
		currbaud = 4800
		return
	endif
	if currbaud == 4800
		currbaud = 2400
		return
	endif
	if currbaud == 2400
		currbaud = 1200
		reterror = 1
		return
	endif
	currbaud = 19200		; in case nothing worked
endproc

; this routine synchronizes with the scopemeter by determining the
; current serial port speed and then returns.  Meter and PCPLUS are
; left at rate defined above
; 0 if successful
; 1 if not

proc grab_meter
	intparm	reterror	; return from this procedure
	strparm idstring	; identification string captured
	integer ret,retget	; return code from called routines
	integer bauddone	; complete baudrate cycle
	integer doneflag	; done with sync up, skip to end
	integer numsync		; number of sync attempts at buad
	string	tmpstr		; string to send to meter to reset baud

	doneflag = 0
	bauddone = 0
	currbaud = 19200
	set baud currbaud	; try the default case of high speed
	
	while (!bauddone) && (!doneflag)
		numsync = 0
		while (!doneflag) && (numsync < numsynctries)
			call send2meter with "id",&ret
			numsync++

			; if everything really ok
			if (ret == 0)
				doneflag = 1
				call getmeter with &tmpstr,&retget

				; error on response string
				if retget
					doneflag = 0
				endif
			endif
		endwhile

		; try the next baud rate if applicable
		if (!doneflag)
			call cycle_baud with &bauddone
			set baud currbaud
		endif
	endwhile
	if (!doneflag)
		reterror = 1
		return
	endif	

	; synced up and the current baud rate, set to that defined
	strfmt tmpstr "pc %li,n,8,1" fullbaudcom
	call send2meter with tmpstr,&ret
	if ret
		reterror = 1 
		return
	endif

	; wait for meter to reset baud rate
	pause 1

	currbaud = fullbaudcom
	set baud fullbaudcom

	; confirm that we really have a link at the fast rate
	call send2meter with "id",&ret
	if ret
		reterror = 1 
		return
	endif
	call getmeter with &idstring,&retget
	if retget
		reterror = 1 
		return
	endif
	reterror = 0
endproc

; this routine gets the response string from the meter
; If the response was succesful, then a string is returned and
; of 0 indicates successful
; of 1 indicates a continuation packet is pending
; of 2 indicates a failure
; NOTE THIS ROUTINE IS LIMITED TO 80 characters per string

proc getmeter
	strparm outstr			; string to return
	intparm reterror		; error code to return

	integer newchar			; the latest character acquired
	integer	counter			; length of the string to check for 
					; overflow of string

	outstr = ""
	comgetcd newchar
	while (newchar != -1) && (newchar != cret)
		strfmt outstr "%s%c" outstr newchar
		strlen outstr counter

		; test to see if this is a implicit continuation string
		; should never happen
		if (counter >= maxstrlen)
			reterror = 1
			return
		endif
		comgetcd newchar
	endwhile
	if (newchar == cret)
		reterror = 0
		return
	endif
	reterror = 2
endproc

proc write_user
	strparm outstr
	string tmpstr

	strfmt tmpstr "%s`r`n" outstr
	message tmpstr
endproc

; this routine only sends the data in the input string
; return error code
; of 1 indicates an ack error existed on the receive
; this is a warning that the ack code is incorrect
; of 2 indicates a sync problem existed on the receive (or timeout)
; this is a fatal
; Response string must be handled separately.

proc send2meter
	strparm instr
	intparm reterror

	string tmpstr
	integer retack			; acknowledge byte
	integer terminator
	integer comcounter		; how many times have we tried?

	rflush				; clean up anything that has been 
					; received
	strfmt tmpstr "%s`r" instr	; format up the data to send
	transmit tmpstr

	comcounter = 0
	comgetc retack
	while (comcounter < pausetimes) && (retack == -1)
		comcounter++
		mspause pausecheck
		comgetc retack
	endwhile
	if retack == -1			; timeout!
		reterror = 2
		return
	endif

	comcounter = 0
	comgetc terminator		; pitch the terminator
	while (comcounter < pausetimes) && (terminator == -1)
		comcounter++
		mspause pausecheck
		comgetc terminator
	endwhile

	if terminator != cret		; sync up problem or timeout
		reterror = 2
		return
	endif

	if retack != '0'		; check the ack code
		reterror = 1
		return
	endif

	reterror = 0
endproc
