Repository: usdot-fhwa-OPS/V2X-Hub
Pull request #696: Fix sdsm flir
Author: login: paulbourelly999
Created: 2025-04-08T21:11:18Z | Merged: 2025-04-09T17:19:43Z

<!-- Thanks for the contribution, this is awesome. -->

# PR Details
## Description
This PR is intended to fix the SDSM implementation for the Pedestrian Plugin. Issues included
- existing implementation would send single SDSM for each object instead of objects in a single SDSM
- existing implementation would use detected object id as source ID instead of infrastructure ID
- existing implementation would populate reference position with detected object long and lat and not populate x and y offset. 
- existing implementation had a 2020 TIM even though default J2735 version is 2016.

Fixed included
- update to parse all detections from FLIR camera and populate objects in SDSM
- update implementation to use INFRASTRUCTURE ID as source ID
- update implementation to use x and y offset received from FLIR camera for x and y offset
- update implementation to include configurable long and lat coordinates for reference location
- update default configuration to use 2016 TIM 

**NOTE : This implementation is not release ready as it includes duplication from TIM plugin and Sensor Data Sharing Service. To allow for demonstration this functionality will remain in a separate demo branch. Revised implementation of this functionality will be added to stable V2X Hub branches**
<!--- Describe your changes in detail -->

## Related Issue
[VS-32
](https://usdot-carma.atlassian.net/browse/VS-32)<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

## Motivation and Context
VIP Demo
<!--- Why is this change required? What problem does it solve? -->

## How Has This Been Tested?
Integration Tested 

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [x] Defect fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that cause existing functionality to change)

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [ ] I have added any new packages to the sonar-scanner.properties file
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [x] I have read the **CONTRIBUTING** document.
[V2XHUB Contributing Guide](https://github.com/usdot-fhwa-OPS/V2X-Hub/blob/develop/Contributing.md) 
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.



Diff:
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 109c44838..f63bf2685 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -4,7 +4,8 @@
             "name": "Linux",
             "includePath": [
                 "${workspaceFolder}/**",
-                "/opt/carma/include"
+                "/opt/carma/include",
+                "/opt/carma/include/stol-j2735-201603-carma"
             ],
             "defines": [],
             "compilerPath": "/usr/bin/gcc",
diff --git a/scripts/install_dependencies.sh b/scripts/install_dependencies.sh
index de5c0af30..a2df24737 100755
--- a/scripts/install_dependencies.sh
+++ b/scripts/install_dependencies.sh
@@ -37,7 +37,8 @@ DEPENDENCIES="build-essential \
     rapidjson-dev \
     librapidxml-dev \
     libprotobuf-c-dev \
-    curl"
+    curl \
+    python3-pip"
 
 # STOL library dependencies
 LIBRARY_DEPENDENCIES=" \
diff --git a/src/tmx/TmxUtils/src/simulation/SimulationEnvUtils.cpp b/src/tmx/TmxUtils/src/simulation/SimulationEnvUtils.cpp
index a659b3502..41a47c8c5 100644
--- a/src/tmx/TmxUtils/src/simulation/SimulationEnvUtils.cpp
+++ b/src/tmx/TmxUtils/src/simulation/SimulationEnvUtils.cpp
@@ -14,19 +14,15 @@ namespace tmx::utils::sim{
     }
 
     std::string get_sim_config(const char *config_name, bool required) {
-        if (is_simulation_mode() && config_name) {
-            if ( std::getenv(config_name) != nullptr) {
-                std::string config =  std::getenv(config_name);
-                return config;
-            }
-            else {
-                std::string config_name_str = config_name;
-                if ( required ) {
-                    throw TmxException("Required simulation config " + config_name_str + " not set!");
-                }
+        if ( std::getenv(config_name) != nullptr) {
+            std::string config =  std::getenv(config_name);
+            return config;
+        }
+        else {
+            std::string config_name_str = config_name;
+            if ( required ) {
+                throw TmxException("Required simulation config " + config_name_str + " not set!");
             }
-        } else {
-            throw TmxException("V2X-Hub not in sumulation mode or config param name is null pointer!");
         }
         return "";
     } 
diff --git a/src/v2i-hub/PedestrianPlugin/README.md b/src/v2i-hub/PedestrianPlugin/README.md
new file mode 100644
index 000000000..f10b9a149
--- /dev/null
+++ b/src/v2i-hub/PedestrianPlugin/README.md
@@ -0,0 +1,33 @@
+# Pedestrian Plugin Documentation
+
+## Introduction
+
+This plugin is responsible for generating PSM (Personal Safety Message), SDSM (Sensor Data Sharing Message) and TIM (Traver Information Message) for pedestrians. The data for these messages can come from REST POST calls of PSM to broadcast, FLIR camera detections or a static TIM message sent in configuration
+
+## Related Plugins
+
+A list of plugins related to the Pedestrian Plugin.
+
+### Immediate Forward Plugin
+
+For RSU Immediate Message Forwarding (IMF) functionality forward PSM, SDSM or TIM 
+
+## Configuration/Deployment
+
+This plugin has several configuration parameters. Below these are listed out as together with descriptions on how to set them.
+
+
+## Design
+
+
+### Messages
+
+**PSM**: Personal Saftey Message
+**SDSM**: Sensor Data Sharing Message
+**TIM**: Traveler Information Message
+## Functionality Testing
+
+Testing the functionality of a configured instance of the Pedestrian plugin simply follow the steps outlined below
+
+1) Call `python3 -m pip install -r ./scripts/requirements.txt`
+2) Run the test script to mock FLIR camera detections `python3 ./scripts/websocketServer.py` or the script to mock sending REST POST requests `python3 ./scripts/sendPsm.PY`
diff --git a/src/v2i-hub/PedestrianPlugin/manifest.json b/src/v2i-hub/PedestrianPlugin/manifest.json
index 168f4180f..c4478fa3f 100644
--- a/src/v2i-hub/PedestrianPlugin/manifest.json
+++ b/src/v2i-hub/PedestrianPlugin/manifest.json
@@ -45,7 +45,7 @@
 		},
 		{
             "key":"StaticTim",
-            "default":"{\"TravelerInformation\":{\"msgCnt\":\"1\",\"timeStamp\":\"3960\",\"packetID\":\"8D442EF003FC6B1B01\",\"urlB\":\"null\",\"dataFrames\":{\"TravelerDataFrame\":{\"notUsed\":\"0\",\"frameType\":{\"advisory\":\"\"},\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":\"389550358\",\"long\":\"-771495007\"},\"viewAngle\":\"1111111111111111\",\"mutcdCode\":{\"warning\":\"\"}}},\"startYear\":\"2025\",\"startTime\":\"3960\",\"durationTime\":\"32000\",\"priority\":\"5\",\"notUsed1\":\"0\",\"regions\":{\"GeographicalPath\":{\"name\":\"WesternPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389550358\",\"long\":\"-771495007\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0000000000111100\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"1556\",\"lat\":\"-454\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"1676\",\"lat\":\"-254\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"5293\",\"lat\":\"-531\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"NorthernPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389551020\",\"long\":\"-771492660\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"1110000000000011\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-791\",\"lat\":\"-1103\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-610\",\"lat\":\"-876\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-3\",\"lat\":\"2\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-1149\",\"lat\":\"-1750\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-133\",\"lat\":\"-257\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-121\",\"lat\":\"-538\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"25\",\"lat\":\"-360\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"241\",\"lat\":\"-469\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"260\",\"lat\":\"-232\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"159\",\"lat\":\"-84\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"SouthernPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389549055\",\"long\":\"-771494061\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0000001111000000\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"602\",\"lat\":\"849\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"834\",\"lat\":\"1109\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"353\",\"lat\":\"584\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"1646\",\"lat\":\"3238\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"EasternPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389549656\",\"long\":\"-771491766\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0011110000000000\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-1693\",\"lat\":\"241\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"-4063\",\"lat\":\"1160\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"-2311\",\"lat\":\"981\"}}}}}}}}}},\"notUsed2\":\"0\",\"notUsed3\":\"0\",\"content\":{\"advisory\":{\"SEQUENCE\":{\"item\":{\"itis\":\"9486\"}},\"SEQUENCE\":{\"item\":{\"itis\":\"13585\"}}}},\"url\":\"null\"}}}}",
+            "default":"{\"TravelerInformation\":{\"msgCnt\":\"1\",\"timeStamp\":\"3960\",\"packetID\":\"8D442EF003FC6B1B01\",\"urlB\":\"null\",\"dataFrames\":{\"TravelerDataFrame\":{\"sspTimRights\":\"0\",\"frameType\":{\"advisory\":\"\"},\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":\"389550358\",\"long\":\"-771495007\"},\"viewAngle\":\"1111111111111111\",\"mutcdCode\":{\"warning\":\"\"}}},\"startYear\":\"2025\",\"startTime\":\"3960\",\"duratonTime\":\"32000\",\"priority\":\"5\",\"sspLocationRights\":\"0\",\"regions\":{\"GeographicalPath\":{\"name\":\"WesternPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389550358\",\"long\":\"-771495007\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0000000000111100\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"1556\",\"lat\":\"-454\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"1676\",\"lat\":\"-254\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"5293\",\"lat\":\"-531\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"NorthernPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389551020\",\"long\":\"-771492660\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"1110000000000011\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-791\",\"lat\":\"-1103\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-610\",\"lat\":\"-876\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-3\",\"lat\":\"2\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-1149\",\"lat\":\"-1750\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-133\",\"lat\":\"-257\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-121\",\"lat\":\"-538\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"25\",\"lat\":\"-360\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"241\",\"lat\":\"-469\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"260\",\"lat\":\"-232\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"159\",\"lat\":\"-84\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"SouthernPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389549055\",\"long\":\"-771494061\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0000001111000000\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"602\",\"lat\":\"849\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"834\",\"lat\":\"1109\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"353\",\"lat\":\"584\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"1646\",\"lat\":\"3238\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"EasternPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389549656\",\"long\":\"-771491766\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0011110000000000\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-1693\",\"lat\":\"241\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"-4063\",\"lat\":\"1160\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"-2311\",\"lat\":\"981\"}}}}}}}}}},\"sspMsgRights1\":\"0\",\"sspMsgRights2\":\"0\",\"content\":{\"advisory\":{\"SEQUENCE\":{\"item\":{\"itis\":\"9486\"}},\"SEQUENCE\":{\"item\":{\"itis\":\"13585\"}}}},\"url\":\"null\"}}}}",
             "description":"Static Tim message to be broadcasted."
         },
 		{
@@ -57,6 +57,16 @@
             "key":"LogLevel",
             "default":"INFO",
             "description":"The log level for this plugin"
-        }
+        },
+		{
+			"key":"FLIRLat",
+            "default":"45.45",
+            "description":"Latitude coordinate for the FLIR camera location in degrees(-90,90)."
+		},
+		{
+			"key":"FLIRLon",
+            "default":"-45.45",
+            "description":"Longitude coordinate for the FLIR camera location in degrees(-180,180)."
+		}
 	]
 }
