/* QuickFigure GPS Tool 1.0 Copyright 1994-1995 PelicanWare, Inc. All Rights Reserved. Written By Don A. Vollum */ //standard constants: constant kAppName := "GPS Tool"; constant kAppSym := '|gpsTool:donv|; constant kToolArray := '|qfTools:qfig:donv|; //notification function: defConst('kErrFunc, func(errorString) begin getRoot():notify(ensureInternal(kNotifyAlert),ensureInternal(kAppName),ensureInternal(errorString)); end); partData := {}; partData.ToolInfo := {name: kAppName, path: kAppSym}; installScript := func(partFrame,removeFrame) begin //move it into the removeFrame so that we can use it in the removeScript: removeFrame.(ensureInternal('toolInfo)) := ensureInternal(partFrame.PartData.ToolInfo); //get the reference to the layout, and add it to the root (using buildContext //to turn it into a view): getRoot().(ensureInternal(kAppSym)) := buildContext(partframe.partData.mainView); //add the tool reference to the tool array, creating the array if it doesn't exist: if not hasSlot(getRoot(),kToolArray) then getRoot().(ensureInternal(kToolArray)) := totalClone([]); addDeferredAction(func() addArraySlot(getRoot().(kToolArray),removeFrame.ToolInfo),'[]); end; removeScript := func(removeFrame) begin //get rid of the reference in the tool array: if hasSlot(getRoot(),kToolArray) then begin setRemove(getRoot().(kToolArray),removeFrame.toolInfo); end; //get rid of the reference in the root: if hasSlot(getRoot(),kAppSym) then removeSlot(getRoot(),kAppSym); end; // ---- End Project Data ---- // ---- File GPS Tool Main Layout-1 ---- gpsToolMain := {GPSEndpoint: nil, epDisconnect: func() begin // Called to disconnect the endpoint. getGlobals().iobusy := nil; if GPSEndpoint then begin //close out the endpoint. GPSEndpoint:flushInput(); GPSEndpoint.nextInputSpec := nil; GPSEndpoint:setInputSpec(NIL); GPSEndpoint:abort(); //dispose the endpoint in a delayed action: addDelayedAction(func() perform(self,'cleanUpSerial,[]),[],1000); end; end, viewQuitScript: func() begin if self.GPSEndpoint and getGlobals().ioBusy then :epDisconnect(); end, getPosition: func() begin /* This routine instantiates the endpoint, sets the inputSpec, and establishes a timeout function, which will be called if there is no response after 30 seconds. */ //first, check if the serial port is busy: if getGlobals().iobusy then begin call kerrFunc with ("The serial port is already in use."); GPSEndpoint := nil; self:close(); return; end; //define the enpoint in RAM with a _proto to the endpoint in the package: GPSEndpoint := {_proto: protoGPSEndpoint, _parent: self, getReading: {inputForm: 'string, endCharacter: unicodeCR, inputScript: func(endpoint, s) begin //we only take one reading, so disconnect as soon as we get it. perform(endpoint,'epDisconnect,[]); perform(endpoint, 'usePosition, [s]); end} }; //set the system's serial port busy flag: getGlobals().iobusy := true; //initialize the endpoint: local anErr; anErr:=GPSEndpoint:Instantiate(GPSEndpoint,nil); anErr:=GPSEndpoint:Connect(nil,nil); //If there's an error, show an error message: if anErr then begin call kErrFunc with ("Couldn't connect. Check your cables and settings"); self:close(); //close, because this app is a one-shot deal. return; end; //set the inputSpec: GPSEndpoint:setInputSpec(GPSEndpoint.getReading); //put a timeout function into the queue, so that the app will bail after 30 seconds: addDelayedAction(func() getRoot().(kAppSym):timeout(),[],30000); end, usePosition: func(rawData) begin /* The GPS outputs comma-delimited text, so first we parse the string into an array, with each element containing one comma-delimited piece: */ local GPSInfo := []; //holds the elements of the GPS string. local commaPos := 0; //break the string up into array elements. while commaPos := strPos(rawData,",",commaPos) do begin local endPos := strPos(rawdata,",",commaPos+1); if not endPos then endPos := strLen(rawData); addArraySlot(GPSInfo,subStr(rawData,commaPos+1,endPos-commaPos-1)); commaPos := commaPos + 1; end; //collect the position info (gpsInfo[2] is "N" or "S" while gpsInfo[1] is the long., etc.): local returnInfo := []; addArraySlot(returnInfo,gpsInfo[2]&gpsInfo[1]); addArraySlot(returnInfo,gpsInfo[4] & gpsInfo[3]); //number of GPS satelites being received is element 6: local numSats := stringToNumber(gpsInfo[6]); local satString; if numSats =1 then satString := "satellite" else satString := "satellites"; /*if we're receiving less than 3 then we don't have a valid position. Otherwise, we want to tell the user where he is and how many satelites we have. */ if numSats < 3 then returnString := "The GPS is not receiving enough data (only" && numberStr(numSats) && satString & ") to provide a position." else returnString := "Your current position is" && returnInfo[0] & "," && returnInfo[1] & ". The GPS is receiving" && numberStr(numSats) && satString &"."; call kErrFunc with (returnString); //return the data to QuickFigure: getRoot().|qfig:donv|:ddxScript(nr,nc,returnInfo); self:close(); end, cleanUpSerial: func() begin //disposes of the endpoint (called in a delayedAction by epDisconnect). GPSEndpoint:Disconnect(); GPSEndpoint:Dispose(); end, viewFlags: 576, data: nil, ddxScript: func(numRows,numCols,cellArray,dummy) begin /* This routine is called when the user taps on the Tools button in QuickFigure. It checks that only two cells are selected (one for Latitude and one for Longitude), opens the main view (really a status window), and calls the :getPosition() routine. */ if length(cellArray) <> 2 then begin call kErrFunc with ("You must select two cells in QuickFigure before using the GPS Tool."); return; end; data := cellArray; nr := numRows; nc := numCols; getRoot().(kAppSym):open(); refreshViews(); :getPosition(); end, viewBounds: {left: -8, top: 62, right: 172, bottom: 114}, nc: nil, protoGPSEndpoint: { _proto: protoEndpoint, // the basic serial endpoint with the serial port configuration configOptions: [ { label: kCMSAsyncSerial, type: 'service, opCode: opSetRequired }, { label: kCMOSerialIOParms, type: 'option, opCode: opSetNegotiate, data: { bps: k9600bps, dataBits: k8DataBits, stopBits: k1StopBits, parity: kNoParity } }, { label: kCMOInputFlowControlParms, type: 'option, opCode: opSetNegotiate, data: { xonChar: unicodeDC1, xoffChar: unicodeDC3, useSoftFlowControl: true, useHardFlowControl: nil } }, ], exceptionHandler: func(exception) begin //-16005 is "Cancelled"-- not really an error. if exception.data <> -16005 then begin call kErrFunc with ("There was a communications error."); perform(endPoint, 'epDisconnect, []); end; end, } , ddxFrom: nil //QuickFigure puts it's symbol here when calling the app., nr: nil, timeout: func() begin /* Called by :getPosition() if the GPS doesn't respond with in 30 seconds. Shows an error message, and closes the app. The viewQuitScript contains code to shut down the endpoint if it's still active, so we don't need to worry about that here. */ //if the app is visible, close it. if visible(getRoot().(kAppSym)) then begin call kErrFunc with ("There was no response from the GPS. Please check your connection and try again."); getRoot().(kAppSym):close(); end; end, _proto: protoFloater, debug: "gpsToolMain" }; _view000 := /* child of gpsToolMain */ {text: "Getting Position from GPS...", viewBounds: {left: 8, top: 8, right: 184, bottom: 32}, _proto: protoStaticText }; cancelButton := /* child of gpsToolMain */ { buttonClickScript: func() begin getRoot().(kAppSym):close(); end, text: "Cancel", viewBounds: {left: 58, top: 34, right: 118, bottom: 46}, _proto: protoTextButton, debug: "cancelButton" }; // After Script for "gpsToolMain" thisView := gpsToolMain; // Makes the view template accessible to the install and remove scripts: partData.mainView := thisView; // ---- Beginning of section for non used Layout files ---- // End of output