[Firebug-cvs] firebug/web gps_driver.html,1.3,1.4
Brought to you by:
doolin
From: <cs...@us...> - 2003-05-23 15:46:48
|
Update of /cvsroot/firebug/firebug/web In directory sc8-pr-cvs1:/tmp/cvs-serv7036 Modified Files: gps_driver.html Log Message: updated gps doc Index: gps_driver.html =================================================================== RCS file: /cvsroot/firebug/firebug/web/gps_driver.html,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** gps_driver.html 2 May 2003 17:52:13 -0000 1.3 --- gps_driver.html 23 May 2003 15:15:21 -0000 1.4 *************** *** 1,246 **** ! <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ! <html xmlns="http://www.w3.org/1999/xhtml"> ! ! <head> ! <link type="text/css" rel="stylesheet" href="firebug.css"> ! <link rel="SHORTCUT ICON" href="./images/favicon.ico"> ! <title>FireBug --- GPS Driver</title> ! <meta name="author" content="Carmel Majidi, UC Berkeley" /=""> ! </head> ! ! <body> ! ! ! ! <h1>FireBug --- GPS Driver</h1> ! ! ! <p> ! FireBug uses the <tt>gps</tt> driver to interface with a GPS receiver ! and handle location information. ! </p> ! ! <h2>Introduction</h2> ! ! <p> ! The current driver implements standard NMEA protocol to interact ! with an AXIOM GPS receiver. Running <tt>gpsM.nc</tt> on the client mote ! initializes the receiver for GPS Fix Data (GGA) reception. Incoming GGA data ! is checked by the client for validity, parsed, and then stored in its EEPROM ! flash memory. ! </p> ! ! ! <h2>How <tt>gps</tt> works</h2> ! ! <p> ! GPS receivers provide location and time information in a variety ! of data formats. At initialization, the receiver's UART is configured for ! a prescribed baud rate and the desired data format (in our case, GGA) is ! defined. Next, the client's UART is set to the same baud. When the GPS ! module has collected sufficient data to assemble a GGA message it sends ! a start indicator to the client followed by the data sequence and terminator ! over the UART. The location data is extracted and stored in a line of the ! client's EEPROM. ! </p> ! ! <p> ! Values stored in the client's memory can be retrieved and broadcasted over ! the radio at any time with <tt>GenericBase</tt>. Instructions on this are ! given at the end of this guide. ! </p> ! ! <h2>Sending Commands to the Receiver (Initialization)</h2> ! ! <p> ! Communication between the client and receiver is handled by ! <tt>gps_packet.nc</tt>. UART configuration and ! NMEA operational mode messages are sent out via serial using ! the HPLUART interface. To set the receiver to 9600 baud and NMEA ! data format, each character of the command string is first placed ! as an array entry in the buffer, TxBuffer. If nothing else is ! being transmitted at that moment (i.e. TState == GPS_TX_IDLE), ! the message is uploaded to the reciever using the command ! <tt>txPacket</tt> in <tt>gps_packetM.nc</tt>, ! which utilizes the <tt> HPLUART.put</tt> command. ! </p> ! ! ! ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"><b>gps_packetM.nc</b> ! <pre> ...<br> command result_t Packet.gpsSet() {<br> ...<br> pTx = (char *) &TxBuffer;<br> i = (char)strlen(TxBuffer);<br> call txPacket((char *)pTx, i);<br> return SUCCESS;<br> }<br><br> command result_t txPacket(char *msg, uint8 NofBytes){<br> if(TState == GPS_TX_IDLE) {<br> send_ptr = (char*)msg; //save pointer, will pass back at end<br> pTx = (char*)msg; <br> TxMsgLength = NofBytes;<br> tx_count = 1; //first byte being sent<br> TState = GPS_TX_GO;<br> if(call HPLUART.put(pTx[0])) {<br> return SUCCESS;<br> }<br> else {<br> TState = GPS_TX_IDLE;<br> tx_count = 0;<br> return FAIL;<br> }<br> }<br> else{<br> return FAIL;<br> }<br> } ...</pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! <p> When UART byte transmission is completed, the event <tt>HPLUART.putDone</tt> ! is signaled, which sets TState back to GPS_TX_IDLE. ! </p> ! ! ! ! ! <h2>Receiving Data from GPS Module</h2> ! ! ! <p> ! When data comes in from the GPS receiver through the UART, the ! event <tt>HPLUART.get(uint8_t data)</tt> is signalled, starting a sequence ! of operations in which the received data is checked, parsed, and the ultimately ! stored. <tt>HPLUART.get</tt> signals <tt>rxPacket</tt> ! in <tt>gps_packetM.nc</tt>, which uses the local function ! <tt>fgpsParse</tt> to extract data from the GGA message and ! build a GPSdataStruct data structure. GPSdataStruct is defined ! in <tt>gps.h</tt>. ! </p> ! ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"><b>gps.h </b> ! <pre> struct GPSMsg {<br> char LatDegrees; //(0-90)<br> char LatMinutes; //(0-59)<br> int LatSeconds; //2 bytes (0-59999)<br> char LongDegrees; //(0-180)<br> char LongMinutes; //(0-59)<br> int LongSeconds; //2 bytes<br> char Status; //(SE=00, SW=01, NE=10, NW=11);<br> };<br></pre> ! <b>gps_packetM.nc</b> ! <pre> ...<br> GPSdataStruct *pGPS;<br> ...<br> void fgpsParse(char *pGGA) {<br><br> pGGA++;<br><br> NS = (pGGA[23]=='N') ? 1 : 0;<br> EW = (pGGA[46]=='W') ? 1 : 0;<br><br> pGPS->LatDegrees = 10*(pGGA[18]-'0') + (pGGA[15]-'0');<br> pGPS->LatMinutes = 10*(pGGA[19]-'0') + (pGGA[17]-'0');<br> pGPS->LatSeconds = 1000*(pGGA[21]-'0') + 100*(pGGA[22]-'0') + 10*(pGGA[23]-'0') + (pGGA[20]-'0');<br> pGPS->LongDegrees = 100*(pGGA[24]-'0') + 10*(pGGA[28]-'0') + (pGGA[25]-'0');<br> pGPS->LongMinutes = 10*(pGGA[29]-'0') + (pGGA[27]-'0');<br> pGPS->LongSeconds = 1000*(pGGA[30]-'0') + 100*(pGGA[31]-'0') + 10*(pGGA[32]-'0') + (pGGA[33]-'0');<br> pGPS->Status = EW | (NS<<4); <br> } <br></pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! ! <p><tt>rxPacket</tt> then uses a mask to determine whether the message is ! valid ! </p> ! ! <pre> pGPS = (GPSdataStruct *) &pTOS->data[7];<br> if( pGPS->Status & FIXMASK ) {<br> nmea_ready = TRUE;<br> }<br></pre> ! <p> where pTOS is a TOS_MsgPtr, and nmea_ready is a flag that indicates whether ! the received data can be stored. The command <tt>gpsLog</tt> stores location ! data with <tt>Logger.write(line_number, (char *)gps_data)</tt> .<br> ! </p> ! ! ! ! <h2>Switch Statement</h2> ! ! ! <p> ! GPS initialization and message handling are implemented through a switch ! statement, which allows for the appropriate time delay between successive ! commands. ! </p> ! ! ! <center> ! <table class="code"> ! <tbody> ! <tr class="code"> ! <td width="100%"><b>gpsM.nc</b> ! <pre> command result_t StdControl.start() { ! ClockTickDivider = 0; ! Ticksper100mSec = 12; ! cGPSState = GPS_POWERON; ! call Clock.setRate(TOS_CLK_DIV,2); ! return call SubControl.start(); ! }<br><br> event result_t Clock.fire() { ! ! if (cGPSState == GPS_IDLE) { ! return SUCCESS; ! } ! ! //Handler for high rate user clocks ! ClockTickDivider++; ! if (ClockTickDivider < Ticksper100mSec){ ! return SUCCESS; ! } ! ClockTickDivider = 0; <br><br> switch (cGPSState) { ! ! case GPS_POWERON: ! TOSH_CLR_PW1_PIN(); // Poweron GPS ! call SetBaud(GPS_BAUD4800); ! NextGPSState = GPS_WAKEUP; ! break; ! ! case GPS_WAKEUP: ! call Packet.gpsSet(); // set GPS to 9600 baud, NMEA format ! NextGPSState = GPS_INIT; ! break; ! ! case GPS_INIT: ! call SetBaud(GPS_BAUD9600); ! call Leds.greenOn(); // DEBUG: GPS Initialized ! NextGPSState = GPS_LOCATE; ! break; ! ! case GPS_LOCATE: ! if (call Packet.nmeaReady()) { ! call Packet.gpsLog(); ! NextGPSState = GPS_POWEROFF; ! } ! break; ! ! case GPS_POWEROFF: ! TOSH_SET_PW1_PIN(); // Poweroff GPS ! NextGPSState = GPS_IDLE; ! break; ! } ! ! cGPSState = NextGPSState; ! return SUCCESS; ! }</pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! <p>The commands TOSH_CLR_PW1_PIN() and TOSH_CLR_PW1_PIN() power the ! GPS receiver on and off by clearing and setting the first pin on the serial ! port, respectively. Here, TOS_CLK_DIV = 32; hence, the command ! <tt> Clock.SetRate(TOS_CLK_DIV,2)</tt> means that there will be 32 ticks ! per clock firing and 4096 ticks per second -> one clock firing every ! 8 milliseconds. The statement <tt>if(ClockTickDivider < Ticksper100mSec)...</tt> ! is a handler for high rate user clocks. Ticksper100mSec must be set correctly. ! For Ticksper100mSec = 12, the switch statement will be called every ! 12 clock fires (i.e. every 100 msec). That is, subsequent implementation ! commands will occur every 100 msec. </p> ! <p><tt><br> ! </tt></p> ! ! ! <h2>Retrieving Location Information from Client</h2> ! ! ! ! <p> ! To retrieve data, load a second mote with <code>GenericBase</code> and ! perform the following: ! </p> ! ! <ol> ! <li>Leaving the GenericBase mote connected to the programming board, ! start the serial port forwarding service using the command ! <code>java net.tinyos.sf.SerialForward</code> ! </li> ! ! <li>Broadcast retrieve command over the radio: ! <code>java net.tinyos.tools.BcastInject ! <group ID> read_log ! <gps mote ID></code> ! </li> ! ! <li>Packet is sent to the base station via radio ! </li> ! </ol> ! ! <hr /> ! ! <p> ! Last updated: $Date$ by $Author$. ! </p> ! ! </body> ! </html> --- 1,211 ---- ! <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ! <html xmlns="http://www.w3.org/1999/xhtml"> ! <head name="author" content="Carmel Majidi, UC Berkeley" /="" type="text/css" rel="stylesheet" href="firebug.css"> ! <title>FireBug --- GPS Driver</title> ! ! <meta name="author" content="Carmel Majidi, UC Berkeley" /=""> ! ! <link type="text/css" rel="stylesheet" href="firebug.css"> ! ! <link rel="SHORTCUT ICON" href="./images/favicon.ico"> ! ! <meta name="author" content="Carmel Majidi, UC Berkeley" /=""> ! </head> ! ! ! ! <body> ! <h1>FireBug --- GPS Driver</h1> ! <p> FireBug uses the <tt>gps</tt> driver to interface with a GPS ! receiver and handle location information. </p> ! <h2>Introduction</h2> ! <p> The current driver implements standard NMEA protocol to interact ! with an AXIOM GPS receiver. Running <tt>gpsM.nc</tt> on the client ! mote initializes the receiver for GPS Fix Data (GGA) reception. Incoming ! GGA data is checked by the client for validity, parsed, and then stored ! in its EEPROM flash memory. </p> ! <h2>How <tt>gps</tt> works</h2> ! <p> GPS receivers provide location and time information in a variety ! of data formats. At initialization, the client's UART is set to ! the same baud rate as the GPS receiver. Next, <tt>clearGPS()</tt> is ! called, which commands the receiver to block all output. The receiver ! requires several seconds before it can start processing NMEA commands ! following power on. For this reason, the first command in <tt>clearGPS()</tt> ! is sent 100 times until the receiver has warmed up.</p> ! <p>For this application, a single GGA message is required. To acquire this, ! <tt>getGPS()</tt> is called, which requests GGA data at 1 Hz. The ! number of satellites used in constructing each GGA message is then determined. ! When this number exceeds three, the corresponding message is parsed ! and stored in the client's EEPROM.</p> ! <p> Values stored in the client's memory can the be retrieved and broadcasted ! over the radio at any time with <tt>GenericBase</tt>. Instructions ! on this are given at the end of this guide. </p> ! <h2>Sending Commands to the Receiver</h2> ! <p> Communication between the client and receiver is handled by <tt> ! gpsM.nc</tt>. After the client's second UART (UART1) is ! set to 4800 baud, NMEA commands may be sent to the gps receiver. For ! SiRF chips, these generally have the form:</p> ! <center> ! <p>$PSRF,103,<b>Message type</b>,00,<b>Rate</b>,01,*<b>Checksum</b></p> ! </center> ! <p>followed by a carriage return ('\r') and linefeed ('\n'). There are six ! message types: </p> ! <center> ! <p>GGA=00, GLL=01, GSA=02, GSV=03, RMC=04, VTG=05</p> ! </center> ! <p> To block output of a certain message type, set Rate = 00. Rate = 01 ! corresponds to a 1 Hz output. Finally, the checksum is computed by performing ! an XOR on all characters, including the comma delimiters, between $ and *. ! Each character of the above string is contained as an element in the array ! <tt> cmd_msg</tt>, which is used throughout <tt>gpsM.nc</tt>. By changing ! array entries, different commands can be sent to the receiver, as shown ! below:</p> ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"><b>gpsM.nc</b> ! <pre> command result_t StdControl.start() {<br><br> j = 0;<br><br> cmd_msg[j++] = '$';<br> cmd_msg[j++] = 'P';<br> cmd_msg[j++] = 'S';<br> cmd_msg[j++] = 'R';<br> cmd_msg[j++] = 'F';<br> cmd_msg[j++] = '1';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = '3';<br> cmd_msg[j++] = ',';<br> cmd_msg[j++] = '0';<br> j++;<br> cmd_msg[j++] = ',';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = ',';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = ',';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = '1';<br> cmd_msg[j++] = '*';<br> cmd_msg[j++] = '2';<br> j++;<br> cmd_msg[j++] = '\r';<br> cmd_msg[j++] = '\n';<br> cmd_msg[j++] = 0x00;<br><br> call clearGPS();<br> call getGPS();<br> return call SubControl.start();<br> }<br><br> command result_t clearGPS() { <br> ...<br> // Clear GLL<br> cmd_msg[10] = '1';<br> cmd_msg[22] = '5';<br> for (i = 0; i < j; i++){<br> loop_until_bit_is_set(UCSR1A, UDRE);<br> outb(UDR1,cmd_msg[i]);<br> }<br> ...<br> }<br><br> command result_t getGPS() { <br> ...<br> // Request GGA data at 1 Hz<br> cmd_msg[10] = '0';<br> cmd_msg[16] = '1';<br> cmd_msg[22] = '5';<br> for (i = 0; i < j; i++){<br> loop_until_bit_is_set(UCSR1A, UDRE);<br> outb(UDR1,cmd_msg[i]);<br> }<br> ...<br> }<br></pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! <p>Here, the command outb(UDR1,cmd_msg[i]) sends the byte at entry <i>i</i> ! of <tt>cmd_msg</tt> out to UART1. </p> ! <h2>Receiving Data from GPS Module</h2> ! <p>Data enters into the client from the receiver via UART1. Messages from ! the receiver are collected byte by byte with the command <tt>inp(UDR1)</tt> ! and temporarily stored in an array, <tt>rxBuffer</tt>. Data is ! collected only after the GGA start sequence, <tt>$GPGGA</tt>, is completed. ! Collection stops when the * delimiter is reached, after which point, ! the 40th and 41st entries of the buffer are combined to determine the number ! of satellites, i.e.</p> ! <center> ! <p>num_satellites = 10*(rxBuffer[40] - '0') + (rxBuffer[41] - '0');</p> ! </center> ! <p>If <tt>num_satellite</tt> < 4, <tt>rxBuffer</tt> is cleared and the ! client waits again for the GGA start sequence to pass in the subsequent ! message until it resumes data collection. Otherwise, the data stored in ! the buffer is parsed and stored in EEPRROM using <tt>logGPS</tt>.</p> ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"> ! <pre> command result_t getGPS() {<br> ... <br> while(num_satellites < 4) {<br> k = 0;<br> incoming = TRUE;<br> call waitGPS();<br> while(incoming) {<br> if (inp(UCSR1A) & (1 << RXC)){<br> data = inp(UDR1);<br> if (data == '*') {<br> incoming = FALSE;<br> }<br> rxBuffer[k++] = data;<br> }<br> }<br> num_satellites = 10*(rxBuffer[40] - '0') + (rxBuffer[41] - '0'); <br> }<br><br> // Parse and store input<br> call logGPS(rxBuffer);<br> return SUCCESS;<br> }<br><br> command result_t waitGPS() {<br> uint8_t last[3]; // array of last 3 characters from GPS <br> bool waiting = TRUE;<br> <br> while(waiting) {<br> last[3] = last[2];<br> last[2] = last[1];<br> if (inp(UCSR1A) & (1 << RXC)) {<br> last[1] = inp(UDR1);<br> }<br> if(last[3]=='G') {<br> if(last[2]=='G') {<br> if(last[1]=='A') {<br> waiting = FALSE;<br> }<br> }<br> }<br> }<br> return SUCCESS;<br> }<br></pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! <h2>Logging and Retrieving Data</h2> ! <p>Fields in the GGA message are comma delimited. These are parsed with <tt> ! logGPS()</tt>, which simultaneously stores the data into the client's EEPROM ! using <tt>LoggerWrite.write</tt>. One line of memory is reserved for each ! field, and these are numbered as follows:<br> ! <br> ! </p> ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td valign="Top"><b>Field</b><br> ! </td> ! <td valign="Top"><b>Line #<br> ! </b></td> ! <td valign="Top"><b>Field<br> ! </b></td> ! <td valign="Top"><b>Line #</b><br> ! </td> ! </tr> ! <tr> ! <td valign="Top">UTC Position<br> ! </td> ! <td valign="Top">25<br> ! </td> ! <td valign="Top">HDOP<br> ! </td> ! <td valign="Top">32<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Latitude<br> ! </td> ! <td valign="Top">26<br> ! </td> ! <td valign="Top">MSL Altitude<br> ! </td> ! <td valign="Top">33<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">N/S Indicator<br> ! </td> ! <td valign="Top">27<br> ! </td> ! <td valign="Top">Altitude Units<br> ! </td> ! <td valign="Top">34<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Longitude<br> ! </td> ! <td valign="Top">28<br> ! </td> ! <td valign="Top">Geoid Separation<br> ! </td> ! <td valign="Top">35<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">E/W Indicator<br> ! </td> ! <td valign="Top">29<br> ! </td> ! <td valign="Top">Separation Units<br> ! </td> ! <td valign="Top">36<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Position Fix Indicator<br> ! </td> ! <td valign="Top">30<br> ! </td> ! <td valign="Top">Age of DGPS Correlation<br> ! </td> ! <td valign="Top">37<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Satellites Used<br> ! </td> ! <td valign="Top">31<br> ! </td> ! <td valign="Top">DGPS Reference Station ID<br> ! </td> ! <td valign="Top">39<br> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! <p> To retrieve data, load a second mote with <code>GenericBase</code> and ! perform the following: </p> ! <ol> ! <li>Leaving the GenericBase mote connected to the programming board, ! start the serial port forwarding service using the command ! <code>java net.tinyos.sf.SerialForward</code></li> ! <li>Broadcast retrieve command over the radio: <code>java net.tinyos.tools.gpsBcast ! <group ID> <b>Field Name</b> <gps mote ! ID></code></li> ! <li>Packet is sent to the base station via radio. Contained in the packet ! payload is the data for the selected field. </li> ! </ol> ! <hr /=""> ! <p> Last updated: $Date$ by $Author$. ! </p> ! </body> ! </html> |