diff --git a/CMakeLists.txt b/CMakeLists.txt index c664f0ed8..995f6b724 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -201,6 +201,7 @@ set(HEADERS filter_vecs.h format.h formspec.h + garmin.h garmin_fit.h garmin_fs.h garmin_gpi.h diff --git a/garmin.cc b/garmin.cc index cfe7674a0..ce6fa3207 100644 --- a/garmin.cc +++ b/garmin.cc @@ -19,6 +19,8 @@ */ +#include "garmin.h" + #include // for assert #include // for INT_MAX #include // for atan2, floor, sqrt @@ -32,7 +34,6 @@ #include // for QRegularExpression #include // for QString #include // for QTextCodec -#include // for QVector #include // for CaseInsensitive #include // for qPrintable, foreach @@ -44,7 +45,6 @@ #include "grtcirc.h" // for DEG #include "jeeps/gpsapp.h" // for GPS_Set_Baud_Rate, GPS_Init, GPS_Pre... #include "jeeps/gpscom.h" // for GPS_Command_Get_Lap, GPS_Command_Get... -#include "jeeps/gpsdevice.h" // for gpsdevh #include "jeeps/gpsmem.h" // for GPS_Track_Del, GPS_Way_Del, GPS_Pvt_Del #include "jeeps/gpsport.h" // for int32 #include "jeeps/gpsprot.h" // for gps_waypt_type, gps_category_type @@ -56,109 +56,34 @@ #define MYNAME "GARMIN" -static const char* portname; -static MakeShort* mkshort_handle; -static GPS_PWay* tx_waylist; -static GPS_PWay* tx_routelist; -static GPS_PWay* cur_tx_routelist_entry; -static GPS_PTrack* tx_tracklist; -static GPS_PTrack* cur_tx_tracklist_entry; -static int my_track_count = 0; -static char* getposn = nullptr; -static char* poweroff = nullptr; -static char* eraset = nullptr; -static char* resettime = nullptr; -static char* snlen = nullptr; -static char* snwhiteopt = nullptr; -static char* deficon = nullptr; -static char* category = nullptr; -static char* categorybitsopt = nullptr; -static char* baudopt = nullptr; -static char* opt_codec = nullptr; -static int baud = 0; -static int categorybits; -static bool receiver_must_upper = true; -static QTextCodec* codec{nullptr}; #define MILITANT_VALID_WAYPT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -/* Technically, even this is a little loose as spaces aren't allowed */ -static const char* valid_waypt_chars = MILITANT_VALID_WAYPT_CHARS " "; -static QRegularExpression invalid_char_re; - -static -QVector garmin_args = { - { - "snlen", &snlen, "Length of generated shortnames", nullptr, - ARGTYPE_INT, "1", nullptr, nullptr - }, - { - "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { "deficon", &deficon, "Default icon name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr }, - { - "get_posn", &getposn, "Return current position as a waypoint", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "power_off", &poweroff, "Command unit to power itself down", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "erase_t", &eraset, "Erase existing courses when writing new ones", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "resettime", &resettime, "Sync GPS time to computer time", - nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr - }, - { - "category", &category, "Category number to use for written waypoints", - nullptr, ARGTYPE_INT, "1", "16", nullptr - }, - { - "bitscategory", &categorybitsopt, "Bitmap of categories", - nullptr, ARGTYPE_INT, "1", "65535", nullptr - }, - { - "baud", &baudopt, "Speed in bits per second of serial port (baud=9600)", - nullptr, ARGTYPE_INT, ARG_NOMINMAX, nullptr - }, - { - "codec", &opt_codec, "override codec to use for device", - nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr - }, - -}; - -static const char* d103_symbol_from_icon_number(unsigned int n); -static int d103_icon_number_from_symbol(const QString& s); -static void garmin_fs_garmin_after_read(GPS_PWay way, Waypoint* wpt, int protoid); -static void garmin_fs_garmin_before_write(const Waypoint* wpt, GPS_PWay way, int protoid); - -static QByteArray str_from_unicode(const QString& qstr) + +QByteArray GarminFormat::str_from_unicode(const QString& qstr) { return codec->fromUnicode(qstr); } -static QString str_to_unicode(const QByteArray& cstr) +QString GarminFormat::str_to_unicode(const QByteArray& cstr) { return codec->toUnicode(cstr); } -static void -write_char_string(char* dest, const char* source, size_t destsize) +void +GarminFormat::write_char_string(char* dest, const char* source, size_t destsize) { // we zero fill and always terminate within the dest buffer. strncpy(dest, source, destsize - 1); dest[destsize-1] = 0; } -static void -rw_init(const QString& fname) +void +GarminFormat::rw_init(const QString& fname) { receiver_must_upper = true; const char* receiver_charset = "US-ASCII"; + /* Technically, even this is a little loose as spaces aren't allowed */ + const char* valid_waypt_chars = MILITANT_VALID_WAYPT_CHARS " "; if (!mkshort_handle) { mkshort_handle = new MakeShort; @@ -385,14 +310,14 @@ rw_init(const QString& fname) assert(invalid_char_re.isValid()); } -static void -rd_init(const QString& fname) +void +GarminFormat::rd_init(const QString& fname) { rw_init(fname); } -static void -rw_deinit() +void +GarminFormat::rw_deinit() { if (gps_baud_rate != DEFAULT_BAUD) { if (0 == GPS_Set_Baud_Rate(portname, DEFAULT_BAUD)) { @@ -407,8 +332,8 @@ rw_deinit() portname = nullptr; } -static int -waypt_read_cb(int total_ct, GPS_PWay* /*unused*/) +int +GarminFormat::waypt_read_cb(int total_ct, GPS_PWay* /*unused*/) { if (global_opts.verbose_status) { static int i; @@ -418,8 +343,8 @@ waypt_read_cb(int total_ct, GPS_PWay* /*unused*/) return 0; } -static void -waypt_read() +void +GarminFormat::waypt_read() { int n; GPS_PWay* way = nullptr; @@ -485,14 +410,14 @@ waypt_read() } } -static int lap_read_nop_cb(int /*unused*/, GPS_SWay** /*unused*/) +int GarminFormat::lap_read_nop_cb(int /*unused*/, GPS_SWay** /*unused*/) { return 0; } // returns 1 if the waypoint's start_time can be found // in the laps array, 0 otherwise -static unsigned int checkWayPointIsAtSplit(Waypoint* wpt, GPS_PLap* laps, int nlaps) +unsigned int GarminFormat::checkWayPointIsAtSplit(Waypoint* wpt, GPS_PLap* laps, int nlaps) { int result = 0; @@ -518,9 +443,8 @@ static unsigned int checkWayPointIsAtSplit(Waypoint* wpt, GPS_PLap* laps, int nl return result; } -static void -track_read() +GarminFormat::track_read() { GPS_PTrack* array; route_head* trk_head = nullptr; @@ -602,9 +526,8 @@ track_read() xfree(array); } -static void -route_read() +GarminFormat::route_read() { GPS_PWay* array; /* TODO: Fixes warning but is it right? @@ -661,8 +584,8 @@ route_read() * code, we convert the PVT (position/velocity/time) data from the receiver * to the data type we use throughout. Yes, we do lose some data that way. */ -static void -pvt2wpt(GPS_PPvt_Data pvt, Waypoint* wpt) +void +GarminFormat::pvt2wpt(GPS_PPvt_Data pvt, Waypoint* wpt) { wpt->altitude = pvt->alt; wpt->latitude = pvt->lat; @@ -721,17 +644,15 @@ pvt2wpt(GPS_PPvt_Data pvt, Waypoint* wpt) } } -static gpsdevh* pvt_fd; - -static void -pvt_init(const QString& fname) +void +GarminFormat::rd_position_init(const QString& fname) { rw_init(fname); GPS_Command_Pvt_On(qPrintable(fname), &pvt_fd); } -static Waypoint* -pvt_read(posn_status* posn_status) +Waypoint* +GarminFormat::rd_position(posn_status* posn_status) { auto* wpt = new Waypoint; GPS_PPvt_Data pvt = GPS_Pvt_New(); @@ -763,8 +684,8 @@ pvt_read(posn_status* posn_status) return nullptr; } -static void -data_read() +void +GarminFormat::read() { if (poweroff) { return; @@ -785,8 +706,8 @@ data_read() } } -static GPS_PWay -sane_GPS_Way_New() +GPS_PWay +GarminFormat::sane_GPS_Way_New() { GPS_PWay way = GPS_Way_New(); if (!way) { @@ -811,8 +732,8 @@ sane_GPS_Way_New() return way; } -static int -waypt_write_cb(GPS_PWay* /*unused*/) +int +GarminFormat::waypt_write_cb(GPS_PWay* /*unused*/) { int n = waypt_count(); @@ -828,8 +749,8 @@ waypt_write_cb(GPS_PWay* /*unused*/) * If we're using smart names, try to put the cache info in the * description. */ -static const char* -get_gc_info(const Waypoint* wpt) +const char* +GarminFormat::get_gc_info(const Waypoint* wpt) { if (global_opts.smart_names) { if (wpt->gc_data->type == Geocache::type_t::gt_virtual) { @@ -857,8 +778,8 @@ get_gc_info(const Waypoint* wpt) return ""; } -static int -waypoint_prepare() +int +GarminFormat::waypoint_prepare() { int i; int n = waypt_count(); @@ -890,10 +811,10 @@ waypoint_prepare() * cleaning */ QByteArray ident = mkshort_handle->mkshort( - global_opts.synthesize_shortnames ? - str_from_unicode(src) : - str_from_unicode(wpt->shortname), - false); + global_opts.synthesize_shortnames ? + str_from_unicode(src) : + str_from_unicode(wpt->shortname), + false); /* Should not be a strcpy as 'ident' isn't really a C string, * but rather a garmin "fixed length" buffer that's padded * to the end with spaces. So this is NOT (strlen+1). @@ -969,8 +890,8 @@ waypoint_prepare() return n; } -static void -waypoint_write() +void +GarminFormat::waypoint_write() { int n = waypoint_prepare(); @@ -988,8 +909,8 @@ waypoint_write() xfree(tx_waylist); } -static void -route_hdr_pr(const route_head* rte) +void +GarminFormat::route_hdr_pr(const route_head* rte) { (*cur_tx_routelist_entry)->rte_num = rte->rte_num; (*cur_tx_routelist_entry)->isrte = 1; @@ -1000,8 +921,8 @@ route_hdr_pr(const route_head* rte) } } -static void -route_waypt_pr(const Waypoint* wpt) +void +GarminFormat::route_waypt_pr(const Waypoint* wpt) { GPS_PWay rte = *cur_tx_routelist_entry; @@ -1053,8 +974,8 @@ route_waypt_pr(const Waypoint* wpt) cur_tx_routelist_entry++; } -static void -route_write() +void +GarminFormat::route_write() { int n = 2 * route_waypt_count(); /* Doubled for the islink crap. */ @@ -1065,12 +986,18 @@ route_write() tx_routelist[i] = sane_GPS_Way_New(); } - route_disp_all(route_hdr_pr, nullptr, route_waypt_pr); + auto route_hdr_pr_lambda = [this](const route_head* rte)->void { + route_hdr_pr(rte); + }; + auto route_waypt_pr_lambda = [this](const Waypoint* waypointp)->void { + route_waypt_pr(waypointp); + }; + route_disp_all(route_hdr_pr_lambda, nullptr, route_waypt_pr_lambda); GPS_Command_Send_Route(portname, tx_routelist, n); } -static void -track_hdr_pr(const route_head* trk_head) +void +GarminFormat::track_hdr_pr(const route_head* trk_head) { (*cur_tx_tracklist_entry)->ishdr = true; if (!trk_head->rte_name.isEmpty()) { @@ -1084,8 +1011,8 @@ track_hdr_pr(const route_head* trk_head) my_track_count++; } -static void -track_waypt_pr(const Waypoint* wpt) +void +GarminFormat::track_waypt_pr(const Waypoint* wpt) { (*cur_tx_tracklist_entry)->lat = wpt->latitude; (*cur_tx_tracklist_entry)->lon = wpt->longitude; @@ -1100,10 +1027,10 @@ track_waypt_pr(const Waypoint* wpt) cur_tx_tracklist_entry++; } -static int -track_prepare() +int +GarminFormat::track_prepare() { - int32_t n = track_waypt_count() + track_count(); + int32_t n = track_waypt_count() + track_count(); tx_tracklist = (GPS_STrack**) xcalloc(n, sizeof(GPS_PTrack)); cur_tx_tracklist_entry = tx_tracklist; @@ -1111,15 +1038,21 @@ track_prepare() tx_tracklist[i] = GPS_Track_New(); } my_track_count = 0; - track_disp_all(track_hdr_pr, nullptr, track_waypt_pr); + auto track_hdr_pr_lambda = [this](const route_head* rte)->void { + track_hdr_pr(rte); + }; + auto track_waypt_pr_lambda = [this](const Waypoint* waypointp)->void { + track_waypt_pr(waypointp); + }; + track_disp_all(track_hdr_pr_lambda, nullptr, track_waypt_pr_lambda); GPS_Prepare_Track_For_Device(&tx_tracklist, &n); return n; } -static void -track_write() +void +GarminFormat::track_write() { int n = track_prepare(); GPS_Command_Send_Track(portname, tx_tracklist, n, (eraset)? 1 : 0); @@ -1130,8 +1063,8 @@ track_write() xfree(tx_tracklist); } -static void -course_write() +void +GarminFormat::course_write() { int i; @@ -1152,8 +1085,8 @@ course_write() xfree(tx_tracklist); } -static void -data_write() +void +GarminFormat::write() { if (poweroff) { return; @@ -1180,42 +1113,8 @@ data_write() } } - -ff_vecs_t garmin_vecs = { - ff_type_serial, - FF_CAP_RW_ALL, - rd_init, - rw_init, - rw_deinit, - rw_deinit, - data_read, - data_write, - nullptr, - &garmin_args, - { pvt_init, pvt_read, rw_deinit, nullptr, nullptr, nullptr } -}; - -static const char* d103_icons[16] = { - "dot", - "house", - "gas", - "car", - "fish", - "boat", - "anchor", - "wreck", - "exit", - "skull", - "flag", - "camp", - "circle_x", - "deer", - "1st_aid", - "back-track" -}; - -static const char* -d103_symbol_from_icon_number(unsigned int n) +const char* +GarminFormat::d103_symbol_from_icon_number(unsigned int n) { if (n <= 15) { return d103_icons[n]; @@ -1224,8 +1123,8 @@ d103_symbol_from_icon_number(unsigned int n) } } -static int -d103_icon_number_from_symbol(const QString& s) +int +GarminFormat::d103_icon_number_from_symbol(const QString& s) { if (s.isNull()) { return 0; @@ -1239,8 +1138,8 @@ d103_icon_number_from_symbol(const QString& s) return 0; } -static void -garmin_fs_garmin_after_read(const GPS_PWay way, Waypoint* wpt, const int protoid) +void +GarminFormat::garmin_fs_garmin_after_read(const GPS_PWay way, Waypoint* wpt, const int protoid) { auto* gmsd = new garmin_fs_t(protoid); wpt->fs.FsChainAdd(gmsd); @@ -1273,8 +1172,8 @@ garmin_fs_garmin_after_read(const GPS_PWay way, Waypoint* wpt, const int protoid garmin_fs_t::set_addr(gmsd, str_to_unicode(QByteArray(way->addr, qstrnlen(way->addr, sizeof(way->addr))))); } -static void -garmin_fs_garmin_before_write(const Waypoint* wpt, GPS_PWay way, const int protoid) +void +GarminFormat::garmin_fs_garmin_before_write(const Waypoint* wpt, GPS_PWay way, const int protoid) { const garmin_fs_t* gmsd = garmin_fs_t::find(wpt); diff --git a/garmin.h b/garmin.h new file mode 100644 index 000000000..0139a861d --- /dev/null +++ b/garmin.h @@ -0,0 +1,206 @@ +/* + Jeeps wrapper for Garmin serial protocol. + + Copyright (C) 2002, 2003, 2004, 2005, 2006 Robert Lipe, robertlipe+source@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + */ +#ifndef GARMIN_H_INCLUDED_ +#define GARMIN_H_INCLUDED_ + +#include // for size_t + +#include // for QByteArray +#include // for QRegularExpression +#include // for QString +#include // for QTextCodec +#include // for QVector + +#include "defs.h" +#include "format.h" // for Format +#include "jeeps/gpsdevice.h" // for gpsdevh +#include "jeeps/gpssend.h" // for GPS_PWay, GPS_SWay, GPS_PTrack, GPS_PPvt_Data, GPS_SLap +#include "mkshort.h" // for MakeShort + + +class GarminFormat : public Format +{ +public: + QVector* get_args() override + { + return &garmin_args; + } + + ff_type get_type() const override + { + return ff_type_serial; + } + + QVector get_cap() const override + { + return FF_CAP_RW_ALL; + } + + void rd_init(const QString& fname) override; + void read() override; + void rd_deinit() override + { + rw_deinit(); + } + void wr_init(const QString& fname) override + { + rw_init(fname); + } + void write() override; + void wr_deinit() override + { + rw_deinit(); + } + void rd_position_init(const QString& fname) override; + Waypoint* rd_position(posn_status* status) override; + void rd_position_deinit() override + { + rw_deinit(); + } + +private: + /* Member Functions */ + + QByteArray str_from_unicode(const QString& qstr); + QString str_to_unicode(const QByteArray& cstr); + static void write_char_string(char* dest, const char* source, size_t destsize); + void rw_init(const QString& fname); + void rw_deinit(); + static int waypt_read_cb(int total_ct, GPS_SWay** /* unused */); + void waypt_read(); + static int lap_read_nop_cb(int /* unused */, GPS_SWay** /* unused */); + static unsigned int checkWayPointIsAtSplit(Waypoint* wpt, GPS_SLap** laps, int nlaps); + void track_read(); + void route_read(); + static void pvt2wpt(GPS_PPvt_Data pvt, Waypoint* wpt); + static GPS_SWay* sane_GPS_Way_New(); + static int waypt_write_cb(GPS_SWay** /* unused */); + static const char* get_gc_info(const Waypoint* wpt); + int waypoint_prepare(); + void waypoint_write(); + void route_hdr_pr(const route_head* rte); + void route_waypt_pr(const Waypoint* wpt); + void route_write(); + void track_hdr_pr(const route_head* trk_head); + void track_waypt_pr(const Waypoint* wpt); + int track_prepare(); + void track_write(); + void course_write(); + static const char* d103_symbol_from_icon_number(unsigned int n); + static int d103_icon_number_from_symbol(const QString& s); + void garmin_fs_garmin_after_read(GPS_PWay way, Waypoint* wpt, int protoid); + void garmin_fs_garmin_before_write(const Waypoint* wpt, GPS_PWay way, int protoid); + + /* Data Members */ + + const char* portname{}; + MakeShort* mkshort_handle{}; + GPS_PWay* tx_waylist{}; + GPS_PWay* tx_routelist{}; + GPS_PWay* cur_tx_routelist_entry{}; + GPS_PTrack* tx_tracklist{}; + GPS_PTrack* cur_tx_tracklist_entry{}; + int my_track_count = 0; + char* getposn = nullptr; + char* poweroff = nullptr; + char* eraset = nullptr; + char* resettime = nullptr; + char* snlen = nullptr; + char* snwhiteopt = nullptr; + char* deficon = nullptr; + char* category = nullptr; + char* categorybitsopt = nullptr; + char* baudopt = nullptr; + char* opt_codec = nullptr; + int baud = 0; + int categorybits{}; + bool receiver_must_upper = true; + QTextCodec* codec{nullptr}; + + QRegularExpression invalid_char_re; + + QVector garmin_args = { + { + "snlen", &snlen, "Length of generated shortnames", nullptr, + ARGTYPE_INT, "1", nullptr, nullptr + }, + { + "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { "deficon", &deficon, "Default icon name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr }, + { + "get_posn", &getposn, "Return current position as a waypoint", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "power_off", &poweroff, "Command unit to power itself down", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "erase_t", &eraset, "Erase existing courses when writing new ones", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "resettime", &resettime, "Sync GPS time to computer time", + nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr + }, + { + "category", &category, "Category number to use for written waypoints", + nullptr, ARGTYPE_INT, "1", "16", nullptr + }, + { + "bitscategory", &categorybitsopt, "Bitmap of categories", + nullptr, ARGTYPE_INT, "1", "65535", nullptr + }, + { + "baud", &baudopt, "Speed in bits per second of serial port (baud=9600)", + nullptr, ARGTYPE_INT, ARG_NOMINMAX, nullptr + }, + { + "codec", &opt_codec, "override codec to use for device", + nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr + }, + + }; + + gpsdevh* pvt_fd{}; + + static constexpr const char* d103_icons[16] = { + "dot", + "house", + "gas", + "car", + "fish", + "boat", + "anchor", + "wreck", + "exit", + "skull", + "flag", + "camp", + "circle_x", + "deer", + "1st_aid", + "back-track" + }; +}; +#endif // GARMIN_H_INCLUDED_ diff --git a/vecs.cc b/vecs.cc index c4c7a7a99..f35289088 100644 --- a/vecs.cc +++ b/vecs.cc @@ -43,6 +43,7 @@ #include "dg-100.h" // for Dg100FileFormat, Dg100SerialFormat, Dg200FileFormat, Dg200SerialFormat #include "exif.h" // for ExifFormat #include "format.h" // for Format +#include "garmin.h" // for GarminFormat #include "garmin_fit.h" // for GarminFitFormat #include "garmin_gpi.h" // for GarminGPIFormat #include "gbversion.h" // for WEB_DOC_DIR @@ -75,7 +76,6 @@ extern ff_vecs_t geo_vecs; -extern ff_vecs_t garmin_vecs; extern ff_vecs_t ozi_vecs; #if MAXIMAL_ENABLED extern ff_vecs_t tpg_vecs; @@ -115,7 +115,7 @@ struct Vecs::Impl { * of this class is constructed. */ GpxFormat gpx_fmt; - LegacyFormat garmin_fmt {garmin_vecs}; + GarminFormat garmin_fmt; GdbFormat gdb_fmt; NmeaFormat nmea_fmt; LegacyFormat ozi_fmt {ozi_vecs};