Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/qemu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: QEMU to run BigEndian s390x Linux

on:
push:
workflow_dispatch:

jobs:
# build:
# runs-on: ubuntu-latest
# steps:
# - name: Setup multiarch/qemu-user-static
# run: |
# docker run --rm --privileged multiarch/qemu-user-static:register --reset
# - name: s390x-linux
# #uses: docker://multiarch/ubuntu-core:s390x-focal
# uses: docker://s390x/ubuntu:latest
# with:
# args: >
# bash -c
# "uname -a &&
# lscpu | grep Endian &&
# apt-get -y update &&
# DEBIAN_FRONTEND=noninteractive apt-get -y install git cmake g++ pkg-config libusb-1.0-0-dev libxml2-dev libboost-dev libboost-exception-dev libboost-program-options-dev libboost-test-dev valgrind &&
# git clone https://github.com/ralovich/antpm &&
# cd antpm &&
# cmake -B build -S src -DCMAKE_BUILD_TYPE=Release -DUSE_BOOST_TEST=TRUE -DUSE_GANT=TRUE &&
# cmake --build build --config Release -j &&
# (cd build && ctest -C Release --rerun-failed --output-on-failure -j 4 --timeout 120)
# "
# platforms: linux/s390x

# secondtry:
# runs-on: ubuntu-latest
# steps:
# - name: secondtry
# run: >
# docker run --rm --privileged multiarch/qemu-user-static:register --reset &&
# docker run --rm --platform linux/s390x s390x/ubuntu:latest
# bash -c
# "uname -a &&
# lscpu | grep Endian &&
# apt-get -y update &&
# DEBIAN_FRONTEND=noninteractive apt-get -y install git cmake g++ pkg-config libusb-1.0-0-dev libxml2-dev libboost-dev libboost-exception-dev libboost-program-options-dev libboost-test-dev valgrind &&
# git clone https://github.com/ralovich/antpm &&
# cd antpm &&
# cmake -B build -S src -DCMAKE_BUILD_TYPE=Release -DUSE_BOOST_TEST=TRUE -DUSE_GANT=TRUE &&
# cmake --build build --config Release -j &&
# (cd build && ctest -C Release --rerun-failed --output-on-failure -j 4 --timeout 120)
# "

build:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Run Tests in Docker
run: >
docker run
--rm
-v $(pwd):/${{ github.workspace }}
-w ${{ github.workspace }}
--platform linux/s390x
ubuntu:latest
bash -c
"uname -m &&
lscpu | grep Endian &&
apt-get -y update &&
DEBIAN_FRONTEND=noninteractive apt-get -y install cmake g++ pkg-config libusb-1.0-0-dev libxml2-dev libboost-dev libboost-exception-dev libboost-program-options-dev libboost-test-dev valgrind &&
cmake -B build -S src -DCMAKE_BUILD_TYPE=Release -DUSE_BOOST_TEST=TRUE -DUSE_GANT=TRUE &&
cmake --build build --config Release -j &&
(cd build && ctest -C Release --rerun-failed --output-on-failure -j 4 --timeout 240)
"
19 changes: 19 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ MESSAGE(STATUS "CMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG=1")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG=1")

MESSAGE(STATUS "CMAKE_CXX_BYTE_ORDER=${CMAKE_CXX_BYTE_ORDER}")
IF(CMAKE_CXX_BYTE_ORDER)
IF(CMAKE_CXX_BYTE_ORDER STREQUAL "BIG_ENDIAN")
ADD_DEFINITIONS(-D__BIG_ENDIAN_BITFIELD=1)
MESSAGE(STATUS "BigEndian")
ELSE()
MESSAGE(STATUS "LittleEndian")
ENDIF()
ELSE()
MESSAGE(STATUS "TestBigEndian")
INCLUDE(TestBigEndian)
TEST_BIG_ENDIAN(TBE_DETECTED)
MESSAGE(STATUS "BigEndian=${TBE_DETECTED}")
IF(TBE_DETECTED)
ADD_DEFINITIONS(-D__BIG_ENDIAN_BITFIELD=1)
ENDIF()
ENDIF()


IF(MSVC)
SET(LIBUSB_ROOT "C:/vcpkg/installed/x64-windows" CACHE PATH "Libusb PATH")
SET(BOOST_ROOT "c:/local/boost_1_87_0" CACHE PATH "Boost PATH" )
Expand Down
29 changes: 27 additions & 2 deletions src/FIT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@

#include "common.hpp"

#include <boost/endian/conversion.hpp>

using namespace std;

