113 lines
2.5 KiB
C++
113 lines
2.5 KiB
C++
#include <iostream>
|
|
#include <fstream>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
#include <filesystem>
|
|
#include <ctime>
|
|
#include <algorithm>
|
|
|
|
static constexpr uint8_t magic[] = {0xf6, 0x76, 0xd8, 0x09};
|
|
|
|
struct __attribute__((packed)) Frame {
|
|
uint64_t time;
|
|
uint32_t steps;
|
|
uint8_t batteryPercent;
|
|
uint8_t heartRate;
|
|
uint8_t pad[2];
|
|
};
|
|
|
|
bool arrayeq(const uint8_t* a, const uint8_t* b, size_t len)
|
|
{
|
|
for(size_t i = 0; i < len; ++i)
|
|
{
|
|
if(a[i] != b[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<Frame> readFile(const std::filesystem::path& path)
|
|
{
|
|
std::ifstream file;
|
|
file.open(path, std::ios_base::binary | std::ios_base::in);
|
|
if(!file.is_open())
|
|
{
|
|
std::cout<<"could not open "<<path<<'\n';
|
|
return {};
|
|
}
|
|
|
|
uint8_t magicRef[4];
|
|
file.read(reinterpret_cast<char*>(&magicRef), 4);
|
|
|
|
if(!arrayeq(magic, magicRef, 4))
|
|
{
|
|
std::cout<<path<<" is not a valid infitime log file\n";
|
|
return {};
|
|
}
|
|
|
|
uint8_t versionMajor;
|
|
uint8_t versionMinor;
|
|
file.read(reinterpret_cast<char*>(&versionMajor), 1);
|
|
file.read(reinterpret_cast<char*>(&versionMinor), 1);
|
|
|
|
if(versionMajor > 1 || file.bad())
|
|
{
|
|
std::cout<<path<<" is a file of version "<<versionMajor<<'.'<<versionMinor<<" this application supports only versions 1.x and below\n";
|
|
return {};
|
|
}
|
|
|
|
uint16_t size;
|
|
file.read(reinterpret_cast<char*>(&size), sizeof(size));
|
|
|
|
if(sizeof(Frame) != size)
|
|
{
|
|
std::cout<<path<<" contains frames of an unexpected size\n";
|
|
return {};
|
|
}
|
|
|
|
uint32_t length;
|
|
file.read(reinterpret_cast<char*>(&length), sizeof(length));
|
|
|
|
std::vector<Frame> frames;
|
|
frames.reserve(length);
|
|
|
|
for(size_t i = 0; i < length && !file.bad(); ++i)
|
|
{
|
|
Frame frame = {};
|
|
file.read(reinterpret_cast<char*>(&frame), sizeof(frame));
|
|
|
|
if(frame.time != 0)
|
|
frames.push_back(frame);
|
|
}
|
|
|
|
std::sort(frames.begin(), frames.end(), [](const Frame& a, const Frame& b){return a.time < b.time;});
|
|
return frames;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
if(argc < 2)
|
|
{
|
|
std::cout<<"Usage: "<<(argc > 0 ? argv[0] : "infinilog")<<" [LOG_FILE]\n";
|
|
return 1;
|
|
}
|
|
|
|
std::vector<Frame> frames = readFile(argv[1]);
|
|
|
|
if(frames.empty())
|
|
return 1;
|
|
|
|
std::cout<<"timestamp, steps, battery percent, heart rate\n";
|
|
for(auto& frame : frames) {
|
|
std::time_t time = frame.time;
|
|
std::tm* ptm = std::localtime(&time);
|
|
char timeBuffer[32];
|
|
std::strftime(timeBuffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm);
|
|
|
|
std::cout<<timeBuffer<<", "<<frame.steps<<", "<<static_cast<int>(frame.batteryPercent)<<", "<<static_cast<int>(frame.heartRate)<<'\n';
|
|
}
|
|
|
|
return 0;
|
|
}
|