diff --git a/src/v2i-hub/PedestrianPlugin/scripts/websocketServer.py b/src/v2i-hub/PedestrianPlugin/scripts/websocketServer.py
index 56ba097a3..ad8c08a8b 100644
--- a/src/v2i-hub/PedestrianPlugin/scripts/websocketServer.py
+++ b/src/v2i-hub/PedestrianPlugin/scripts/websocketServer.py
@@ -5,6 +5,7 @@
 import websockets
 import json
 import argparse
+from datetime import datetime, timezone
 
 # Sample Pededertian Presence Tracking Data
 message = {
@@ -15,20 +16,36 @@
         {
             "angle": "263.00000000",
             "class": "Pedestrian",
-            "iD": "15968646",
+            "iD": "7",
             "latitude": "38.95499217",
             "longitude": "-77.14920953",
             "speed": "1.41873741",
             "x": "0.09458912",
             "y": "14.80903757",
+        },
+        {
+            "angle": "45.00000000",
+            "class": "Pedestrian",
+            "iD": "8",
+            "latitude": "38.95499600",
+            "longitude": "-77.14920200",
+            "speed": "2.132",
+            "x": "-5.09458912",
+            "y": "7.80903757",
         }
     ],
     "type": "PedestrianPresenceTracking",
 }
-
+def update_timestamp():
+    """Update the 'time' field in the message to the current UTC time."""
+    # Get the current UTC time with milliseconds
+    utc_time = datetime.now(timezone.utc)
+    formatted_time = utc_time.isoformat(timespec='milliseconds').replace("+00:00", "Z")
+    message["time"] = formatted_time
 async def sendMessage(websocket):
     """Send the JSON message to the client periodically."""
     while True:
+        update_timestamp()  # Update the timestamp before sending the message
         await websocket.send(json.dumps(message))
         print("Message sent to client")
         await asyncio.sleep(1)  # interval to send the message
diff --git a/src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp b/src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
index 001016242..654cb3d06 100644
--- a/src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
+++ b/src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
@@ -13,7 +13,7 @@ namespace PedestrianPlugin
         PLOG(logERROR) << what << ": " << ec.message();
     }
 
