Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,3 @@ BasedOnStyle: Chromium
---
Language: Cpp
ColumnLimit: 140
AlignArrayOfStructures: Left
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveDeclarations: Consecutive
AlignConsecutiveShortCaseStatements:
Enabled: true




66 changes: 43 additions & 23 deletions fbw-common/src/wasm/terronnd/src/navigationdisplay/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <MSFS/Render/stb_image.h>
#pragma clang diagnostic pop
#include <cstdint>
#include <cstring>
#include <iostream>
#include <string_view>
#include <vector>
Expand Down Expand Up @@ -39,11 +40,11 @@ class DisplayBase {
public:
struct NdConfiguration {
types::Length range;
std::uint8_t mode;
bool terrOnNd;
bool terrOnVd;
float potentiometer;
bool powered;
std::uint8_t mode;
bool terrOnNd;
bool terrOnVd;
float potentiometer;
bool powered;
};

DisplayBase(const DisplayBase&) = delete;
Expand All @@ -54,21 +55,24 @@ class DisplayBase {
virtual void update(const NdConfiguration& config) = 0;

DisplaySide side() const;
void destroy();
void render(sGaugeDrawData* pDrawData);
void destroy();
void render(sGaugeDrawData* pDrawData);

protected:
DisplaySide _side;
NdConfiguration _configuration;
std::size_t _frameBufferSize;
int _nanovgImage;
NVGcontext* _context;
std::shared_ptr<simconnect::ClientDataArea<types::ThresholdData>> _thresholds;
DisplaySide _side;
NdConfiguration _configuration;
std::size_t _frameBufferSize;
int _nanovgImage;
NVGcontext* _context;
std::shared_ptr<simconnect::ClientDataArea<types::ThresholdData>> _thresholds;
std::shared_ptr<simconnect::ClientDataAreaBuffered<std::uint8_t, SIMCONNECT_CLIENTDATA_MAX_SIZE>> _frameData;

DisplayBase(DisplaySide side, FsContext context);

void destroyImage();

static constexpr std::size_t MaxFrameByteCount = 4 * 1024 * 1024;
static constexpr std::uint32_t MaxFrameDimension = 4096;
};

/**
Expand All @@ -85,12 +89,12 @@ template <std::string_view const& NdMinElevation,
class Display : public DisplayBase {
private:
std::shared_ptr<simconnect::LVarObject<NdMinElevation, NdMinElevationMode, NdMaxElevation, NdMaxElevationMode>> _ndThresholdData;
bool _ignoreNextFrame;
bool _ignoreNextFrame;

void resetNavigationDisplayData() {
this->_ndThresholdData->template value<NdMinElevation>() = -1;
this->_ndThresholdData->template value<NdMinElevation>() = -1;
this->_ndThresholdData->template value<NdMinElevationMode>() = 0;
this->_ndThresholdData->template value<NdMaxElevation>() = -1;
this->_ndThresholdData->template value<NdMaxElevation>() = -1;
this->_ndThresholdData->template value<NdMaxElevationMode>() = 0;
this->_ndThresholdData->writeValues();
}
Expand All @@ -107,7 +111,8 @@ class Display : public DisplayBase {
* @param side The display side
* @param context The gauge context
*/
Display(simconnect::Connection& connection, DisplaySide side, FsContext context) : DisplayBase(side, context), _ndThresholdData(nullptr) {
Display(simconnect::Connection& connection, DisplaySide side, FsContext context)
: DisplayBase(side, context), _ndThresholdData(nullptr), _ignoreNextFrame(false) {
this->_ndThresholdData = connection.lvarObject<NdMinElevation, NdMinElevationMode, NdMaxElevation, NdMaxElevationMode>();

// write initial values to avoid invalid drawings
Expand All @@ -123,18 +128,24 @@ class Display : public DisplayBase {
this->_nanovgImage =
nvgCreateImageMem(this->_context, 0, this->_frameData->data().data(), static_cast<int>(this->_frameBufferSize));
if (this->_nanovgImage == 0) {
std::cerr << fmt::format("TERR ON ND: Unable to create the image from the stream. Reason: {}", stbi_failure_reason());
const char* reason = stbi_failure_reason();
std::cerr << fmt::format("TERR ON ND: Unable to create the image from the stream. Reason: {}",
reason != nullptr ? reason : "unknown")
<< std::endl;
}

return;
}

// Otherwise, decode the PNG manually and update the existing image
int decodedWidth, decodedHeight;
int decodedWidth, decodedHeight;
uint8_t* decodedImage = stbi_load_from_memory(this->_frameData->data().data(), static_cast<int>(this->_frameBufferSize),
&decodedWidth, &decodedHeight, nullptr, 4);
if (decodedImage == nullptr) {
std::cerr << fmt::format("TERR ON ND: Unable to create the image from the stream. Reason: {}", stbi_failure_reason());
const char* reason = stbi_failure_reason();
std::cerr << fmt::format("TERR ON ND: Unable to create the image from the stream. Reason: {}",
reason != nullptr ? reason : "unknown")
<< std::endl;
return;
}

Expand Down Expand Up @@ -162,17 +173,26 @@ class Display : public DisplayBase {
this->_thresholds->requestArea(SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET);
this->_thresholds->setAlwaysChanges(true);
this->_thresholds->setOnChangeCallback([=]() {
this->_frameBufferSize = this->_thresholds->data().frameByteCount;
const std::uint32_t frameByteCount = this->_thresholds->data().frameByteCount;
if (frameByteCount == 0 || frameByteCount > DisplayBase::MaxFrameByteCount) {
// corrupted or incompatible packet: allocating this size could kill the module
std::cerr << "TERR ON ND: Ignoring thresholds packet with implausible frame size: " << frameByteCount << std::endl;
this->_frameBufferSize = 0;
this->_frameData->reserve(0);
return;
}

this->_frameBufferSize = frameByteCount;
this->_frameData->reserve(this->_frameBufferSize);
this->_ignoreNextFrame =
this->_ignoreNextFrame &&
(this->_thresholds->data().firstFrame == 0 || this->_configuration.mode != this->_thresholds->data().displayMode ||
this->_configuration.range != (this->_thresholds->data().displayRange * types::nauticmile));

if (!this->_ignoreNextFrame) {
this->_ndThresholdData->template value<NdMinElevation>() = this->_thresholds->data().lowerThreshold;
this->_ndThresholdData->template value<NdMinElevation>() = this->_thresholds->data().lowerThreshold;
this->_ndThresholdData->template value<NdMinElevationMode>() = this->_thresholds->data().lowerThresholdMode;
this->_ndThresholdData->template value<NdMaxElevation>() = this->_thresholds->data().upperThreshold;
this->_ndThresholdData->template value<NdMaxElevation>() = this->_thresholds->data().upperThreshold;
this->_ndThresholdData->template value<NdMaxElevationMode>() = this->_thresholds->data().upperThresholdMode;
this->_ndThresholdData->writeValues();
}
Expand Down
49 changes: 11 additions & 38 deletions fbw-common/src/wasm/terronnd/src/simconnect/clientdataarea.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ class ClientDataAreaBase : public base::Changeable {
friend Connection;

protected:
HANDLE* _connection;
HANDLE* _connection;
std::uint32_t _dataId;
std::uint32_t _definitionId;
bool _alwaysChanges;
bool _alwaysChanges;

ClientDataAreaBase(HANDLE* connection, std::uint32_t dataId, std::uint32_t definitionId)
: _connection(connection), _dataId(dataId), _definitionId(definitionId), _alwaysChanges(false) {}
Expand Down Expand Up @@ -178,22 +178,26 @@ class ClientDataAreaBuffered : public ClientDataAreaBase {

private:
std::vector<T> _content;
std::size_t _expectedByteCount;
std::size_t _receivedBytes;
std::size_t _expectedByteCount{};
std::size_t _receivedBytes{};

ClientDataAreaBuffered(HANDLE* connection, std::uint32_t dataId, std::uint32_t definitionId)
: ClientDataAreaBase(connection, dataId, definitionId), _content() {}
: ClientDataAreaBase(connection, dataId, definitionId), _content(), _expectedByteCount(0), _receivedBytes(0) {}
ClientDataAreaBuffered(const ClientDataAreaBuffered<T, ChunkSize>&) = delete;

ClientDataAreaBuffered<T, ChunkSize>& operator=(const ClientDataAreaBuffered<T, ChunkSize>&) = delete;

void receivedData(void* data) override {
if (this->_receivedBytes >= this->_expectedByteCount) {
return;
}

std::size_t remainingBytes = this->_expectedByteCount - this->_receivedBytes;
if (remainingBytes > ChunkSize) {
remainingBytes = ChunkSize;
}

std::memcpy(&this->_content.data()[this->_receivedBytes], data, remainingBytes);
std::memcpy(&this->_content[this->_receivedBytes], data, remainingBytes);
this->_receivedBytes += remainingBytes;

if (this->_receivedBytes >= this->_expectedByteCount) {
Expand All @@ -220,45 +224,14 @@ class ClientDataAreaBuffered : public ClientDataAreaBase {
*/
bool allocateArea(bool readOnlyForOthers) { return this->allocateClientArea(readOnlyForOthers, ChunkSize); }

/**
* @brief Sets an area object and sends it to the receivers
* @return true if the are is send
* @return false if the setting failed
*/
bool setArea() {
if (*this->_connection == 0) {
return false;
}

HRESULT result = S_OK;
std::size_t sentBytes = 0;

while (sentBytes < this->_content.size()) {
std::size_t remainingBytes = this->_content.size() - sentBytes;

if (remainingBytes >= ChunkSize) {
result &= SimConnect_SetClientData(*this->_connection, this->_dataId, this->_definitionId, SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT,
0, ChunkSize, &this->_content.data()[sentBytes]);
sentBytes += ChunkSize;
} else {
std::array<T, ChunkSize> buffer{};
std::memcpy(buffer.data(), &this->_content.data()[sentBytes], remainingBytes);
result &= SimConnect_SetClientData(*this->_connection, this->_dataId, this->_definitionId, SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT,
0, ChunkSize, buffer.data());
sentBytes += remainingBytes;
}
}

return SUCCEEDED(result);
}

/**
* @brief Reserves internal data to receive the data
* @param expectedByteCount Number of expected bytes in streaming cases
*/
void reserve(std::size_t expectedByteCount) {
this->_expectedByteCount = expectedByteCount;
this->_content.reserve(expectedByteCount);
this->_content.resize(expectedByteCount);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely sure if this was an issue, but as size never gets initialized with reserve, the later usage with memcpy and the underlying pointer is not really defined when size = 0.

Image

this->_receivedBytes = 0;
}

Expand Down
Loading