📄 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. LvD: Comparison of this driver with a SnoopyPro log of MapSource for Windows communication with the unit: Mapsource transmits an undocumented PL (physical layer) package with Pid equal to 16 immediately after receipt of the Pid_Session_started PL package and receives a PL package with Pid 17 and a payload of 4 bytes in return. Without documentation of what info is in the returned package, there does not seem a reason to reproduce it. More interestingly, immediately before sending a Pid_Records package, Mapsource transmits a similar package, but with Pid_Records (27) replaced by 28, and that reports zero packages to follow. The suspicion is obviously that there are Garmin units out there that have chips with Pid_Records mistyped as 28 instead of 27. Logic seems to say that Garmin knows best what bugs there are in their firmware and should be followed. Transmitting a packet with a Pid of 28 in general may not be a problem since the specification says to ignore packages you do not understand. However, it is not quite clear whether this extends only to the host or also to Garmin devices. I assume however it does. See 5.1, "Undocumented application packets" and 6.3 It is not clear to me in some cases how many packets are to be send in a Pid_Records/Pid_Xfer_Cmplt sequence. So I am making it then to be one packet. I am not aware that Garmin devices actually "monitor the progress" of the transfers. LvD: EOT**********************************************************************************************/#include "CDevice.h"#include <Garmin.h>#include <iostream>#include <sstream>#include <QtGui>using namespace EtrexLegendCx;using namespace Garmin;using namespace std;CDevice::CDevice() : usb(0){ copyright = "<h1>QLandkarte Device Driver for EtrexLegendCx</h1>" "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>" "<p>© 2007 by Oliver Eichler (oliver.eichler@gmx.de)</p>" "<p>© 2007 eTrex Legend Cx specific portions Bob Heise (heise2k@gmail.com)</p>" "<p>© 2007 Edits by Leon van Dommelen (dommelen@eng.fsu.edu)</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>";}CDevice::~CDevice(){}void CDevice::_acquire(){ // activate the driver usb = new CUSB(); usb->open(); usb->syncup(); // check the product ID if(usb->getProductId() != 0x01a5 && usb->getProductId() != 0x0124 && usb->getProductId() != 0x0312 && usb->getProductId() != 0x02b6){ throw exce_t(errSync,"No eTrex LegendCx compatible unit detected. Please retry to select other device driver."); } // Terminate if the requirements are not met if (usb->getDataType(0,'A',(uint16_t)100) != 110 || usb->getDataType(0,'A',(uint16_t)400) != 110 || usb->getDataType(0,'A',(uint16_t)301) != 312 || usb->getDataType(1,'A',(uint16_t)301) != 302) { if(strncmp(usb->getProductString().c_str(), "eTrex LegendCx", 14) == 0){ throw exce_t(errSync,"This eTrex LegendCx unit does not support the expected protocols?! Please try to select another device driver."); } else{ throw exce_t(errSync,"This unit is not eTrex LegendCx compatible. Please try to select another device driver."); } }}void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * key, void (*callback)(uint32_t,uint32_t,void*), void* data){ if(usb == 0) return; Packet_t command; Packet_t response; // We do not know whether this will work if(strncmp(usb->getProductString().c_str(), "eTrex LegendCx", 14) != 0 && strncmp(usb->getProductString().c_str(), "GPSMap76CSX", 11) != 0 && strncmp(usb->getProductString().c_str(), "GPSMap76CX", 10) != 0 && strncmp(usb->getProductString().c_str(), "GPSMap60CSX", 11) != 0 && strncmp(usb->getProductString().c_str(), "GPSMap60CX", 10) != 0 && strncmp(usb->getProductString().c_str(), "eTrex VentureCx", 15) != 0 && strncmp(usb->getProductString().c_str(), "eTrex VistaCx", 13) != 0 && strncmp(usb->getProductString().c_str(), "eTrex Venture HC", 16) != 0 && strncmp(usb->getProductString().c_str(), "eTrex Vista HCx", 15) != 0){ int res = QMessageBox::question(0,QObject::tr("Map upload is unverified"),QObject::tr("Map upload is unverified for this device and may damage it! Proceed at your own risk?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::No); if(res == QMessageBox::No){ throw exce_t(errRuntime,"Upload aborted."); } } // ask for SD Ram capacity command.type = GUSB_APPLICATION_LAYER; command.id = Pid_Command_Data; command.size = 2; *(uint16_t*)command.payload = Cmnd_Transfer_Mem; usb->write(command); // try to read SD Ram capacity uint32_t memory = 0; while(usb->read(response)){ if(response.id == Pid_Capacity_Data){ cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl; memory = ((uint32_t*)response.payload)[1]; } } if(memory < size){ stringstream msg; msg << "Failed to send map: Unit has not enough memory (available/needed): " << memory << "/" << size << " bytes"; throw exce_t(errRuntime,msg.str()); } // send unlock key if present if(key){ command.type = GUSB_APPLICATION_LAYER; command.id = Pid_Tx_Unlock_Key; command.size = strlen(key) + 1; memcpy(command.payload,key,command.size); usb->write(command); while(usb->read(response)){ if(response.id == Pid_Ack_Unlock_key){ //TODO read data } } } // switch to map transfer mode erase old map(?) command.type = GUSB_APPLICATION_LAYER; command.id = 75; command.size = 2; *(uint16_t*)command.payload = 0x000A; usb->write(command); // read incoming data while(usb->read(response)){ if(response.id == 74){ //TODO read data } } // transfer file uint32_t total = size; uint32_t offset = 0, chunkSize; command.type = GUSB_APPLICATION_LAYER; command.id = 36; // transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes while(size){ chunkSize = (size < (GUSB_PAYLOAD_SIZE - sizeof(offset))) ? size : (GUSB_PAYLOAD_SIZE - 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; usb->write(command); if(callback) callback(total - size, total, data); } // terminate map transfer mode (?) command.type = GUSB_APPLICATION_LAYER; command.id = 45; command.size = 2; *(uint16_t*)command.payload = 0x000A; usb->write(command);}void CDevice::_queryMap(std::list<Map_t>& maps){ maps.clear(); if(usb == 0) return; Packet_t command; Packet_t response; // Request map overview table command.type = GUSB_APPLICATION_LAYER; 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"); usb->write(command); uint32_t size = 1024; uint32_t fill = 0; char * pData = (char*)calloc(1,size); while(usb->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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -