OpenCPN Partial API docs
garmin_wrapper.cpp
1 /*
2  Garmin Jeeps - OpenCPN Interface Wrapper.
3 
4  Copyright (C) 2010 David S Register
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA
19 
20  */
21 
22 #include "config.h"
23 
24 #include "model/garmin_wrapper.h"
25 
26 #include "gpsapp.h"
27 #include "garmin_gps.h"
28 #include "gpsserial.h"
29 
30 #define GPS_DEBUG
31 
32 static gpsdevh *my_gps_devh;
33 
34 wxString GetLastGarminError(void) {
35  return wxString(GetDeviceLastError(), wxConvUTF8);
36 }
37 
38 /*
39  Verify and force port closure after every called routine.
40  This is necessary for aborts in Windows environment, since ports cannot be
41  multiply opened.
42 */
43 
44 /* Wrapped interface from higher level objects */
45 int Garmin_GPS_Init(const wxString &port_name) {
46  int ret;
47  GPS_Enable_Error();
48  GPS_Enable_Warning();
49  GPS_Enable_User();
50  GPS_Enable_Diagnose();
51  char m[1];
52  m[0] = '\0';
53 
54  GPS_Error(m);
55 
56  ret = GPS_Init(port_name.mb_str());
57  VerifyPortClosed();
58 
59  return ret;
60 }
61 
62 int Garmin_GPS_Open(wxString &port_name) {
63  return GPS_Init(port_name.mb_str());
64 }
65 
66 int Garmin_GPS_PVT_On(wxString &port_name) {
67  return Garmin_Serial_GPS_PVT_On(port_name.mb_str());
68 }
69 
70 int Garmin_GPS_PVT_Off(wxString &port_name) {
71  return Garmin_Serial_GPS_PVT_Off(port_name.mb_str());
72 }
73 
74 int Garmin_GPS_GetPVT(void *pvt) {
75  return GPS_Serial_Command_Pvt_Get((GPS_PPvt_Data *)pvt);
76 }
77 
78 void Garmin_GPS_ClosePortVerify(void) { VerifyPortClosed(); }
79 
80 wxString Garmin_GPS_GetSaveString() {
81  return wxString(gps_save_string, wxConvUTF8);
82 }
83 
84 void Garmin_GPS_PrepareWptData(GPS_PWay pway, RoutePoint *prp) {
85  pway->lat = prp->m_lat;
86  pway->lon = prp->m_lon;
87  pway->alt_is_unknown = 1;
88  pway->alt = 0.0;
89  strncpy(pway->ident, (prp->GetName().Truncate(6)).mb_str(), 6);
90 }
91 
92 int Garmin_GPS_SendWaypoints(const wxString &port_name,
93  RoutePointList *wplist) {
94  int ret_val = 0;
95 
96  int nPoints = wplist->GetCount();
97 
98  // Create the array of GPS_PWays
99 
100  GPS_SWay **ppway = (GPS_SWay **)malloc(nPoints * sizeof(GPS_PWay));
101 
102  // and the GPS_Oways themselves
103  for (int i = 0; i < nPoints; i++) ppway[i] = GPS_Way_New();
104 
105  // Now fill in the useful elements
106  for (int i = 0; i < nPoints; i++) {
107  GPS_PWay pway = ppway[i];
108  wxRoutePointListNode *node = wplist->Item(i);
109  RoutePoint *prp = node->GetData();
110 
111  Garmin_GPS_PrepareWptData(pway, prp);
112  }
113 
114  // Transmit the list to the GPS receiver
115  int xfer_result = GPS_Command_Send_Waypoint(
116  port_name.mb_str(), ppway, nPoints, 0 /*int (*cb)(GPS_PWay *)*/);
117  ret_val = xfer_result;
118 
119  // Free all the memory
120  for (int i = 0; i < nPoints; i++) GPS_Way_Del(&ppway[i]);
121 
122  free(ppway);
123 
124  VerifyPortClosed();
125  return ret_val;
126 }
127 
128 // This routine creates an array of waypoint structures for an A200 route
129 // transfer according to the "Garmin GPS Interface Specification" page 20.
130 // The returned array contains the following packets:
131 //
132 // route header packet
133 // waypoint packet
134 // ...
135 // waypoint packet
136 //
137 // The total number of elements in the array (route header packet and
138 // all waypoint packets) is returned in the "size" argument.
139 
140 GPS_SWay **Garmin_GPS_Create_A200_Route(Route *pr, int route_number,
141  int *size) {
142  RoutePointList *wplist = pr->pRoutePointList;
143  int nPoints = wplist->GetCount();
144 
145  // Create the array of GPS_PWays
146  // There will be one extra for the route header
147 
148  *size = nPoints + 1;
149 
150  GPS_SWay **ppway = (GPS_SWay **)malloc((*size) * sizeof(GPS_PWay));
151 
152  // and the GPS_Oways themselves
153  for (int i = 0; i < nPoints + 1; i++) ppway[i] = GPS_Way_New();
154 
155  // Now fill in the useful elements
156 
157  // Element 0 is a route record
158 
159  GPS_PWay pway = ppway[0];
160  pway->isrte = true;
161  pway->rte_num = route_number;
162  strncpy(pway->rte_ident, (pr->m_RouteNameString.Truncate(255)).mb_str(), 255);
163  strncpy(pway->rte_cmnt, (pr->m_RouteNameString.Truncate(19)).mb_str(), 19);
164 
165  // Elements 1..n are waypoints
166  for (int i = 1; i < *size; i++) {
167  GPS_PWay pway = ppway[i];
168  wxRoutePointListNode *node = wplist->Item(i - 1);
169  RoutePoint *prp = node->GetData();
170 
171  Garmin_GPS_PrepareWptData(pway, prp);
172  }
173 
174  return ppway;
175 }
176 
177 // This routine creates an array of waypoint structures for an A201 route
178 // transfer according to the "Garmin GPS Interface Specification" page 21.
179 // The returned array contains the following packets:
180 //
181 // route header packet
182 // waypoint packet
183 // link packet
184 // waypoint packet
185 // link packet
186 // ...
187 // waypoint packet
188 //
189 // The total number of elements in the array (route header packet, link
190 // packets and waypoint packets) is returned in the "size" argument.
191 
192 GPS_SWay **Garmin_GPS_Create_A201_Route(Route *pr, int route_number,
193  int *size) {
194  RoutePointList *wplist = pr->pRoutePointList;
195  int nPoints = wplist->GetCount();
196 
197  // Create the array of GPS_PWays
198  // There will be one for the route header, n for each way point
199  // and n-1 for each link
200 
201  *size = 1 + nPoints + (nPoints - 1);
202 
203  GPS_SWay **ppway = (GPS_SWay **)malloc((*size) * sizeof(GPS_PWay));
204 
205  // and the GPS_Oways themselves
206  for (int i = 0; i < *size; i++) ppway[i] = GPS_Way_New();
207 
208  // Now fill in the useful elements
209 
210  // Element 0 is a route record
211 
212  GPS_PWay pway = ppway[0];
213  pway->isrte = true;
214  pway->rte_num = route_number;
215  strncpy(pway->rte_ident, (pr->m_RouteNameString.Truncate(255)).mb_str(), 255);
216  strncpy(pway->rte_cmnt, (pr->m_RouteNameString.Truncate(19)).mb_str(), 19);
217 
218  // Odd elements 1,3,5... are waypoints
219  // Even elements 2,4,6... are links
220  for (int i = 1; i < *size; i++) {
221  if (i % 2 == 1) /* Odd */
222  {
223  GPS_PWay pway = ppway[i];
224  wxRoutePointListNode *node = wplist->Item((i - 1) / 2);
225  RoutePoint *prp = node->GetData();
226 
227  Garmin_GPS_PrepareWptData(pway, prp);
228  } else /* Even */
229  {
230  /* Apparently, 0 filled links are OK */
231  GPS_PWay pway = ppway[i];
232  pway->islink = true;
233  pway->rte_link_class = 0;
234  memset(pway->rte_link_subclass, 0, sizeof(pway->rte_link_subclass));
235  memset(pway->rte_link_ident, 0, sizeof(pway->rte_link_ident));
236  }
237  }
238 
239  return ppway;
240 }
241 
242 int Garmin_GPS_SendRoute(const wxString &port_name, Route *pr,
243  N0183DlgCtx dlg_ctx) {
244  int ret_val = 0;
245 
246  int route_number = 1;
247 
248  // If the device supports unique numbered waypoints,
249  // Then we must query the device to find an empty number
250  if ((gps_rte_hdr_type == pD200) || (gps_rte_hdr_type == pD201)) {
251  // Retrieve <ALL> routes from the device
252  GPS_Diag("Garmin: trying to get free route number");
253  GPS_PWay *pprouteway;
254  int32 npacks = GPS_A200_Get(port_name.mb_str(), &pprouteway);
255  if (npacks < 0) return npacks;
256  dlg_ctx.set_value(40);
257 
258 // Iterate on the packets, finding the first route number from [0..9] that
259 // is not present
260 
261 // An array of route numbers, set element to true as encountered
262 bool brn[10];
263 for (int i = 0; i < 10; i++) brn[i] = false;
264 
265 for (int ip = 0; ip < npacks; ip++) {
266  GPS_PWay pway = pprouteway[ip];
267  if (pway->isrte) {
268  if ((pway->rte_num < 10)) brn[pway->rte_num] = true;
269  }
270 }
271 
272 // Find the first candidate within [1..9] that is unused
273 bool bfound_empty = false;
274 for (int i = 1; i < 10; i++) {
275  if (brn[i] == false) {
276  route_number = i;
277  bfound_empty = true;
278  break;
279  }
280 }
281 GPS_Diag("Using route number: %d", route_number);
282 
283 // Ask the user if it is all right to overwrite
284 if (!bfound_empty) {
285  if (!dlg_ctx.confirm_overwrite()) {
286  return 0;
287  }
288 }
289 }
290 
291 // Based on the route transfer protocol create the array of transfer packets
292 GPS_SWay **ppway;
293 int elements = 0;
294 if (gps_route_transfer == pA201)
295 ppway = Garmin_GPS_Create_A201_Route(pr, route_number, &elements);
296 else
297 ppway = Garmin_GPS_Create_A200_Route(pr, route_number, &elements);
298 
299 // Transmit the Route to the GPS receiver
300 int xfer_result = GPS_Command_Send_Route(port_name.mb_str(), ppway, elements);
301 ret_val = xfer_result;
302 
303 // Free all the memory
304 for (int i = 0; i < elements; i++) GPS_Way_Del(&ppway[i]);
305 
306 free(ppway);
307  dlg_ctx.set_value(80);
308 
309  VerifyPortClosed();
310  return ret_val;
311 }
312 
313 /*
314 int Garmin_USB_On(void)
315 {
316  int ret_val = GPS_Device_On("usb:", &my_gps_devh);
317 
318  return ret_val;
319 }
320 
321 int Garmin_USB_Off(void)
322 {
323  int ret_val = GPS_Device_Off(my_gps_devh);
324 
325  return ret_val;
326 }
327 */
Definition: route.h:75