Skip to content

Commit

Permalink
ClientDataBufferedArea (WIP)
Browse files Browse the repository at this point in the history
ClientDataBufferedArea (WIP)

ClientDataBuffereArea (WIP)
  • Loading branch information
frankkopp committed Feb 19, 2023
1 parent a522d35 commit 599bd16
Show file tree
Hide file tree
Showing 10 changed files with 355 additions and 36 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ add_subdirectory(fbw-a380x/src/wasm/fbw_a380)

add_subdirectory(fbw-a32nx/src/wasm/extra-backend)
add_subdirectory(fbw-a380x/src/wasm/extra-backend)

add_subdirectory(fbw-a32nx/src/wasm/terronnd)
4 changes: 2 additions & 2 deletions fbw-a32nx/src/wasm/extra-backend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "")
# Configure the build as required
set(FBW_ROOT "../../../..")
set(AIRCRAFT "A32NX")
set(EXAMPLES "NO_EXAMPLES") # EXAMPLES, NO_EXAMPLES
set(LOG_LEVEL 4) # ZERO_LVL=0 CRITICAL_LVL=1 ERROR_LVL=2 WARN_LVL=3 INFO_LVL=4 DEBUG_LVL=5 VERBOSE=6 TRACE_LVL=7
set(EXAMPLES "EXAMPLES") # EXAMPLES, NO_EXAMPLES
set(LOG_LEVEL 5) # ZERO_LVL=0 CRITICAL_LVL=1 ERROR_LVL=2 WARN_LVL=3 INFO_LVL=4 DEBUG_LVL=5 VERBOSE=6 TRACE_LVL=7
set(LOGGING "LOG_LEVEL=${LOG_LEVEL}")

# Configure the build for the current OS - local on Windows or CI/dev-env on Linux
Expand Down
128 changes: 107 additions & 21 deletions fbw-a32nx/src/wasm/extra-backend/src/Example/ExampleModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#ifdef EXAMPLES

#include <string>

#include "logging.h"
#include "ExampleModule.h"
#include "NamedVariable.h"
Expand Down Expand Up @@ -127,7 +129,7 @@ bool ExampleModule::initialize() {
beaconLightSetEventPtr, UNITS.Bool, true, false, 0, 0);