namespace antpm{
Expand Down Expand Up @@ -863,6 +865,7 @@ string FIT::getDataString(uint8_t *ptr, uint8_t size, uint8_t baseType, uint8_t
case BT_Int16:
{
int16_t val = *(int16_t *)ptr;
boost::endian::little_to_native_inplace(val);
if (val == 0x7FFF)
{
strstrm << "undefined";
Expand All @@ -877,6 +880,7 @@ string FIT::getDataString(uint8_t *ptr, uint8_t size, uint8_t baseType, uint8_t
case BT_Uint16z:
{
uint16_t val = *(uint16_t *)ptr;
boost::endian::little_to_native_inplace(val);
if (val == 0xFFFF)
{
strstrm << "undefined";
Expand Down Expand Up @@ -922,6 +926,7 @@ string FIT::getDataString(uint8_t *ptr, uint8_t size, uint8_t baseType, uint8_t
case BT_Int32:
{
int32_t val = *(int32_t *)ptr;
boost::endian::little_to_native_inplace(val);
if (val == 0x7FFFFFFF)
{
strstrm << "undefined";
Expand All @@ -947,6 +952,7 @@ string FIT::getDataString(uint8_t *ptr, uint8_t size, uint8_t baseType, uint8_t
case BT_Uint32z:
{
uint32_t val = *(uint32_t *)ptr;
boost::endian::little_to_native_inplace(val);
if (val == 0xFFFFFFFF)
{
strstrm << "undefined";
Expand Down Expand Up @@ -998,7 +1004,7 @@ string FIT::getDataString(uint8_t *ptr, uint8_t size, uint8_t baseType, uint8_t
bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
{
ostringstream strstrm;

LOG(LOG_DBG2) << "Parsing FIT file\n";

FITHeader fitHeader;
Expand All @@ -1007,6 +1013,11 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)

uint8_t *ptr = &fitData.front();
memcpy(&fitHeader, ptr, sizeof(fitHeader));
boost::endian::little_to_native_inplace(fitHeader.headerSize);
boost::endian::little_to_native_inplace(fitHeader.protocolVersion);
boost::endian::little_to_native_inplace(fitHeader.profileVersion);
boost::endian::little_to_native_inplace(fitHeader.dataSize);
boost::endian::little_to_native_inplace(fitHeader.headerCRC);

// FIT header CRC
uint16_t crc = 0;
Expand All @@ -1030,6 +1041,7 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
}

uint16_t fitCRC = *(uint16_t *)(ptr+fitHeader.dataSize);
boost::endian::little_to_native_inplace(fitCRC);
if (crc != fitCRC /*&& fitCRC != 0*/)
{
LOG(LOG_WARN) << hex << uppercase << setw(4) << setfill('0') << "Invalid FIT CRC (" << crc << "!=" << fitCRC << ")\n";
Expand Down Expand Up @@ -1062,6 +1074,7 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)

RecordFixed rfx;
memcpy(&rfx, ptr, sizeof(rfx));
boost::endian::little_to_native_inplace(rfx.globalNum);
ptr += sizeof(rfx);
bytes -= sizeof(rfx);

Expand Down Expand Up @@ -1126,6 +1139,7 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
case 4: // Creation Time
{
fileCreationTime = *(uint32_t*)ptr;
boost::endian::little_to_native_inplace(fileCreationTime);
mCreationTimestamp = fileCreationTime;
break;
}
Expand All @@ -1139,6 +1153,7 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
case 253: // Timestamp
{
time = *(uint32_t*)ptr;
boost::endian::little_to_native_inplace(time);
// TODO: add to gpx?
tstamps.push_back(time);
break;
Expand All @@ -1153,25 +1168,29 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
case 253: // Timestamp
{
time = *(uint32_t*)ptr;
boost::endian::little_to_native_inplace(time);
gpx.tracks.back().trackSegs.back().trackPoints[time].time = time;
tstamps.push_back(time);
break;
}
case 0: // Latitude
{
int32_t latitude = *(int32_t*)ptr;
boost::endian::little_to_native_inplace(latitude);
gpx.tracks.back().trackSegs.back().trackPoints[time].latitude = latitude;
break;
}
case 1: // Longitude
{
uint32_t longitude = *(int32_t*)ptr;
boost::endian::little_to_native_inplace(longitude);
gpx.tracks.back().trackSegs.back().trackPoints[time].longitude = longitude;
break;
}
case 2: // Altitude
{
uint16_t altitude = *(uint16_t*)ptr;
boost::endian::little_to_native_inplace(altitude);
gpx.tracks.back().trackSegs.back().trackPoints[time].altitude = altitude;
break;
}
Expand All @@ -1197,6 +1216,7 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
case 253: // Timestamp
{
time = *(uint32_t*)ptr;
boost::endian::little_to_native_inplace(time);
gpx.wayPoints.back().time = time;
tstamps.push_back(time);
break;
Expand All @@ -1210,12 +1230,14 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
case 1: // Latitude
{
int32_t latitude = *(int32_t*)ptr;
boost::endian::little_to_native_inplace(latitude);
gpx.wayPoints.back().latitude = latitude;
break;
}
case 2: // Longitude
{
int32_t longitude = *(int32_t*)ptr;
boost::endian::little_to_native_inplace(longitude);
gpx.wayPoints.back().longitude = longitude;
break;
}
Expand All @@ -1226,6 +1248,7 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
case 4: // Altitude
{
uint16_t altitude = *(uint16_t*)ptr;
boost::endian::little_to_native_inplace(altitude);
gpx.wayPoints.back().altitude = altitude;
break;
}
Expand Down Expand Up @@ -1274,8 +1297,10 @@ bool FIT::parse(vector<uint8_t> &fitData, GPX &gpx)
}
case 6: // Average Speed
{
uint16_t as = *(uint16_t*)ptr;
boost::endian::little_to_native_inplace(as);
// unit: m/s * 1000
double speed = (double)(*(uint16_t*)ptr) / 1000;
double speed = (double)(as) / 1000.0;
strstrm << speed;

break;
Expand Down
41 changes: 40 additions & 1 deletion src/FIT.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@
#include <map>
#include <sstream>
#include <ctime>

#include <boost/endian/arithmetic.hpp>

namespace antpm{

using namespace boost::endian;

#pragma pack(1)
struct FITHeader
Expand All @@ -59,27 +60,44 @@ struct FITHeader
uint8_t signature[4];
uint16_t headerCRC;
};
static_assert(sizeof(FITHeader) == 14);

struct RecordNormalHeader
{
#if !defined (__BIG_ENDIAN_BITFIELD)
uint8_t localMessageType:4;
uint8_t reserved:2;
uint8_t messageType:1;
uint8_t headerType:1;
#else
uint8_t headerType:1;
uint8_t messageType:1;
uint8_t reserved:2;
uint8_t localMessageType:4;
#endif
};
static_assert(sizeof(RecordNormalHeader) == 1);

struct RecordCompressedTimeStampHeader
{
#if !defined (__BIG_ENDIAN_BITFIELD)
uint8_t timeOffset:5;
uint8_t localMessageType:2;
uint8_t headerType:1;
#else
uint8_t headerType:1;
uint8_t localMessageType:2;
uint8_t timeOffset:5;
#endif
};
static_assert(sizeof(RecordCompressedTimeStampHeader) == 1);

union RecordHeader
{
RecordNormalHeader normalHeader;
RecordCompressedTimeStampHeader ctsHeader;
};
static_assert(sizeof(RecordHeader) == 1);

struct RecordFixed
{
Expand All @@ -88,26 +106,36 @@ struct RecordFixed
uint16_t globalNum;
uint8_t fieldsNum;
};
static_assert(sizeof(RecordFixed) == 5);

struct RecordField
{
uint8_t definitionNum;
uint8_t size;
uint8_t baseType;
};
static_assert(sizeof(RecordField) == 3);

struct BaseTypeBits
{
#if !defined (__BIG_ENDIAN_BITFIELD)
uint8_t baseTypeNum:5;
uint8_t reserved:2;
uint8_t endianAbility:1;
#else
uint8_t endianAbility:1;
uint8_t reserved:2;
uint8_t baseTypeNum:5;
#endif
};
static_assert(sizeof(BaseTypeBits) == 1);

union BaseType
{
BaseTypeBits bits;
uint8_t byte;
};
static_assert(sizeof(BaseType) == 1);

struct ZeroFileRecord
{
Expand All @@ -118,17 +146,28 @@ struct ZeroFileRecord
uint8_t fileDataTypeFlags;
struct
{
#if !defined (__BIG_ENDIAN_BITFIELD)
uint8_t reserved:2;
uint8_t crypto:1;
uint8_t append:1;
uint8_t archive:1;
uint8_t erase:1;
uint8_t write:1;
uint8_t read:1;
#else
uint8_t read:1;
uint8_t write:1;
uint8_t erase:1;
uint8_t archive:1;
uint8_t append:1;
uint8_t crypto:1;
uint8_t reserved:2;
#endif
} generalFileFlags;
uint32_t fileSize;
uint32_t timeStamp;
};
static_assert(sizeof(ZeroFileRecord) == 16);

struct DirectoryHeader
{
Expand Down
Loading
Loading