"Unpack" OutGuage data in C++

Discussion in 'Programming' started by MegaBytesMe, Nov 8, 2022.

  1. MegaBytesMe

    MegaBytesMe
    Expand Collapse

    Joined:
    May 9, 2018
    Messages:
    12
    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 ---
     
  2. tdev

    tdev
    Expand Collapse
    Developer
    BeamNG Team

    Joined:
    Aug 3, 2012
    Messages:
    3,031
    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 :)
     
    #2 tdev, Nov 8, 2022
    Last edited: Nov 8, 2022
  3. Urmila

    Urmila
    Expand Collapse

    Joined:
    Dec 28, 2023
    Messages:
    1
    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.
     
  4. umarkhan

    umarkhan
    Expand Collapse

    Joined:
    Dec 28, 2023
    Messages:
    1
    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:

    1. 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.
    2. 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.
    3. 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.
    4. 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.
    5. 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.
    6. 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.
    7. 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.
    8. 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.
     
  5. vulcan-dev

    vulcan-dev
    Expand Collapse

    Joined:
    Jan 28, 2017
    Messages:
    245
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice