Skip to content
Commits on Source (4)
Subproject commit 8a0ea2d0e699863df5fe1c91caf2d7b0855957be
Subproject commit a00f9a27afbf5f75dab7db2368b9b9b6fcb395e1
......@@ -4,15 +4,61 @@
namespace inaf::oasbo::Packets {
class AstriHornGeneric : public inaf::oasbo::PacketLib::BasePacket {
/**
* @brief Represents a generic ASTRI horn packet.
* @note the "magic numbers" in the implementation of this class derived from the ASTRI Camera BEE – Camera Camera Data Acquisition
* Interface Control Document.
* If the document is updated, be sure to update the magic numbers appropriately.
* This class inherits from the BasePacket class and provides
* functionality specific to ASTRI horn packets.
*/
class AstriHornGeneric: public inaf::oasbo::Packets::BasePacket {
public:
AstriHornGeneric(inaf::oasbo::PacketLib::BasePacketStructure &structure) : BasePacket(structure){}
/**
* @brief Constructs an AstriHornGeneric object with the given packet structure.
*
* @param structure The packet structure to be used.
*/
AstriHornGeneric(inaf::oasbo::Packets::BasePacketStructure &structure) :
BasePacket(structure) {
}
/**
* @brief Gets the size of the header in bytes.
*
* @return The size of the header.
*/
uint getHeaderSize() const override;
/**
* @brief Gets the size of the payload in bytes.
*
* @return The size of the payload.
*/
uint getPayloadSize() const override;
/**
* @brief Gets the size of the tail in bytes.
*
* @return The size of the tail.
*/
uint getTailSize() const override;
/**
* @brief Checks if the packet has a recognized header.
*
* @return True if the packet has a recognized header, false otherwise.
*/
bool hasRecognizedHeader() const override;
/**
* @brief Checks if the given buffer contains a recognized header.
*
* @param buff The buffer to check.
* @return True if the buffer contains a recognized header, false otherwise.
*/
bool isRecognizedHeader(std::vector<uint8_t> buff) const override;
};
}
}
/*
*
* Created on: Mar 1, 2021
* Author: astrisw
/**
* @brief This file contains the definition of the recognizedPackets for Astri Horn.
*
* The recognizedPackets vector is a static member of the inaf::oasbo::Packets::AstriHorn namespace.
* It stores tuples representing recognized packets, where each tuple contains three values:
* - The first value represents the packet type.
* - The second value represents the packet subtype.
* - The third value represents the packet length.
*
*/
#pragma once
#include <vector>
......@@ -16,6 +20,5 @@ static std::vector<std::tuple<size_t, size_t, size_t>> recognizedPackets = {
std::make_tuple(1, 3, 13268), std::make_tuple(1, 4, 13268),
std::make_tuple(2, 1, 9568), std::make_tuple(2, 2, 10900),
std::make_tuple(10, 1, 4526), std::make_tuple(10, 2, 19040),
std::make_tuple(15, 1, 12)
};
std::make_tuple(15, 1, 12) };
}
......@@ -4,39 +4,211 @@
namespace inaf::oasbo::Packets {
class AstriMaGeneric : public inaf::oasbo::PacketLib::BasePacket {
/**
* @brief The AstriMaGeneric class represents a generic packet used in the ASTRI DAQ system.
*
* @note the "magic numbers" in the implementation of this class derived from the ASTRI Camera BEE – Camera Camera Data Acquisition
* Interface Control Document.
* If the document is updated, be sure to update the magic numbers appropriately.
* This class inherits from the BasePacket class in the inaf::oasbo::Packets namespace.
* It provides methods to retrieve various properties of the packet, such as header size, payload size, tail size,
* telescope ID, type, subtype, SSC, packet length, date and time information, event counter, and various flags.
*/
class AstriMaGeneric: public inaf::oasbo::Packets::BasePacket {
public:
AstriMaGeneric(inaf::oasbo::PacketLib::BasePacketStructure &structure) : BasePacket(structure){}
AstriMaGeneric(inaf::oasbo::PacketLib::BasePacket &other) : BasePacket(other){}
/**
* @brief Constructs an AstriMaGeneric object with the given packet structure.
*
* @param structure The packet structure.
*/
AstriMaGeneric(inaf::oasbo::Packets::BasePacketStructure &structure) :
BasePacket(structure) {
}
/**
* @brief Constructs an AstriMaGeneric object by copying another BasePacket object.
*
* @param other The other BasePacket object to copy.
*/
AstriMaGeneric(inaf::oasbo::Packets::BasePacket &other) :
BasePacket(other) {
}
/**
* @brief Gets the size of the header in bytes.
*
* @return The size of the header.
*/
uint getHeaderSize() const override;
/**
* @brief Gets the size of the payload in bytes.
*
* @return The size of the payload.
*/
uint getPayloadSize() const override;
/**
* @brief Gets the size of the tail in bytes.
*
* @return The size of the tail.
*/
uint getTailSize() const override;
/**
* @brief Checks if the packet has a recognized header.
*
* @return True if the packet has a recognized header, false otherwise.
*/
bool hasRecognizedHeader() const override;
/**
* @brief Checks if the given buffer contains a recognized header.
*
* @param buff The buffer to check.
* @return True if the buffer contains a recognized header, false otherwise.
*/
bool isRecognizedHeader(std::vector<uint8_t> buff) const override;
/**
* @brief Gets the telescope ID field value.
*
* @return The telescope ID value.
*/
uint getTelescopeID() const;
/**
* @brief Gets the type of the packet.
*
* @return The packet type.
*/
uint getType() const;
/**
* @brief Gets the subtype of the packet.
*
* @return The packet subtype.
*/
uint getSubType() const;
/**
* @brief Gets the SSC field value.
*
* @return The SSC value.
*/
uint getSSC() const;
/**
* @brief Gets the packetlength field value.
*
* @return The packet length.
*/
uint getPacketLength() const;
/**
* @brief Gets the year field value.
*
* @return The year.
*/
uint getYear() const;
/**
* @brief Gets the month field value.
*
* @return The month.
*/
uint getMonth() const;
/**
* @brief Gets the day field value.
*
* @return The day.
*/
uint getDay() const;
/**
* @brief Gets the hour field value.
*
* @return The hour.
*/
uint getHour() const;
/**
* @brief Gets the minutes field value.
*
* @return The minutes.
*/
uint getMinutes() const;
/**
* @brief Gets the seconds field value.
*
* @return The seconds.
*/
uint getSeconds() const;
/**
* @brief get the validtime field value
*
* @return validtime
*/
bool getValidTime() const;
/**
* @brief Gets the time tag nanoseconds field value
*
* @return time tag nanoseconds.
*/
uint getTimeTagNanoseconds() const;
/**
* @brief Gets the event counter field value.
*
* @return The event counter.
*/
uint getEventCounter() const;
/**
* @brief get the lif field value.
*
* @return lid value
*/
bool getLid() const;
/**
* @brief get the fibst field value.
*
* @return fibst value.
*/
bool fibSt() const;
/**
* @brief get the fibCont field value.
*
* @return fibCont value.
*/
bool fibCont() const;
bool fibPuls() const;
uint rgbCont() const;
uint rgbPuls() const;
/**
* @brief get the fibPuls field value.
*
* @return fibPuls value.
*/
bool fibPuls() const;
/**
* @brief get the rgbCont field value.
*
* @return rgbCont value.
*/
uint rgbCont() const;
/**
* @brief get the rgbPuls field value.
*
* @return rgbPuls value.
*/
uint rgbPuls() const;
};
}
/*
*
* Created on: Mar 1, 2021
* Author: astrisw
/**
* @brief This file contains the definition of the recognizedPackets for Astri MA.
*
* The recognizedPackets vector is a static member of the inaf::oasbo::Packets::AstriMa namespace.
* It stores tuples representing recognized packets, where each tuple contains three values:
* - The first value represents the packet type.
* - The second value represents the packet subtype.
* - The third value represents the packet length.
*
*/
#pragma once
#include <vector>
......@@ -15,6 +19,5 @@ static std::vector<std::tuple<size_t, size_t, size_t>> recognizedPackets = {
std::make_tuple(1, 1, 10014), std::make_tuple(1, 4, 12980),
std::make_tuple(2, 2, 12976), std::make_tuple(10, 1, 11098),
std::make_tuple(10, 2, 9566), std::make_tuple(10, 3, 9566),
std::make_tuple(15, 1, 10)
};
std::make_tuple(15, 1, 10) };
}
/*
* PacketLib.h
*
* Created on: Nov 24, 2022
* Author: valerio
*/
#ifndef INCLUDE_INAF_OAS_PACKET_STRUCTURE_JSON_H_
#define INCLUDE_INAF_OAS_PACKET_STRUCTURE_JSON_H_
#pragma once
#include <Base_Packet.h>
#include <fstream>
......@@ -20,21 +12,53 @@ template<class K, class V, class dummy_compare, class A>
using my_workaround_fifo_map = fifo_map<K, V, fifo_map_compare<K>, A>;
using my_json = basic_json<my_workaround_fifo_map>;
namespace inaf::oasbo::Packets {
class PacketStructureJson : public inaf::oasbo::PacketLib::BasePacketStructure {
/**
* @brief Represents a JSON packet structure for ASTRI DAQ.
*
* This class extends the BasePacketStructure class and provides functionality
* to convert JSON data into a tuple vector and read the structure from a source.
* The compatible json files are in config folder.
*/
class PacketStructureJson: public inaf::oasbo::Packets::BasePacketStructure {
protected:
static std::optional<Structure> convertToTupleVector(const my_json &data, uint &count);
/**
* @brief Converts JSON data into a tuple vector.
*
* @param data The JSON data to convert.
* @param count The count of tuples in the vector.
* @return An optional structure representing the tuple vector.
*/
static std::optional<Structure> convertToTupleVector(const my_json &data,
uint &count);
/**
* @brief Reads the packet structure from a source.
*
* @param source The source from which to read the structure.
* @return The structure read from the source.
*/
static Structure readStructureFromSource(std::string source);
public:
PacketStructureJson(std::string source) : BasePacketStructure(source, &readStructureFromSource){
/**
* @brief Constructs a PacketStructureJson object with the specified source.
*
* @param source The source from which to read the structure.
*/
PacketStructureJson(std::string source) :
BasePacketStructure(source, &readStructureFromSource) {
}
PacketStructureJson(const BasePacketStructure &other) : BasePacketStructure(other){
/**
* @brief Constructs a PacketStructureJson object from another BasePacketStructure object.
*
* @param other The BasePacketStructure object to copy from.
*/
PacketStructureJson(const BasePacketStructure &other) :
BasePacketStructure(other) {
}
};
}
#endif /* INCLUDE_INAF_OAS_PACKET_STRUCTURE_JSON_H_ */
#include <Astri_Horn_Generic.h>
#include <Astri_Horn_Recognized_Packet.h>
......
#include <Astri_MA_Generic.h>
#include <Astri_MA_Recognized_Packet.h>
......@@ -21,9 +20,10 @@ uint AstriMaGeneric::getTelescopeID() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.0 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.0 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -56,9 +56,10 @@ uint AstriMaGeneric::getSSC() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.3 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.3 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -67,9 +68,10 @@ uint AstriMaGeneric::getPacketLength() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.4 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.4 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -78,9 +80,10 @@ uint AstriMaGeneric::getYear() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.5 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.5 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -89,9 +92,10 @@ uint AstriMaGeneric::getMonth() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.6 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.6 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -100,9 +104,10 @@ uint AstriMaGeneric::getDay() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.7 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.7 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -111,9 +116,10 @@ uint AstriMaGeneric::getHour() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.8 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.8 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -122,9 +128,10 @@ uint AstriMaGeneric::getMinutes() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.9 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.9 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -133,9 +140,10 @@ uint AstriMaGeneric::getSeconds() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.10 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.10 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -144,9 +152,10 @@ bool AstriMaGeneric::getValidTime() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.11 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.11 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -155,9 +164,10 @@ uint AstriMaGeneric::getTimeTagNanoseconds() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.12 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.12 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -166,9 +176,10 @@ uint AstriMaGeneric::getEventCounter() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.13 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.13 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -177,9 +188,10 @@ bool AstriMaGeneric::getLid() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.14 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.14 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -188,9 +200,10 @@ bool AstriMaGeneric::fibSt() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.15 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.15 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -199,9 +212,10 @@ bool AstriMaGeneric::fibCont() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.16 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.16 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -210,9 +224,10 @@ bool AstriMaGeneric::fibPuls() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.17 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.17 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -221,9 +236,10 @@ uint AstriMaGeneric::rgbCont() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.18 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.18 to get TelescopeID." << std::endl;
return -1;
}
}
......@@ -232,9 +248,10 @@ uint AstriMaGeneric::rgbPuls() const {
if (val.has_value())
return val.value();
else {
time_t now = time(nullptr);
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[AstriMA Packet]\t" << "Cannot access field n.19 to get TelescopeID." << std::endl;
<< "]\t[AstriMA Packet]\t"
<< "Cannot access field n.19 to get TelescopeID." << std::endl;
return -1;
}
}
......
......@@ -8,9 +8,10 @@ Structure PacketStructureJson::readStructureFromSource(std::string source) {
Structure s_empty;
std::ifstream file;
file.open(source, std::ios::in);
if (!file.is_open()) {
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") <<"]\t[PacketStructure Json]\t" << "Could not open file: "
if (!file.is_open()) { // error handling
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[PacketStructure Json]\t" << "Could not open file: "
<< source << std::endl;
std::cerr << "\t Returning empty structure" << std::endl;
return s_empty;
......@@ -20,16 +21,20 @@ Structure PacketStructureJson::readStructureFromSource(std::string source) {
try {
file >> data;
} catch (nlohmann::detail::parse_error &ex) {
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") <<"]\t[PacketStructure Json]\t" << ex.what() << "\n\t\tReturning empty structure" << std::endl;
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[PacketStructure Json]\t" << ex.what()
<< "\n\t\tReturning empty structure" << std::endl;
return s_empty;
}
std::optional<Structure> s_tmp = convertToTupleVector(data, count);
file.close();
if (s_tmp.has_value())
return s_tmp.value();
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") <<"]\t[PacketStructure Json]\t" << "Returning empty structure" << std::endl;
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[PacketStructure Json]\t" << "Returning empty structure"
<< std::endl;
return s_empty;
}
......@@ -37,16 +42,18 @@ std::optional<Structure> PacketStructureJson::convertToTupleVector(
const my_json &data, uint &count) {
std::optional<Structure> out = Structure();
for (auto it = data.begin(); it != data.end(); ++it) {
if (it.value().is_object()) {
if (it.value().find("size") == it.value().end()
|| it.value().find("fields") == it.value().end()
if (it.value().is_object()) { // array found
if (it.value().find("size") == it.value().end() // error handling
|| it.value().find("fields") == it.value().end()
|| it.value().size() != 2) {
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") <<"]\t[PacketStructure Json]\t" << "Error in file: "
time_t now = time(nullptr);
std::cerr << "["
<< std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[PacketStructure Json]\t" << "Error in file: "
<< it.value().dump() << std::endl;
return std::nullopt;
}
for (uint i = 0; i < it.value()["size"]; i++) {
for (uint i = 0; i < it.value()["size"]; i++) { // convert to tuple vector the json array
std::optional<Structure> subArray = convertToTupleVector(
it.value()["fields"], count).value();
if (!subArray.has_value())
......@@ -59,10 +66,12 @@ std::optional<Structure> PacketStructureJson::convertToTupleVector(
out.value().insert(out.value().end(), subArray.value().begin(),
subArray.value().end());
}
} else {
if (!it.value().is_number_integer()) {
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") <<"]\t[PacketStructure Json]\t" << "Not an int: "
} else { // single field found
if (!it.value().is_number_integer()) { // error handling
time_t now = time(nullptr);
std::cerr << "["
<< std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[PacketStructure Json]\t" << "Not an int: "
<< it.value().dump() << std::endl;
return std::nullopt;
}
......