// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*- // // u-blox UBX GPS driver for ArduPilot and ArduPilotMega. // Code by Michael Smith, Jordi Munoz and Jose Julio, DIYDrones.com // // This library is free software; you can redistribute it and / or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // #include "AP_GPS_UBLOX.h" #include // Constructors //////////////////////////////////////////////////////////////// AP_GPS_UBLOX::AP_GPS_UBLOX(Stream *s) : GPS(s) { } // Public Methods ////////////////////////////////////////////////////////////// void AP_GPS_UBLOX::init(void) { // XXX it might make sense to send some CFG_MSG,CFG_NMEA messages to get the // right reporting configuration. _port->flush(); _epoch = TIME_OF_WEEK; idleTimeout = 1200; } // Process bytes available from the stream // // The stream is assumed to contain only messages we recognise. If it // contains other messages, and those messages contain the preamble // bytes, it is possible for this code to fail to synchronise to the // stream immediately. Without buffering the entire message and // re-processing it from the top, this is unavoidable. The parser // attempts to avoid this when possible. // bool AP_GPS_UBLOX::read(void) { uint8_t data; int numc; bool parsed = false; numc = _port->available(); for (int i = 0; i < numc; i++) { // Process bytes received // read the next byte data = _port->read(); switch(_step) { // Message preamble detection // // If we fail to match any of the expected bytes, we reset // the state machine and re-consider the failed byte as // the first byte of the preamble. This improves our // chances of recovering from a mismatch and makes it less // likely that we will be fooled by the preamble appearing // as data in some other message. // case 1: if (PREAMBLE2 == data) { _step++; break; } _step = 0; // FALLTHROUGH case 0: if(PREAMBLE1 == data) _step++; break; // Message header processing // // We sniff the class and message ID to decide whether we // are going to gather the message bytes or just discard // them. // // We always collect the length so that we can avoid being // fooled by preamble bytes in messages. // case 2: _step++; if (CLASS_NAV == data) { _gather = true; // class is interesting, maybe gather _ck_b = _ck_a = data; // reset the checksum accumulators } else { _gather = false; // class is not interesting, discard } break; case 3: _step++; _ck_b += (_ck_a += data); // checksum byte _msg_id = data; if (_gather) { // if class was interesting switch(data) { case MSG_POSLLH: // message is interesting _expect = sizeof(ubx_nav_posllh); break; case MSG_STATUS: _expect = sizeof(ubx_nav_status); break; case MSG_SOL: _expect = sizeof(ubx_nav_solution); break; case MSG_VELNED: _expect = sizeof(ubx_nav_velned); break; default: _gather = false; // message is not interesting } } break; case 4: _step++; _ck_b += (_ck_a += data); // checksum byte _payload_length = data; // payload length low byte break; case 5: _step++; _ck_b += (_ck_a += data); // checksum byte _payload_length += (uint16_t)data; // payload length high byte _payload_counter = 0; // prepare to receive payload if (_payload_length != _expect) _gather = false; break; // Receive message data // case 6: _ck_b += (_ck_a += data); // checksum byte if (_gather) // gather data if requested _buffer.bytes[_payload_counter] = data; if (++_payload_counter == _payload_length) _step++; break; // Checksum and message processing // case 7: _step++; if (_ck_a != data) _step = 0; // bad checksum break; case 8: _step = 0; if (_ck_b != data) break; // bad checksum if (_gather) { parsed = _parse_gps(); // Parse the new GPS packet } } } return parsed; } // Private Methods ///////////////////////////////////////////////////////////// bool AP_GPS_UBLOX::_parse_gps(void) { switch (_msg_id) { case MSG_POSLLH: time = _buffer.posllh.time; longitude = _buffer.posllh.longitude; latitude = _buffer.posllh.latitude; altitude = _buffer.posllh.altitude_msl / 10; break; case MSG_STATUS: fix = (_buffer.status.fix_status & NAV_STATUS_FIX_VALID) && (_buffer.status.fix_type == FIX_3D); break; case MSG_SOL: fix = (_buffer.solution.fix_status & NAV_STATUS_FIX_VALID) && (_buffer.solution.fix_type == FIX_3D); num_sats = _buffer.solution.satellites; hdop = _buffer.solution.position_DOP; break; case MSG_VELNED: speed_3d = _buffer.velned.speed_3d; // cm/s ground_speed = _buffer.velned.speed_2d; // cm/s ground_course = _buffer.velned.heading_2d / 1000; // Heading 2D deg * 100000 rescaled to deg * 100 break; default: return false; } return true; }