Hi all, I am trying to unpack the OutGuage data in C++. I have seen that in the snippet provided by @angelo234 (link to thread https://www.beamng.com/threads/outgauge-support-specifications.82507/) you can simply do: Code: outgauge_pack = struct.unpack('I3sxH2B7f2I3f15sx15sx', data) to "unpack" the OutGuage data in Python. I am looking for a way to do this in C++. Any suggestions/ideas? I managed to get some stuff working (namely carName (partially, shows bea (then gibberish) then m followed by more gibberish), gear (partially, seems like it is trying to be presented as a Unicode character as when I shift between neutral to 5th it changes icons however, reverse and 6th don't display anything), speed, rpm, turbo, engine temp, fuel, oil temp, throttle, brake, clutch. The other stuff like time (shows 0? Not sure if that is expected behavior), info (always shows 57344), playerID (nothing), oilPressure (always shows 0, not sure if that is expected behaviour), dashLights (always shows 1910), showLights (always 0) and both Display1 and Display2 (nothing). Here is my code: Code: // struct I3sxH2B7f2I3f15sx15sx in python: // make unsigned int called time unsigned int time; // make 3 byte char called carName char carName[3]; // make pad byte called pad1 char pad1; // make unsiogned short called info unsigned short info; // make 2 unsigned char called gear AND playerID unsigned char gear, playerID; // make 7 floats called speed, rpm, turbo, engineTemp, fuel, oilPressure, oilTemp float speed, rpm, turbo, engineTemp, fuel, oilPressure, oilTemp; // make 2 unsigned ints called dashLights and showLights unsigned int dashLights, showLights; // make 3 floats called throttle, brake, clutch float throttle, brake, clutch; // make 15 byte char called display1 char display1[15]; // make pad byte called pad2 char pad2; // make 15 byte char called display2 char display2[15]; // WORKING: carName (partial), gear (partial), speed, rpm, turbo, engine temp, fuel, oil temp, throttle, brake, clutch // unpack the data memcpy(&time, buf, 4); memcpy(&carName, buf + 4, 3); memcpy(&pad1, buf + 7, 1); memcpy(&info, buf + 8, 2); memcpy(&gear, buf + 10, 1); memcpy(&playerID, buf + 11, 1); memcpy(&speed, buf + 12, 4); memcpy(&rpm, buf + 16, 4); memcpy(&turbo, buf + 20, 4); memcpy(&engineTemp, buf + 24, 4); memcpy(&fuel, buf + 28, 4); memcpy(&oilPressure, buf + 32, 4); memcpy(&oilTemp, buf + 36, 4); memcpy(&dashLights, buf + 40, 4); memcpy(&showLights, buf + 44, 4); memcpy(&throttle, buf + 48, 4); memcpy(&brake, buf + 52, 4); memcpy(&clutch, buf + 56, 4); memcpy(&display1, buf + 60, 15); memcpy(&pad2, buf + 75, 1); memcpy(&display2, buf + 76, 15); // display the data cout << "Time: " << time << endl; cout << "Car Name: " << carName << endl; cout << "Info: " << info << endl; cout << "Gear: " << gear << endl; cout << "Player ID: " << playerID << endl; cout << "Speed: " << speed << endl; cout << "RPM: " << rpm << endl; cout << "Turbo: " << turbo << endl; cout << "Engine Temp: " << engineTemp << endl; cout << "Fuel: " << fuel << endl; cout << "Oil Pressure: " << oilPressure << endl; cout << "Oil Temp: " << oilTemp << endl; cout << "Dash Lights: " << dashLights << endl; cout << "Show Lights: " << showLights << endl; cout << "Throttle: " << throttle << endl; cout << "Brake: " << brake << endl; cout << "Clutch: " << clutch << endl; cout << "Display 1: " << display1 << endl; cout << "Display 2: " << display2 << endl; cout << "Message from " << inet_ntop(AF_INET, &client.sin_addr, clientIp, 256) << " on port " << ntohs(client.sin_port) << endl; This is the output from the terminal after running this: Code: Car Name: bea╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠m╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ Info: 57344 Gear: ☻ Player ID: Speed: 9.85487 RPM: 4687.34 Turbo: 0.730583 Engine Temp: 85.7656 Fuel: 0.997031 Oil Pressure: 0 Oil Temp: 90.4124 Dash Lights: 1910 Show Lights: 0 Throttle: 1 Brake: 0 Clutch: 0 Display 1: Display 2: Message from 127.0.0.1 on port 50289 Any ideas on how to get everything else functional? Thanks --- Post updated ---
That's the offical one, see lua\vehicle\extensions\outgauge.lua Code: typedef struct outgauge_t { unsigned time; // I time in milliseconds (to check order) char car[4]; // 4s Car name unsigned short flags; // H Info (see OG_x below) char gear; // c Reverse:0, Neutral:1, First:2... char plid; // c Unique ID of viewed player (0 = none) float speed; // f M/S float rpm; // f RPM float turbo; // f BAR float engTemp; // f C float fuel; // f 0 to 1 float oilPressure; // f BAR float oilTemp; // f C unsigned dashLights; // I Dash lights available (see DL_x below) unsigned showLights; // I Dash lights currently switched on float throttle; // f 0 to 1 float brake; // f 0 to 1 float clutch; // f 0 to 1 char display1[16]; // c Usually Fuel char display2[16]; // c Usually Settings int id; // i optional - only if OutGauge ID is specified } outgauge_t; let me compare Btw, the format seems to be rather "I4sHccfffffffIIfffcci" You don't need to 'unpack' the data in c/c++. I.e. Code: // if the data is in the pointer buf: //char* buf = <> outgauge_t* data = (outgauge_t*)buf; cout << "Dash Lights: " << data->dashLights << endl; I hope that helps Otherwise let us know
It seems like there might be a typo in your request, but assuming you're asking about "Gauge in C++," I'll provide you with some information. If you had something else in mind, please clarify. In C++, a gauge could refer to a graphical representation of a value within a specific range, often used in user interfaces to display measurements or progress visually. To create a simple text-based gauge, you can use ASCII characters to represent the progress. Here's a basic example: cpp #include <iostream> void drawGauge(int value, int maxValue, int gaugeWidth) { int progress = (value * gaugeWidth) / maxValue; std::cout << "["; for (int i = 0; i < gaugeWidth; ++i) { if (i < progress) { std::cout << "="; } else { std::cout << " "; } } std::cout << "] " << (progress * 100 / gaugeWidth) << "%\n"; } int main() { int value = 75; // Replace this with your actual value int maxValue = 100; int gaugeWidth = 20; drawGauge(value, maxValue, gaugeWidth); return 0; } This example defines a drawGauge function that takes a value, a maximum value, and the width of the gauge. It then calculates the progress and prints a simple text-based gauge to the console. You can customize this code based on your specific requirements or integrate it into a graphical user interface if needed.
To unpack OutGuage data in C++, you need to follow a systematic approach based on the structure and format of the data. Below is a generic guide: Understand Data Structure: Review the OutGuage data format and identify the structure of the information it contains. This could include details about data types, sizes, and the arrangement of fields. Use Binary Operations or Serialization: Implement binary operations or leverage serialization libraries in C++ to interpret the raw data. Bitwise operations may be necessary to extract specific bits or bytes. Define Data Structures: Define C++ structures or classes that mirror the structure of the OutGuage data. Ensure proper alignment and data types to match the expected format. Read and Extract Data: Read the binary data into your defined structures using appropriate C++ I/O operations. Extract relevant information from each field according to the OutGuage data specifications. Handle Endianness: Be mindful of endianness differences between systems. If the data uses a specific endianness, ensure that your C++ code handles it correctly during unpacking. Verify and Validate: Implement validation checks to ensure the integrity of the unpacked data. Verify checksums or any other integrity measures defined in the OutGuage data. Testing: Conduct thorough testing with sample data to validate the correctness of your unpacking algorithm. This step is crucial for ensuring your C++ code accurately interprets various scenarios. Error Handling: Implement robust error-handling mechanisms to manage unexpected situations, such as corrupt or malformed data. Here's a simplified example assuming a binary data structure: cpp #include <iostream> #include <fstream> #pragma pack(1) // Ensure no padding in structures struct OutGuageData { int sensor1; float sensor2; // Add more fields as per the actual data structure }; int main() { std::ifstream inFile("outguage_data.bin", std::ios::binary); if (!inFile) { std::cerr << "Error opening file\n"; return 1; } OutGuageData outGuage; inFile.read(reinterpret_cast<char*>(&outGuage), sizeof(outGuage)); // Now outGuage contains the unpacked data, access fields as needed inFile.close(); return 0; } Note: This is a simplified example, and the actual implementation would depend on the specifics of the OutGuage data format. Always refer to the documentation or specifications provided for accurate unpacking.
I'm sure you've already gotten plenty of help, but just in case you want an actual example, here's mine vulcan-dev/bog: BeamNG OutGauge Example (github.com) Note: This is C, but you can very easily convert it to C++