#pragma once

#include <array>
#include <cstdint>
#include "data_format.hpp"

//
// ============================================================
// 32-bit (float / int32 / uint32)
// ============================================================

// float (IEEE-754, Modbus 2 registers)
std::array<std::uint16_t, 2>
encode_float(float value, const DataFormat& fmt);

float
decode_float(std::uint16_t r0,
             std::uint16_t r1,
             const DataFormat& fmt);

// signed 32-bit
std::array<std::uint16_t, 2>
encode_int32(std::int32_t value, const DataFormat& fmt);

std::int32_t
decode_int32(std::uint16_t r0,
             std::uint16_t r1,
             const DataFormat& fmt);

// unsigned 32-bit
std::array<std::uint16_t, 2>
encode_uint32(std::uint32_t value, const DataFormat& fmt);

std::uint32_t
decode_uint32(std::uint16_t r0,
              std::uint16_t r1,
              const DataFormat& fmt);


//
// ============================================================
// 64-bit (double / int64 / uint64)
// ============================================================

// double (IEEE-754, Modbus 4 registers)
std::array<std::uint16_t, 4>
encode_double(double value, const DataFormat& fmt);

double
decode_double(std::uint16_t r0,
              std::uint16_t r1,
              std::uint16_t r2,
              std::uint16_t r3,
              const DataFormat& fmt);

// signed 64-bit
std::array<std::uint16_t, 4>
encode_int64(std::int64_t value, const DataFormat& fmt);

std::int64_t
decode_int64(std::uint16_t r0,
             std::uint16_t r1,
             std::uint16_t r2,
             std::uint16_t r3,
             const DataFormat& fmt);

// unsigned 64-bit
std::array<std::uint16_t, 4>
encode_uint64(std::uint64_t value, const DataFormat& fmt);

std::uint64_t
decode_uint64(std::uint16_t r0,
              std::uint16_t r1,
              std::uint16_t r2,
              std::uint16_t r3,
              const DataFormat& fmt);
