44 # define M_PI_F 3.14159265358979323846f 47 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) 48 #define ASH_UNUSED(x) (void)x; 51 #define ASH_DEBUG(...) {} 57 _satellite_info(satellite_info),
58 _gps_position(gps_position),
59 _heading_offset(heading_offset)
86 for (
int i = 0 ; i < len; i++) {
93 if ((memcmp(
_rx_buffer + 3,
"ZDA,", 3) == 0) && (uiCalcComma == 6)) {
112 double ashtech_time = 0.0;
113 int day = 0, month = 0, year = 0, local_time_off_hour = 0, local_time_off_min = 0;
117 if (bufptr && *(++bufptr) !=
',') { ashtech_time = strtod(bufptr, &endp); bufptr = endp; }
119 if (bufptr && *(++bufptr) !=
',') { day = strtol(bufptr, &endp, 10); bufptr = endp; }
121 if (bufptr && *(++bufptr) !=
',') { month = strtol(bufptr, &endp, 10); bufptr = endp; }
123 if (bufptr && *(++bufptr) !=
',') { year = strtol(bufptr, &endp, 10); bufptr = endp; }
125 if (bufptr && *(++bufptr) !=
',') { local_time_off_hour = strtol(bufptr, &endp, 10); bufptr = endp; }
127 if (bufptr && *(++bufptr) !=
',') { local_time_off_min = strtol(bufptr, &endp, 10); bufptr = endp; }
130 int ashtech_hour =
static_cast<int>(ashtech_time / 10000);
131 int ashtech_minute =
static_cast<int>((ashtech_time - ashtech_hour * 10000) / 100);
132 double ashtech_sec =
static_cast<double>(ashtech_time - ashtech_hour * 10000 - ashtech_minute * 100);
137 struct tm timeinfo = {};
138 timeinfo.tm_year = year - 1900;
139 timeinfo.tm_mon = month - 1;
140 timeinfo.tm_mday = day;
141 timeinfo.tm_hour = ashtech_hour;
142 timeinfo.tm_min = ashtech_minute;
143 timeinfo.tm_sec = int(ashtech_sec);
144 timeinfo.tm_isdst = 0;
147 time_t epoch = mktime(&timeinfo);
150 uint64_t usecs =
static_cast<uint64_t
>((ashtech_sec -
static_cast<uint64_t
>(ashtech_sec))) * 1000000;
158 ts.tv_nsec = usecs * 1000;
214 double ashtech_time = 0.0, lat = 0.0, lon = 0.0, alt = 0.0;
215 int num_of_sv = 0, fix_quality = 0;
217 char ns =
'?', ew =
'?';
223 if (bufptr && *(++bufptr) !=
',') { ashtech_time = strtod(bufptr, &endp); bufptr = endp; }
225 if (bufptr && *(++bufptr) !=
',') { lat = strtod(bufptr, &endp); bufptr = endp; }
227 if (bufptr && *(++bufptr) !=
',') { ns = *(bufptr++); }
229 if (bufptr && *(++bufptr) !=
',') { lon = strtod(bufptr, &endp); bufptr = endp; }
231 if (bufptr && *(++bufptr) !=
',') { ew = *(bufptr++); }
233 if (bufptr && *(++bufptr) !=
',') { fix_quality = strtol(bufptr, &endp, 10); bufptr = endp; }
235 if (bufptr && *(++bufptr) !=
',') { num_of_sv = strtol(bufptr, &endp, 10); bufptr = endp; }
237 if (bufptr && *(++bufptr) !=
',') { hdop = strtod(bufptr, &endp); bufptr = endp; }
239 if (bufptr && *(++bufptr) !=
',') { alt = strtod(bufptr, &endp); bufptr = endp; }
250 _gps_position->
lat =
static_cast<int>((int(lat * 0.01) + (lat * 0.01 - int(lat * 0.01)) * 100.0 / 60.0) * 10000000);
251 _gps_position->
lon =
static_cast<int>((int(lon * 0.01) + (lon * 0.01 - int(lon * 0.01)) * 100.0 / 60.0) * 10000000);
255 if (fix_quality <= 0) {
263 if (fix_quality == 5) { fix_quality = 3; }
283 }
else if (memcmp(
_rx_buffer,
"$GPHDT,", 7) == 0 && uiCalcComma == 2) {
294 if (bufptr && *(++bufptr) !=
',') {
295 heading = strtof(bufptr, &endp); bufptr = endp;
297 ASH_DEBUG(
"heading update: %.3f", (
double)heading);
299 heading *=
M_PI_F / 180.0f;
309 }
else if ((memcmp(
_rx_buffer,
"$PASHR,POS,", 11) == 0) && (uiCalcComma == 18)) {
345 int coordinatesFound = 0;
346 double ashtech_time = 0.0, lat = 0.0, lon = 0.0, alt = 0.0;
347 int num_of_sv = 0, fix_quality = 0;
348 double track_true = 0.0, ground_speed = 0.0, age_of_corr = 0.0;
349 double hdop = 99.9, vdop = 99.9, pdop = 99.9, tdop = 99.9, vertic_vel = 0.0;
350 char ns =
'?', ew =
'?';
358 if (bufptr && *(++bufptr) !=
',') { fix_quality = strtol(bufptr, &endp, 10); bufptr = endp; }
360 if (bufptr && *(++bufptr) !=
',') { num_of_sv = strtol(bufptr, &endp, 10); bufptr = endp; }
362 if (bufptr && *(++bufptr) !=
',') { ashtech_time = strtod(bufptr, &endp); bufptr = endp; }
364 if (bufptr && *(++bufptr) !=
',') {
369 lat = strtod(bufptr, &endp);
371 if (bufptr != endp) {coordinatesFound++;}
376 if (bufptr && *(++bufptr) !=
',') { ns = *(bufptr++); }
378 if (bufptr && *(++bufptr) !=
',') {
379 lon = strtod(bufptr, &endp);
381 if (bufptr != endp) {coordinatesFound++;}
386 if (bufptr && *(++bufptr) !=
',') { ew = *(bufptr++); }
388 if (bufptr && *(++bufptr) !=
',') {
389 alt = strtod(bufptr, &endp);
391 if (bufptr != endp) {coordinatesFound++;}
396 if (bufptr && *(++bufptr) !=
',') { age_of_corr = strtod(bufptr, &endp); bufptr = endp; }
398 if (bufptr && *(++bufptr) !=
',') { track_true = strtod(bufptr, &endp); bufptr = endp; }
400 if (bufptr && *(++bufptr) !=
',') { ground_speed = strtod(bufptr, &endp); bufptr = endp; }
402 if (bufptr && *(++bufptr) !=
',') { vertic_vel = strtod(bufptr, &endp); bufptr = endp; }
404 if (bufptr && *(++bufptr) !=
',') { pdop = strtod(bufptr, &endp); bufptr = endp; }
406 if (bufptr && *(++bufptr) !=
',') { hdop = strtod(bufptr, &endp); bufptr = endp; }
408 if (bufptr && *(++bufptr) !=
',') { vdop = strtod(bufptr, &endp); bufptr = endp; }
410 if (bufptr && *(++bufptr) !=
',') { tdop = strtod(bufptr, &endp); bufptr = endp; }
420 _gps_position->
lat =
static_cast<int>((int(lat * 0.01) + (lat * 0.01 - int(lat * 0.01)) * 100.0 / 60.0) * 10000000);
421 _gps_position->
lon =
static_cast<int>((int(lon * 0.01) + (lon * 0.01 - int(lon * 0.01)) * 100.0 / 60.0) * 10000000);
427 if (coordinatesFound < 3) {
431 if (fix_quality == 9 || fix_quality == 10) {
434 }
else if (fix_quality == 12 || fix_quality == 22) {
437 }
else if (fix_quality == 13 || fix_quality == 23) {
453 float track_rad =
static_cast<float>(track_true) *
M_PI_F / 180.0
f;
455 float velocity_ms =
static_cast<float>(ground_speed) / 1.9438445
f;
456 float velocity_north =
static_cast<float>(velocity_ms) * cosf(track_rad);
457 float velocity_east =
static_cast<float>(velocity_ms) * sinf(track_rad);
470 }
else if ((memcmp(
_rx_buffer + 3,
"GST,", 3) == 0) && (uiCalcComma == 8)) {
495 double ashtech_time = 0.0, lat_err = 0.0, lon_err = 0.0, alt_err = 0.0;
496 double min_err = 0.0, maj_err = 0.0, deg_from_north = 0.0, rms_err = 0.0;
504 if (bufptr && *(++bufptr) !=
',') { ashtech_time = strtod(bufptr, &endp); bufptr = endp; }
506 if (bufptr && *(++bufptr) !=
',') { rms_err = strtod(bufptr, &endp); bufptr = endp; }
508 if (bufptr && *(++bufptr) !=
',') { maj_err = strtod(bufptr, &endp); bufptr = endp; }
510 if (bufptr && *(++bufptr) !=
',') { min_err = strtod(bufptr, &endp); bufptr = endp; }
512 if (bufptr && *(++bufptr) !=
',') { deg_from_north = strtod(bufptr, &endp); bufptr = endp; }
514 if (bufptr && *(++bufptr) !=
',') { lat_err = strtod(bufptr, &endp); bufptr = endp; }
516 if (bufptr && *(++bufptr) !=
',') { lon_err = strtod(bufptr, &endp); bufptr = endp; }
518 if (bufptr && *(++bufptr) !=
',') { alt_err = strtod(bufptr, &endp); bufptr = endp; }
520 _gps_position->
eph = sqrtf(static_cast<float>(lat_err) * static_cast<float>(lat_err)
521 + static_cast<float>(lon_err) * static_cast<float>(lon_err));
526 }
else if ((memcmp(
_rx_buffer + 3,
"GSV,", 3) == 0)) {
560 int all_msg_num = 0, this_msg_num = 0, tot_sv_visible = 0;
567 memset(sat, 0,
sizeof(sat));
569 if (bufptr && *(++bufptr) !=
',') { all_msg_num = strtol(bufptr, &endp, 10); bufptr = endp; }
571 if (bufptr && *(++bufptr) !=
',') { this_msg_num = strtol(bufptr, &endp, 10); bufptr = endp; }
573 if (bufptr && *(++bufptr) !=
',') { tot_sv_visible = strtol(bufptr, &endp, 10); bufptr = endp; }
575 if ((this_msg_num < 1) || (this_msg_num > all_msg_num)) {
589 if (this_msg_num == all_msg_num) {
590 end = tot_sv_visible - (this_msg_num - 1) * 4;
601 for (
int y = 0 ; y < end ; y++) {
602 if (bufptr && *(++bufptr) !=
',') { sat[y].svid = strtol(bufptr, &endp, 10); bufptr = endp; }
604 if (bufptr && *(++bufptr) !=
',') { sat[y].elevation = strtol(bufptr, &endp, 10); bufptr = endp; }
606 if (bufptr && *(++bufptr) !=
',') { sat[y].azimuth = strtol(bufptr, &endp, 10); bufptr = endp; }
608 if (bufptr && *(++bufptr) !=
',') { sat[y].snr = strtol(bufptr, &endp, 10); bufptr = endp; }
618 }
else if (memcmp(
_rx_buffer,
"$PASHR,NAK", 10) == 0) {
625 }
else if (memcmp(
_rx_buffer,
"$PASHR,ACK", 10) == 0) {
632 }
else if (memcmp(
_rx_buffer,
"$PASHR,PRT,", 11) == 0 && uiCalcComma == 3) {
639 }
else if (memcmp(
_rx_buffer,
"$PASHR,RID,", 11) == 0) {
653 }
else if (memcmp(
_rx_buffer,
"$PASHR,RECEIPT,", 15) == 0) {
663 char *finished_find = strstr((
char *)
_rx_buffer,
"FINISHED,");
666 const bool error = strstr((
const char *)_rx_buffer,
"ERR");
674 double lat = 0., lon = 0.;
676 char ns =
'?', ew =
'?';
677 bufptr = finished_find + 9;
679 bufptr = strstr(bufptr,
",");
681 if (bufptr) { bufptr = strstr(bufptr + 1,
","); }
683 if (bufptr && *(++bufptr) !=
',') { lat = strtod(bufptr, &endp); bufptr = endp; }
685 if (bufptr && *(++bufptr) !=
',') { ns = *(bufptr++); }
687 if (bufptr && *(++bufptr) !=
',') { lon = strtod(bufptr, &endp); bufptr = endp; }
689 if (bufptr && *(++bufptr) !=
',') { ew = *(bufptr++); }
691 if (bufptr && *(++bufptr) !=
',') { alt = strtod(bufptr, &endp); bufptr = endp; }
693 if (ns ==
'S') { lat = -lat; }
695 if (ew ==
'W') { lon = -lon; }
697 lat = int(lat * 0.01) + (lat * 0.01 - int(lat * 0.01)) * 100.0 / 60.0;
698 lon = int(lon * 0.01) + (lon * 0.01 - int(lon * 0.01)) * 100.0 / 60.0;
730 const char *rtcm_options[] = {
731 "$PASHS,NME,POS,%c,ON,0.2\r\n",
733 "$PASHS,RT3,1074,%c,ON,1\r\n",
734 "$PASHS,RT3,1084,%c,ON,1\r\n",
735 "$PASHS,RT3,1094,%c,ON,1\r\n",
737 "$PASHS,RT3,1114,%c,ON,1\r\n",
738 "$PASHS,RT3,1124,%c,ON,1\r\n",
739 "$PASHS,RT3,1006,%c,ON,1\r\n",
740 "$PASHS,RT3,1033,%c,ON,31\r\n",
741 "$PASHS,RT3,1013,%c,ON,1\r\n",
742 "$PASHS,RT3,1029,%c,ON,1\r\n",
743 "$PASHS,RT3,1230,%c,ON\r\n",
746 "$PASHS,RT3,1005,%c,ON,1\r\n",
747 "$PASHS,RT3,1077,%c,ON,1\r\n",
748 "$PASHS,RT3,1087,%c,ON,1\r\n",
751 for (
unsigned int conf_i = 0; conf_i <
sizeof(rtcm_options) /
sizeof(rtcm_options[0]); conf_i++) {
752 int str_len = snprintf(buffer,
sizeof(buffer), rtcm_options[conf_i],
_port);
784 while (j < bytes_count) {
804 int ret =
read(buf,
sizeof(buf), timeout * 2);
810 }
else if (ret == 0) {
814 }
else if (ret > 0) {
827 #define HEXDIGIT_CHAR(d) ((char)((d) + (((d) < 0xA) ? '0' : 'A'-0xA))) 854 }
else if (b ==
'*') {
876 uint8_t checksum = 0;
880 for (; buffer < bufend; buffer++) { checksum ^= *buffer; }
920 if (
write(buf, buf_length) != buf_length) {
931 ASH_DEBUG(
"waiting for reply for command %i", (
int)command);
956 const unsigned baudrates_to_try[] = {9600, 38400, 19200, 57600, 115200};
957 bool success =
false;
959 unsigned test_baudrate;
961 for (
unsigned int baud_i = 0; !success && baud_i <
sizeof(baudrates_to_try) /
sizeof(baudrates_to_try[0]); baud_i++) {
962 test_baudrate = baudrates_to_try[baud_i];
964 if (baudrate > 0 && baudrate != test_baudrate) {
970 ASH_DEBUG(
"baudrate set to %i", test_baudrate);
972 const char port_config[] =
"$PASHQ,PRT\r\n";
974 for (
int run = 0; run < 2; ++run) {
975 write(port_config,
sizeof(port_config) - 1);
978 ASH_DEBUG(
"got port for baudrate %i", test_baudrate);
991 const unsigned desired_baudrate = 115200;
993 baudrate = test_baudrate;
995 if (baudrate != desired_baudrate) {
996 baudrate = desired_baudrate;
997 const char baud_config[] =
"$PASHS,SPD,%c,9\r\n";
998 char baud_config_str[
sizeof(baud_config)];
999 int len = snprintf(baud_config_str,
sizeof(baud_config_str), baud_config,
_port);
1000 write(baud_config_str, len);
1008 for (
int run = 0; run < 10; ++run) {
1010 const char port_config[] =
"$PASHQ,PRT\r\n";
1011 write(port_config,
sizeof(port_config) - 1);
1023 ASH_DEBUG(
"Successfully configured the baudrate");
1049 const char board_identification[] =
"$PASHQ,RID\r\n";
1051 if (
write(board_identification,
sizeof(board_identification) - 1) ==
sizeof(board_identification) - 1) {
1053 ASH_DEBUG(
"command %s failed", board_identification);
1060 const char update_rate[] =
"$PASHS,POP,20\r\n";
1063 ASH_DEBUG(
"command %s failed", update_rate);
1072 if (use_dual_mode) {
1074 const char duo_mode[] =
"$PASHS,SNS,DUO,2\r\n";
1077 ASH_DEBUG(
"command %s failed", duo_mode);
1081 const char solo_mode[] =
"$PASHS,SNS,SOL\r\n";
1084 ASH_DEBUG(
"command %s failed", solo_mode);
1089 const char *config_options[] = {
1090 "$PASHS,NME,ALL,%c,OFF\r\n",
1091 "$PASHS,ATM,ALL,%c,OFF\r\n",
1092 "$PASHS,OUT,%c,ON\r\n",
1093 "$PASHS,NME,ZDA,%c,ON,3\r\n",
1094 "$PASHS,NME,GST,%c,ON,3\r\n",
1095 "$PASHS,NME,POS,%c,ON,0.05\r\n",
1096 "$PASHS,NME,GSV,%c,ON,1\r\n" 1099 for (
unsigned int conf_i = 0; conf_i <
sizeof(config_options) /
sizeof(config_options[0]); conf_i++) {
1100 int len = snprintf(buffer,
sizeof(buffer), config_options[conf_i],
_port);
1108 if (use_dual_mode) {
1110 const char heading_output[] =
"$PASHS,NME,HDT,%c,ON,0.05\r\n";
1111 int len = snprintf(buffer,
sizeof(buffer), heading_output,
_port);
1124 status.mean_accuracy = 0;
1125 const bool valid =
false;
1126 const bool active =
true;
1127 status.flags = (int)valid | ((
int)active << 1);
1148 const char avg_pos[] =
"$PASHS,POS,AVG,%i\r\n";
1159 const char *config_options[] = {
1160 "$PASHS,ANP,OWN,TRM55971.00\r\n",
1161 "$PASHS,STI,0001\r\n" 1165 for (
unsigned int conf_i = 0; conf_i <
sizeof(config_options) /
sizeof(config_options[0]); conf_i++) {
1167 ASH_DEBUG(
"command %s failed", config_options[conf_i]);
1176 ASH_DEBUG(
"setting base station position");
1180 double latitude = settings.
latitude;
1182 if (latitude < 0.) {
1183 latitude = -latitude;
1191 latitude = ((int)latitude) * 100. + (latitude - ((int)latitude)) * 60.;
1195 if (longitude < 0.) {
1196 longitude = -longitude;
1204 longitude = ((int)longitude) * 100. + (longitude - ((int)longitude)) * 60.;
1206 int len = snprintf(buffer,
sizeof(buffer),
"$PASHS,POS,%.8f,%c,%.8f,%c,%.5f,PC1",
1207 latitude, ns, longitude, ew, (
double)settings.
altitude);
1209 if (len >= 0 && len < (
int)
sizeof(buffer)) {
1215 ASH_DEBUG(
"snprintf failed (buffer too short)");
1227 status.latitude = latitude;
1228 status.longitude = longitude;
1229 status.altitude = altitude;
1231 status.mean_accuracy = 0;
1232 status.flags = (int)valid | ((
int)active << 1);
void surveyInStatus(SurveyInStatus &status)
union GPSBaseStationSupport::BaseSettings::@4 settings
static struct vehicle_status_s status
RTCMParsing * _rtcm_parsing
int handleMessage(int len)
int writeAckedCommand(const void *buf, int buf_length, unsigned timeout)
Write a command and wait for a (N)Ack.
int receive(unsigned timeout) override
receive & handle new data from the device
int setBaudrate(int baudrate)
set the Baudrate
NMEACommandState _command_state
void reset()
reset the parsing state
int read(uint8_t *buf, int buf_length, int timeout)
read from device
struct satellite_info_s * _satellite_info
#define ASH_RESPONSE_TIMEOUT
bool _correction_output_activated
FixedPositionSettings fixed_position
struct vehicle_gps_position_s * _gps_position
int write(const void *buf, int buf_length)
write to the device
int32_t timestamp_time_relative
void activateCorrectionOutput()
enable output of correction output
uint8_t _rx_buffer[ASHTECH_RECV_BUFFER_SIZE]
bool _got_pashr_pos_message
If we got a PASHR,POS message, we will ignore GGA messages.
void gotRTCMMessage(uint8_t *buf, int buf_length)
got an RTCM message from the device
NMEACommand _waiting_for_command
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
int configure(unsigned &baudrate, OutputMode output_mode) override
configure the device
int(* GPSCallbackPtr)(GPSCallbackType type, void *data1, int data2, void *user)
Callback function for platform-specific stuff.
void receiveWait(unsigned timeout_min)
receive data for at least the specified amount of time
GPSDriverAshtech(GPSCallbackPtr callback, void *callback_user, struct vehicle_gps_position_s *gps_position, struct satellite_info_s *satellite_info, float heading_offset=0.f)
#define GPS_READ_BUFFER_SIZE
buffer size for the read() call. Messages can be longer than that.
uint64_t _last_timestamp_time
request RTCM output. This is used for (fixed position) base stations
void sendSurveyInStatusUpdate(bool active, bool valid, double latitude=(double) NAN, double longitude=(double) NAN, float altitude=NAN)
uint16_t messageLength() const
uint8_t * message() const
GPS driver base class with Base Station Support.
virtual ~GPSDriverAshtech()
uint8_t _rate_count_lat_lon
gps_abstime _survey_in_start
BaseSettings _base_settings
SurveyInSettings survey_in
uint16_t _rx_buffer_bytes
int waitForReply(NMEACommand command, const unsigned timeout)
#define gps_absolute_time
Get the current time in us.
AshtechBoard _board
board we are connected to
NMEADecodeState _decode_state
void setClock(timespec &t)
bool addByte(uint8_t b)
add a byte to the message
char _port
port we are connected to (e.g.
void activateRTCMOutput()