LCOV - code coverage report
Current view: top level - AP_GPS - AP_GPS_GSOF.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 97 106 91.5 %
Date: 2026-09-09 11:02:08 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : 
      16             : //
      17             : //  Trimble GPS driver for ArduPilot.
      18             : //  Code by Michael Oborne
      19             : //
      20             : //  Usage in SITL with hardware for debugging: 
      21             : //    sim_vehicle.py -v Plane -A "--serial3=uart:/dev/ttyUSB0" --console --map -DG
      22             : //    param set GPS1_TYPE 11 // GSOF
      23             : //    param set SERIAL3_PROTOCOL 5 // GPS
      24             : //
      25             : // Usage with NET parameters and ethernet in SITL with hardware:
      26             : //     param set NET_ENABLE 1
      27             : //     param set NET_P1_TYPE 2
      28             : //     param set NET_P1_PROTOCOL 5
      29             : //     param set SERIAL3_PROTOCOL 0
      30             : //     param set SIM_GPS1_TYPE 0
      31             : //     param set NET_P1_PORT 44444
      32             : //     param set GPS1_TYPE 11
      33             : //     param set GPS_AUTO_CONFIG 0
      34             : // 
      35             : //  Pure SITL usage:
      36             : //    sim_vehicle.py -v Plane --console --map -DG
      37             : //    param set SIM_GPS1_TYPE 11 // GSOF
      38             : //    param set GPS1_TYPE 11 // GSOF
      39             : //    param set SERIAL3_PROTOCOL 5 // GPS
      40             : 
      41             : #define AP_MATH_ALLOW_DOUBLE_FUNCTIONS 1
      42             : 
      43             : #include "AP_GPS.h"
      44             : #include "AP_GPS_GSOF.h"
      45             : #include <AP_Logger/AP_Logger.h>
      46             : #include <AP_HAL/utility/sparse-endian.h>
      47             : #include <GCS_MAVLink/GCS.h>
      48             : 
      49             : #if AP_GPS_GSOF_ENABLED
      50             : 
      51             : extern const AP_HAL::HAL& hal;
      52             : 
      53           1 : AP_GPS_GSOF::AP_GPS_GSOF(AP_GPS &_gps,
      54             :                          AP_GPS::Params &_params,
      55             :                          AP_GPS::GPS_State &_state,
      56           1 :                          AP_HAL::UARTDriver *_port) :
      57           1 :     AP_GPS_Backend(_gps, _params, _state, _port)
      58             : {
      59             : 
      60           1 :     if (port == nullptr) {
      61           0 :         GCS_SEND_TEXT(MAV_SEVERITY_ERROR, "GSOF instance %d has no port", state.instance);
      62           0 :         return;
      63             :     }
      64             : 
      65           1 :     const uint16_t gsofmsgreq[5] = {
      66             :         AP_GSOF::POS_TIME,
      67             :         AP_GSOF::POS,
      68             :         AP_GSOF::VEL,
      69             :         AP_GSOF::DOP,
      70             :         AP_GSOF::POS_SIGMA
      71             :     };
      72             :     // https://receiverhelp.trimble.com/oem-gnss/index.html#GSOFmessages_Overview.html?TocPath=Output%2520Messages%257CGSOF%2520Messages%257COverview%257C_____0
      73             :     // The maximum number of outputs allowed with GSOF is 10
      74             :     static_assert(ARRAY_SIZE(gsofmsgreq) <= 10, "The maximum number of outputs allowed with GSOF is 10.");
      75           1 :     requested_msgs = AP_GSOF::MsgTypes(gsofmsgreq);
      76             :     
      77             : 
      78           1 :     constexpr uint8_t default_com_port = static_cast<uint8_t>(HW_Port::COM2);
      79           1 :     params.com_port.set_default(default_com_port);
      80           1 :     const auto com_port = params.com_port;
      81           1 :     if (!validate_com_port(com_port)) {
      82             :         // The user parameter for COM port is not a valid GSOF port
      83           0 :         GCS_SEND_TEXT(MAV_SEVERITY_ERROR, "GSOF instance %d has invalid COM port setting of %d", state.instance, (unsigned)com_port);
      84           0 :         return;
      85             :     }
      86             : 
      87           1 :     if (gps._auto_config >= AP_GPS::GPS_AUTO_CONFIG_ENABLE_SERIAL_ONLY) {
      88           1 :         requestBaud(static_cast<HW_Port>(unsigned(com_port)));
      89             :     }
      90             : 
      91           1 :     const uint32_t now = AP_HAL::millis();
      92           1 :     gsofmsg_time = now + 110;
      93             : }
      94             : 
      95         693 : bool AP_GPS_GSOF::configure(void)
      96             : {
      97         693 :     const uint32_t now = AP_HAL::millis();
      98             : 
      99         693 :     if (gsofmsgreq_index < (requested_msgs.count())) {
     100          30 :         const auto com_port = params.com_port.get();
     101          30 :         if (!validate_com_port(com_port)) {
     102             :             // The user parameter for COM port is not a valid GSOF port
     103           0 :             return false;
     104             :         }
     105          30 :         if (now > gsofmsg_time) {
     106          13 :             for (uint16_t i = next_req_gsof; i < requested_msgs.size(); i++){
     107          13 :                 if (requested_msgs.get(i)) {
     108           5 :                     next_req_gsof = i;
     109           5 :                     break;
     110             :                 }
     111             :             }
     112           5 :             requestGSOF(next_req_gsof, static_cast<HW_Port>(com_port), Output_Rate::FREQ_10_HZ);
     113           5 :             gsofmsg_time = now + 110;
     114           5 :             gsofmsgreq_index++;
     115           5 :             next_req_gsof++;
     116             :         }
     117             :     }
     118         693 :     return true;
     119             : }
     120             : 
     121             : // Process all bytes available from the stream
     122             : //
     123             : bool
     124         693 : AP_GPS_GSOF::read(void)
     125             : {
     126         693 :     if (gps._auto_config >= AP_GPS::GPS_AUTO_CONFIG_ENABLE_SERIAL_ONLY) {
     127         693 :         if (!configure()) return false;
     128             :     }
     129        8295 :     while (port->available() > 0) {
     130        7661 :         const uint8_t temp = port->read();
     131             : #if AP_GPS_DEBUG_LOGGING_ENABLED
     132             :         log_data(&temp, 1);
     133             : #endif
     134        7661 :         AP_GSOF::MsgTypes parsed {};
     135        7661 :         const int parse_status = parse(temp, parsed);
     136        7661 :         if(parse_status == PARSED_GSOF_DATA) {
     137         124 :             if (parsed.get(AP_GSOF::POS_TIME) &&
     138         123 :                 parsed.get(AP_GSOF::POS) && 
     139         121 :                 parsed.get(AP_GSOF::VEL) && 
     140         184 :                 parsed.get(AP_GSOF::DOP) && 
     141          60 :                 parsed.get(AP_GSOF::POS_SIGMA)
     142             :             )
     143             :             {
     144          59 :                 pack_state_data();
     145          59 :                 return true;
     146             :             }
     147             :         }          
     148             :     }
     149             : 
     150         634 :     return false;
     151             : }
     152             : 
     153             : void
     154           1 : AP_GPS_GSOF::requestBaud(const HW_Port portindex)
     155             : {
     156           1 :     uint8_t buffer[19] = {0x02,0x00,0x64,0x0d,0x00,0x00,0x00, // application file record
     157             :                           0x03, 0x00, 0x01, 0x00, // file control information block
     158             :                           0x02, 0x04, static_cast<uint8_t>(portindex), 0x07, 0x00,0x00, // serial port baud format
     159             :                           0x00,0x03
     160           1 :                          }; // checksum
     161             : 
     162           1 :     buffer[4] = packetcount++;
     163             : 
     164           1 :     uint8_t checksum = 0;
     165          18 :     for (uint8_t a = 1; a < (sizeof(buffer) - 1); a++) {
     166          17 :         checksum += buffer[a];
     167             :     }
     168             : 
     169           1 :     buffer[17] = checksum;
     170             : 
     171           1 :     port->write((const uint8_t*)buffer, sizeof(buffer));
     172           1 : }
     173             : 
     174             : void
     175           5 : AP_GPS_GSOF::requestGSOF(const uint8_t messageType, const HW_Port portIndex, const Output_Rate rateHz)
     176             : {
     177           5 :     uint8_t buffer[21] = {0x02,0x00,0x64,0x0f,0x00,0x00,0x00, // application file record
     178             :                           0x03,0x00,0x01,0x00, // file control information block
     179             :                           0x07,0x06,0x0a,static_cast<uint8_t>(portIndex),static_cast<uint8_t>(rateHz),0x00,messageType,0x00, // output message record
     180             :                           0x00,0x03
     181           5 :                          }; // checksum
     182             : 
     183           5 :     buffer[4] = packetcount++;
     184             : 
     185           5 :     uint8_t checksum = 0;
     186         100 :     for (uint8_t a = 1; a < (sizeof(buffer) - 1); a++) {
     187          95 :         checksum += buffer[a];
     188             :     }
     189             : 
     190           5 :     buffer[19] = checksum;
     191             : 
     192           5 :     port->write((const uint8_t*)buffer, sizeof(buffer));
     193           5 : }
     194             : 
     195             : bool
     196          31 : AP_GPS_GSOF::validate_com_port(const uint8_t com_port) const
     197             : {
     198          31 :     switch(com_port) {
     199          31 :         case static_cast<uint8_t>(HW_Port::COM1):
     200             :         case static_cast<uint8_t>(HW_Port::COM2):
     201          31 :             return true;
     202           0 :         default:
     203           0 :             return false;
     204             :     }
     205             : }
     206             : 
     207             : void
     208          59 : AP_GPS_GSOF::pack_state_data() 
     209             : {
     210             :     // TODO should we pack time data if there is no fix?
     211          59 :     state.time_week_ms = pos_time.time_week_ms;
     212          59 :     state.time_week = pos_time.time_week;
     213          59 :     state.num_sats = pos_time.num_sats;
     214             : 
     215          59 :     if ((pos_time.pos_flags1 & 1)) { // New position
     216          59 :         state.status = AP_GPS_FixType::FIX_3D;
     217          59 :         if ((pos_time.pos_flags2 & 1)) { // Differential position 
     218          59 :             state.status = AP_GPS_FixType::DGPS;
     219          59 :             if (pos_time.pos_flags2 & 2) { // Differential position method
     220          59 :                 if (pos_time.pos_flags2 & 4) {// Differential position method
     221          59 :                     state.status = AP_GPS_FixType::RTK_FIXED;
     222             :                 } else {
     223           0 :                     state.status = AP_GPS_FixType::RTK_FLOAT;
     224             :                 }
     225             :             }
     226             :         }
     227             :     } else {
     228           0 :         state.status = AP_GPS_FixType::NONE;
     229             :     }
     230             : 
     231          59 :     state.location.lat = (int32_t)(RAD_TO_DEG_DOUBLE * position.latitude_rad * (double)1e7);
     232          59 :     state.location.lng = (int32_t)(RAD_TO_DEG_DOUBLE * position.longitude_rad * (double)1e7);
     233          59 :     state.location.alt = (int32_t)(position.altitude * 100);
     234          59 :     state.last_gps_time_ms = AP_HAL::millis();
     235             : 
     236          59 :     if ((vel.velocity_flags & 1) == 1) {
     237          59 :         state.ground_speed = vel.horizontal_velocity;
     238          59 :         state.ground_course = wrap_360(degrees(vel.heading));
     239          59 :         fill_3d_velocity();
     240          59 :         state.velocity.z = -vel.vertical_velocity;
     241          59 :         state.have_vertical_velocity = true;
     242             :     }
     243             : 
     244          59 :     state.hdop = (uint16_t)(dop.hdop * 100);
     245          59 :     state.vdop = (uint16_t)(dop.vdop * 100);
     246             : 
     247          59 :     state.horizontal_accuracy = (pos_sigma.sigma_east + pos_sigma.sigma_north) / 2;
     248          59 :     state.vertical_accuracy = pos_sigma.sigma_up;
     249          59 :     state.have_horizontal_accuracy = true;
     250          59 :     state.have_vertical_accuracy = true;
     251          59 : }
     252             : #endif

Generated by: LCOV version 1.14