-    void FLIRWebSockAsyncClnSession::run(char const* host, char const* port, float cameraRotation, const char* cameraViewName, char const* hostString, bool generatePSM, bool generateSDSM, bool generateTIM)
+    void FLIRWebSockAsyncClnSession::run(char const* host, char const* port, float cameraRotation, const char* cameraViewName, char const* hostString, bool generatePSM, bool generateSDSM, bool generateTIM, double fLIRLat, double fLIRLon)
     {
 	    // Save these for later
         host_ = host;
@@ -23,6 +23,8 @@ namespace PedestrianPlugin
         generatePSM_ = generatePSM;
         generateSDSM_ = generateSDSM;
         generateTIM_ = generateTIM;
+        fLIRLat_ = fLIRLat;
+        fLIRLon_ = fLIRLon;
 
         PLOG(logDEBUG) << "Host: "<< host <<" ; port: "<< port << " ; host string: "<< hostString;
 
@@ -195,19 +197,29 @@ namespace PedestrianPlugin
     void FLIRWebSockAsyncClnSession::processPedestrianData(const pt::ptree& pr, const std::string& time)
     {
     try {
+        // Declare initial null and J2735 default values if not provided by FLIR.
+        int angle = 0;
+        float rawAlpha = 0.0f;
+        int alpha = 28800; // Default for J2735 unavailable DE_Angle
+        std::string lat = "";
+        std::string lon = "";
+        int speed = 8191; // Default for unavailable DE_Speed and DE_Velocity
+        int id = 0;
+        std::string infraId = "";
+        std::string idResult = "";
+        std::string objID = "";
+        std::string xOffset = ""; // Offset of detected track from FLIR position in m
+        std::string yOffset = "";
+        std::string detObjXmlStr;
+
+        // Parse out seconds from datetime string
+        std::vector<int> dateTimeArr = timeStringParser(time);
+
+        PLOG(logINFO) << "Received FLIR camera data at: " << dateTimeArr[0] << "/" << dateTimeArr[1] << "/" << dateTimeArr[2]
+                        << " " << dateTimeArr[3] << ":" << dateTimeArr[4] << ":" << dateTimeArr[5] << ":" << dateTimeArr[6];    
+
         for (auto &it: pr.get_child("track")) 
         {
-            // Declare initial null and J2735 default values if not provided by FLIR.
-            int angle = 0;
-            float rawAlpha = 0.0f;
-            int alpha = 28800; // Default for J2735 unavailable DE_Angle
-            std::string lat = "";
-            std::string lon = "";
-            int speed = 8191; // Default for unavailable DE_Speed and DE_Velocity
-            int id = 0;
-            std::string idResult = "";
-            std::string objID = "";
-
             // Parse angle
             if (!it.second.get_child("angle").data().empty())
             {
@@ -227,38 +239,36 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon in degress to 1/10 microdegrees (J2735 units) 
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon in degress to 1/10 microdegrees (J2735 units) 
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                // Convert x/y offset in m (FLIR) to 1/10 m (J2735)
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
                 // Convert received lat/lon to J2735 lat/lon format
-                lat = it.second.get_child("latitude").data();
-                lat.erase(std::remove(lat.begin(), lat.end(), '.'), lat.end());
-                lat.pop_back();
+                xOffset = std::to_string(xOffsetInt);
             }
-
-            // Parse longitude
-            if (!it.second.get_child("longitude").data().empty())
+            if (!it.second.get_child("y").data().empty())
             {
-                // Convert received lat/lon to J2735 lat/lon format
-                lon = it.second.get_child("longitude").data();
-                lon.erase(std::remove(lon.begin(), lon.end(), '.'), lon.end());
-                lon.pop_back();
+                // Convert x/y offset in m (FLIR) to 1/10 m (J2735)
+                int yOffsetInt = std::round(std::stod(it.second.get_child("y").data())*10);
+                yOffset = std::to_string(yOffsetInt);
             }
 
+
             // Parse speed
             if (!it.second.get_child("speed").data().empty())
             {
@@ -266,30 +276,32 @@ namespace PedestrianPlugin
                 // Convert to units of 0.02 m/s for J2735 Speed and Velocity format
                 float rawSpeed = std::stof(it.second.get_child("speed").data());
                 speed = static_cast<int>(std::round(rawSpeed / 0.02f));
-            }
+            }                  
 
-            // Parse out seconds from datetime string
-            std::vector<int> dateTimeArr = timeStringParser(time);                       
-
-            msgCount += 1;
-            if (msgCount > 127) {
-                msgCount = 0;
+            if (generateSDSM_ == false)
+            {
+                msgCount += 1;
+                if (msgCount > 127) {
+                    msgCount = 0;
+                }
             }
 
-            PLOG(logINFO) << "Received FLIR camera data at: " << dateTimeArr[0] << "/" << dateTimeArr[1] << "/" << dateTimeArr[2]
-                          << " " << dateTimeArr[3] << ":" << dateTimeArr[4] << ":" << dateTimeArr[5] << ":" << dateTimeArr[6];  
+            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";  
 
-            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << lat << ", " << lon <<
+            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << xOffset << ", " << yOffset <<
                           "), traveling at speed: " << speed << ", with heading: " << alpha << " degrees";
 
-            PLOG(logINFO) << "Message count: " << msgCount;
-            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";
-
             std::lock_guard<mutex> lock(_msgLock);
             if (generatePSM_ == true)
             {
+                // Convert Object ID to 4 octet string
+                std::stringstream idstream;
+                idstream << std::hex << id;
+                auto objectTempId = idstream.str();
+                int strLengthDiff = 8 - static_cast<int>(objectTempId.length());
+                objectTempId.append(strLengthDiff, '0');
                 // Constructing PSM XML to send to BroadcastPedDet function
-                std::string psm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><PersonalSafetyMessage><basicType><aPEDESTRIAN/></basicType><secMark>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</secMark><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><id>)xml" + idResult + R"xml(</id><position><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></position><accuracy><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></accuracy><speed>)xml" + std::to_string(speed) + R"xml(</speed><heading>)xml" + std::to_string(alpha) + R"xml(</heading><pathHistory><initialPosition><utcTime><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></utcTime><long>0</long><lat>0</lat></initialPosition><crumbData><PathHistoryPoint><latOffset>0</latOffset><lonOffset>0</lonOffset><elevationOffset>0</elevationOffset><timeOffset>1</timeOffset></PathHistoryPoint></crumbData></pathHistory></PersonalSafetyMessage>)xml";
+                std::string psm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><PersonalSafetyMessage><basicType><aPEDESTRIAN/></basicType><secMark>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</secMark><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><id>)xml" + objectTempId + R"xml(</id><position><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></position><accuracy><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></accuracy><speed>)xml" + std::to_string(speed) + R"xml(</speed><heading>)xml" + std::to_string(alpha) + R"xml(</heading><pathHistory><initialPosition><utcTime><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></utcTime><long>0</long><lat>0</lat></initialPosition><crumbData><PathHistoryPoint><latOffset>0</latOffset><lonOffset>0</lonOffset><elevationOffset>0</elevationOffset><timeOffset>1</timeOffset></PathHistoryPoint></crumbData></pathHistory></PersonalSafetyMessage>)xml";
                 PLOG(logDEBUG) << std::endl << psm_xml_str;
                 psmxml = psm_xml_str;
                 msgQueue.push(psmxml);
@@ -297,10 +309,16 @@ namespace PedestrianPlugin
             if (generateSDSM_ == true)
             {
                 // Constructing SDSM XML to send to BroadcastPedDet function
-                std::string sdsm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><SensorDataSharingMessage><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><sourceID>)xml" + idResult + R"xml(</sourceID><equipmentType><rsu/></equipmentType><sDSMTimeStamp><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></sDSMTimeStamp><refPos><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></refPos><refPosXYConf><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></refPosXYConf><objects><DetectedObjectData><detObjCommon><objType><vru/></objType><objTypeCfd>98</objTypeCfd><objectID>)xml" + objID + R"xml(</objectID><measurementTime>0</measurementTime><timeConfidence><time-000-001/></timeConfidence><pos><offsetX>0</offsetX><offsetY>0</offsetY></pos><posConfidence><pos><a20cm/></pos><elevation><elev-000-20/></elevation></posConfidence><speed>)xml" + std::to_string(speed) + R"xml(</speed><speedConfidence><prec0-1ms/></speedConfidence><heading>)xml" + std::to_string(alpha) + R"xml(</heading><headingConf><prec05deg/></headingConf></detObjCommon></DetectedObjectData></objects></SensorDataSharingMessage>)xml";
-                PLOG(logDEBUG) << std::endl << sdsm_xml_str;
-                sdsmxml = sdsm_xml_str;
-                msgQueue.push(sdsmxml);
+                // Append each track as a string to a DetectedObjectList
+                std::string detObjTempStr = R"xml(<DetectedObjectData><detObjCommon><objType><vru/></objType><objTypeCfd>98</objTypeCfd><objectID>)xml" + objID + 
+                                                R"xml(</objectID><measurementTime>0</measurementTime><timeConfidence><time-000-001/></timeConfidence><pos><offsetX>)xml" + xOffset + 
+                                                R"xml(</offsetX><offsetY>)xml" + yOffset + 
+                                                R"xml(</offsetY></pos><posConfidence><pos><a20cm/></pos><elevation><elev-000-20/></elevation></posConfidence><speed>)xml" + std::to_string(speed) + 
+                                                R"xml(</speed><speedConfidence><prec0-1ms/></speedConfidence><heading>)xml" + std::to_string(alpha) + 
+                                                R"xml(</heading><headingConf><prec05deg/></headingConf></detObjCommon></DetectedObjectData>)xml";
+                PLOG(logDEBUG) << std::endl << detObjTempStr;
+
+                detObjXmlStr.append(detObjTempStr);
             }
             if (generateTIM_ == true)
             {
@@ -313,6 +331,33 @@ namespace PedestrianPlugin
                 setPedestrainPresence(true);
             }
         }
+        // If generating SDSMs, append the string of DetectedObjects to an sdsm_xml_str
+        if (generateSDSM_ == true)
+        {
+            // separate count due to combined tracks under SDSM
+            msgCount += 1;
+            if (msgCount > 127) {
+                msgCount = 0;
+            }
+
+            // Get the current TemporaryID of the infrastructure source
+            infraId = sim::get_sim_config(sim::INFRASTRUCTURE_ID);
+            std::string infraIdStr = infraId.substr(infraId.find_first_of('_')+1);
+            unsigned int infraIdInt = std::stoi(infraIdStr);
+            // Convert the id to 4 octet string
+            std::stringstream idstream;
+            idstream << std::hex << infraIdInt;
+            auto rsuTempId = idstream.str();
+            int strLengthDiff = 8 - static_cast<int>(rsuTempId.length());
+            rsuTempId.append(strLengthDiff, '0');
+
+            std::string sdsm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><SensorDataSharingMessage><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><sourceID>)xml" + rsuTempId + R"xml(</sourceID><equipmentType><rsu/></equipmentType><sDSMTimeStamp><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></sDSMTimeStamp><refPos><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></refPos><refPosXYConf><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></refPosXYConf><objects>)xml" + detObjXmlStr + R"xml(</objects></SensorDataSharingMessage>)xml";
+            PLOG(logDEBUG) << std::endl << sdsm_xml_str;
+            sdsmxml = sdsm_xml_str;
+            msgQueue.push(sdsmxml);
+
+            detObjXmlStr = "";
+        }
     }
     catch(const ptree_error &e) {
         PLOG(logERROR) << "Error with track data:  " << e.what();
diff --git a/src/v2i-hub/PedestrianPlugin/src/PedestrianPlugin.cpp b/src/v2i-hub/PedestrianPlugin/src/PedestrianPlugin.cpp
index 6f7205ecb..2859d4855 100644
--- a/src/v2i-hub/PedestrianPlugin/src/PedestrianPlugin.cpp
+++ b/src/v2i-hub/PedestrianPlugin/src/PedestrianPlugin.cpp
@@ -53,7 +53,7 @@ int PedestrianPlugin::StartWebSocket(const FLIRConfiguration & config)
 	// Create a session and run it
 	auto flirSession = std::make_shared<FLIRWebSockAsyncClnSession>(ioc);
     // Launch the asynchronous operation
-	flirSession->run(config.socketIp.c_str(), config.socketPort.c_str(), config.FLIRCameraRotation, config.FLIRCameraViewName.c_str(), config.apiSubscription.c_str(), generatePSM, generateSDSM, generateTIM);	
+	flirSession->run(config.socketIp.c_str(), config.socketPort.c_str(), config.FLIRCameraRotation, config.FLIRCameraViewName.c_str(), config.apiSubscription.c_str(), generatePSM, generateSDSM, generateTIM, fLIRLat, fLIRLon);	
 	flirSessions.push_back(flirSession);
 	PLOG(logDEBUG) << "Successfully running the I/O service.";	
     runningWebSocket = true;
@@ -263,6 +263,8 @@ void PedestrianPlugin::UpdateConfigSettings()
 	GetConfigValue<uint16_t>("WebServicePort", webport, &_cfgLock);
 	GetConfigValue<std::string>("DataProvider", dataprovider, &_cfgLock);
 	GetConfigValue<std::string>("FLIROutput", flirOutput, &_cfgLock);
+	GetConfigValue<double>("FLIRLat", fLIRLat, &_cfgLock);
+	GetConfigValue<double>("FLIRLon", fLIRLon, &_cfgLock);
 
 	std::string flirConfigsStr;
 	GetConfigValue<std::string>("FLIRConfigurations", flirConfigsStr, &_cfgLock);
@@ -370,7 +372,7 @@ void PedestrianPlugin::BroadcastPedDet(const std::string &msgXML)
 	ss << msgXML;
 
 	container.load<XML>(ss);
-
+	
 	PLOG(logDEBUG2) << "In PedestrianPlugin::BroadcastPedDet: Incoming Message: " << std::endl << msgXML;
 	auto receivedType = parseMessage(msgXML);
 
diff --git a/src/v2i-hub/PedestrianPlugin/src/include/FLIRWebSockAsyncClnSession.hpp b/src/v2i-hub/PedestrianPlugin/src/include/FLIRWebSockAsyncClnSession.hpp
index 7131e7224..cc0d0c758 100644
--- a/src/v2i-hub/PedestrianPlugin/src/include/FLIRWebSockAsyncClnSession.hpp
+++ b/src/v2i-hub/PedestrianPlugin/src/include/FLIRWebSockAsyncClnSession.hpp
@@ -22,6 +22,7 @@
 #include <cmath>
 #include <atomic>
 #include "TravelerInformationMessageHelper.hpp"
+#include <simulation/SimulationEnvUtils.h>
 
 namespace beast = boost::beast;         // from <boost/beast.hpp>
 namespace http = beast::http;           // from <boost/beast/http.hpp>
@@ -46,6 +47,8 @@ namespace PedestrianPlugin
         bool generatePSM_;
         bool generateSDSM_;
         bool generateTIM_;
+        double fLIRLat_;
+        double fLIRLon_;
         /***
          * Each websocket is connected to one camera responsible for one region/view at an intersection.
          * This isPedestrainPresent indicator signify whether there is a pedestrain in that region or not.
@@ -91,7 +94,7 @@ namespace PedestrianPlugin
      * @param port port to connect to
      * @param cameraRotation calculated camera rotation
      */
-    void run(char const* host, char const* port, float cameraRotation,const char* cameraViewName, char const* hostString, bool generatePSM, bool generateSDSM, bool generateTIM);
+    void run(char const* host, char const* port, float cameraRotation,const char* cameraViewName, char const* hostString, bool generatePSM, bool generateSDSM, bool generateTIM, double fLIRLat, double fLIRLon);
     
     /**
      * @brief Lookup the domain name of the IP address from run function.
diff --git a/src/v2i-hub/PedestrianPlugin/src/include/PedestrianPlugin.hpp b/src/v2i-hub/PedestrianPlugin/src/include/PedestrianPlugin.hpp
index 2befa991d..957be7f01 100644
--- a/src/v2i-hub/PedestrianPlugin/src/include/PedestrianPlugin.hpp
+++ b/src/v2i-hub/PedestrianPlugin/src/include/PedestrianPlugin.hpp
@@ -152,6 +152,9 @@ class PedestrianPlugin: public PluginClient
 	bool generateSDSM = false;
 	bool generateTIM = false;
 
+	double fLIRLat = 45.45;
+	double fLIRLon = 45.45;
+
 	// TODO: Set an endpoint for XML post messages and update documentation.
 	// API URL to accept XML
 	const QString Msg_Receive = "";


Reviews:
user: login: willjohnsonk
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:55:19Z
user: login: willjohnsonk
body: Update test script to test multiple tracks to ensure multiple detections are appended to the SDSM correctly
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:56:38Z
user: login: dan-du-car
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T14:12:21Z
user: login: dan-du-car
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T14:14:35Z
user: login: paulbourelly999
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:05:48Z
user: login: paulbourelly999
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:08:42Z
user: login: paulbourelly999
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:09:35Z
user: login: paulbourelly999
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:09:52Z
user: login: paulbourelly999
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:10:04Z
user: login: paulbourelly999
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:10:21Z
user: login: paulbourelly999
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:15:17Z
user: login: dan-du-car
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:44:22Z
user: login: willjohnsonk
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:47:46Z
user: login: dan-du-car
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T16:12:23Z
user: login: willjohnsonk
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T17:18:39Z

Review comments:
diff_hunk: @@ -14,19 +14,15 @@ namespace tmx::utils::sim{
     }
 
     std::string get_sim_config(const char *config_name, bool required) {
path: src/tmx/TmxUtils/src/simulation/SimulationEnvUtils.cpp
user: login: willjohnsonk
body: Is this how we want to be accessing RSU TempIDs long term or is this just a fix for the demo? This method usage will probably be unclear to most. Assumed not in scope
created_at: 2025-04-09T13:41:56Z
author_association: CONTRIBUTOR
path: src/v2i-hub/PedestrianPlugin/scripts/websocketServer.py
user: login: willjohnsonk
body: I would add a README to this directory or as a comment to this script that indicates there is a dependency on specific package versions in requirements.txt. Mostly because I'm blind
created_at: 2025-04-09T13:44:20Z
author_association: CONTRIBUTOR
path: src/v2i-hub/PedestrianPlugin/scripts/websocketServer.py
user: login: willjohnsonk
body: This file doesn't have the latest "update_timestamp" method that @jwillmartin added. May be other changes, I sent the latest version on Teams a couple of days ago.
created_at: 2025-04-09T13:48:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: dan-du-car
body: The lat and long are expressed as expressed in 1/10th integer microdegrees in J2735, isn't this multiply *10e7 instead?
created_at: 2025-04-09T13:53:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: dan-du-car
body: Is this x and y provided by the camera? Why does it times 10?
created_at: 2025-04-09T13:58:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
                 // Convert received lat/lon to J2735 lat/lon format
-                lat = it.second.get_child("latitude").data();
-                lat.erase(std::remove(lat.begin(), lat.end(), '.'), lat.end());
-                lat.pop_back();
+                xOffset = std::to_string(xOffsetInt);
             }
-
-            // Parse longitude
-            if (!it.second.get_child("longitude").data().empty())
+            if (!it.second.get_child("y").data().empty())
             {
+                int yOffsetInt = std::round(std::stod(it.second.get_child("y").data())*10);
+
                 // Convert received lat/lon to J2735 lat/lon format
-                lon = it.second.get_child("longitude").data();
-                lon.erase(std::remove(lon.begin(), lon.end(), '.'), lon.end());
-                lon.pop_back();
+                yOffset = std::to_string(yOffsetInt);
             }
 
+
             // Parse speed
             if (!it.second.get_child("speed").data().empty())
             {
                 // Speed from the FLIR camera is reported in m/s
                 // Convert to units of 0.02 m/s for J2735 Speed and Velocity format
                 float rawSpeed = std::stof(it.second.get_child("speed").data());
                 speed = static_cast<int>(std::round(rawSpeed / 0.02f));
-            }
-
-            // Parse out seconds from datetime string
-            std::vector<int> dateTimeArr = timeStringParser(time);                       
+            }                  
 
-            msgCount += 1;
-            if (msgCount > 127) {
-                msgCount = 0;
+            if (generateSDSM_ == false)
+            {
+                msgCount += 1;
+                if (msgCount > 127) {
+                    msgCount = 0;
+                }
             }
 
-            PLOG(logINFO) << "Received FLIR camera data at: " << dateTimeArr[0] << "/" << dateTimeArr[1] << "/" << dateTimeArr[2]
-                          << " " << dateTimeArr[3] << ":" << dateTimeArr[4] << ":" << dateTimeArr[5] << ":" << dateTimeArr[6];  
+            PLOG(logINFO) << "Message count: " << msgCount;
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: dan-du-car
body: Do we need these logINFO? or logDEBUG below? Does  not seem to add any value.
created_at: 2025-04-09T13:59:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
                 // Convert received lat/lon to J2735 lat/lon format
-                lat = it.second.get_child("latitude").data();
-                lat.erase(std::remove(lat.begin(), lat.end(), '.'), lat.end());
-                lat.pop_back();
+                xOffset = std::to_string(xOffsetInt);
             }
-
-            // Parse longitude
-            if (!it.second.get_child("longitude").data().empty())
+            if (!it.second.get_child("y").data().empty())
             {
+                int yOffsetInt = std::round(std::stod(it.second.get_child("y").data())*10);
+
                 // Convert received lat/lon to J2735 lat/lon format
-                lon = it.second.get_child("longitude").data();
-                lon.erase(std::remove(lon.begin(), lon.end(), '.'), lon.end());
-                lon.pop_back();
+                yOffset = std::to_string(yOffsetInt);
             }
 
+
             // Parse speed
             if (!it.second.get_child("speed").data().empty())
             {
                 // Speed from the FLIR camera is reported in m/s
                 // Convert to units of 0.02 m/s for J2735 Speed and Velocity format
                 float rawSpeed = std::stof(it.second.get_child("speed").data());
                 speed = static_cast<int>(std::round(rawSpeed / 0.02f));
-            }
-
-            // Parse out seconds from datetime string
-            std::vector<int> dateTimeArr = timeStringParser(time);                       
+            }                  
 
-            msgCount += 1;
-            if (msgCount > 127) {
-                msgCount = 0;
+            if (generateSDSM_ == false)
+            {
+                msgCount += 1;
+                if (msgCount > 127) {
+                    msgCount = 0;
+                }
             }
 
-            PLOG(logINFO) << "Received FLIR camera data at: " << dateTimeArr[0] << "/" << dateTimeArr[1] << "/" << dateTimeArr[2]
-                          << " " << dateTimeArr[3] << ":" << dateTimeArr[4] << ":" << dateTimeArr[5] << ":" << dateTimeArr[6];  
+            PLOG(logINFO) << "Message count: " << msgCount;
+            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";  
 
-            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << lat << ", " << lon <<
+            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << xOffset << ", " << yOffset <<
                           "), traveling at speed: " << speed << ", with heading: " << alpha << " degrees";
 
-            PLOG(logINFO) << "Message count: " << msgCount;
-            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";
-
             std::lock_guard<mutex> lock(_msgLock);
             if (generatePSM_ == true)
             {
+                // Convert Object ID to 4 octet string
+                std::stringstream idstream;
+                idstream << std::hex << id;
+                auto objectTempId = idstream.str();
+                int str_length_diff = 8 - static_cast<int>(objectTempId.length());
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: dan-du-car
body: Please use consistent variable case. `str_length_diff `to `strLengthDiff`?
created_at: 2025-04-09T14:00:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
                 // Convert received lat/lon to J2735 lat/lon format
-                lat = it.second.get_child("latitude").data();
-                lat.erase(std::remove(lat.begin(), lat.end(), '.'), lat.end());
-                lat.pop_back();
+                xOffset = std::to_string(xOffsetInt);
             }
-
-            // Parse longitude
-            if (!it.second.get_child("longitude").data().empty())
+            if (!it.second.get_child("y").data().empty())
             {
+                int yOffsetInt = std::round(std::stod(it.second.get_child("y").data())*10);
+
                 // Convert received lat/lon to J2735 lat/lon format
-                lon = it.second.get_child("longitude").data();
-                lon.erase(std::remove(lon.begin(), lon.end(), '.'), lon.end());
-                lon.pop_back();
+                yOffset = std::to_string(yOffsetInt);
             }
 
+
             // Parse speed
             if (!it.second.get_child("speed").data().empty())
             {
                 // Speed from the FLIR camera is reported in m/s
                 // Convert to units of 0.02 m/s for J2735 Speed and Velocity format
                 float rawSpeed = std::stof(it.second.get_child("speed").data());
                 speed = static_cast<int>(std::round(rawSpeed / 0.02f));
-            }
-
-            // Parse out seconds from datetime string
-            std::vector<int> dateTimeArr = timeStringParser(time);                       
+            }                  
 
-            msgCount += 1;
-            if (msgCount > 127) {
-                msgCount = 0;
+            if (generateSDSM_ == false)
+            {
+                msgCount += 1;
+                if (msgCount > 127) {
+                    msgCount = 0;
+                }
             }
 
-            PLOG(logINFO) << "Received FLIR camera data at: " << dateTimeArr[0] << "/" << dateTimeArr[1] << "/" << dateTimeArr[2]
-                          << " " << dateTimeArr[3] << ":" << dateTimeArr[4] << ":" << dateTimeArr[5] << ":" << dateTimeArr[6];  
+            PLOG(logINFO) << "Message count: " << msgCount;
+            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";  
 
-            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << lat << ", " << lon <<
+            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << xOffset << ", " << yOffset <<
                           "), traveling at speed: " << speed << ", with heading: " << alpha << " degrees";
 
-            PLOG(logINFO) << "Message count: " << msgCount;
-            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";
-
             std::lock_guard<mutex> lock(_msgLock);
             if (generatePSM_ == true)
             {
+                // Convert Object ID to 4 octet string
+                std::stringstream idstream;
+                idstream << std::hex << id;
+                auto objectTempId = idstream.str();
+                int str_length_diff = 8 - static_cast<int>(objectTempId.length());
+                objectTempId.append(str_length_diff, '0');
                 // Constructing PSM XML to send to BroadcastPedDet function
-                std::string psm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><PersonalSafetyMessage><basicType><aPEDESTRIAN/></basicType><secMark>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</secMark><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><id>)xml" + idResult + R"xml(</id><position><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></position><accuracy><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></accuracy><speed>)xml" + std::to_string(speed) + R"xml(</speed><heading>)xml" + std::to_string(alpha) + R"xml(</heading><pathHistory><initialPosition><utcTime><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></utcTime><long>0</long><lat>0</lat></initialPosition><crumbData><PathHistoryPoint><latOffset>0</latOffset><lonOffset>0</lonOffset><elevationOffset>0</elevationOffset><timeOffset>1</timeOffset></PathHistoryPoint></crumbData></pathHistory></PersonalSafetyMessage>)xml";
+                std::string psm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><PersonalSafetyMessage><basicType><aPEDESTRIAN/></basicType><secMark>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</secMark><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><id>)xml" + objectTempId + R"xml(</id><position><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></position><accuracy><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></accuracy><speed>)xml" + std::to_string(speed) + R"xml(</speed><heading>)xml" + std::to_string(alpha) + R"xml(</heading><pathHistory><initialPosition><utcTime><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></utcTime><long>0</long><lat>0</lat></initialPosition><crumbData><PathHistoryPoint><latOffset>0</latOffset><lonOffset>0</lonOffset><elevationOffset>0</elevationOffset><timeOffset>1</timeOffset></PathHistoryPoint></crumbData></pathHistory></PersonalSafetyMessage>)xml";
                 PLOG(logDEBUG) << std::endl << psm_xml_str;
                 psmxml = psm_xml_str;
                 msgQueue.push(psmxml);
             }
             if (generateSDSM_ == true)
             {
                 // Constructing SDSM XML to send to BroadcastPedDet function
-                std::string sdsm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><SensorDataSharingMessage><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><sourceID>)xml" + idResult + R"xml(</sourceID><equipmentType><rsu/></equipmentType><sDSMTimeStamp><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></sDSMTimeStamp><refPos><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></refPos><refPosXYConf><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></refPosXYConf><objects><DetectedObjectData><detObjCommon><objType><vru/></objType><objTypeCfd>98</objTypeCfd><objectID>)xml" + objID + R"xml(</objectID><measurementTime>0</measurementTime><timeConfidence><time-000-001/></timeConfidence><pos><offsetX>0</offsetX><offsetY>0</offsetY></pos><posConfidence><pos><a20cm/></pos><elevation><elev-000-20/></elevation></posConfidence><speed>)xml" + std::to_string(speed) + R"xml(</speed><speedConfidence><prec0-1ms/></speedConfidence><heading>)xml" + std::to_string(alpha) + R"xml(</heading><headingConf><prec05deg/></headingConf></detObjCommon></DetectedObjectData></objects></SensorDataSharingMessage>)xml";
-                PLOG(logDEBUG) << std::endl << sdsm_xml_str;
-                sdsmxml = sdsm_xml_str;
-                msgQueue.push(sdsmxml);
+                // Append each track as a string to a DetectedObjectList
+                std::string det_obj_temp_str = R"xml(<DetectedObjectData><detObjCommon><objType><vru/></objType><objTypeCfd>98</objTypeCfd><objectID>)xml" + objID + 
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: dan-du-car
body: Please use consistent variable naming convention
created_at: 2025-04-09T14:07:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -195,19 +197,29 @@ namespace PedestrianPlugin
     void FLIRWebSockAsyncClnSession::processPedestrianData(const pt::ptree& pr, const std::string& time)
     {
     try {
+        // Declare initial null and J2735 default values if not provided by FLIR.
+        int angle = 0;
+        float rawAlpha = 0.0f;
+        int alpha = 28800; // Default for J2735 unavailable DE_Angle
+        std::string lat = "";
+        std::string lon = "";
+        int speed = 8191; // Default for unavailable DE_Speed and DE_Velocity
+        int id = 0;
+        std::string infraId = "";
+        std::string idResult = "";
+        std::string objID = "";
+        std::string xOffset = ""; // Offset of detected track from FLIR position in m
+        std::string yOffset = "";
+        std::string det_obj_xml_str;
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: dan-du-car
body: Please use consistent variable naming convention. A simple inline comment to describe the purpose of this `det_obj_xml_str`
created_at: 2025-04-09T14:08:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
                 // Convert received lat/lon to J2735 lat/lon format
-                lat = it.second.get_child("latitude").data();
-                lat.erase(std::remove(lat.begin(), lat.end(), '.'), lat.end());
-                lat.pop_back();
+                xOffset = std::to_string(xOffsetInt);
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: dan-du-car
body: Not sure if this comment apply to the following line of code. The same comment for y offset
created_at: 2025-04-09T14:10:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -45,7 +45,7 @@
 		},
 		{
             "key":"StaticTim",
-            "default":"{\"TravelerInformation\":{\"msgCnt\":\"1\",\"timeStamp\":\"3960\",\"packetID\":\"8D442EF003FC6B1B01\",\"urlB\":\"null\",\"dataFrames\":{\"TravelerDataFrame\":{\"notUsed\":\"0\",\"frameType\":{\"advisory\":\"\"},\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":\"389550358\",\"long\":\"-771495007\"},\"viewAngle\":\"1111111111111111\",\"mutcdCode\":{\"warning\":\"\"}}},\"startYear\":\"2025\",\"startTime\":\"3960\",\"durationTime\":\"32000\",\"priority\":\"5\",\"notUsed1\":\"0\",\"regions\":{\"GeographicalPath\":{\"name\":\"WesternPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389550358\",\"long\":\"-771495007\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0000000000111100\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"1556\",\"lat\":\"-454\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"1676\",\"lat\":\"-254\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"5293\",\"lat\":\"-531\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"NorthernPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389551020\",\"long\":\"-771492660\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"1110000000000011\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-791\",\"lat\":\"-1103\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-610\",\"lat\":\"-876\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-3\",\"lat\":\"2\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-1149\",\"lat\":\"-1750\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-133\",\"lat\":\"-257\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-121\",\"lat\":\"-538\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"25\",\"lat\":\"-360\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"241\",\"lat\":\"-469\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"260\",\"lat\":\"-232\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"159\",\"lat\":\"-84\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"SouthernPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389549055\",\"long\":\"-771494061\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0000001111000000\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"602\",\"lat\":\"849\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"834\",\"lat\":\"1109\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"353\",\"lat\":\"584\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"1646\",\"lat\":\"3238\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"EasternPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389549656\",\"long\":\"-771491766\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0011110000000000\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-1693\",\"lat\":\"241\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"-4063\",\"lat\":\"1160\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"-2311\",\"lat\":\"981\"}}}}}}}}}},\"notUsed2\":\"0\",\"notUsed3\":\"0\",\"content\":{\"advisory\":{\"SEQUENCE\":{\"item\":{\"itis\":\"9486\"}},\"SEQUENCE\":{\"item\":{\"itis\":\"13585\"}}}},\"url\":\"null\"}}}}",
+            "default":"{\"TravelerInformation\":{\"msgCnt\":\"1\",\"timeStamp\":\"3960\",\"packetID\":\"8D442EF003FC6B1B01\",\"urlB\":\"null\",\"dataFrames\":{\"TravelerDataFrame\":{\"sspTimRights\":\"0\",\"frameType\":{\"advisory\":\"\"},\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":\"389550358\",\"long\":\"-771495007\"},\"viewAngle\":\"1111111111111111\",\"mutcdCode\":{\"warning\":\"\"}}},\"startYear\":\"2025\",\"startTime\":\"3960\",\"duratonTime\":\"32000\",\"priority\":\"5\",\"sspLocationRights\":\"0\",\"regions\":{\"GeographicalPath\":{\"name\":\"WesternPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389550358\",\"long\":\"-771495007\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0000000000111100\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"1556\",\"lat\":\"-454\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"1676\",\"lat\":\"-254\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"5293\",\"lat\":\"-531\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"NorthernPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389551020\",\"long\":\"-771492660\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"1110000000000011\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-791\",\"lat\":\"-1103\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-610\",\"lat\":\"-876\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-3\",\"lat\":\"2\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-1149\",\"lat\":\"-1750\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-133\",\"lat\":\"-257\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-121\",\"lat\":\"-538\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"25\",\"lat\":\"-360\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"241\",\"lat\":\"-469\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"260\",\"lat\":\"-232\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"159\",\"lat\":\"-84\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"SouthernPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389549055\",\"long\":\"-771494061\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0000001111000000\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"602\",\"lat\":\"849\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"834\",\"lat\":\"1109\"}}},\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"353\",\"lat\":\"584\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"1646\",\"lat\":\"3238\"}}}}}}}}},\"GeographicalPath\":{\"name\":\"EasternPedestrianCrossing\",\"id\":{\"region\":\"0\",\"id\":\"0\"},\"anchor\":{\"lat\":\"389549656\",\"long\":\"-771491766\"},\"laneWidth\":\"600\",\"directionality\":{\"reverse\":\"\"},\"closedPath\":{\"false\":\"\"},\"direction\":\"0011110000000000\",\"description\":{\"path\":{\"scale\":\"0\",\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":{\"delta\":{\"node-LL1\":{\"lon\":\"-1693\",\"lat\":\"241\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"-4063\",\"lat\":\"1160\"}}},\"NodeLL\":{\"delta\":{\"node-LL2\":{\"lon\":\"-2311\",\"lat\":\"981\"}}}}}}}}}},\"sspMsgRights1\":\"0\",\"sspMsgRights2\":\"0\",\"content\":{\"advisory\":{\"SEQUENCE\":{\"item\":{\"itis\":\"9486\"}},\"SEQUENCE\":{\"item\":{\"itis\":\"13585\"}}}},\"url\":\"null\"}}}}",
             "description":"Static Tim message to be broadcasted."
path: src/v2i-hub/PedestrianPlugin/manifest.json
user: login: dan-du-car
body: Can we update the description to be specific that we are using reference of 2016 version J2735 specs?
created_at: 2025-04-09T14:14:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,19 +14,15 @@ namespace tmx::utils::sim{
     }
 
     std::string get_sim_config(const char *config_name, bool required) {
path: src/tmx/TmxUtils/src/simulation/SimulationEnvUtils.cpp
user: login: paulbourelly999
body: In the future we want to use infrastructure ID as RSU Source ID. This is already what we do in SensorDataSharingService. Since this functionality currently exists in carma-streets changing this method signature will not  be a change we need to make in stable branches (develop and master) if we use the Sensor Data Sharing Service to generate SDSMs from FLIR Camera detections which is why I left the method name untouched here.
created_at: 2025-04-09T15:05:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: paulbourelly999
body: No I made this mistake initially 10e7 is 100 000 000 and we want 10 000 000.
created_at: 2025-04-09T15:08:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: paulbourelly999
body: I will leave a comment here. The camera provides offset in meters and SDSM measures offset on in 10 cm increments
created_at: 2025-04-09T15:09:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
                 // Convert received lat/lon to J2735 lat/lon format
-                lat = it.second.get_child("latitude").data();
-                lat.erase(std::remove(lat.begin(), lat.end(), '.'), lat.end());
-                lat.pop_back();
+                xOffset = std::to_string(xOffsetInt);
             }
-
-            // Parse longitude
-            if (!it.second.get_child("longitude").data().empty())
+            if (!it.second.get_child("y").data().empty())
             {
+                int yOffsetInt = std::round(std::stod(it.second.get_child("y").data())*10);
+
                 // Convert received lat/lon to J2735 lat/lon format
-                lon = it.second.get_child("longitude").data();
-                lon.erase(std::remove(lon.begin(), lon.end(), '.'), lon.end());
-                lon.pop_back();
+                yOffset = std::to_string(yOffsetInt);
             }
 
+
             // Parse speed
             if (!it.second.get_child("speed").data().empty())
             {
                 // Speed from the FLIR camera is reported in m/s
                 // Convert to units of 0.02 m/s for J2735 Speed and Velocity format
                 float rawSpeed = std::stof(it.second.get_child("speed").data());
                 speed = static_cast<int>(std::round(rawSpeed / 0.02f));
-            }
-
-            // Parse out seconds from datetime string
-            std::vector<int> dateTimeArr = timeStringParser(time);                       
+            }                  
 
-            msgCount += 1;
-            if (msgCount > 127) {
-                msgCount = 0;
+            if (generateSDSM_ == false)
+            {
+                msgCount += 1;
+                if (msgCount > 127) {
+                    msgCount = 0;
+                }
             }
 
-            PLOG(logINFO) << "Received FLIR camera data at: " << dateTimeArr[0] << "/" << dateTimeArr[1] << "/" << dateTimeArr[2]
-                          << " " << dateTimeArr[3] << ":" << dateTimeArr[4] << ":" << dateTimeArr[5] << ":" << dateTimeArr[6];  
+            PLOG(logINFO) << "Message count: " << msgCount;
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: paulbourelly999
body: I can remove this.
created_at: 2025-04-09T15:09:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
                 // Convert received lat/lon to J2735 lat/lon format
-                lat = it.second.get_child("latitude").data();
-                lat.erase(std::remove(lat.begin(), lat.end(), '.'), lat.end());
-                lat.pop_back();
+                xOffset = std::to_string(xOffsetInt);
             }
-
-            // Parse longitude
-            if (!it.second.get_child("longitude").data().empty())
+            if (!it.second.get_child("y").data().empty())
             {
+                int yOffsetInt = std::round(std::stod(it.second.get_child("y").data())*10);
+
                 // Convert received lat/lon to J2735 lat/lon format
-                lon = it.second.get_child("longitude").data();
-                lon.erase(std::remove(lon.begin(), lon.end(), '.'), lon.end());
-                lon.pop_back();
+                yOffset = std::to_string(yOffsetInt);
             }
 
+
             // Parse speed
             if (!it.second.get_child("speed").data().empty())
             {
                 // Speed from the FLIR camera is reported in m/s
                 // Convert to units of 0.02 m/s for J2735 Speed and Velocity format
                 float rawSpeed = std::stof(it.second.get_child("speed").data());
                 speed = static_cast<int>(std::round(rawSpeed / 0.02f));
-            }
-
-            // Parse out seconds from datetime string
-            std::vector<int> dateTimeArr = timeStringParser(time);                       
+            }                  
 
-            msgCount += 1;
-            if (msgCount > 127) {
-                msgCount = 0;
+            if (generateSDSM_ == false)
+            {
+                msgCount += 1;
+                if (msgCount > 127) {
+                    msgCount = 0;
+                }
             }
 
-            PLOG(logINFO) << "Received FLIR camera data at: " << dateTimeArr[0] << "/" << dateTimeArr[1] << "/" << dateTimeArr[2]
-                          << " " << dateTimeArr[3] << ":" << dateTimeArr[4] << ":" << dateTimeArr[5] << ":" << dateTimeArr[6];  
+            PLOG(logINFO) << "Message count: " << msgCount;
+            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";  
 
-            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << lat << ", " << lon <<
+            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << xOffset << ", " << yOffset <<
                           "), traveling at speed: " << speed << ", with heading: " << alpha << " degrees";
 
-            PLOG(logINFO) << "Message count: " << msgCount;
-            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";
-
             std::lock_guard<mutex> lock(_msgLock);
             if (generatePSM_ == true)
             {
+                // Convert Object ID to 4 octet string
+                std::stringstream idstream;
+                idstream << std::hex << id;
+                auto objectTempId = idstream.str();
+                int str_length_diff = 8 - static_cast<int>(objectTempId.length());
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: paulbourelly999
body: Will do
created_at: 2025-04-09T15:10:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
+            int latInt = std::round(fLIRLat_* 10e6);
+            lat = std::to_string(latInt);
+            // Convert configured lat/lon to J2735 lat/lon format
+            int lonInt = std::round(fLIRLon_* 10e6);
+            lon = std::to_string(lonInt);
+            
+            if (!it.second.get_child("x").data().empty())
             {
+                int xOffsetInt = std::round(std::stod(it.second.get_child("x").data())*10);
                 // Convert received lat/lon to J2735 lat/lon format
-                lat = it.second.get_child("latitude").data();
-                lat.erase(std::remove(lat.begin(), lat.end(), '.'), lat.end());
-                lat.pop_back();
+                xOffset = std::to_string(xOffsetInt);
             }
-
-            // Parse longitude
-            if (!it.second.get_child("longitude").data().empty())
+            if (!it.second.get_child("y").data().empty())
             {
+                int yOffsetInt = std::round(std::stod(it.second.get_child("y").data())*10);
+
                 // Convert received lat/lon to J2735 lat/lon format
-                lon = it.second.get_child("longitude").data();
-                lon.erase(std::remove(lon.begin(), lon.end(), '.'), lon.end());
-                lon.pop_back();
+                yOffset = std::to_string(yOffsetInt);
             }
 
+
             // Parse speed
             if (!it.second.get_child("speed").data().empty())
             {
                 // Speed from the FLIR camera is reported in m/s
                 // Convert to units of 0.02 m/s for J2735 Speed and Velocity format
                 float rawSpeed = std::stof(it.second.get_child("speed").data());
                 speed = static_cast<int>(std::round(rawSpeed / 0.02f));
-            }
-
-            // Parse out seconds from datetime string
-            std::vector<int> dateTimeArr = timeStringParser(time);                       
+            }                  
 
-            msgCount += 1;
-            if (msgCount > 127) {
-                msgCount = 0;
+            if (generateSDSM_ == false)
+            {
+                msgCount += 1;
+                if (msgCount > 127) {
+                    msgCount = 0;
+                }
             }
 
-            PLOG(logINFO) << "Received FLIR camera data at: " << dateTimeArr[0] << "/" << dateTimeArr[1] << "/" << dateTimeArr[2]
-                          << " " << dateTimeArr[3] << ":" << dateTimeArr[4] << ":" << dateTimeArr[5] << ":" << dateTimeArr[6];  
+            PLOG(logINFO) << "Message count: " << msgCount;
+            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";  
 
-            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << lat << ", " << lon <<
+            PLOG(logINFO) << "Received FLIR camera data for pedestrian " << idResult << " at location: (" << xOffset << ", " << yOffset <<
                           "), traveling at speed: " << speed << ", with heading: " << alpha << " degrees";
 
-            PLOG(logINFO) << "Message count: " << msgCount;
-            PLOG(logDEBUG) << "Sent XMLs to BroadcastPedDet: ";
-
             std::lock_guard<mutex> lock(_msgLock);
             if (generatePSM_ == true)
             {
+                // Convert Object ID to 4 octet string
+                std::stringstream idstream;
+                idstream << std::hex << id;
+                auto objectTempId = idstream.str();
+                int str_length_diff = 8 - static_cast<int>(objectTempId.length());
+                objectTempId.append(str_length_diff, '0');
                 // Constructing PSM XML to send to BroadcastPedDet function
-                std::string psm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><PersonalSafetyMessage><basicType><aPEDESTRIAN/></basicType><secMark>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</secMark><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><id>)xml" + idResult + R"xml(</id><position><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></position><accuracy><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></accuracy><speed>)xml" + std::to_string(speed) + R"xml(</speed><heading>)xml" + std::to_string(alpha) + R"xml(</heading><pathHistory><initialPosition><utcTime><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></utcTime><long>0</long><lat>0</lat></initialPosition><crumbData><PathHistoryPoint><latOffset>0</latOffset><lonOffset>0</lonOffset><elevationOffset>0</elevationOffset><timeOffset>1</timeOffset></PathHistoryPoint></crumbData></pathHistory></PersonalSafetyMessage>)xml";
+                std::string psm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><PersonalSafetyMessage><basicType><aPEDESTRIAN/></basicType><secMark>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</secMark><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><id>)xml" + objectTempId + R"xml(</id><position><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></position><accuracy><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></accuracy><speed>)xml" + std::to_string(speed) + R"xml(</speed><heading>)xml" + std::to_string(alpha) + R"xml(</heading><pathHistory><initialPosition><utcTime><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></utcTime><long>0</long><lat>0</lat></initialPosition><crumbData><PathHistoryPoint><latOffset>0</latOffset><lonOffset>0</lonOffset><elevationOffset>0</elevationOffset><timeOffset>1</timeOffset></PathHistoryPoint></crumbData></pathHistory></PersonalSafetyMessage>)xml";
                 PLOG(logDEBUG) << std::endl << psm_xml_str;
                 psmxml = psm_xml_str;
                 msgQueue.push(psmxml);
             }
             if (generateSDSM_ == true)
             {
                 // Constructing SDSM XML to send to BroadcastPedDet function
-                std::string sdsm_xml_str = R"xml(<?xml version="1.0" encoding="UTF-8"?><SensorDataSharingMessage><msgCnt>)xml" + std::to_string(msgCount) + R"xml(</msgCnt><sourceID>)xml" + idResult + R"xml(</sourceID><equipmentType><rsu/></equipmentType><sDSMTimeStamp><year>)xml" + std::to_string(dateTimeArr[0]) + R"xml(</year><month>)xml" + std::to_string(dateTimeArr[1]) + R"xml(</month><day>)xml" + std::to_string(dateTimeArr[2]) + R"xml(</day><hour>)xml" + std::to_string(dateTimeArr[3]) + R"xml(</hour><minute>)xml" + std::to_string(dateTimeArr[4]) + R"xml(</minute><second>)xml" + std::to_string(dateTimeArr[6]) + R"xml(</second></sDSMTimeStamp><refPos><lat>)xml" + lat + R"xml(</lat><long>)xml" + lon + R"xml(</long></refPos><refPosXYConf><semiMajor>255</semiMajor><semiMinor>255</semiMinor><orientation>65535</orientation></refPosXYConf><objects><DetectedObjectData><detObjCommon><objType><vru/></objType><objTypeCfd>98</objTypeCfd><objectID>)xml" + objID + R"xml(</objectID><measurementTime>0</measurementTime><timeConfidence><time-000-001/></timeConfidence><pos><offsetX>0</offsetX><offsetY>0</offsetY></pos><posConfidence><pos><a20cm/></pos><elevation><elev-000-20/></elevation></posConfidence><speed>)xml" + std::to_string(speed) + R"xml(</speed><speedConfidence><prec0-1ms/></speedConfidence><heading>)xml" + std::to_string(alpha) + R"xml(</heading><headingConf><prec05deg/></headingConf></detObjCommon></DetectedObjectData></objects></SensorDataSharingMessage>)xml";
-                PLOG(logDEBUG) << std::endl << sdsm_xml_str;
-                sdsmxml = sdsm_xml_str;
-                msgQueue.push(sdsmxml);
+                // Append each track as a string to a DetectedObjectList
+                std::string det_obj_temp_str = R"xml(<DetectedObjectData><detObjCommon><objType><vru/></objType><objTypeCfd>98</objTypeCfd><objectID>)xml" + objID + 
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: paulbourelly999
body: Will do
created_at: 2025-04-09T15:10:21Z
author_association: CONTRIBUTOR
path: src/v2i-hub/PedestrianPlugin/scripts/websocketServer.py
user: login: paulbourelly999
body: Since this is not going to be our long term functionality. Is there concern with spending time on documentation for functionality that will not be maintained in its current state.
created_at: 2025-04-09T15:15:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -227,80 +239,87 @@ namespace PedestrianPlugin
             if (!it.second.get_child("iD").data().empty()) 
             {
                 id = std::stoi(it.second.get_child("iD").data());
-
-                // Convert the id to 4 octet string
-                std::stringstream idstream;
-                idstream << std::hex << id;
-                idResult = idstream.str();
-                int str_length_diff = 8 - static_cast<int>(idResult.length());
-                idResult.append(str_length_diff, '0');
-
-                // Need to convert ID for SDSM
-                // Map the value to be less than 65535
-                auto mappedID = id % 65535;
-                objID = std::to_string(mappedID);
+                if (id > 65535)
+                {
+                    throw std::out_of_range("ID out of range");
+                }
+                objID = std::to_string(id);
             }
 
-            // Parse latitude
-            if (!it.second.get_child("latitude").data().empty())
+            
+            // Convert configured lat/lon to J2735 lat/lon format
path: src/v2i-hub/PedestrianPlugin/src/FLIRWebSockAsyncClnSession.cpp
user: login: dan-du-car
body: > No I made this mistake initially 10e7 is 100 000 000 and we want 10 000 000.

Could we use a descriptive constant` (With inline comment: convert from degree to 1/10 miscrodegree)` for 10e6 and reuse it?
created_at: 2025-04-09T15:44:22Z
author_association: CONTRIBUTOR
path: src/v2i-hub/PedestrianPlugin/scripts/websocketServer.py
user: login: willjohnsonk
body: As discussed documentation should be minimal, only need to point out the requirements dependency when using the test script.
created_at: 2025-04-09T15:47:46Z
author_association: CONTRIBUTOR

PR comments:
user: login: dan-du-car
created_at: 2025-04-09T14:46:54Z
body: Not sure where the changes are for this PR statement "update to parse all detections from FLIR camera and populate objects in SDSM"
author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-04-09T16:22:09Z
body: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=usdot-fhwa-ops_V2X-Hub&pullRequest=696) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [0.0% Line Coverage on New Code](https://sonarcloud.io/dashboard?id=usdot-fhwa-ops_V2X-Hub&pullRequest=696) (required ≥ 80%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=usdot-fhwa-ops_V2X-Hub&pullRequest=696)


author_association: NONE