// Data definition variables
std::vector <DataDefinition> exampleDataDef = {
std::vector<DataDefinition> exampleDataDef = {
{"LIGHT STROBE", 0, UNITS.Bool},
{"LIGHT WING", 0, UNITS.Bool},
{"ZULU TIME"},
Expand Down Expand Up @@ -161,6 +163,64 @@ bool ExampleModule::initialize() {
LOG_ERROR("Failed to request periodic data from sim");
}

// Big client data area owned by an external module
bigClientDataPtr =
dataManager->make_clientdataarea_var<BigClientData>("BIG CLIENT DATA");
bigClientDataPtr->setSkipChangeCheck(true);
bigClientDataPtr->addCallback([=]() {
// Big Client Data
LOG_INFO_BLOCK(
std::cout << "--- CALLBACK: BIG CLIENT DATA (External - reading)" << std::endl;
std::cout << bigClientDataPtr->str() << std::endl;
std::cout << "Bid Client Data data: " << std::endl;
auto s = std::string_view((const char*) &bigClientDataPtr->data().dataChunk, 100);
std::cout << bigClientDataPtr->data().dataChunk.size() << " bytes: " << s
<< " ... " << std::endl;
)
});
if (!bigClientDataPtr->requestPeriodicDataFromSim(SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET)) {
LOG_ERROR("Failed to request periodic data from sim");
}

// Metadata for the ClientDataBufferedAreaVariable test
metaDataPtr =
dataManager->make_clientdataarea_var<BufferedAreaMetaData>("HUGE CLIENT DATA META DATA");
metaDataPtr->setSkipChangeCheck(true);
metaDataPtr->addCallback([=]() {
hugeClientDataPtr->reserve(metaDataPtr->data().size);
// Huge Client Data Meta Data
LOG_INFO_BLOCK(
std::cout << "--- CALLBACK: HUGE CLIENT META DATA (External - reading)" << std::endl;
std::cout << metaDataPtr->str() << std::endl;
std::cout << "HUGE CLIENT DATA META DATA size = " << metaDataPtr->data().size
<< " fingerprint = " << metaDataPtr->data().hash << std::endl;
std::cout << std::endl;
);
});
if (!metaDataPtr->requestPeriodicDataFromSim(SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET)) {
LOG_ERROR("Failed to request periodic data from sim");
}

// ClientDataBufferedAreaVariable test
hugeClientDataPtr =
dataManager->make_clientdatabufferedarea_var<BYTE, SIMCONNECT_CLIENTDATA_MAX_SIZE>("HUGE CLIENT DATA");
hugeClientDataPtr->setSkipChangeCheck(true);
hugeClientDataPtr->addCallback([=]() {
LOG_INFO_BLOCK(
std::cout << "--- CALLBACK: HUGE CLIENT DATA (External - reading)" << std::endl;
std::cout << hugeClientDataPtr->str() << std::endl;
const uint64_t fingerPrintFvn = fingerPrintFVN(hugeClientDataPtr->getData());
std::cout << "HUGE CLIENT DATA size = " << hugeClientDataPtr->getData().size()
<< " fingerprint = " << fingerPrintFvn
<< " fingerprint match = " << std::boolalpha
<< (fingerPrintFvn == metaDataPtr->data().hash) << std::endl;
std::cout << std::endl;
)
});
if (!SUCCEEDED(hugeClientDataPtr->requestPeriodicDataFromSim(SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET))) {
LOG_ERROR("Failed to request periodic data from sim");
}

isInitialized = true;
LOG_INFO("ExampleModule initialized");
return true;
Expand All @@ -181,13 +241,34 @@ bool ExampleModule::update([[maybe_unused]] sGaugeDrawData* pData) {
// It is ready after the click on "READY TO FLY"
if (!msfsHandler->getA32NxIsReady()) return true;

// Un-throttled tests
// if (metaDataPtr->hasChanged()) {
// // Huge Client Data Meta Data
// LOG_INFO("--- HUGE CLIENT META DATA (External - reading)");
// hugeClientDataPtr->reserve(metaDataPtr->data().size);
// std::cout << metaDataPtr->str() << std::endl;
// std::cout << "Huge client data size: " << metaDataPtr->data().size << std::endl;
// std::cout << "Huge client data hash: " << metaDataPtr->data().hash << std::endl;
// }

// if (hugeClientDataPtr->hasChanged()) {
// LOG_INFO("--- HUGE CLIENT DATA (External - reading)");
// std::cout << hugeClientDataPtr->str() << std::endl;
// std::cout << "Huge client data size: " << hugeClientDataPtr->getData().size() << std::endl;
// std::string s(hugeClientDataPtr->getData().data(), hugeClientDataPtr->getData().size());
// auto fingerprint = fingerPrintFVN(s);
// std::cout << "Fingerprint: " << fingerprint << std::endl;
// std::cout << "Fingerprint is " << (fingerprint == metaDataPtr->data().hash ? "equal" : "not equal") << std::endl;
// }

// Use this to throttle output frequency while you are debugging
if (msfsHandler->getTickCounter() % 100 == 0) {

[[maybe_unused]] const FLOAT64 timeStamp = msfsHandler->getTimeStamp();
[[maybe_unused]] const UINT64 tickCounter = msfsHandler->getTickCounter();



// difference if using different units
/*
debugLVAR3Ptr->setAndWriteToSim(msfsHandler->getTickCounter());
Expand All @@ -200,7 +281,7 @@ bool ExampleModule::update([[maybe_unused]] sGaugeDrawData* pData) {
LOG_INFO("debugLVAR2Ptr DEBUG_LVAR " + std::to_string(debugLVAR2Ptr->updateFromSim(msfsHandler->getTimeStamp(), msfsHandler->getTickCounter())));
LOG_INFO("debugLVAR3Ptr DEBUG_LVAR " + std::to_string(debugLVAR3Ptr->updateFromSim(msfsHandler->getTimeStamp(), msfsHandler->getTickCounter())));
*/
// this second read of the duplicate should not trigger a read from the sim
// this second read of the duplicate should not trigger a read from the sim
/*
LOG_INFO("debugLVAR4Ptr DEBUG_LVAR "
+ std::to_string(reinterpret_cast<int>(debugLVARPtr.get())) + " "
Expand Down Expand Up @@ -246,6 +327,7 @@ bool ExampleModule::update([[maybe_unused]] sGaugeDrawData* pData) {
// Testing client data variables
// Can be tested together with https://github.com/frankkopp/fbw-cpp-framework-test

/*
// This local data sent to other clients
LOG_INFO("--- EXAMPLE CLIENT DATA (Owning - sending)");
std::cout << exampleClientDataPtr->str() << std::endl;
Expand All @@ -262,7 +344,9 @@ bool ExampleModule::update([[maybe_unused]] sGaugeDrawData* pData) {
exampleClientDataPtr->data().anInt16++;
exampleClientDataPtr->data().anInt8++;
// exampleClientDataPtr->writeDataToSim();
*/

/*
// This is external data from an external client
LOG_INFO("--- EXAMPLE 2 CLIENT DATA (External - reading)");
std::cout << exampleClientData2Ptr->str() << std::endl;
Expand All @@ -275,7 +359,28 @@ bool ExampleModule::update([[maybe_unused]] sGaugeDrawData* pData) {
std::cout << "INT64 " << exampleClientData2Ptr->data().anInt64 << std::endl;
std::cout << "FLOAT32 " << exampleClientData2Ptr->data().aFloat32 << std::endl;
std::cout << "FLOAT64 " << exampleClientData2Ptr->data().aFloat64 << std::endl;
*/

/*
LOG_INFO("--- DataDefinition Example)");
std::cout << "strobeLightSwitch = " << exampleDataPtr->data().strobeLightSwitch << std::endl;
std::cout << "wingLightSwitch = " << exampleDataPtr->data().wingLightSwitch << std::endl;
std::cout << "zuluTime = " << exampleDataPtr->data().zuluTime << std::endl;
std::cout << "localTime = " << exampleDataPtr->data().localTime << std::endl;
std::cout << "absoluteTime = " << INT64(exampleDataPtr->data().absoluteTime) << std::endl;
std::cout << "aircraftTTitle = " << exampleDataPtr->data().aircraftTTitle << std::endl;
*/

/*
LOG_INFO("--- LVAR Example)");
std::cout << "debugLVARPtr = " << debugLVARPtr->get() << " changed? "
<< (debugLVARPtr->hasChanged() ? "yes" : "no")
<< " debugLVARPtr time = " << msfsHandler->getTimeStamp()
<< " tick = " << msfsHandler->getTickCounter()
<< std::endl;
// Set a variable which does not auto write
// debugLVARPtr->setAndWriteToSim(debugLVARPtr->get() + 1);
*/

// Read vars which auto update each tick
/*
Expand Down Expand Up @@ -322,25 +427,6 @@ bool ExampleModule::update([[maybe_unused]] sGaugeDrawData* pData) {
<< std::endl;
*/

LOG_INFO("--- DataDefinition Example)");
// TODO: the char array might need a check for null termination - it could have overwritten
// the rest of the struct and beyond
std::cout << "strobeLightSwitch = " << exampleDataPtr->data().strobeLightSwitch << std::endl;
std::cout << "wingLightSwitch = " << exampleDataPtr->data().wingLightSwitch << std::endl;
std::cout << "zuluTime = " << exampleDataPtr->data().zuluTime << std::endl;
std::cout << "localTime = " << exampleDataPtr->data().localTime << std::endl;
std::cout << "absoluteTime = " << INT64(exampleDataPtr->data().absoluteTime) << std::endl;
std::cout << "aircraftTTitle = " << exampleDataPtr->data().aircraftTTitle << std::endl;

LOG_INFO("--- LVAR Example)");
std::cout << "debugLVARPtr = " << debugLVARPtr->get() << " changed? "
<< (debugLVARPtr->hasChanged() ? "yes" : "no")
<< " debugLVARPtr time = " << msfsHandler->getTimeStamp()
<< " tick = " << msfsHandler->getTickCounter()
<< std::endl;
// Set a variable which does not auto write
// debugLVARPtr->setAndWriteToSim(debugLVARPtr->get() + 1);

// Test writing an aircraft variable by toggling the beacon light switch
// Immediate write
/*
Expand Down
32 changes: 32 additions & 0 deletions fbw-a32nx/src/wasm/extra-backend/src/Example/ExampleModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#ifndef FLYBYWIRE_EXAMPLEMODULE_H
#define FLYBYWIRE_EXAMPLEMODULE_H

#include <array>

#include "Module.h"
#include "DataManager.h"
#include "Event.h"
Expand Down Expand Up @@ -74,6 +76,22 @@ class ExampleModule : public Module {
} __attribute__((packed));
std::shared_ptr<ClientDataAreaVariable<ExampleClientData2>> exampleClientData2Ptr;

// ClientDataArea variable for testing
struct BigClientData {
std::array<BYTE, SIMCONNECT_CLIENTDATA_MAX_SIZE> dataChunk;
} __attribute__((packed));
std::shared_ptr<ClientDataAreaVariable<BigClientData>> bigClientDataPtr;

// ClientDataArea variable for meta data for ClientDataBufferedAreaVariable
struct BufferedAreaMetaData {
UINT64 size;
UINT64 hash;
} __attribute__((packed));
std::shared_ptr<ClientDataAreaVariable<BufferedAreaMetaData>> metaDataPtr;

// ClientDataBufferedArea variable for testing
std::shared_ptr<ClientDataBufferedAreaVariable<BYTE, SIMCONNECT_CLIENTDATA_MAX_SIZE>> hugeClientDataPtr;

// Events
EventPtr beaconLightSetEventPtr;
[[maybe_unused]] CallbackID beaconLightSetCallbackID{};
Expand All @@ -99,6 +117,20 @@ class ExampleModule : public Module {
bool postUpdate(sGaugeDrawData* pData) override;
bool shutdown() override;

private:

// Fowler-Noll-Vo hash function
uint64_t fingerPrintFVN(std::vector<BYTE> &data) {
const uint64_t FNV_offset_basis = 14695981039346656037ULL;
const uint64_t FNV_prime = 1099511628211ULL;
uint64_t hash = FNV_offset_basis;
for (BYTE c: data) {
hash ^= static_cast<uint64_t>(c);
hash *= FNV_prime;
}
return hash;
}

};

#endif //FLYBYWIRE_EXAMPLEMODULE_H
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ class ClientDataAreaVariable : public SimObjectBase {
* sim.<p/>
* This method can be very efficient as the sim will only send the data when it is required and
* the DataManager will not have to manage the updates.<p/>
* If this is used make sure to have autoRead set to false otherwise this will throw an error.
* If this is used make sure to have autoRead set to false otherwise this will throw an error.<p/>
* OBS: If a repeating periodic update is requested the data will be updated and callbacks will
* be called even if the sim if paused
* @param period the SIMCONNECT_CLIENT_DATA_PERIOD with which the sim should send the data
* @param periodFlags the SIMCONNECT_CLIENT_DATA_REQUEST_FLAG with which the sim should send the data
* @param origin The number of Period events that should elapse before transmission of the data
Expand Down Expand Up @@ -226,10 +228,8 @@ class ClientDataAreaVariable : public SimObjectBase {

void processSimData(const SIMCONNECT_RECV* pData, FLOAT64 simTime, UINT64 tickCounter) override {
LOG_TRACE("ClientDataAreaVariable: Received client data: " + name);
const auto pClientData = reinterpret_cast<const SIMCONNECT_RECV_CLIENT_DATA*>(pData);

SIMPLE_ASSERT(pClientData->dwRequestID == requestId,
"ClientDataAreaVariable::processSimData: Request ID mismatch: " + name);
const auto pClientData = reinterpret_cast<const SIMCONNECT_RECV_CLIENT_DATA*>(pData);

// if not required then skip the rather expensive check for change
if (skipChangeCheck || std::memcmp(&pClientData->dwData, &this->dataStruct, sizeof(T)) != 0) {
Expand Down
Loading

0 comments on commit 599bd16

Please sign in to comment.