This is an automated email from the git hooks/post-receive script. mira-guest pushed a commit to branch master in repository garmindev.
commit 46ec8642ed6c3bb0dc96241e7cb0f8baf8ccbfd8 Author: Jaromír Mikeš <mira.mi...@seznam.cz> Date: Sat Apr 25 17:27:51 2015 +0200 Imported Upstream version 0.3.4+svn3432 --- .kdev4/GarminDev.kdev4 | 14 -- CMakeLists.txt | 3 +- CMakeLists.txt.user | 164 ------------- GarminDev.kdev4 | 3 - src/CMakeLists.txt | 1 + src/CUSB.cpp | 184 ++++++--------- src/CUSB.h | 13 +- src/CUSB_MacOSX.cpp | 55 +---- src/CUSB_common.cpp | 152 ++++++++++++ src/EtrexLegend/CDevice.cpp | 12 +- src/EtrexLegendC/CDevice.cpp | 12 +- src/ForeRunner/CMakeLists.txt | 2 +- src/ForeRunner/loader.cpp | 16 ++ src/GPSMap60CSx/CDevice.cpp | 10 +- src/GPSMap60CSx/CMakeLists.txt | 1 + src/GPSMap60CSx/loader.cpp | 19 ++ src/GPSMap76/CDevice.cpp | 12 +- src/{ForeRunner => Oregon}/CMakeLists.txt | 15 +- src/Oregon/Oregon.cpp | 264 +++++++++++++++++++++ src/Oregon/Oregon.h | 78 +++++++ src/Oregon/Oregon.txt | 122 ++++++++++ src/{ForeRunner => Oregon}/loader.cpp | 35 ++- src/Platform.h | 370 ++++++++++++++++++++---------- 23 files changed, 1053 insertions(+), 504 deletions(-) diff --git a/.kdev4/GarminDev.kdev4 b/.kdev4/GarminDev.kdev4 deleted file mode 100644 index 48e2c4c..0000000 --- a/.kdev4/GarminDev.kdev4 +++ /dev/null @@ -1,14 +0,0 @@ -[Buildset] -BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x00) - -[CMake] -BuildDirs=/home/oeichler/data/cpp/build_GarminDev/ -CMakeDir=/usr/share/cmake/Modules -Current CMake Binary=file:///usr/bin/cmake -CurrentBuildDir=file:///home/oeichler/data/cpp/build_GarminDev/ -CurrentBuildType= -CurrentInstallDir= -ProjectRootRelative=./ - -[Project] -VersionControlSupport=kdevsubversion diff --git a/CMakeLists.txt b/CMakeLists.txt index 51b72e7..e702018 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ set(VER_MINOR 18) #this one is for the release version set(PACKAGE_VER_MAJOR 0) set(PACKAGE_VER_MINOR 3) -set(PACKAGE_VER_PATCH 4) +set(PACKAGE_VER_PATCH 5) add_definitions(-DVER_MAJOR=${VER_MAJOR} -DVER_MINOR=${VER_MINOR}) @@ -68,6 +68,7 @@ add_subdirectory(./src/EtrexLegend) add_subdirectory(./src/EtrexH) add_subdirectory(./src/whatGarmin) add_subdirectory(./src/ForeRunner) +add_subdirectory(./src/Oregon) install( DIRECTORY diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user deleted file mode 100644 index 6dc6ee3..0000000 --- a/CMakeLists.txt.user +++ /dev/null @@ -1,164 +0,0 @@ -<!DOCTYPE QtCreatorProject> -<qtcreator> - <data> - <variable>activeRunConfiguration</variable> - <value type="int">0</value> - </data> - <data> - <variable>activebuildconfiguration</variable> - <value type="QString">all</value> - </data> - <data> - <variable>buildConfiguration-all</variable> - <valuemap type="QVariantMap"> - <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString">all</value> - <value key="buildDirectory" type="QString">/home/oeichler/data/cpp/build_GarminDev</value> - <value key="msvcVersion" type="QString"></value> - </valuemap> - </data> - <data> - <variable>buildconfiguration-all-buildstep0</variable> - <valuemap type="QVariantMap"> - <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString">all</value> - <valuelist key="abstractProcess.Environment" type="QVariantList"> - <value type="QString">COLORTERM=1</value> - <value type="QString">CPU=x86_64</value> - <value type="QString">CSHEDIT=emacs</value> - <value type="QString">CVS_RSH=ssh</value> - <value type="QString">DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-MWaTkAosos,guid=81e4d1222652271161bd5b894befa52c</value> - <value type="QString">DESKTOP_SESSION=default</value> - <value type="QString">DISPLAY=:0</value> - <value type="QString">DM_CONTROL=/var/run/xdmctl</value> - <value type="QString">ENV=/etc/bash.bashrc</value> - <value type="QString">FROM_HEADER=</value> - <value type="QString">GPG_AGENT_INFO=/tmp/gpg-6GvjOy/S.gpg-agent:2023:1</value> - <value type="QString">GS_LIB=/home/oeichler/.fonts</value> - <value type="QString">GTK2_RC_FILES=/etc/gtk-2.0/gtkrc:/usr/share/themes//QtCurve/gtk-2.0/gtkrc:/home/oeichler/.gtkrc-2.0-qtengine:/home/oeichler/.gtkrc-2.0:/home/oeichler/.kde4/share/config/gtkrc-2.0</value> - <value type="QString">GTK_IM_MODULE=cedilla</value> - <value type="QString">GTK_RC_FILES=/etc/gtk/gtkrc:/home/oeichler/.gtkrc::/home/oeichler/.kde4/share/config/gtkrc</value> - <value type="QString">G_BROKEN_FILENAMES=1</value> - <value type="QString">G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-15,CP1252</value> - <value type="QString">HISTSIZE=1000</value> - <value type="QString">HOME=/home/oeichler</value> - <value type="QString">HOST=linux-1jnh</value> - <value type="QString">HOSTNAME=linux-1jnh</value> - <value type="QString">HOSTTYPE=x86_64</value> - <value type="QString">INPUTRC=/home/oeichler/.inputrc</value> - <value type="QString">JAVA_BINDIR=/usr/lib64/jvm/java/bin</value> - <value type="QString">JAVA_HOME=/usr/lib64/jvm/java</value> - <value type="QString">JAVA_ROOT=/usr/lib64/jvm/java</value> - <value type="QString">JDK_HOME=/usr/lib64/jvm/java</value> - <value type="QString">JRE_HOME=/usr//jvm/jre</value> - <value type="QString">KDE_FULL_SESSION=true</value> - <value type="QString">KDE_MULTIHEAD=false</value> - <value type="QString">KDE_SESSION_UID=1000</value> - <value type="QString">KDE_SESSION_VERSION=4</value> - <value type="QString">LANG=de_DE.UTF-8</value> - <value type="QString">LANGUAGE=</value> - <value type="QString">LD_LIBRARY_PATH=/opt/qtcreator-1.3.1/lib/qtcreator:/usr/lib64/mpi/gcc/openmpi/lib64</value> - <value type="QString">LESS=-M -I</value> - <value type="QString">LESSCLOSE=lessclose.sh %s %s</value> - <value type="QString">LESSKEY=/etc/lesskey.bin</value> - <value type="QString">LESSOPEN=lessopen.sh %s</value> - <value type="QString">LESS_ADVANCED_PREPROCESSOR=no</value> - <value type="QString">LOGNAME=oeichler</value> - <value type="QString">LS_COLORS=no=00:fi=00:di=01;34:ln=00;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=41;33;01:ex=00;32:*.cmd=00;32:*.exe=01;32:*.com=01;32:*.bat=01;32:*.btm=01;32:*.dll=01;32:*.tar=00;31:*.tbz=00;31:*.tgz=00;31:*.rpm=00;31:*.deb=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.lzma=00;31:*.zip=00;31:*.zoo=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.tb2=00;31:*.tz2=00;31:*.tbz2=00;31:*.xz=00;31:*.avi=01;35:*.bmp=01;35:*.fli=01;35:*.gif=01;35:*.jpg=01;3 [...] - <value type="QString">LS_OPTIONS=-N --color=tty -T 0</value> - <value type="QString">MACHTYPE=x86_64-suse-linux</value> - <value type="QString">MAIL=/var/spool/mail/oeichler</value> - <value type="QString">MANPATH=/usr/lib64/mpi/gcc/openmpi/share/man:/usr/local/man:/usr/local/share/man:/usr/share/man:/usr/man</value> - <value type="QString">MINICOM=-c on</value> - <value type="QString">MORE=-sl</value> - <value type="QString">NNTPSERVER=news</value> - <value type="QString">OSTYPE=linux</value> - <value type="QString">PAGER=less</value> - <value type="QString">PATH=/opt/qtcreator-1.3.1/bin/:/usr/lib64/mpi/gcc/openmpi/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/X11R6/bin:/usr/games:/opt/kde3/bin:/usr/lib/mit/bin:/usr/lib/mit/sbin:/usr/lib/qt3/bin</value> - <value type="QString">PROFILEREAD=true</value> - <value type="QString">PWD=/home/oeichler</value> - <value type="QString">PYTHONSTARTUP=/etc/pythonstart</value> - <value type="QString">QTDIR=/usr/lib/qt3</value> - <value type="QString">QT_IM_MODULE=xim</value> - <value type="QString">QT_IM_SWITCHER=imsw-multi</value> - <value type="QString">QT_PLUGIN_PATH=/home/oeichler/.kde4/lib64/kde4/plugins/:/usr/lib64/kde4/plugins/</value> - <value type="QString">QT_SYSTEM_DIR=/usr/share/desktop-data</value> - <value type="QString">SDK_HOME=/usr/lib64/jvm/java</value> - <value type="QString">SESSION_MANAGER=local/linux-1jnh:@/tmp/.ICE-unix/2737,unix/linux-1jnh:/tmp/.ICE-unix/2737</value> - <value type="QString">SHELL=/bin/bash</value> - <value type="QString">SHLVL=1</value> - <value type="QString">SSH_AGENT_PID=2024</value> - <value type="QString">SSH_ASKPASS=/usr/lib64/ssh/x11-ssh-askpass</value> - <value type="QString">SSH_AUTH_SOCK=/tmp/ssh-prWUj1940/agent.1940</value> - <value type="QString">TERM=xterm</value> - <value type="QString">TMPDIR=/tmp</value> - <value type="QString">USER=oeichler</value> - <value type="QString">USE_FAM=</value> - <value type="QString">WINDOWMANAGER=/usr/bin/startkde</value> - <value type="QString">WINDOWPATH=7</value> - <value type="QString">XAUTHLOCALHOSTNAME=linux-1jnh</value> - <value type="QString">XCURSOR_THEME=Oxygen_Blue</value> - <value type="QString">XDG_CONFIG_DIRS=/etc/xdg</value> - <value type="QString">XDG_DATA_DIRS=/usr/local/share:/usr/share:/etc/opt/kde3/share:/opt/kde3/share</value> - <value type="QString">XDG_SESSION_COOKIE=00ae16e1b7de5857b484b7014aef75cb-1273996585.770895-1731118709</value> - <value type="QString">XDM_MANAGED=method=classic,auto</value> - <value type="QString">XKEYSYMDB=/usr/share/X11/XKeysymDB</value> - <value type="QString">XMODIFIERS=@im=local</value> - <value type="QString">XNLSPATH=/usr/share/X11/nls</value> - <value type="QString">XSESSION_IS_UP=yes</value> - </valuelist> - <value key="abstractProcess.IgnoreReturnValue" type="bool">false</value> - <valuelist key="abstractProcess.arguments" type="QVariantList"/> - <value key="abstractProcess.command" type="QString">make</value> - <value key="abstractProcess.enabled" type="bool">true</value> - <value key="abstractProcess.workingDirectory" type="QString">/home/oeichler/data/cpp/build_GarminDev</value> - </valuemap> - </data> - <data> - <variable>buildconfiguration-all-cleanstep0</variable> - <valuemap type="QVariantMap"> - <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString">all</value> - <valuelist key="additionalArguments" type="QVariantList"> - <value type="QString">clean</value> - </valuelist> - <value key="cleanConfig" type="bool">true</value> - </valuemap> - </data> - <data> - <variable>buildconfigurations</variable> - <valuelist type="QVariantList"> - <value type="QString">all</value> - </valuelist> - </data> - <data> - <variable>buildstep0</variable> - <valuemap type="QVariantMap"> - <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString"></value> - </valuemap> - </data> - <data> - <variable>buildsteps</variable> - <valuelist type="QVariantList"> - <value type="QString">CMakeProjectManager.MakeStep</value> - </valuelist> - </data> - <data> - <variable>cleanstep0</variable> - <valuemap type="QVariantMap"> - <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString"></value> - <value key="clean" type="bool">true</value> - </valuemap> - </data> - <data> - <variable>cleansteps</variable> - <valuelist type="QVariantList"> - <value type="QString">CMakeProjectManager.MakeStep</value> - </valuelist> - </data> - <data> - <variable>defaultFileEncoding</variable> - <value type="QByteArray">UTF-8</value> - </data> - <data> - <variable>project</variable> - <valuemap type="QVariantMap"/> - </data> -</qtcreator> diff --git a/GarminDev.kdev4 b/GarminDev.kdev4 deleted file mode 100644 index deeaa43..0000000 --- a/GarminDev.kdev4 +++ /dev/null @@ -1,3 +0,0 @@ -[Project] -Manager=KDevCMakeManager -Name=GarminDev diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index def25f4..958320f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,7 @@ set(SRCS Garmin.cpp IDeviceDefault.cpp ILink.cpp + CUSB_common.cpp ) set(HDRS diff --git a/src/CUSB.cpp b/src/CUSB.cpp index ea04881..56c5420 100644 --- a/src/CUSB.cpp +++ b/src/CUSB.cpp @@ -44,9 +44,7 @@ using namespace std; #define USB_INTERRUPT_TIMEOUT 3000 #define USB_BULK_TIMEOUT 30000 -#undef DBG - -#define DBG_LINE_SIZE 16 +#define DBG CUSB::CUSB() : busses(0) @@ -123,55 +121,31 @@ void CUSB::close2() } -void CUSB::debug(const char * mark, const Packet_t& data) +int CUSB::_bulk_read(Packet_t& data) { -#ifndef DBG - return; -#endif - unsigned i; - uint32_t size; - unsigned bytes = DBG_LINE_SIZE; - char buf[DBG_LINE_SIZE + 1]; - memset(buf,0x20,sizeof(buf));buf[DBG_LINE_SIZE] = 0; - - cout << mark << endl << " "; + int res; - const uint8_t * pData = (const uint8_t*)&data; + res = ::usb_bulk_read(udev,epBulkIn,(char*)&data,sizeof(data),USB_BULK_TIMEOUT); - size = gar_endian(uint32_t, data.size); - if(size > GUSB_MAX_BUFFER_SIZE) { - cerr << "WARNING! Data size " << data.size << " exceeds buffer size." << endl; - cerr << "Truncate to " << GUSB_MAX_BUFFER_SIZE << "." << endl; - size = GUSB_PAYLOAD_SIZE; + if (res > 0) { + debug("b >>", data); + return res; } - for(i = 0; i < (size + GUSB_HEADER_SIZE); ++i) { - if(i && !(i % DBG_LINE_SIZE)) { - cout << " " << buf << endl << " "; - memset(buf,0x20,sizeof(buf));buf[DBG_LINE_SIZE] = 0; - bytes = DBG_LINE_SIZE; - } - - cout.width(2); - cout.fill('0'); - cout << hex << (unsigned)pData[i] << " "; - - if(isprint(pData[i])) { - buf[i%DBG_LINE_SIZE] = pData[i]; - } - else { - buf[i%DBG_LINE_SIZE] = '.'; + if (res == 0) { + Packet_t cont; + res = ::usb_interrupt_read(udev,epIntrIn,(char*)&cont,sizeof(cont), 100); + if (res > 0) { + debug("i (cont) >>", cont); + if (gar_endian(uint16_t, cont.id) == GUSB_DATA_AVAILABLE) + return _bulk_read(data); } - - --bytes; - } - for(i=0; i < bytes; i++) cout << " "; - cout << " " << buf << dec << endl; + doBulkRead = false; + return res; } - int CUSB::read(Packet_t& data) { int res; @@ -181,30 +155,22 @@ int CUSB::read(Packet_t& data) data.size = 0; if(doBulkRead) { - res = ::usb_bulk_read(udev,epBulkIn,(char*)&data,sizeof(data),USB_BULK_TIMEOUT); - - if (res > 0) - debug("b >>", data); - -#if defined(HAVE_BIGENDIAN) - // endian fix for id and size - data.id = gar_endian(uint16_t, data.id); - data.size = gar_endian(uint32_t, data.size); -#endif // big endian platform - } - else { + res = _bulk_read(data); + } else { res = ::usb_interrupt_read(udev,epIntrIn,(char*)&data,sizeof(data),USB_INTERRUPT_TIMEOUT); - - if (res > 0) + if (res > 0) { debug("i >>", data); - -#if defined(HAVE_BIGENDIAN) - // endian fix for id and size - data.id = gar_endian(uint16_t, data.id); - data.size = gar_endian(uint32_t, data.size); -#endif // big endian platform + if(gar_endian(uint16_t, data.id) == GUSB_DATA_AVAILABLE) { + doBulkRead = true; + res = _bulk_read(data); + } + } } + // endian fix for id and size + data.id = gar_endian(uint16_t, data.id); + data.size = gar_endian(uint32_t, data.size); + // Some devices sending data on the interrupt pipe seem // to timeout occasionally. It seems to be save to ignore this // timeout. @@ -212,16 +178,6 @@ int CUSB::read(Packet_t& data) res = 0; } - // switch to bulk pipe - if((res > 0) && (data.id == GUSB_DATA_AVAILABLE)) { - doBulkRead = true; - } - - // switch to interrupt pipe on errors or zero size packages - if(res <= 0) { - doBulkRead = false; - } - if(res < 0) { stringstream msg; msg << "USB read failed:" << usb_strerror(); @@ -377,72 +333,61 @@ void CUSB::syncup(void) write(gpack_session_start); if((res = read(response)) > 0) break; } - if(res == 0) { - throw exce_t(errSync,"Failed to sync. up with device"); + if(res == 0 || response.id != GUSB_SESSION_STARTED) { + throw exce_t(errSync,"Failed to sync. up with device. Initial session could not be started."); } - if(response.id == GUSB_SESSION_STARTED) { - Packet_t command; - Packet_t response; - - command.type = GUSB_APPLICATION_LAYER; - command.id = Pid_Product_Rqst; - command.size = 0; - - write(command); - - protocolArraySize = 0; - while(read(response)) { - if(response.id == Pid_Product_Data) { - //TODO read data - Product_Data_t * pData = (Product_Data_t*)response.payload; - productId = gar_load(uint16_t, pData->product_id); - softwareVersion = gar_load(int16_t, pData->software_version); - productString = pData->str; + std::list<Packet_t> results; + std::list<Packet_t>::iterator ret; + if (0 >= run_product_request( results )) + throw exce_t(errSync,"Failed to sync. up with device. Product data request failed."); + + protocolArraySize = -1; + for (ret = results.begin(); ret != results.end(); ret++) { + if(ret->id == Pid_Product_Data) { + //TODO read data + Product_Data_t * pData = (Product_Data_t*)ret->payload; + productId = gar_load(uint16_t, pData->product_id); + softwareVersion = gar_load(int16_t, pData->software_version); + productString = pData->str; #ifdef DBG - cout << "Product: " << hex << productId << " " << dec << softwareVersion << " " << productString << endl; + cout << "Product: " << hex << productId << " " << dec << softwareVersion << " " << productString << endl; #endif - } + } - if(response.id == Pid_Ext_Product_Data) { - //TODO read data - } + if(ret->id == Pid_Ext_Product_Data) { + //TODO read data + } - if(response.id == Pid_Protocol_Array) { - // note: we cannot use a Protocol_Data_t here due to alignment issues - // on some platforms... - uint8_t * p = response.payload; - for(uint32_t i = 0; i < response.size; i += sizeof(Protocol_Data_t)) { - uint8_t pr_tag = *p++; - uint16_t pr_data = gar_ptr_load(uint16_t, p); - p += 2; + if(ret->id == Pid_Protocol_Array) { + // note: we cannot use a Protocol_Data_t here due to alignment issues + // on some platforms... + uint8_t * p = ret->payload; + for(uint32_t i = 0; i < ret->size; i += sizeof(Protocol_Data_t)) { + uint8_t pr_tag = *p++; + uint16_t pr_data = gar_ptr_load(uint16_t, p); + p += 2; #ifdef DBG - cout << "Protocol: "<< (char)pr_tag << dec << pr_data << endl; + cout << "Protocol: "<< (char)pr_tag << dec << pr_data << endl; #endif - ++protocolArraySize; - protocolArray[protocolArraySize].tag = pr_tag; - protocolArray[protocolArraySize].data = pr_data; - } ++protocolArraySize; + protocolArray[protocolArraySize].tag = pr_tag; + protocolArray[protocolArraySize].data = pr_data; + } #ifdef DBG - cout << "protocolArraySize:" << protocolArraySize << endl; + cout << "protocolArraySize:" << protocolArraySize << endl; #endif - // - if(!doBulkRead) return; - } + // + if(!doBulkRead) return; } - return; } - - throw exce_t(errSync,"Failed to sync. up with device"); } uint16_t CUSB::getDataType(int data_no, char tag, uint16_t protocol) { - if (protocolArraySize == 0) - { + if ( (protocolArraySize - 1 - data_no) < 0) { return 0; } @@ -452,6 +397,7 @@ uint16_t CUSB::getDataType(int data_no, char tag, uint16_t protocol) if (protocolArray[i].data == protocol) { // accept data_no=-1 as a protocol verification only if (data_no == -1) return (uint16_t) 1; + if (protocolArraySize < i + 1 + data_no) return 0; if ((char)protocolArray[i+1+data_no].tag == 'D') { return protocolArray[i+1+data_no].data; } diff --git a/src/CUSB.h b/src/CUSB.h index 43df5a3..a282d06 100644 --- a/src/CUSB.h +++ b/src/CUSB.h @@ -23,6 +23,7 @@ #define CUSB_H #include <string> +#include <list> #ifdef __APPLE__ # include <pthread.h> # include <IOKit/IOTypes.h> @@ -51,6 +52,8 @@ namespace Garmin if your device does not fit into the protocol implementation at all, subclass it and make your fixes. */ + typedef int (*CUSB_cb_t)(Packet_t& incoming, void* cb_ctx); + class CUSB : public ILink { public: @@ -72,6 +75,13 @@ namespace Garmin */ virtual void syncup(); + int run_transaction(uint8_t type, uint16_t id, uint8_t * payload, uint32_t p_size, + CUSB_cb_t data_cb, void* cb_ctx); + + int run_app_command(unsigned command, CUSB_cb_t data_cb, void* cb_ctx); + int run_app_command(unsigned command, std::list<Packet_t>& result); + int run_product_request(std::list<Packet_t>& result); + uint16_t getProductId(){return productId;} int16_t getSoftwareVersion(){return softwareVersion;} const std::string& getProductString(){return productString;} @@ -118,7 +128,7 @@ namespace Garmin uint16_t productId; int16_t softwareVersion; std::string productString; - uint32_t protocolArraySize; + int32_t protocolArraySize; Protocol_Data_t protocolArray[GUSB_PAYLOAD_SIZE]; #ifdef __APPLE__ @@ -138,6 +148,7 @@ namespace Garmin pthread_cond_t ir_cond; struct readIntrCmnd_t * readIntrCmnd; #endif + int _bulk_read(Packet_t&); }; } diff --git a/src/CUSB_MacOSX.cpp b/src/CUSB_MacOSX.cpp index 0443369..20ef48a 100644 --- a/src/CUSB_MacOSX.cpp +++ b/src/CUSB_MacOSX.cpp @@ -49,10 +49,7 @@ using namespace std; #define GUSB_SESSION_START 5 #define GUSB_SESSION_STARTED 6 -//#undef DBG -#define DBG - -#define DBG_LINE_SIZE 16 +#undef DBG namespace Garmin { @@ -285,56 +282,6 @@ void CUSB::close2() } -void CUSB::debug(const char * mark, const Packet_t& data) -{ -#ifndef DBG - return; -#endif - unsigned i; - uint32_t size; - unsigned bytes = DBG_LINE_SIZE; - char buf[DBG_LINE_SIZE + 1]; - - memset(buf, 0x20, sizeof(buf)); - buf[DBG_LINE_SIZE] = 0; - - cout << mark << endl << " "; - - const uint8_t * pData = (const uint8_t*) &data; - - size = gar_endian(uint32_t, data.size); - if (size > GUSB_MAX_BUFFER_SIZE) { - cerr << "WARNING! Data size " << data.size << " exceeds buffer size." << endl; - cerr << "Truncate to " << GUSB_MAX_BUFFER_SIZE << "." << endl; - size = GUSB_PAYLOAD_SIZE; - } - - for (i = 0; i < (size + GUSB_HEADER_SIZE); ++i) { - if (i && !(i % DBG_LINE_SIZE)) { - cout << " " << buf << endl << " "; - memset(buf, 0x20, sizeof(buf)); - buf[DBG_LINE_SIZE] = 0; - bytes = DBG_LINE_SIZE; - } - - cout.width(2); - cout.fill('0'); - cout << hex << (unsigned) pData[i] << " "; - - if (isprint(pData[i])) - buf[i % DBG_LINE_SIZE] = pData[i]; - else - buf[i % DBG_LINE_SIZE] = '.'; - - --bytes; - - } - for (i = 0; i < bytes; i++) cout << " "; - cout << " " << buf << dec << endl; - -} - - int CUSB::read(Packet_t& data) { IOReturn res; diff --git a/src/CUSB_common.cpp b/src/CUSB_common.cpp new file mode 100644 index 0000000..c7f26ff --- /dev/null +++ b/src/CUSB_common.cpp @@ -0,0 +1,152 @@ + +/********************************************************************************************** + Copyright (C) 2007 Oliver Eichler oliver.eich...@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 "CUSB.h" +#include "IDevice.h" +#include "Platform.h" + +#include <iostream> + +using namespace Garmin; +using namespace std; + + +static int _reduce(Packet_t& incoming, void * ctx); + +// This file contains common functions used by both the libusb and the Mac OS X (IOKit) USB code + +#define DBG_LINE_SIZE 16 + +#define DBG + +void CUSB::debug(const char * mark, const Packet_t& data) +{ +#ifndef DBG + return; +#endif + unsigned i; + uint32_t size; + unsigned bytes = DBG_LINE_SIZE; + char buf[DBG_LINE_SIZE + 1]; + + memset(buf, 0x20, sizeof(buf)); + buf[DBG_LINE_SIZE] = 0; + + cout << mark << endl << " "; + + const uint8_t * pData = (const uint8_t*) &data; + + size = gar_endian(uint32_t, data.size); + if (size > GUSB_MAX_BUFFER_SIZE) { + cerr << "WARNING! Data size " << data.size << " exceeds buffer size." << endl; + cerr << "Truncate to " << GUSB_MAX_BUFFER_SIZE << "." << endl; + size = GUSB_PAYLOAD_SIZE; + } + + for (i = 0; i < (size + GUSB_HEADER_SIZE); ++i) { + if (i && !(i % DBG_LINE_SIZE)) { + cout << " " << buf << endl << " "; + memset(buf, 0x20, sizeof(buf)); + buf[DBG_LINE_SIZE] = 0; + bytes = DBG_LINE_SIZE; + } + + cout.width(2); + cout.fill('0'); + cout << hex << (unsigned) pData[i] << " "; + + if (isprint(pData[i])) + buf[i % DBG_LINE_SIZE] = pData[i]; + else + buf[i % DBG_LINE_SIZE] = '.'; + + --bytes; + + } + for (i = 0; i < bytes; i++) cout << " "; + cout << " " << buf << dec << endl; + +} + + +int CUSB::run_transaction(uint8_t type, uint16_t id, uint8_t * payload, uint32_t p_size, + CUSB_cb_t data_cb, void* cb_ctx) { + + Packet_t req, resp; + int ret=0, ret2; + + if (p_size > GUSB_PAYLOAD_SIZE) + throw exce_t(errRuntime, "Trying to run a command with an illegal payload size."); + + req.type = type; + req.id = id; + req.size = p_size; + memcpy(req.payload, payload, p_size); + + write(req); + + while (0 < (ret2 = read(resp)) ) { + ret += ret2; + if (data_cb) { + ret2 = data_cb(resp, cb_ctx); + if( 0 > ret2) ret = ret2; + if (1 > ret2) break; + } + } + + return ret; +} + +int CUSB::run_app_command(unsigned command, CUSB_cb_t data_cb, void* cb_ctx) +{ + uint16_t cmd = gar_endian(uint16_t, command); + + return run_transaction(GUSB_APPLICATION_LAYER, Pid_Command_Data, + (uint8_t *)&cmd, sizeof(cmd), data_cb, cb_ctx); +} + + +int CUSB::run_app_command(unsigned command, std::list<Packet_t>& result) +{ + uint16_t cmd = gar_endian(uint16_t, command); + result.clear(); + + return run_transaction(GUSB_APPLICATION_LAYER, Pid_Command_Data, + (uint8_t *)&cmd, sizeof(cmd), _reduce, &result); +} + +int CUSB::run_product_request(std::list<Packet_t>& result) +{ + result.clear(); + return run_transaction(GUSB_APPLICATION_LAYER, Pid_Product_Rqst, + 0, 0, _reduce, &result); +} + + +static int _reduce(Packet_t& incoming, void * ctx) +{ + std::list<Packet_t>* cumulated = reinterpret_cast<std::list<Packet_t>*>(ctx); + cumulated->push_back(Packet_t()); + Packet_t& n = cumulated->back(); + memcpy(&n, &incoming, sizeof (n)); + return sizeof(incoming); +} diff --git a/src/EtrexLegend/CDevice.cpp b/src/EtrexLegend/CDevice.cpp index 1a552ac..15fc615 100644 --- a/src/EtrexLegend/CDevice.cpp +++ b/src/EtrexLegend/CDevice.cpp @@ -127,7 +127,7 @@ void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * ke 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"; + msg << "Failed to send map: Unit has not enough memory (available/needed): " << memory << "/" << size << " bytes"; throw exce_t(errBlocked,msg.str()); } } @@ -238,7 +238,7 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) 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"; + msg << "Failed to send map: Unit has not enough memory (available/needed): " << memory << "/" << size << " bytes"; throw exce_t(errRuntime,msg.str()); } } @@ -295,6 +295,7 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) uint32_t total = size; uint32_t offset = 0, chunkSize; uint8_t buffer[GUSB_PAYLOAD_SIZE - sizeof(offset)]; + size_t chunks_read; command.id = 36; // USB: transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes @@ -303,7 +304,12 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) chunkSize = (size < (254 - sizeof(offset))) ? size : (254 - sizeof(offset)); command.size = chunkSize + sizeof(offset); - fread(buffer, chunkSize, 1, fid); + chunks_read = fread(buffer, chunkSize, 1, fid); + if (chunks_read != 1) { + stringstream msg; + msg << "Failed to read chunk from map " << filename; + throw exce_t(errRuntime,msg.str()); + } *(uint32_t*)command.payload = offset; memcpy(command.payload + sizeof(offset),buffer,chunkSize); diff --git a/src/EtrexLegendC/CDevice.cpp b/src/EtrexLegendC/CDevice.cpp index 0477593..f747896 100644 --- a/src/EtrexLegendC/CDevice.cpp +++ b/src/EtrexLegendC/CDevice.cpp @@ -249,7 +249,7 @@ void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * ke 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"; + msg << "Failed to send map: Unit has not enough memory (available/needed): " << memory << "/" << size << " bytes"; throw exce_t(errRuntime,msg.str()); } } @@ -346,7 +346,7 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) 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"; + msg << "Failed to send map: Unit has not enough memory (available/needed): " << memory << "/" << size << " bytes"; throw exce_t(errRuntime,msg.str()); } } @@ -394,6 +394,7 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) uint32_t total = size; uint32_t offset = 0, chunkSize; uint8_t buffer[GUSB_PAYLOAD_SIZE - sizeof(offset)]; + size_t chunks_read; command.type = GUSB_APPLICATION_LAYER; command.id = 36; @@ -402,7 +403,12 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) chunkSize = (size < (GUSB_PAYLOAD_SIZE - sizeof(offset))) ? size : (GUSB_PAYLOAD_SIZE - sizeof(offset)); command.size = chunkSize + sizeof(offset); - fread(buffer, chunkSize, 1, fid); + chunks_read = fread(buffer, chunkSize, 1, fid); + if (chunks_read != 1) { + stringstream msg; + msg << "Failed to read chunk from map " << filename; + throw exce_t(errRuntime,msg.str()); + } *(uint32_t*)command.payload = offset; memcpy(command.payload + sizeof(offset),buffer,chunkSize); diff --git a/src/ForeRunner/CMakeLists.txt b/src/ForeRunner/CMakeLists.txt index 140e4a9..43f4cf5 100644 --- a/src/ForeRunner/CMakeLists.txt +++ b/src/ForeRunner/CMakeLists.txt @@ -15,7 +15,7 @@ add_library(Forerunner305 SHARED ${SRCS} ${HDRS}) target_link_libraries(Forerunner305 garmin ${LIBUSB_LIBRARIES} pthread) set(ALIASES - + Forerunner205 ) foreach(var ${ALIASES}) diff --git a/src/ForeRunner/loader.cpp b/src/ForeRunner/loader.cpp index 256efec..08e3f24 100644 --- a/src/ForeRunner/loader.cpp +++ b/src/ForeRunner/loader.cpp @@ -47,3 +47,19 @@ extern "C" WIN_EXPORT Garmin::IDevice * initForerunner305(const char * version) // FR305::device->screenheight = 240; return FR305::device; } + + + +extern "C" WIN_EXPORT Garmin::IDevice * initForerunner205(const char * version) +{ + if(strncmp(version,INTERFACE_VERSION,5) != 0) { + return 0; + } + if(FR305::device == 0) { + FR305::device = new FR305::CDevice(); + } + FR305::device->devname = "Forerunner205"; + // FR305::device->screenwidth = 160; + // FR305::device->screenheight = 240; + return FR305::device; +} diff --git a/src/GPSMap60CSx/CDevice.cpp b/src/GPSMap60CSx/CDevice.cpp index 7dee617..96a0a45 100644 --- a/src/GPSMap60CSx/CDevice.cpp +++ b/src/GPSMap60CSx/CDevice.cpp @@ -33,7 +33,7 @@ using namespace GPSMap60CSx; using namespace Garmin; using namespace std; -#if defined(HAVE_BIGENDIAN) || !defined(CAN_UNALIGNED) +#if !defined(CAN_UNALIGNED) # define DBG_SHOW_WAYPOINT # define UNTESTED throw exce_t(errSync, "This function has not yet been tested on your platform.") #else @@ -397,6 +397,7 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) uint32_t total = size; uint32_t offset = 0, chunkSize; uint8_t buffer[GUSB_PAYLOAD_SIZE - sizeof(offset)]; + size_t chunks_read; command.type = GUSB_APPLICATION_LAYER; command.id = 36; @@ -405,7 +406,12 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) chunkSize = (size < (GUSB_PAYLOAD_SIZE - sizeof(offset))) ? size : (GUSB_PAYLOAD_SIZE - sizeof(offset)); command.size = chunkSize + sizeof(offset); - fread(buffer, chunkSize, 1, fid); + chunks_read = fread(buffer, chunkSize, 1, fid); + if (chunks_read != 1) { + stringstream msg; + msg << "Failed to read chunk from map " << filename; + throw exce_t(errRuntime,msg.str()); + } *(uint32_t*)command.payload = gar_endian(uint32_t, offset); memcpy(command.payload + sizeof(offset),buffer,chunkSize); diff --git a/src/GPSMap60CSx/CMakeLists.txt b/src/GPSMap60CSx/CMakeLists.txt index d8a512b..5c5d3b6 100644 --- a/src/GPSMap60CSx/CMakeLists.txt +++ b/src/GPSMap60CSx/CMakeLists.txt @@ -25,6 +25,7 @@ set(ALIASES EtrexVistaHCx EtrexLegendHCx EtrexLegendCx + EtrexLegendH GPSMap76Cx Quest ) diff --git a/src/GPSMap60CSx/loader.cpp b/src/GPSMap60CSx/loader.cpp index 88b6411..d49dd1d 100644 --- a/src/GPSMap60CSx/loader.cpp +++ b/src/GPSMap60CSx/loader.cpp @@ -62,6 +62,8 @@ extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap76CSx(const char * version) GPSMap60CSx::device->devid = 0x0124; GPSMap60CSx::device->screenwidth = 160; GPSMap60CSx::device->screenheight = 240; + GPSMap60CSx::device->screenhflip = false; + GPSMap60CSx::device->screenvflip = true; return GPSMap60CSx::device; } @@ -233,6 +235,7 @@ extern "C" WIN_EXPORT Garmin::IDevice * initEtrexSummitHC(const char * version) // GPSMap60CSx::device->devid = 0x0694; GPSMap60CSx::device->screenwidth = 176; GPSMap60CSx::device->screenheight = 220; + GPSMap60CSx::device->screenhflip = true; return GPSMap60CSx::device; } @@ -253,3 +256,19 @@ extern "C" WIN_EXPORT Garmin::IDevice * initEtrexLegendCx(const char * version) GPSMap60CSx::device->screenhflip = true; return GPSMap60CSx::device; } + +extern "C" WIN_EXPORT Garmin::IDevice * initEtrexLegendH(const char * version) +{ + if(strncmp(version,INTERFACE_VERSION,5) != 0) { + return 0; + } + if(GPSMap60CSx::device == 0) { + GPSMap60CSx::device = new GPSMap60CSx::CDevice(); + } + GPSMap60CSx::device->devname = "eTrex Legend H"; + GPSMap60CSx::device->devid = 957; + GPSMap60CSx::device->screenwidth = 160; + GPSMap60CSx::device->screenheight = 288; +// GPSMap60CSx::device->screenhflip = true; + return GPSMap60CSx::device; +} diff --git a/src/GPSMap76/CDevice.cpp b/src/GPSMap76/CDevice.cpp index 5479898..7186081 100644 --- a/src/GPSMap76/CDevice.cpp +++ b/src/GPSMap76/CDevice.cpp @@ -133,7 +133,7 @@ void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * /* 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"; + msg << "Failed to send map: Unit has not enough memory (available/needed): " << memory << "/" << size << " bytes"; throw exce_t(errBlocked,msg.str()); } } @@ -240,7 +240,7 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) 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"; + msg << "Failed to send map: Unit has not enough memory (available/needed): " << memory << "/" << size << " bytes"; throw exce_t(errRuntime,msg.str()); } } @@ -297,6 +297,7 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) uint32_t total = size; uint32_t offset = 0, chunkSize; uint8_t buffer[GUSB_PAYLOAD_SIZE - sizeof(offset)]; + size_t chunks_read; command.id = 36; // USB: transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes @@ -305,7 +306,12 @@ void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key) chunkSize = (size < (254 - sizeof(offset))) ? size : (254 - sizeof(offset)); command.size = chunkSize + sizeof(offset); - fread(buffer, chunkSize, 1, fid); + chunks_read = fread(buffer, chunkSize, 1, fid); + if (chunks_read != 1) { + stringstream msg; + msg << "Failed to read chunk from map " << filename; + throw exce_t(errRuntime,msg.str()); + } *(uint32_t*)command.payload = offset; memcpy(command.payload + sizeof(offset),buffer,chunkSize); diff --git a/src/ForeRunner/CMakeLists.txt b/src/Oregon/CMakeLists.txt similarity index 51% copy from src/ForeRunner/CMakeLists.txt copy to src/Oregon/CMakeLists.txt index 140e4a9..c515f99 100644 --- a/src/ForeRunner/CMakeLists.txt +++ b/src/Oregon/CMakeLists.txt @@ -3,26 +3,27 @@ set(CMAKE_VERBOSE_MAKEFILE ON) set(SRCS loader.cpp - CDevice.cpp + Oregon.cpp ) set(HDRS - CDevice.h + Oregon.h ) include_directories(../ ${LIBUSB_INCLUDE_DIRS}) -add_library(Forerunner305 SHARED ${SRCS} ${HDRS}) -target_link_libraries(Forerunner305 garmin ${LIBUSB_LIBRARIES} pthread) +add_library(Oregon SHARED ${SRCS} ${LIBUSB_LIBRARIES} ${HDRS}) +target_link_libraries(Oregon garmin pthread) set(ALIASES - + Oregon450 ) + foreach(var ${ALIASES}) message(" ${var}") - add_custom_command( TARGET Forerunner305 + add_custom_command( TARGET Oregon POST_BUILD - COMMAND ln ARGS -sf libForerunner305${SHARED_LIB_EXT} lib${var}${SHARED_LIB_EXT} + COMMAND ln ARGS -sf libOregon${SHARED_LIB_EXT} lib${var}${SHARED_LIB_EXT} WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} ) endforeach(var) diff --git a/src/Oregon/Oregon.cpp b/src/Oregon/Oregon.cpp new file mode 100644 index 0000000..35869d6 --- /dev/null +++ b/src/Oregon/Oregon.cpp @@ -0,0 +1,264 @@ +/********************************************************************************************** + Copyright (C) 2010 Thilo Fromm <kont...@thilo-fromm.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 "config.h" +#include "Oregon.h" +#include "CUSB.h" + +#include <iostream> + +#include <stdio.h> +#include <unistd.h> +#include <signal.h> + +#ifdef WIN32 +#include <windows.h> +#endif + +#include <unistd.h> + +#define GUSB_DATA_AVAILABLE 2 +#define GUSB_SESSION_START 5 +#define GUSB_SESSION_STARTED 6 + +#define USB_INTERRUPT_TIMEOUT 3000 +#define USB_BULK_TIMEOUT 30000 + +using namespace Garmin; +using namespace std; + +namespace Garmin { + + Oregon::Oregon() : usb(0), devid(0), _rt_pvt_thread_handle(0) + { + pthread_mutex_init(&mutex, NULL); + pthread_mutex_init(&_rt_pvt_thread_mutex, NULL); + memset(&_rt_pvt_data, 0x00, sizeof(_rt_pvt_data)); + } + + Oregon::~Oregon() + { + + } + + + /* public API implementation see IDeviceDefault.cpp. */ + + + +/* ------------------------------- + * private methods + * --------------- + */ + + void Oregon::_acquire() + { + usb = new Garmin::CUSB(); + usb->open(); + usb->syncup(); + + if(strncmp(usb->getProductString().c_str(), devname.c_str(), devname.size()) != 0) { + string msg = "No " + devname + " unit detected; found \"" + + usb->getProductString().c_str() + "\" instead. Please retry to select other device driver."; + throw exce_t(errSync,msg); + } + } + /* -- */ + + void Oregon::_release() + { + if (!usb) + return; + usb->close2(); + delete usb; + usb = 0; + } + /* -- */ + + void Oregon::_parse_tracks(std::list<Garmin::Track_t>& tracks, std::list<Packet_t> & raw) { + std::list<Packet_t>::iterator i; + unsigned total = 0, num_tracks = 0; + Garmin::Track_t * curr; + + for (i = raw.begin(); i != raw.end(); i++) { + if(i->id == Pid_Records) + total = gar_ptr_load(uint16_t, i->payload); + + if(i->id == Pid_Trk_Hdr) { + D312_Trk_Hdr_t * hdr = (D312_Trk_Hdr_t*)i->payload; + tracks.push_back(Track_t()); + curr = &tracks.back(); + *curr << *hdr; + } + + if(i->id == Pid_Trk_Data) { + D302_Trk_t * data = (D302_Trk_t*)i->payload; + if(data->new_trk) { + tracks.push_back(Track_t()); + Track_t& new_track = tracks.back(); + new_track.color = curr->color; + new_track.dspl = curr->dspl; + char str[256]; + snprintf(str, sizeof(str), "%s_%d", curr->ident.c_str(), num_tracks++); + new_track.ident = str; + } + + TrkPt_t pt; + pt << *data; + curr->track.push_back(pt); + + if (total && (num_tracks % 50 == 0)) { + double progress = (num_tracks * 100.0) / total; + callback(progress,0, 0,0,"Transferring tracks."); + } + } + + if(i->id == Pid_Xfer_Cmplt) + break; + } + + return; + } + /* -- */ + + void Oregon::_downloadTracks(std::list<Garmin::Track_t>& tracks) + { + + if(usb == 0) return; + + std::list<Packet_t> ret; + int cancel = 0; // FIXME: Caancel currently does nothing. + tracks.clear(); + + callback(0,0, &cancel, 0,"Transferring tracks."); + + if (0 > usb->run_app_command(Cmnd_Transfer_Trk, ret) ) + throw exce_t(errRead, "Error downloading track data."); + + _parse_tracks(tracks, ret); + + callback(100,0, &cancel,0,"done"); + } + /* -- */ + + + void * _rt_pvt_thread(void * ctx) + { + Oregon * dev = (Oregon*) ctx; + try { + CMutexLocker lock(dev->mutex); + + dev->_acquire(); + + if (0 > dev->usb->run_app_command(Cmnd_Start_Pvt_Data, 0, 0) ) + throw exce_t(errRuntime, "START PVT DATA command to device failed."); + + while (dev->_rt_pvt_thread_handle == pthread_self()) { + Packet_t pvt; + if( (0 < dev->usb->read(pvt)) && (pvt.id == Pid_Pvt_Data) ) { + dev->_rt_pvt_data << *(D800_Pvt_Data_t*) pvt.payload; + cout << "PVT data received." << endl; + } + } + + if (0 > dev->usb->run_app_command(Cmnd_Stop_Pvt_Data, 0, 0) ) + throw exce_t(errRuntime, "STOP PVT DATA command to device failed."); + dev->_release(); + } catch(exce_t& e) { + dev->lasterror = "Realtime thread failed. " + e.msg; + } + dev->_rt_pvt_thread_handle = 0; + } + /* -- */ + + void Oregon::_setRealTimeMode(bool mode) + { + CMutexLocker lock2(_rt_pvt_thread_mutex); + if (_rt_pvt_thread_handle && !mode) + _rt_pvt_thread_handle = 0; + else if (!_rt_pvt_thread_handle && mode) { + CMutexLocker lock(mutex); + _acquire(); // check for device presence. The public IF doesn't do this. + _release(); + pthread_create(&_rt_pvt_thread_handle, NULL, _rt_pvt_thread, this); + } + } + /* -- */ + + void Oregon::_getRealTimePos(Garmin::Pvt_t& pvt) + { + if (ESRCH == pthread_kill(_rt_pvt_thread_handle, 0)) { + /* thread already dead */ + throw exce_t(errRuntime,lasterror); + } + + pvt = _rt_pvt_data; + } + /* -- */ + + + void Oregon::_getDevProperties(Garmin::DevProperties_t& dev_properties) + { + // mark all properties as not having been set to meaningful values + properties.set.all = (uint32_t) 0; + + if(usb == 0) return; + Packet_t command; + Packet_t response; + + // ask for SD Ram capacity + command.type = GUSB_APPLICATION_LAYER; + command.id = Pid_Command_Data; + command.size = 2; + *(uint16_t*)command.payload = gar_endian(uint16_t, Cmnd_Transfer_Mem); + usb->write(command); + + // try to read SD Ram capacity + uint32_t memory = 0; + uint16_t tile_limit = 0; + while(usb->read(response)) { + if(response.id == Pid_Capacity_Data) { + tile_limit = gar_ptr_load(uint16_t, response.payload + 2); + memory = gar_ptr_load(uint32_t, response.payload + 4); + } + } + if(tile_limit == 0) { + throw exce_t(errRuntime,"Failed to send map: Unable to find the tile limit of the GPS"); + } + if(memory == 0) { + throw exce_t(errRuntime,"Failed to send map: Unable to find the available memory of the GPS"); + } + + // add to the properties list + properties.memory_limit = memory; + properties.set.item.memory_limit = 1; + properties.maps_limit = tile_limit; + properties.set.item.maps_limit = 1; + + // return the properties + dev_properties = properties; + + } +} + diff --git a/src/Oregon/Oregon.h b/src/Oregon/Oregon.h new file mode 100644 index 0000000..1946a72 --- /dev/null +++ b/src/Oregon/Oregon.h @@ -0,0 +1,78 @@ +/********************************************************************************************** + Copyright (C) 2010 Thilo Fromm <kont...@thilo-fromm.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. + +**********************************************************************************************/ +#ifndef OREGON_H +#define OREGON_H +#include <pthread.h> +#include <errno.h> + +#include "IDeviceDefault.h" +#include "CUSB.h" + + +#define OREGON_450_DEVID 896 + +namespace Garmin +{ + class Oregon : public IDeviceDefault + { + public: + Oregon(); + virtual ~Oregon(); + + std::string devname; + uint32_t devid; + + /* public API spec see IDeviceDefault.cpp. */ + + protected: + Garmin::CUSB* usb; + + void _acquire(); + void _usb_syncup(); + void _parse_tracks(std::list<Garmin::Track_t>& tracks, std::list<Packet_t> & raw); + + friend void * _rt_pvt_thread(void * ctx); + Pvt_t _rt_pvt_data; + pthread_t _rt_pvt_thread_handle; + pthread_mutex_t _rt_pvt_thread_mutex; + + void _downloadTracks(std::list<Garmin::Track_t>& tracks); + void _setRealTimeMode(bool on); + void _getRealTimePos(Garmin::Pvt_t& pvt); + void _getDevProperties(Garmin::DevProperties_t& dev_properties); + + void _release(); + + + /// the copyright information + std::string copyright; + /// error message of last error + std::string lasterror; + /// serial port string + std::string port; + + /// device properties + Garmin::DevProperties_t properties; + + }; +} +#endif //OREGON_H diff --git a/src/Oregon/Oregon.txt b/src/Oregon/Oregon.txt new file mode 100644 index 0000000..4a1e401 --- /dev/null +++ b/src/Oregon/Oregon.txt @@ -0,0 +1,122 @@ + + +qLandkarte plugin for Garmin Oregon (tested on model 450) +========================================================= + + Thilo Fromm, July 2010 + <kont...@thilo-fromm.de> + +---------------------- + TOC + 1. Status + 2. Problems + 3. Plans + + Appendix: Oregon 450 "whatGarmin" scan protocol dump +---------------------- + + +1. Status +######### + + Some of the (basic) protocols the Oregon supports are documented by Garmin; see + <http://www8.garmin.com/support/pdf/iop_spec.pdf>. As far as things are documented + they will get implemented. Major things, like map upload, or waypoint or + route exchange are not documented. + + Here is what's implemented and working (which isn't much): + ---------------------------------------------------------- + + * The Oregon is recognized and initialised. + * Downloading tracks from the device into qLandkarte works. + * Real Time PVT data works (aka "Live Log"). + + + 1.1. Connecting the Garmin + -------------------------- + - Configure the device's USB interface mode to "Garmin Spanner" + (Setup->System->Interface on the device) + - Connect the device to the computer + - Select "No" when the Garmin asks you whether you'd like to go mass storage + - fire up qLandkarte + - download tracks to the computer + + !?#@?! If you encounter problems, please report to the qLandkarte mailing list !?#@?! + !?#@?! at <qlandkartegt-us...@lists.sourceforge.net>. !?#@?! + + +2. Problems +########### + + A lot of the protocols the Oregon supports are undocumented. The most current + Garmin specification dates back to May 2006. + + + +3. Plans +######## + + In order to fully support the Oregon in qLandkarte the operation semantics of the + undocumented protocols need to be reverse engineered. + + The Oregon should be fully supported by qLandkarte. + + + +Appendix +######## + + Oregon 450 "whatGarmin" scan protocol dump + ========================================== + Protocol: P0 + Protocol: L1 + Protocol: A10 <- A 10: Device command protocol #1 + Protocol: T1 + Protocol: A301 <- A 301: track log transfer protocol + Protocol: D312 + Protocol: D302 + Protocol: A500 <- A 500: Almanac transport protocol + Protocol: D501 + Protocol: A600 <- A 600: Date and Time initialisation Protocol + Protocol: D600 + Protocol: A601 <- A 601: ??? + Protocol: D601 + Protocol: A700 <- A 700: Position initialisation protocol + Protocol: D700 + Protocol: A800 <- A 800: PVT + Protocol: D800 + Protocol: A900 <- A 900: ??? + Protocol: A902 <- A 902: ??? + Protocol: A903 <- A 903: ??? + Protocol: A904 <- A 904: ??? + Protocol: A905 <- A 905: ??? + Protocol: D900 + Protocol: A908 <- A 908: ??? + Protocol: D911 + Protocol: A912 <- A 912: ??? + Protocol: D912 + Protocol: A913 <- A 913: ??? + Protocol: D913 + Protocol: A916 <- A 916: ??? + Protocol: A917 <- A 917: ??? + Protocol: D917 + Protocol: A919 <- A 919: ??? + Protocol: A1010 <- A 1010: ??? + Protocol: A918 <- A 918: ??? + Protocol: D918 + Product name: Oregon 450 Software Version 3.30 + product ID: 896 supports link protocol L001 + supports command protocol A010 + supports track log transfer protocol A301 with D0=312 D1=302 + supports Position/Velocity/Time protocol A800 with D0=800 + Product Data End: Oregon 450 Software Version 3.30 + + + Oregon 450 Software Version 3.30 + product ID: 896 + link protocol L001 + command protocol A010 + track log protocol A301 D312 D302 + PVT protocol A800 D800 + + diff --git a/src/ForeRunner/loader.cpp b/src/Oregon/loader.cpp similarity index 61% copy from src/ForeRunner/loader.cpp copy to src/Oregon/loader.cpp index 256efec..7c9830a 100644 --- a/src/ForeRunner/loader.cpp +++ b/src/Oregon/loader.cpp @@ -1,5 +1,5 @@ /********************************************************************************************** - Copyright (C) 2007 Oliver Eichler oliver.eich...@gmx.de + Copyright (C) 2010 Thilo Fromm <kont...@thilo-fromm.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 @@ -20,11 +20,11 @@ **********************************************************************************************/ #include "config.h" -#include "CDevice.h" +#include "Oregon.h" -namespace FR305 +namespace Garmin { - static CDevice * device = 0; + static Oregon * device = 0; } @@ -34,16 +34,29 @@ namespace FR305 #define WIN_EXPORT #endif -extern "C" WIN_EXPORT Garmin::IDevice * initForerunner305(const char * version) +extern "C" WIN_EXPORT Garmin::IDevice * initOregon(const char * version) { if(strncmp(version,INTERFACE_VERSION,5) != 0) { return 0; } - if(FR305::device == 0) { - FR305::device = new FR305::CDevice(); + if(Garmin::device == 0) { + Garmin::device = new Garmin::Oregon(); } - FR305::device->devname = "Forerunner305"; - // FR305::device->screenwidth = 160; - // FR305::device->screenheight = 240; - return FR305::device; + Garmin::device->devname = "Oregon 450"; + Garmin::device->devid = OREGON_450_DEVID; + return Garmin::device; } + +extern "C" WIN_EXPORT Garmin::IDevice * initOregon450(const char * version) +{ + if(strncmp(version,INTERFACE_VERSION,5) != 0) { + return 0; + } + if(Garmin::device == 0) { + Garmin::device = new Garmin::Oregon(); + } + Garmin::device->devname = "Oregon 450"; + Garmin::device->devid = OREGON_450_DEVID; + return Garmin::device; +} + diff --git a/src/Platform.h b/src/Platform.h index d0f9dc0..743f892 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -17,7 +17,7 @@ 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 + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ============================================================= Why does this file exist, and what should hackers do with it? @@ -34,7 +34,7 @@ little endian (like Intel or ARM) or a big endian (like PowerPC or Sparc). In the latter case, it defines the macro HAVE_BIGENDIAN. In an other test, it checks if your machine supports accessing unaligned memory (like Intel or PowerPC) or if such accesses would fail - (as an ARM or Sparc). If unaligned accesses are supported, the macro CAN_UNALIGNED will + (as on ARM or Sparc). If unaligned accesses are supported, the macro CAN_UNALIGNED will be defined. Of course, the file config.h from the top-level folder has to be included. 2. How to access data @@ -78,7 +78,7 @@ For unaligned variables, use the macro gar_store(<type>, <destination>, <source>) where type may be int16_t, int32_t, int64_t, uint16_t, uint32_t, uint64_t, float or double. - if the valiable is aligned, use "destination = gar_endian(type, source)" which is faster. + if the variable is aligned, use "destination = gar_endian(type, source)" which is faster. (b) the destination is a pointer @@ -101,6 +101,8 @@ #elif HAVE_STDINT_H # include <stdint.h> #elif WIN32 +#include <windows.h> + typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; @@ -110,6 +112,8 @@ typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; +#define isnan(x) _isnan(x) + #else # error neither inttypes.h nor stdint.h are available #endif @@ -128,61 +132,88 @@ typedef unsigned __int64 uint64_t; // big endian platform #define gar_endian(t, x) (__gar_endian_ ## t(x)) -#if defined(HAVE_BYTESWAP_H) +// define swapping +static inline uint16_t +__gar_endian_uint16_t(uint16_t x) +{ + return ((x >> 8) & 0xffu) | ((x & 0xffu) << 8); +} -// platform has byteswap.h -#include <byteswap.h> -#define __gar_endian_int16_t(x) (int16_t)(bswap_16(x)) -#define __gar_endian_int32_t(x) (int32_t)(bswap_32(x)) -#define __gar_endian_int64_t(x) (int64_t)(bswap_64(x)) -#define __gar_endian_uint16_t(x) (uint16_t)(bswap_16(x)) -#define __gar_endian_uint32_t(x) (uint32_t)(bswap_32(x)) -#define __gar_endian_uint64_t(x) (uint64_t)(bswap_64(x)) +static inline uint32_t +__gar_endian_uint32_t(uint32_t x) +{ + return (((x & 0xff000000u) >> 24) | + ((x & 0x00ff0000u) >> 8) | + ((x & 0x0000ff00u) << 8) | + ((x & 0x000000ffu) << 24)); +} -#else +static inline uint64_t +__gar_endian_uint64_t(uint64_t x) +{ + return (((x & 0xff00000000000000ull) >> 56) | + ((x & 0x00ff000000000000ull) >> 40) | + ((x & 0x0000ff0000000000ull) >> 24) | + ((x & 0x000000ff00000000ull) >> 8) | + ((x & 0x00000000ff000000ull) << 8) | + ((x & 0x0000000000ff0000ull) << 24) | + ((x & 0x000000000000ff00ull) << 40) | + ((x & 0x00000000000000ffull) << 56)); +} + +static inline int16_t +__gar_endian_int16_t(int16_t x) +{ + return ((x >> 8) & 0xffu) | ((x & 0xffu) << 8); +} + +static inline int32_t +__gar_endian_int32_t(int32_t x) +{ + return (((x & 0xff000000u) >> 24) | + ((x & 0x00ff0000u) >> 8) | + ((x & 0x0000ff00u) << 8) | + ((x & 0x000000ffu) << 24)); +} -// generic platform - define swapping -#define __gar_endian_uint16_t(x) (uint16_t)((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8)) -#define __gar_endian_uint32_t(x) (uint32_t)((((x) & 0xff000000u) >> 24) | \ -(((x) & 0x00ff0000u) >> 8) | \ -(((x) & 0x0000ff00u) << 8) | \ -(((x) & 0x000000ffu) << 24)) -#define __gar_endian_uint64_t(x) (uint64_t)((((x) & 0xff00000000000000ull) >> 56) | \ -(((x) & 0x00ff000000000000ull) >> 40) | \ -(((x) & 0x0000ff0000000000ull) >> 24) | \ -(((x) & 0x000000ff00000000ull) >> 8) | \ -(((x) & 0x00000000ff000000ull) << 8) | \ -(((x) & 0x0000000000ff0000ull) << 24) | \ -(((x) & 0x000000000000ff00ull) << 40) | \ -(((x) & 0x00000000000000ffull) << 56)) -#define __gar_endian_int16_t(x) (int16_t)((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8)) -#define __gar_endian_int32_t(x) (int32_t)((((x) & 0xff000000u) >> 24) | \ -(((x) & 0x00ff0000u) >> 8) | \ -(((x) & 0x0000ff00u) << 8) | \ -(((x) & 0x000000ffu) << 24)) -#define __gar_endian_int64_t(x) (int64_t)((((x) & 0xff00000000000000ull) >> 56) | \ -(((x) & 0x00ff000000000000ull) >> 40) | \ -(((x) & 0x0000ff0000000000ull) >> 24) | \ -(((x) & 0x000000ff00000000ull) >> 8) | \ -(((x) & 0x00000000ff000000ull) << 8) | \ -(((x) & 0x0000000000ff0000ull) << 24) | \ -(((x) & 0x000000000000ff00ull) << 40) | \ -(((x) & 0x00000000000000ffull) << 56)) -#endif // !HAVE_BYTESWAP_H +static inline int64_t +__gar_endian_int64_t(int64_t x) +{ + return (((x & 0xff00000000000000ull) >> 56) | + ((x & 0x00ff000000000000ull) >> 40) | + ((x & 0x0000ff0000000000ull) >> 24) | + ((x & 0x000000ff00000000ull) >> 8) | + ((x & 0x00000000ff000000ull) << 8) | + ((x & 0x0000000000ff0000ull) << 24) | + ((x & 0x000000000000ff00ull) << 40) | + ((x & 0x00000000000000ffull) << 56)); +} static inline float __gar_endian_float(float x) { - uint32_t __uv = gar_endian(uint32_t, *(uint32_t *)&x); - return *(float *) &__uv; + union { + uint32_t _u; + float _f; + } _v; + + _v._f = x; + _v._u = gar_endian(uint32_t, _v._u); + return _v._f; } static inline double __gar_endian_double(double x) { - uint64_t __uv = gar_endian(uint64_t, *(uint64_t *)&x); - return *(double *) &__uv; + union { + uint64_t _u; + double _d; + } _v; + + _v._d = x; + _v._u = gar_endian(uint64_t, _v._u); + return _v._d; } #endif // HAVE_BIGENDIAN @@ -190,10 +221,10 @@ __gar_endian_double(double x) // macros to deal with pointers or unaligned arguments // load argument of type t from pointer p -#define gar_ptr_load(t, p) __gar_ptr_load_ ## t((p)) +#define gar_ptr_load(t, p) __gar_ptr_load_ ## t((const uint8_t *)(p)) // store argument src of type t in in the location to which the pointer p points -#define gar_ptr_store(t, p, src) __gar_ptr_store_ ## t((p), (src)) +#define gar_ptr_store(t, p, src) __gar_ptr_store_ ## t((uint8_t *)(p), (src)) #if defined(CAN_UNALIGNED) && !defined(HAVE_BIGENDIAN) @@ -226,14 +257,19 @@ __gar_endian_double(double x) #define __gar_ptr_store_float(p, src) (*((float *)(p))) = (src) #define __gar_ptr_store_double(p, src) (*((double *)(p))) = (src) // special Garmin types - use memcpy -#define __gar_ptr_store_uint24_t(p, src) \ -do \ -{ \ - __gar_ptr_store_uint16_t(p, src & 0xfffu); \ - p[2] = src >> 16; \ -} while (0) -#define __gar_ptr_store_int24_t(p, src) \ -__gar_ptr_store_uint24_t(p, src) +static inline void +__gar_ptr_store_int24_t(uint8_t * p, int32_t src) +{ + __gar_ptr_store_uint16_t(p, src & 0xffffu); + p[2] = src >> 16; +} + +static inline void +__gar_ptr_store_uint24_t(uint8_t * p, uint32_t src) +{ + __gar_ptr_store_uint16_t(p, src & 0xffffu); + p[2] = src >> 16; +} #else // machine is either Big Endian or does not support unaligned accesses @@ -244,79 +280,177 @@ __gar_ptr_store_uint24_t(p, src) #define gar_store(t, dst, src) gar_ptr_store(t, (uint8_t *)&(dst), src) // load from pointer - read'n'shift bytes -#define __gar_ptr_load_int16_t(p) ((int16_t)((p)[0] | ((p)[1] << 8))) -#define __gar_ptr_load_int24_t(p) ((int32_t)((p)[0] | ((p)[1] << 8) | \ -((p)[2] << 16))) -#define __gar_ptr_load_int32_t(p) ((int32_t)((p)[0] | ((p)[1] << 8) | \ -((p)[2] << 16) | ((p)[3] << 24))) -#define __gar_ptr_load_int64_t(p) ((int64_t)gar_ptr_load_int32(p) | \ -(((int64_t)gar_ptr_load_int32((p) + 4)) << 32)) -#define __gar_ptr_load_uint16_t(p) ((uint16_t)((p)[0] | ((p)[1] << 8))) -#define __gar_ptr_load_uint24_t(p) ((uint32_t)((p)[0] | ((p)[1] << 8) | \ -((p)[2] << 16))) -#define __gar_ptr_load_uint32_t(p) ((uint32_t)((p)[0] | ((p)[1] << 8) | \ -((p)[2] << 16) | ((p)[3] << 24))) -#define __gar_ptr_load_uint64_t(p) ((uint64_t)__gar_ptr_load_uint32_t(p) | \ -(((uint64_t)__gar_ptr_load_uint32_t((p) + 4)) << 32)) +// use Byte-Reverse operations for PowerPC +static inline uint16_t +__gar_ptr_load_uint16_t(const uint8_t *p) +{ +#ifdef __powerpc__ + register uint16_t temp; + + asm __volatile__ ("lhbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); + return temp; +#else + return (uint16_t)(p[0] | (p[1] << 8)); +#endif +} + +static inline uint32_t +__gar_ptr_load_uint24_t(const uint8_t *p) +{ +#ifdef __powerpc__ + register uint32_t temp; + + asm __volatile__ ("lwbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); + asm __volatile__ ("rlwinm %0,%1,0,8,31" : "=r" (temp) : "r" (temp)); + return temp; +#else + return (uint32_t)(p[0] | (p[1] << 8) | (p[2] << 16)); +#endif +} + +static inline uint32_t +__gar_ptr_load_uint32_t(const uint8_t *p) +{ +#ifdef __powerpc__ + register uint32_t temp; + + asm __volatile__ ("lwbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); + return temp; +#else + return (uint32_t)(p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); +#endif +} + +static inline uint64_t +__gar_ptr_load_uint64_t(const uint8_t *p) +{ + return ((uint64_t)__gar_ptr_load_uint32_t(p) | + ((uint64_t)__gar_ptr_load_uint32_t(p + 4) << 32)); +} + +static inline int16_t +__gar_ptr_load_int16_t(const uint8_t *p) +{ +#ifdef __powerpc__ + register int16_t temp; + + asm __volatile__ ("lhbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); + return temp; +#else + return (int16_t)(p[0] | (p[1] << 8)); +#endif +} + +static inline int32_t +__gar_ptr_load_int24_t(const uint8_t *p) +{ +#ifdef __powerpc__ + register int32_t temp; + + asm __volatile__ ("lwbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); + asm __volatile__ ("rlwinm %0,%1,0,8,31" : "=r" (temp) : "r" (temp)); + return temp; +#else + return p[0] | (p[1] << 8) | (p[2] << 16); +#endif +} + +static inline int32_t +__gar_ptr_load_int32_t(const uint8_t *p) +{ +#ifdef __powerpc__ + register int32_t temp; + + asm __volatile__ ("lwbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); + return temp; +#else + return (int32_t)(p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); +#endif +} + +static inline int64_t +__gar_ptr_load_int64_t(const uint8_t *p) +{ + return ((int64_t)__gar_ptr_load_uint32_t(p) | + ((int64_t)__gar_ptr_load_int32_t(p + 4) << 32)); +} + static inline float -__gar_ptr_load_float(uint8_t * p) +__gar_ptr_load_float(const uint8_t * p) { - uint32_t __uv = gar_ptr_load(uint32_t, p); - return *(float *) &__uv; + union { + uint32_t _u; + float _f; + } _v; + + _v._u = gar_ptr_load(uint32_t, p); + return _v._f; } static inline double -__gar_ptr_load_double(uint8_t * p) +__gar_ptr_load_double(const uint8_t * p) { - uint64_t __uv = gar_ptr_load(uint64_t, p); - return *(double *) &__uv; + union { + uint64_t _u; + double _d; + } _v; + + _v._u = gar_ptr_load(uint64_t, p); + return _v._d; } // macros to store data - use memcpy to store data to pointer -#define __gar_ptr_store_uint16_t(p, src) \ -do \ -{ \ - p[0] = src & 0xffu; \ - p[1] = (src >> 8) & 0xffu; \ -} while (0) -#define __gar_ptr_store_uint24_t(p, src) \ -do \ -{ \ - p[0] = src & 0xffu; \ - p[1] = (src >> 8) & 0xffu; \ - p[2] = (src >> 16) & 0xffu; \ -} while (0) -#define __gar_ptr_store_uint32_t(p, src) \ -do \ -{ \ - p[0] = src & 0xffu; \ - p[1] = (src >> 8) & 0xffu; \ - p[2] = (src >> 16) & 0xffu; \ - p[3] = (src >> 24) & 0xffu; \ -} while (0) -#define __gar_ptr_store_uint64_t(p, src) \ -do \ -{ \ - __gar_ptr_store_uint32_t(p, src & 0xffffffffu); \ - __gar_ptr_store_uint32_t(p + 4, src >> 32); \ -} while (0) -#define __gar_ptr_store_int16_t(p, src) __gar_ptr_store_uint16_t(p, src) -#define __gar_ptr_store_int24_t(p, src) __gar_ptr_store_uint24_t(p, src) -#define __gar_ptr_store_int32_t(p, src) __gar_ptr_store_uint32_t(p, src) -#define __gar_ptr_store_int64_t(p, src) __gar_ptr_store_uint64_t(p, src) -#define __gar_ptr_store_float(p, src) \ -do \ -{ \ - float __fv = gar_endian(float, src); \ - memcpy(p, &__fv, 4); \ -} while (0) -#define __gar_ptr_store_double(p, src) \ -do \ -{ \ - _double __dv = gar_endian(double, src); \ - memcpy(p, &__dv, 8); \ -} while (0) +static inline void +__gar_ptr_store_uint16_t(uint8_t *p, uint16_t src) +{ + p[0] = src & 0xffu; + p[1] = (src >> 8) & 0xffu; +} + +static inline void +__gar_ptr_store_uint24_t(uint8_t *p, uint32_t src) +{ + p[0] = src & 0xffu; + p[1] = (src >> 8) & 0xffu; + p[2] = (src >> 16) & 0xffu; +} + +static inline void +__gar_ptr_store_uint32_t(uint8_t *p, uint32_t src) +{ + p[0] = src & 0xffu; + p[1] = (src >> 8) & 0xffu; + p[2] = (src >> 16) & 0xffu; + p[3] = (src >> 24) & 0xffu; +} + +static inline void +__gar_ptr_store_uint64_t(uint8_t *p, uint64_t src) +{ + __gar_ptr_store_uint32_t(p, src & 0xffffffffu); + __gar_ptr_store_uint32_t(p + 4, src >> 32); +} + +#define __gar_ptr_store_int16_t(p, src) __gar_ptr_store_uint16_t(p, (uint16_t)src) +#define __gar_ptr_store_int24_t(p, src) __gar_ptr_store_uint24_t(p, (uint32_t)src) +#define __gar_ptr_store_int32_t(p, src) __gar_ptr_store_uint32_t(p, (uint32_t)src) +#define __gar_ptr_store_int64_t(p, src) __gar_ptr_store_uint64_t(p, (uint64_t)src) + +static inline void +__gar_ptr_store_float(uint8_t *p, float src) +{ + float __fv = gar_endian(float, src); + memcpy(p, &__fv, 4); +} + +static inline void +__gar_ptr_store_double(uint8_t *p, double src) +{ + double __dv = gar_endian(double, src); + memcpy(p, &__dv, 8); +} + #endif // cannot unaligned or big endian #endif // __PLATFORM_H__ -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/garmindev.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel