Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AP_GPS/AP_GPS_ERB.cpp
Views: 1798
/*1This program is free software: you can redistribute it and/or modify2it under the terms of the GNU General Public License as published by3the Free Software Foundation, either version 3 of the License, or4(at your option) any later version.56This program is distributed in the hope that it will be useful,7but WITHOUT ANY WARRANTY; without even the implied warranty of8MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9GNU General Public License for more details.1011You should have received a copy of the GNU General Public License12along with this program. If not, see <http://www.gnu.org/licenses/>.13*/1415//16// Emlid Reach Binary (ERB) GPS driver for ArduPilot.17// ERB protocol: http://files.emlid.com/ERB.pdf1819#include "AP_GPS.h"20#include "AP_GPS_ERB.h"2122#if AP_GPS_ERB_ENABLED2324#define ERB_DEBUGGING 02526#define STAT_FIX_VALID 0x012728#include <AP_HAL/AP_HAL.h>2930extern const AP_HAL::HAL& hal;3132#if ERB_DEBUGGING33# define Debug(fmt, args ...) do {hal.console->printf("%s:%d: " fmt "\n", __FUNCTION__, __LINE__, ## args); hal.scheduler->delay(1); } while(0)34#else35# define Debug(fmt, args ...)36#endif3738// Process bytes available from the stream39//40// The stream is assumed to contain only messages we recognise. If it41// contains other messages, and those messages contain the preamble42// bytes, it is possible for this code to fail to synchronise to the43// stream immediately. Without buffering the entire message and44// re-processing it from the top, this is unavoidable. The parser45// attempts to avoid this when possible.46//47bool48AP_GPS_ERB::read(void)49{50uint8_t data;51int16_t numc;52bool parsed = false;5354numc = port->available();55for (int16_t i = 0; i < numc; i++) { // Process bytes received5657// read the next byte58data = port->read();59#if AP_GPS_DEBUG_LOGGING_ENABLED60log_data(&data, 1);61#endif6263reset:64switch(_step) {6566// Message preamble detection67//68case 1:69if (PREAMBLE2 == data) {70_step++;71break;72}73_step = 0;74Debug("reset %u", __LINE__);75FALLTHROUGH;76case 0:77if(PREAMBLE1 == data)78_step++;79break;8081// Message header processing82//83case 2:84_step++;85_msg_id = data;86_ck_b = _ck_a = data; // reset the checksum accumulators87break;88case 3:89_step++;90_ck_b += (_ck_a += data); // checksum byte91_payload_length = data; // payload length low byte92break;93case 4:94_step++;95_ck_b += (_ck_a += data); // checksum byte96_payload_length += (uint16_t)(data<<8);97_payload_counter = 0; // prepare to receive payload98break;99100// Receive message data101//102case 5:103_ck_b += (_ck_a += data); // checksum byte104if (_payload_counter < sizeof(_buffer)) {105_buffer[_payload_counter] = data;106}107if (++_payload_counter == _payload_length)108_step++;109break;110111// Checksum and message processing112//113case 6:114_step++;115if (_ck_a != data) {116Debug("bad cka %x should be %x", data, _ck_a);117_step = 0;118goto reset;119}120break;121case 7:122_step = 0;123if (_ck_b != data) {124Debug("bad ckb %x should be %x", data, _ck_b);125break; // bad checksum126}127128if (_parse_gps()) {129parsed = true;130}131break;132}133}134return parsed;135}136137bool138AP_GPS_ERB::_parse_gps(void)139{140switch (_msg_id) {141case MSG_VER:142Debug("Version of ERB protocol %u.%u.%u",143_buffer.ver.ver_high,144_buffer.ver.ver_medium,145_buffer.ver.ver_low);146break;147case MSG_POS:148Debug("Message POS");149_last_pos_time = _buffer.pos.time;150state.location.lng = (int32_t)(_buffer.pos.longitude * (double)1e7);151state.location.lat = (int32_t)(_buffer.pos.latitude * (double)1e7);152state.have_undulation = true;153state.undulation = _buffer.pos.altitude_msl - _buffer.pos.altitude_ellipsoid;154set_alt_amsl_cm(state, _buffer.pos.altitude_msl * 100);155state.status = next_fix;156_new_position = true;157state.horizontal_accuracy = _buffer.pos.horizontal_accuracy * 1.0e-3f;158state.vertical_accuracy = _buffer.pos.vertical_accuracy * 1.0e-3f;159state.have_horizontal_accuracy = true;160state.have_vertical_accuracy = true;161break;162case MSG_STAT:163Debug("Message STAT fix_status=%u fix_type=%u",164_buffer.stat.fix_status,165_buffer.stat.fix_type);166if (_buffer.stat.fix_status & STAT_FIX_VALID) {167if (_buffer.stat.fix_type == AP_GPS_ERB::FIX_FIX) {168next_fix = AP_GPS::GPS_OK_FIX_3D_RTK_FIXED;169} else if (_buffer.stat.fix_type == AP_GPS_ERB::FIX_FLOAT) {170next_fix = AP_GPS::GPS_OK_FIX_3D_RTK_FLOAT;171} else if (_buffer.stat.fix_type == AP_GPS_ERB::FIX_SINGLE) {172next_fix = AP_GPS::GPS_OK_FIX_3D;173} else {174next_fix = AP_GPS::NO_FIX;175state.status = AP_GPS::NO_FIX;176}177} else {178next_fix = AP_GPS::NO_FIX;179state.status = AP_GPS::NO_FIX;180}181state.num_sats = _buffer.stat.satellites;182if (next_fix >= AP_GPS::GPS_OK_FIX_3D) {183// use the uart receive time to make packet timestamps more accurate184set_uart_timestamp(_payload_length + sizeof(erb_header) + 2);185state.last_gps_time_ms = AP_HAL::millis();186state.time_week_ms = _buffer.stat.time;187state.time_week = _buffer.stat.week;188}189break;190case MSG_DOPS:191Debug("Message DOPS");192state.hdop = _buffer.dops.hDOP;193state.vdop = _buffer.dops.vDOP;194break;195case MSG_VEL:196Debug("Message VEL");197_last_vel_time = _buffer.vel.time;198state.ground_speed = _buffer.vel.speed_2d * 0.01f; // m/s199// Heading 2D deg * 100000 rescaled to deg * 100200state.ground_course = wrap_360(_buffer.vel.heading_2d * 1.0e-5f);201state.have_vertical_velocity = true;202state.velocity.x = _buffer.vel.vel_north * 0.01f;203state.velocity.y = _buffer.vel.vel_east * 0.01f;204state.velocity.z = _buffer.vel.vel_down * 0.01f;205state.have_speed_accuracy = true;206state.speed_accuracy = _buffer.vel.speed_accuracy * 0.01f;207_new_speed = true;208break;209case MSG_RTK:210Debug("Message RTK");211state.rtk_baseline_coords_type = RTK_BASELINE_COORDINATE_SYSTEM_NED;212state.rtk_num_sats = _buffer.rtk.base_num_sats;213if (_buffer.rtk.age_cs == 0xFFFF) {214state.rtk_age_ms = 0xFFFFFFFF;215} else {216state.rtk_age_ms = _buffer.rtk.age_cs * 10;217}218state.rtk_baseline_x_mm = _buffer.rtk.baseline_N_mm;219state.rtk_baseline_y_mm = _buffer.rtk.baseline_E_mm;220state.rtk_baseline_z_mm = _buffer.rtk.baseline_D_mm;221state.rtk_accuracy = _buffer.rtk.ar_ratio;222223state.rtk_week_number = _buffer.rtk.base_week_number;224state.rtk_time_week_ms = _buffer.rtk.base_time_week_ms;225break;226default:227Debug("Unexpected message 0x%02x", (unsigned)_msg_id);228return false;229}230// we only return true when we get new position and speed data231// this ensures we don't use stale data232if (_new_position && _new_speed && _last_vel_time == _last_pos_time) {233_new_speed = _new_position = false;234_fix_count++;235return true;236}237return false;238}239240/*241detect a ERB GPS. Adds one byte, and returns true if the stream242matches a ERB243*/244bool245AP_GPS_ERB::_detect(struct ERB_detect_state &state, uint8_t data)246{247reset:248switch (state.step) {249case 1:250if (PREAMBLE2 == data) {251state.step++;252break;253}254state.step = 0;255FALLTHROUGH;256case 0:257if (PREAMBLE1 == data)258state.step++;259break;260case 2:261state.step++;262state.ck_b = state.ck_a = data;263break;264case 3:265state.step++;266state.ck_b += (state.ck_a += data);267state.payload_length = data;268break;269case 4:270state.step++;271state.ck_b += (state.ck_a += data);272state.payload_counter = 0;273break;274case 5:275state.ck_b += (state.ck_a += data);276if (++state.payload_counter == state.payload_length)277state.step++;278break;279case 6:280state.step++;281if (state.ck_a != data) {282state.step = 0;283goto reset;284}285break;286case 7:287state.step = 0;288if (state.ck_b == data) {289return true;290} else {291goto reset;292}293}294return false;295}296#endif297298299