📄 cdevice.cpp
字号:
/********************************************************************************************** Copyright (C) 2007 Oliver Eichler oliver.eichler@gmx.de 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., 59 Temple Place - Suite 330, Boston, MA 02111 USA Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd. or one of its subsidiaries.**********************************************************************************************/#include "CDevice.h"#include <Garmin.h>#include <iostream>#include <sstream>using namespace EtrexLegend;using namespace Garmin;using namespace std;#define GRMN_ETREX_LEGEND 411#define MAP_UPLOAD_BITRATE 115200 // or 57600, 38400, 19200, 9600#define WAYPOINT_DL_BITRATE 57600#define TRACK_DL_BITRATE 57600#define GRMN_DEFAULT_BITRATE 9600CDevice::CDevice() : serial(0){}CDevice::~CDevice(){}const string& CDevice::getCopyright(){ copyright = "<h1>QLandkarte Device Driver for EtrexLegend (EXPERIMENTAL)</h1>" "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>" "<p>© 2007 by Oliver Eichler (oliver.eichler@gmx.de)</p>" "<p>modified 2007 by Andreas Stenglein to work with serial eTrex Legend</p>" "<p>This driver 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. </p>"; return copyright;}void CDevice::_acquire(){ serial = new CSerial(port); //serial = new CSerial(); serial->open(); serial->syncup(); if(strncmp(serial->getProductString().c_str(), devname.c_str(), devname.size()) != 0){ string msg = "No " + devname + " unit detected. Please retry to select other device driver."; throw exce_t(errSync,msg); } if(devid){ if(serial->getProductId() != devid){ string msg = "No " + devname + " unit detected. Please retry to select other device driver."; throw exce_t(errSync,msg); } } else{ string msg = "No " + devname + " unit detected. Please retry to select other device driver."; throw exce_t(errSync,msg); }}void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * key, void (*callback)(uint32_t,uint32_t,void*), void* data){ if(serial == 0) return; int ready= 0; Packet_t command; Packet_t response; // ??? command.id = 0x1C; command.size = 2; *(uint16_t*)command.payload = 0x0000; serial->write(command); // read SD Ram capacity command.id = Pid_Command_Data; command.size = 2; *(uint16_t*)command.payload = Cmnd_Transfer_Mem; serial->write(command); while(serial->read(response) > 0){ // FIXME: if(response.id == Pid_Capacity_Data){ cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl; uint32_t memory = ((uint32_t*)response.payload)[1]; if(memory < size){ stringstream msg; msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes"; throw exce_t(errBlocked,msg.str()); } } }// KEY_UPLOAD: UNTESTED: someone should check how/if this works // send unlock key if present if(key){ command.id = Pid_Tx_Unlock_Key; command.size = strlen(key) + 1; memcpy(command.payload,key,command.size); serial->write(command); while(serial->read(response) > 0 ){ // FIXME: if(response.id == Pid_Ack_Unlock_key){ //TODO read data } } } if (serial->setBitrate( MAP_UPLOAD_BITRATE)) { throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second"); } // switch to map transfer mode erase old map(?) command.id = 75; command.size = 2; *(uint16_t*)command.payload = 0x000A; serial->write(command); ready= 0; while(!ready && serial->read(response) > 0){ if(response.id == 74){ ready= 1; //TODO read data } } uint32_t total = size; uint32_t offset = 0, chunkSize; command.id = 36; // USB: transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes // Serial: transfer file by chunks of 0xfe - sizeof(offset) = 0xfa = 250 bytes while(size){ chunkSize = (size < (254 - sizeof(offset))) ? size : (254 - sizeof(offset)); command.size = chunkSize + sizeof(offset); *(uint32_t*)command.payload = offset; memcpy(command.payload + sizeof(offset),mapdata,chunkSize); size -= chunkSize; mapdata += chunkSize; offset += chunkSize; serial->write(command); if(callback) callback(total - size, total, data); } // terminate map transfer mode (?) command.id = 45; command.size = 2; *(uint16_t*)command.payload = 0x000A; serial->write(command);}void CDevice::_queryMap(std::list<Map_t>& maps){ maps.clear(); if(serial == 0) return; Packet_t command; Packet_t response; // ??? command.id = 0x1C; command.size = 2; *(uint16_t*)command.payload = 0x0000; serial->write(command); // Request map overview table command.id = 0x59; command.size = 19; Map_Request_t * req = (Map_Request_t*)command.payload; req->dummy1 = 0; req->dummy2 = 10; strcpy(req->section,"MAPSOURC.MPS"); serial->write(command); uint32_t size = 1024; uint32_t fill = 0; char * pData = (char*)calloc(1,size); while(serial->read(response)){ // acknowledge request (???) if(response.id == 0x5B){ //TODO: read data } // chunk of MAPSOURC.MPS section // Each chunk is prepended by a chunk counter of type uint8_t. // This has to be skipped. That's why the peculiar math. if(response.id == 0x5A){ // realloc memory if chunk does not fit if((fill + response.size - 1) > size){ size += size; pData = (char*)realloc(pData,size); } memcpy(&pData[fill], response.payload + 1, response.size - 1); fill += response.size - 1; } } Map_Info_t * pInfo = (Map_Info_t*)pData; while(pInfo->tok == 0x4C){ Map_t m; char * pStr = pInfo->name1; m.mapName = pStr; pStr += strlen(pStr) + 1; m.tileName = pStr; maps.push_back(m); pInfo = (Map_Info_t*)(((char*)pInfo) + pInfo->size + sizeof(pInfo->tok) + sizeof(pInfo->size)); } free(pData);}void CDevice::_downloadWaypoints(list<Garmin::Wpt_t>& waypoints){ waypoints.clear(); if(serial == 0) return; Packet_t command; Packet_t response; // ??? command.id = 0x1C; command.size = 2; *(uint16_t*)command.payload = 0x0000; serial->write(command); if (serial->setBitrate( WAYPOINT_DL_BITRATE)) { throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second"); } // request waypoints command.id = Pid_Command_Data; command.size = 2; *(uint16_t*)command.payload = Cmnd_Transfer_Wpt; serial->write(command); while(1){ if(!serial->read(response)) continue; if(response.id == Pid_Records){#ifdef DBG_SHOW_WAYPOINT cout << "number of waypoints:" << *(int16_t*)response.payload << endl;#endif } if(response.id == Pid_Wpt_Data){ D108_Wpt_t * srcWpt = (D108_Wpt_t*)response.payload; waypoints.push_back(Wpt_t()); Wpt_t& tarWpt = waypoints.back(); tarWpt << *srcWpt; } if(response.id == Pid_Xfer_Cmplt){ break; } }// unsupported by etrex Legend ?#if 1 // request proximity waypoints command.id = Pid_Command_Data; command.size = 2; *(uint16_t*)command.payload = Cmnd_Transfer_Prx; serial->write(command); while(1){ if(!serial->read(response)) continue; if(response.id == Pid_Records){ //TODO read data#ifdef DBG_SHOW_WAYPOINT cout << "number of proximity waypoints:" << *(int16_t*)response.payload << endl;#endif } if(response.id == Pid_Prx_Wpt_Data){ D108_Wpt_t * srcWpt = (D108_Wpt_t*)response.payload; waypoints.push_back(Wpt_t()); Wpt_t& tarWpt = waypoints.back(); tarWpt << *srcWpt; } if(response.id == Pid_Xfer_Cmplt){ break; } }#endif#ifdef DBG_SHOW_WAYPOINT list<Wpt_t>::const_iterator wpt = waypoints.begin(); while(wpt != waypoints.end()){ cout << "-------------------------" << endl; cout << "class " << hex << (int)wpt->wpt_class << endl; cout << "dspl_color " << hex << (int)wpt->dspl_color << endl; cout << "dspl_attr " << hex << (int)wpt->dspl_attr << endl; cout << "smbl " << dec <<(int)wpt->smbl << endl; cout << "lat " << wpt->lat << endl; cout << "lon " << wpt->lon << endl; cout << "alt " << wpt->alt << endl; cout << "dpth " << wpt->dpth << endl; cout << "dist " << wpt->dist << endl; cout << "state " << wpt->state << endl; cout << "cc " << wpt->cc << endl; cout << "ete " << wpt->ete << endl; cout << "temp " << wpt->temp << endl; cout << "time " << wpt->time << endl; cout << "category " << wpt->wpt_cat << endl; cout << "ident " << wpt->ident << endl; cout << "comment " << wpt->comment << endl; cout << "facility " << wpt->facility << endl; cout << "city " << wpt->city << endl; cout << "addr " << wpt->addr << endl; cout << "crossroad " << wpt->crossroad << endl; ++wpt; }#endif if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) { throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second"); }}void CDevice::_uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints){ if(serial == 0) return; uint16_t prx_wpt_cnt = 0; list<Wpt_t>::const_iterator wpt = waypoints.begin();// does etrex Legend support prx waypoints? while(wpt != waypoints.end()){ if(wpt->dist != 1e25f) ++prx_wpt_cnt; ++wpt; } Packet_t command; Packet_t response; // ??? command.id = 0x1C; command.size = 2; *(uint16_t*)command.payload = 0x0000; serial->write(command); if (serial->setBitrate( WAYPOINT_DL_BITRATE)) { throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second"); } // transmit proximity waypoints first if(prx_wpt_cnt){ //announce number of records command.id = Pid_Records; command.size = 2; *(uint16_t*)command.payload = prx_wpt_cnt; serial->write(command); wpt = waypoints.begin(); while(wpt != waypoints.end()){ if(wpt->dist != 1e25f){ command.id = Pid_Prx_Wpt_Data; D108_Wpt_t * p = (D108_Wpt_t *)command.payload; command.size = *wpt >> *p; serial->write(command); } ++wpt; } //announce number of records command.id = Pid_Xfer_Cmplt; command.size = 2; *(uint16_t*)command.payload = Cmnd_Transfer_Prx; serial->write(command); } //transmit _all_ waypoints //announce number of records command.id = Pid_Records; command.size = 2; *(uint16_t*)command.payload = waypoints.size(); serial->write(command); wpt = waypoints.begin(); while(wpt != waypoints.end()){ command.id = Pid_Wpt_Data; D108_Wpt_t * p = (D108_Wpt_t *)command.payload; command.size = *wpt >> *p; serial->write(command); ++wpt; } //announce number of records command.id = Pid_Xfer_Cmplt; command.size = 2; *(uint16_t*)command.payload = Cmnd_Transfer_Wpt; serial->write(command); if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) { throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second"); }}void CDevice::_downloadTracks(std::list<Garmin::Track_t>& tracks){ tracks.clear(); if(serial == 0) return; Packet_t command; Packet_t response; // ??? command.id = 0x1C; command.size = 2; *(uint16_t*)command.payload = 0x0000; serial->write(command); if (serial->setBitrate( TRACK_DL_BITRATE)) { throw exce_t(errBlocked, "Failed to change serial link to xxx bit per second"); } command.id = Pid_Command_Data; command.size = 2; *(uint16_t*)command.payload = Cmnd_Transfer_Trk; serial->write(command); int trackidx = 0; string name; Track_t * track = 0; while(1){ if(!serial->read(response)) continue; if(response.id == Pid_Trk_Hdr){ trackidx = 0; D310_Trk_Hdr_t * hdr = (D310_Trk_Hdr_t*)response.payload; tracks.push_back(Track_t()); track = &tracks.back(); *track << *hdr; name = hdr->ident; } if(response.id == Pid_Trk_Data){ D301_Trk_t * data = (D301_Trk_t*)response.payload; TrkPt_t pt; if(data->new_trk){ if(trackidx){ tracks.push_back(Track_t()); Track_t& t = tracks.back(); t.color = track->color; t.dspl = track->dspl; char str[256]; sprintf(str,"%s_%d",name.c_str(),trackidx++); t.ident = str; track = &t; } else{ ++trackidx; } } pt << *data; track->track.push_back(pt); } if(response.id == Pid_Xfer_Cmplt){ break; } } if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) { throw exce_t(errBlocked, "Failed to change serial link to xxx bit per second"); }}void CDevice::_release(){ if(serial == 0) return; serial->close(); delete serial; serial = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -