More fixes on binary data transmission

This commit is contained in:
Pax1601 2023-06-29 08:10:14 +02:00
parent 4d9dd364b6
commit 211cf48681
8 changed files with 213 additions and 167 deletions

View File

@ -22,7 +22,7 @@ export class Unit extends CustomMarker {
#alive: boolean = false;
#human: boolean = false;
#controlled: boolean = false;
#coalition: string = "";
#coalition: string = "neutral";
#country: number = 0;
#name: string = "";
#unitName: string = "";
@ -30,7 +30,7 @@ export class Unit extends CustomMarker {
#state: string = states[0];
#task: string = ""
#hasTask: boolean = false;
#position: LatLng = new LatLng(0, 0);
#position: LatLng = new LatLng(0, 0, 0);
#speed: number = 0;
#heading: number = 0;
#isTanker: boolean = false;
@ -50,13 +50,13 @@ export class Unit extends CustomMarker {
};
#targetID: number = 0;
#targetPosition: LatLng = new LatLng(0, 0);
#ROE: string = ROEs[0];
#reactionToThreat: string = reactionsToThreat[0];
#emissionsCountermeasures: string = emissionsCountermeasures[0];
#ROE: string = ROEs[1];
#reactionToThreat: string = reactionsToThreat[2];
#emissionsCountermeasures: string = emissionsCountermeasures[2];
#TACAN: TACAN = {
isOn: false,
XY: 'X',
callsign: '',
callsign: 'TKR',
channel: 0
};
#radio: Radio = {
@ -135,50 +135,50 @@ export class Unit extends CustomMarker {
setData(dataExtractor: DataExtractor) {
var updateMarker = !getMap().hasLayer(this);
var datumIndex = dataExtractor.extractUInt8();
if (datumIndex == DataIndexes.startOfData) {
while (datumIndex != DataIndexes.endOfData) {
datumIndex = dataExtractor.extractUInt8();
switch (datumIndex) {
case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break;
case DataIndexes.human: this.#human = dataExtractor.extractBool(); break;
case DataIndexes.controlled: this.#controlled = dataExtractor.extractBool(); updateMarker = true; break;
case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); break;
case DataIndexes.country: this.#country = dataExtractor.extractUInt8(); break;
case DataIndexes.name: this.#name = dataExtractor.extractString(); break;
case DataIndexes.unitName: this.#unitName = dataExtractor.extractString(); break;
case DataIndexes.groupName: this.#groupName = dataExtractor.extractString(); break;
case DataIndexes.state: this.#state = enumToState(dataExtractor.extractUInt8()); updateMarker = true; break;
case DataIndexes.task: this.#task = dataExtractor.extractString(); break;
case DataIndexes.hasTask: this.#hasTask = dataExtractor.extractBool(); break;
case DataIndexes.position: this.#position = dataExtractor.extractLatLng(); updateMarker = true; break;
case DataIndexes.speed: this.#speed = dataExtractor.extractFloat64(); updateMarker = true; break;
case DataIndexes.heading: this.#heading = dataExtractor.extractFloat64(); updateMarker = true; break;
case DataIndexes.isTanker: this.#isTanker = dataExtractor.extractBool(); break;
case DataIndexes.isAWACS: this.#isAWACS = dataExtractor.extractBool(); break;
case DataIndexes.onOff: this.#onOff = dataExtractor.extractBool(); break;
case DataIndexes.followRoads: this.#followRoads = dataExtractor.extractBool(); break;
case DataIndexes.fuel: this.#fuel = dataExtractor.extractUInt16(); break;
case DataIndexes.desiredSpeed: this.#desiredSpeed = dataExtractor.extractFloat64(); break;
case DataIndexes.desiredSpeedType: this.#desiredSpeedType = dataExtractor.extractBool() ? "GS" : "CAS"; break;
case DataIndexes.desiredAltitude: this.#desiredAltitude = dataExtractor.extractFloat64(); break;
case DataIndexes.desiredAltitudeType: this.#desiredAltitudeType = dataExtractor.extractFloat64() ? "AGL" : "ASL"; break;
case DataIndexes.leaderID: this.#leaderID = dataExtractor.extractUInt32(); break;
case DataIndexes.formationOffset: dataExtractor.extractOffset(); break;
case DataIndexes.targetID: this.#targetID = dataExtractor.extractUInt32(); break;
case DataIndexes.targetPosition: this.#targetPosition = dataExtractor.extractLatLng(); break;
case DataIndexes.ROE: this.#ROE = enumToROE(dataExtractor.extractUInt8()); break;
case DataIndexes.reactionToThreat: this.#reactionToThreat = enumToReactionToThreat(dataExtractor.extractUInt8()); break;
case DataIndexes.emissionsCountermeasures: this.#emissionsCountermeasures = enumToEmissioNCountermeasure(dataExtractor.extractUInt8()); break;
case DataIndexes.TACAN: this.#TACAN = dataExtractor.extractTACAN(); break;
case DataIndexes.radio: this.#radio = dataExtractor.extractRadio(); break;
case DataIndexes.generalSettings: this.#generalSettings = dataExtractor.extractGeneralSettings(); break;
case DataIndexes.ammo: this.#ammo = dataExtractor.extractAmmo(); break;
case DataIndexes.contacts: this.#contacts = dataExtractor.extractContacts(); break;
case DataIndexes.activePath: this.#activePath = dataExtractor.extractActivePath(); break;
}
var datumIndex = 0;
while (datumIndex != DataIndexes.endOfData) {
datumIndex = dataExtractor.extractUInt8();
switch (datumIndex) {
case DataIndexes.category: dataExtractor.extractString(); break;
case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break;
case DataIndexes.human: this.#human = dataExtractor.extractBool(); break;
case DataIndexes.controlled: this.#controlled = dataExtractor.extractBool(); updateMarker = true; break;
case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); break;
case DataIndexes.country: this.#country = dataExtractor.extractUInt8(); break;
case DataIndexes.name: this.#name = dataExtractor.extractString(); break;
case DataIndexes.unitName: this.#unitName = dataExtractor.extractString(); break;
case DataIndexes.groupName: this.#groupName = dataExtractor.extractString(); break;
case DataIndexes.state: this.#state = enumToState(dataExtractor.extractUInt8()); updateMarker = true; break;
case DataIndexes.task: this.#task = dataExtractor.extractString(); break;
case DataIndexes.hasTask: this.#hasTask = dataExtractor.extractBool(); break;
case DataIndexes.position: this.#position = dataExtractor.extractLatLng(); updateMarker = true; break;
case DataIndexes.speed: this.#speed = dataExtractor.extractFloat64(); updateMarker = true; break;
case DataIndexes.heading: this.#heading = dataExtractor.extractFloat64(); updateMarker = true; break;
case DataIndexes.isTanker: this.#isTanker = dataExtractor.extractBool(); break;
case DataIndexes.isAWACS: this.#isAWACS = dataExtractor.extractBool(); break;
case DataIndexes.onOff: this.#onOff = dataExtractor.extractBool(); break;
case DataIndexes.followRoads: this.#followRoads = dataExtractor.extractBool(); break;
case DataIndexes.fuel: this.#fuel = dataExtractor.extractUInt16(); break;
case DataIndexes.desiredSpeed: this.#desiredSpeed = dataExtractor.extractFloat64(); break;
case DataIndexes.desiredSpeedType: this.#desiredSpeedType = dataExtractor.extractBool() ? "GS" : "CAS"; break;
case DataIndexes.desiredAltitude: this.#desiredAltitude = dataExtractor.extractFloat64(); break;
case DataIndexes.desiredAltitudeType: this.#desiredAltitudeType = dataExtractor.extractFloat64() ? "AGL" : "ASL"; break;
case DataIndexes.leaderID: this.#leaderID = dataExtractor.extractUInt32(); break;
case DataIndexes.formationOffset: this.#formationOffset = dataExtractor.extractOffset(); break;
case DataIndexes.targetID: this.#targetID = dataExtractor.extractUInt32(); break;
case DataIndexes.targetPosition: this.#targetPosition = dataExtractor.extractLatLng(); break;
case DataIndexes.ROE: this.#ROE = enumToROE(dataExtractor.extractUInt8()); break;
case DataIndexes.reactionToThreat: this.#reactionToThreat = enumToReactionToThreat(dataExtractor.extractUInt8()); break;
case DataIndexes.emissionsCountermeasures: this.#emissionsCountermeasures = enumToEmissioNCountermeasure(dataExtractor.extractUInt8()); break;
case DataIndexes.TACAN: this.#TACAN = dataExtractor.extractTACAN(); break;
case DataIndexes.radio: this.#radio = dataExtractor.extractRadio(); break;
case DataIndexes.generalSettings: this.#generalSettings = dataExtractor.extractGeneralSettings(); break;
case DataIndexes.ammo: this.#ammo = dataExtractor.extractAmmo(); break;
case DataIndexes.contacts: this.#contacts = dataExtractor.extractContacts(); break;
case DataIndexes.activePath: this.#activePath = dataExtractor.extractActivePath(); break;
}
}
/* Dead units can't be selected */
this.setSelected(this.getSelected() && this.#alive && !this.getHidden())

View File

@ -36,6 +36,7 @@
<ClInclude Include="include\aircraft.h" />
<ClInclude Include="include\airunit.h" />
<ClInclude Include="include\commands.h" />
<ClInclude Include="include\datatypes.h" />
<ClInclude Include="include\measure.h" />
<ClInclude Include="include\groundunit.h" />
<ClInclude Include="include\helicopter.h" />
@ -52,6 +53,7 @@
<ClCompile Include="src\airunit.cpp" />
<ClCompile Include="src\commands.cpp" />
<ClCompile Include="src\core.cpp" />
<ClCompile Include="src\datatypes.cpp" />
<ClCompile Include="src\measure.cpp" />
<ClCompile Include="src\groundunit.cpp" />
<ClCompile Include="src\helicopter.cpp" />

View File

@ -48,6 +48,9 @@
<ClInclude Include="include\measure.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\datatypes.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\aircraft.cpp">
@ -92,5 +95,8 @@
<ClCompile Include="src\measure.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\datatypes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,49 @@
#pragma once
#include "framework.h"
#pragma pack(push, 1)
namespace DataTypes {
struct TACAN
{
bool isOn = false;
unsigned char channel = 40;
char XY = 'X';
char callsign[4];
};
struct Radio
{
unsigned int frequency = 124000000; // MHz
unsigned char callsign = 1;
unsigned char callsignNumber = 1;
};
struct GeneralSettings
{
bool prohibitJettison = false;
bool prohibitAA = false;
bool prohibitAG = false;
bool prohibitAfterburner = false;
bool prohibitAirWpn = false;
};
struct Ammo {
unsigned short quantity = 0;
char name[33];
unsigned char guidance = 0;
unsigned char category = 0;
unsigned char missileCategory = 0;
};
struct Contact {
unsigned int ID = 0;
unsigned char detectionMethod = 0;
};
}
#pragma pack(pop)
bool operator==(const DataTypes::TACAN& lhs, const DataTypes::TACAN& rhs);
bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs);
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs);
bool operator==(const DataTypes::Ammo& lhs, const DataTypes::Ammo& rhs);
bool operator==(const DataTypes::Contact& lhs, const DataTypes::Contact& rhs);

View File

@ -6,6 +6,7 @@
#include "measure.h"
#include "logger.h"
#include "commands.h"
#include "datatypes.h"
#include <chrono>
using namespace std::chrono;
@ -76,47 +77,6 @@ namespace State
};
};
#pragma pack(push, 1)
namespace DataTypes {
struct TACAN
{
bool isOn = false;
unsigned char channel = 40;
char XY = 'X';
char callsign[4];
};
struct Radio
{
unsigned int frequency = 124000000; // MHz
unsigned char callsign = 1;
unsigned char callsignNumber = 1;
};
struct GeneralSettings
{
bool prohibitJettison = false;
bool prohibitAA = false;
bool prohibitAG = false;
bool prohibitAfterburner = false;
bool prohibitAirWpn = false;
};
struct Ammo {
unsigned short quantity = 0;
char name[32];
unsigned char guidance = 0;
unsigned char category = 0;
unsigned char missileCategory = 0;
};
struct Contact {
unsigned int ID = 0;
unsigned char detectionMethod = 0;
};
}
#pragma pack(pop)
class Unit
{
public:
@ -168,7 +128,7 @@ public:
virtual void setHuman(bool newValue) { updateValue(human, newValue, DataIndex::human); }
virtual void setControlled(bool newValue) { updateValue(controlled, newValue, DataIndex::controlled); }
virtual void setCoalition(unsigned char newValue) { updateValue(coalition, newValue, DataIndex::coalition); }
virtual void setCountry(unsigned int newValue) { updateValue(country, newValue, DataIndex::country); }
virtual void setCountry(unsigned char newValue) { updateValue(country, newValue, DataIndex::country); }
virtual void setName(string newValue) { updateValue(name, newValue, DataIndex::name); }
virtual void setUnitName(string newValue) { updateValue(unitName, newValue, DataIndex::unitName); }
virtual void setGroupName(string newValue) { updateValue(groupName, newValue, DataIndex::groupName); }
@ -197,8 +157,8 @@ public:
virtual void setTACAN(DataTypes::TACAN newValue, bool force = false);
virtual void setRadio(DataTypes::Radio newValue, bool force = false);
virtual void setGeneralSettings(DataTypes::GeneralSettings newValue, bool force = false);
virtual void setAmmo(vector<DataTypes::Ammo> newAmmo) { ammo = newAmmo; }
virtual void setContacts(vector<DataTypes::Contact> newContacts) { contacts = newContacts; }
virtual void setAmmo(vector<DataTypes::Ammo> newValue) { updateValue(ammo, newValue, DataIndex::ammo); }
virtual void setContacts(vector<DataTypes::Contact> newValue) { updateValue(contacts, newValue, DataIndex::contacts); }
virtual void setActivePath(list<Coords> newValue);
/********** Getters **********/
@ -207,7 +167,7 @@ public:
virtual bool getHuman() { return human; }
virtual bool getControlled() { return controlled; }
virtual unsigned int getCoalition() { return coalition; }
virtual unsigned int getCountry() { return country; }
virtual unsigned char getCountry() { return country; }
virtual string getName() { return name; }
virtual string getUnitName() { return unitName; }
virtual string getGroupName() { return groupName; }
@ -244,14 +204,14 @@ protected:
unsigned int ID;
string category;
bool alive = true;
bool alive = false;
bool human = false;
bool controlled = false;
unsigned char coalition;
unsigned int country = NULL;
string name = "undefined";
string unitName = "undefined";
string groupName = "undefined";
unsigned char coalition = NULL;
unsigned char country = NULL;
string name = "";
string unitName = "";
string groupName = "";
unsigned char state = State::NONE;
string task = "";
bool hasTask = false;
@ -260,7 +220,7 @@ protected:
double heading = NULL;
bool isTanker = false;
bool isAWACS = false;
bool onOff = true;
bool onOff = false;
bool followRoads = false;
unsigned short fuel = 0;
double desiredSpeed = 0;
@ -329,7 +289,7 @@ protected:
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
for (auto el: datumValue)
for (auto& el: datumValue)
ss.write((const char*)&el, sizeof(T));
}
};

View File

@ -105,18 +105,27 @@ extern "C" DllExport int coreMissionData(lua_State * L)
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
lua_getglobal(L, "Olympus");
lua_getfield(L, -1, "missionData");
json::value missionData = luaTableToJSON(L, -1);
try
{
lua_getglobal(L, "Olympus");
lua_getfield(L, -1, "missionData");
json::value missionData = luaTableToJSON(L, -1);
if (missionData.has_object_field(L"unitsData"))
unitsManager->updateMissionData(missionData[L"unitsData"]);
if (missionData.has_object_field(L"airbases"))
airbases = missionData[L"airbases"];
if (missionData.has_object_field(L"bullseyes"))
bullseyes = missionData[L"bullseyes"];
if (missionData.has_object_field(L"mission"))
mission = missionData[L"mission"];
if (missionData.has_object_field(L"unitsData"))
unitsManager->updateMissionData(missionData[L"unitsData"]);
if (missionData.has_object_field(L"airbases"))
airbases = missionData[L"airbases"];
if (missionData.has_object_field(L"bullseyes"))
bullseyes = missionData[L"bullseyes"];
if (missionData.has_object_field(L"mission"))
mission = missionData[L"mission"];
}
catch (exception const& e)
{
log(e.what());
}
return(0);
}

View File

@ -0,0 +1,30 @@
#include "datatypes.h"
bool operator==(const DataTypes::TACAN& lhs, const DataTypes::TACAN& rhs)
{
return lhs.isOn == rhs.isOn && lhs.channel == rhs.channel && lhs.XY == rhs.XY && strcmp(lhs.callsign, rhs.callsign) == 0;
}
bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs)
{
return lhs.frequency == rhs.frequency && lhs.callsign == rhs.callsign && lhs.callsignNumber == rhs.callsignNumber;
}
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs)
{
return lhs.prohibitAA == rhs.prohibitAA && lhs.prohibitAfterburner == rhs.prohibitAfterburner && lhs.prohibitAG == rhs.prohibitAG &&
lhs.prohibitAirWpn == rhs.prohibitAirWpn && lhs.prohibitJettison == rhs.prohibitJettison;
}
bool operator==(const DataTypes::Ammo& lhs, const DataTypes::Ammo& rhs)
{
return lhs.category == rhs.category && lhs.guidance == rhs.guidance && lhs.missileCategory == rhs.missileCategory &&
lhs.quantity == rhs.quantity && strcmp(lhs.name, rhs.name) == 0;
}
bool operator==(const DataTypes::Contact& lhs, const DataTypes::Contact& rhs)
{
return lhs.detectionMethod == rhs.detectionMethod && lhs.ID == rhs.ID;
}

View File

@ -15,23 +15,6 @@ using namespace GeographicLib;
extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
// TODO: Make dedicated file
bool operator==(const DataTypes::TACAN& lhs, const DataTypes::TACAN& rhs)
{
return lhs.isOn == rhs.isOn && lhs.channel == rhs.channel && lhs.XY == rhs.XY && lhs.callsign == rhs.callsign;
}
bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs)
{
return lhs.frequency == rhs.frequency && lhs.callsign == rhs.callsign && lhs.callsignNumber == rhs.callsignNumber;
}
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs)
{
return lhs.prohibitAA == rhs.prohibitAA && lhs.prohibitAfterburner == rhs.prohibitAfterburner && lhs.prohibitAG == rhs.prohibitAG &&
lhs.prohibitAirWpn == rhs.prohibitAirWpn && lhs.prohibitJettison == rhs.prohibitJettison;
}
Unit::Unit(json::value json, unsigned int ID) :
ID(ID)
{
@ -138,42 +121,51 @@ void Unit::updateExportData(json::value json, double dt)
void Unit::updateMissionData(json::value json)
{
//if (json.has_number_field(L"fuel"))
// setFuel(short(json[L"fuel"].as_number().to_double() * 100));
//
//if (json.has_object_field(L"ammo")) {
// vector<DataTypes::Ammo> ammo;
// for (auto const& el : json[L"ammo"].as_object()) {
// DataTypes::Ammo ammoItem;
// auto ammoJson = el.second;
// ammoItem.quantity = ammoJson[L"count"].as_number().to_uint32();
// ammoItem.name = to_string(ammoJson[L"desc"][L"displayName"]);
// ammoItem.guidance = ammoJson[L"desc"][L"guidance"].as_number().to_uint32();
// ammoItem.category = ammoJson[L"desc"][L"category"].as_number().to_uint32();
// ammoItem.missileCategory = ammoJson[L"desc"][L"missileCategory"].as_number().to_uint32();
// ammo.push_back(ammoItem);
// }
// setAmmo(ammo);
//}
//
//if (json.has_object_field(L"contacts")) {
// vector<DataTypes::Contact> contacts;
// for (auto const& el : json[L"ammo"].as_object()) {
// DataTypes::Contact contactItem;
// auto contactJson = el.second;
// contactItem.ID = contactJson[L"object"][L"id_"].as_number().to_uint32();
//
// string detectionMethod = to_string(contactJson[L"detectionMethod"]);
// if (detectionMethod.compare("VISUAL")) contactItem.detectionMethod = 1;
// else if (detectionMethod.compare("OPTIC")) contactItem.detectionMethod = 2;
// else if (detectionMethod.compare("RADAR")) contactItem.detectionMethod = 4;
// else if (detectionMethod.compare("IRST")) contactItem.detectionMethod = 8;
// else if (detectionMethod.compare("RWR")) contactItem.detectionMethod = 16;
// else if (detectionMethod.compare("DLINK")) contactItem.detectionMethod = 32;
// contacts.push_back(contactItem);
// }
// setContacts(contacts);
//}
if (json.has_number_field(L"fuel")) {
setFuel(short(json[L"fuel"].as_number().to_double() * 100));
}
if (json.has_object_field(L"ammo")) {
vector<DataTypes::Ammo> ammo;
for (auto const& el : json[L"ammo"].as_object()) {
log(el.second.serialize());
DataTypes::Ammo ammoItem;
auto ammoJson = el.second;
ammoItem.quantity = ammoJson[L"count"].as_number().to_uint32();
string name = to_string(ammoJson[L"desc"][L"displayName"].as_string()).substr(0, sizeof(ammoItem.name) - 1);
strcpy_s(ammoItem.name, sizeof(ammoItem.name), name.c_str());
if (ammoJson[L"desc"].has_number_field(L"guidance"))
ammoItem.guidance = ammoJson[L"desc"][L"guidance"].as_number().to_uint32();
if (ammoJson[L"desc"].has_number_field(L"category"))
ammoItem.category = ammoJson[L"desc"][L"category"].as_number().to_uint32();
if (ammoJson[L"desc"].has_number_field(L"missileCategory"))
ammoItem.missileCategory = ammoJson[L"desc"][L"missileCategory"].as_number().to_uint32();
ammo.push_back(ammoItem);
}
setAmmo(ammo);
}
if (json.has_object_field(L"contacts")) {
vector<DataTypes::Contact> contacts;
for (auto const& el : json[L"contacts"].as_object()) {
DataTypes::Contact contactItem;
auto contactJson = el.second;
contactItem.ID = contactJson[L"object"][L"id_"].as_number().to_uint32();
string detectionMethod = to_string(contactJson[L"detectionMethod"]);
if (detectionMethod.compare("VISUAL")) contactItem.detectionMethod = 1;
else if (detectionMethod.compare("OPTIC")) contactItem.detectionMethod = 2;
else if (detectionMethod.compare("RADAR")) contactItem.detectionMethod = 4;
else if (detectionMethod.compare("IRST")) contactItem.detectionMethod = 8;
else if (detectionMethod.compare("RWR")) contactItem.detectionMethod = 16;
else if (detectionMethod.compare("DLINK")) contactItem.detectionMethod = 32;
contacts.push_back(contactItem);
}
setContacts(contacts);
}
if (json.has_boolean_field(L"hasTask"))
setHasTask(json[L"hasTask"].as_bool());
@ -191,11 +183,9 @@ void Unit::getData(stringstream& ss, unsigned long long time, bool refresh)
// p->heading = heading;
//}
const unsigned char startOfData = DataIndex::startOfData;
const unsigned char endOfData = DataIndex::endOfData;
ss.write((const char*)&ID, sizeof(ID));
ss.write((const char*)&startOfData, sizeof(startOfData));
for (auto d : updateTimeMap) {
if (d.second > time) {
switch (d.first) {