diff --git a/Dockerfile b/Dockerfile index 151a530e7..68b02572d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,7 @@ FROM ubuntu:focal-20220113 ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y sudo cmake gcc-7 g++-7 libboost1.71-all-dev libxerces-c-dev libcurl4-openssl-dev libsnmp-dev libmysqlclient-dev libjsoncpp-dev uuid-dev libusb-dev libusb-1.0-0-dev libftdi-dev swig liboctave-dev gpsd libgps-dev portaudio19-dev libsndfile1-dev libglib2.0-dev libglibmm-2.4-dev libpcre3-dev libsigc++-2.0-dev libxml++2.6-dev libxml2-dev liblzma-dev dpkg-dev libmysqlcppconn-dev libev-dev libuv1-dev git vim zip build-essential libssl-dev qtbase5-dev qtbase5-dev-tools curl libqhttpengine-dev libgtest-dev libcpprest-dev librdkafka-dev +RUN apt-get update && apt-get install -y sudo cmake gcc-7 g++-7 libboost1.71-all-dev libxerces-c-dev libcurl4-openssl-dev libsnmp-dev libmysqlclient-dev libjsoncpp-dev uuid-dev libusb-dev libusb-1.0-0-dev libftdi-dev swig liboctave-dev gpsd libgps-dev portaudio19-dev libsndfile1-dev libglib2.0-dev libglibmm-2.4-dev libpcre3-dev libsigc++-2.0-dev libxml++2.6-dev libxml2-dev liblzma-dev dpkg-dev libmysqlcppconn-dev libev-dev libuv1-dev git vim zip build-essential zlib1g libssl-dev qtbase5-dev qtbase5-dev-tools curl libqhttpengine-dev libgtest-dev libcpprest-dev librdkafka-dev wget WORKDIR cd /usr/src/googletest/googletest RUN mkdir ~/build @@ -39,11 +38,13 @@ RUN make RUN make install WORKDIR /home/V2X-Hub/ext -RUN git clone https://github.com/usdot-fhwa-OPS/qhttpengine.git -WORKDIR /home/V2X-Hub/ext/qhttpengine -RUN cmake . -RUN make -RUN make install +RUN QHTTPENGINE_VERSION=1.0.1 && \ + wget -O qhttpengine-${QHTTPENGINE_VERSION}.tar.gz https://github.com/nitroshare/qhttpengine/archive/refs/tags/${QHTTPENGINE_VERSION}.tar.gz && \ + tar xvf qhttpengine-${QHTTPENGINE_VERSION}.tar.gz && \ + cd qhttpengine-${QHTTPENGINE_VERSION}/ && \ + cmake . && \ + make -j && \ + make install WORKDIR /home/V2X-Hub/ext/ RUN git clone https://github.com/HowardHinnant/date.git diff --git a/README.md b/README.md index 7d176be81..01586ef60 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![CircleCI](https://circleci.com/gh/usdot-fhwa-OPS/V2X-Hub.svg?style=svg)](https://circleci.com/gh/usdot-fhwa-OPS/V2X-Hub) | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=usdot-fhwa-ops_V2X-Hub&metric=alert_status)](https://sonarcloud.io/dashboard?id=usdot-fhwa-ops_V2X-Hub) | ## Release Notes -As of July 29th, 2022, the V2X Hub software platform is on version 7.3.1 See more about release 7.3.1 here: [V2X Hub Release Notes]() +As of Feb 9th, 2023, the V2X Hub software platform is on version 7.4.0 See more about release 7.4.0 here: [V2X Hub Release Notes]() # Overview In order to bring infrastructure components into the Connected Vehicle architecture, you need software that will facilitate the exchange of data in a format that can be understood by both vehicles and infrastructure devices The V2X Hub, takes in data from vehicles via Basic Safety Messages (BSM) in a Society of Automotive Engineers (SAE) standard format and translates the data to a National Transportation Communications for ITS Protocol (NTCIP) that infrastructure components can understand. And vice versa. It translates Signal Phase and Timing (SPaT) data from NTCIP to SAE and sends it to the Roadside Unit (RSU) for broadcast to mobile devices, including vehicles. @@ -21,13 +21,13 @@ The V2X Hub system reduces time needed to create and deploy a roadside based V2X * DMS Plugin – The Dynamic Message Sign (DMS) Plugin will receive messages from other plugins and translate the information to NTCIP 1203 for display on a DMS * MAP Plugin – Produces intersection geometry in J2735 MAP format. * SPAT Plugin – Communicates with a traffic signal controller (TSC) using NTCIP 1202, and creates a J2735 SPaT Message. -* DSRC Immediate Forward Plugin – Sends all J2735 traffic to the 4.1 RSU for transmission out the DSRC radio. +* Immediate Forward Plugin – Sends all J2735 traffic to the 4.1 RSU for transmission out the V2X radio. * Message Receiver Plugin – Receives all J2735 traffic incoming from the 4.1 RSU for consumption by other V2X Hub plugins. * Location Plugin – Communicates with GPS devices producing location information and optionally the NMEA GP* sentences for the V2X Hub system. * RTCM Plugin – Communicates with a NTRIP network to create J2735 RTCM position correction messages. -* ODE Plugin – Pushes data to an operational data environment server using a known IP address and port. +* ODE Forward Plugin – Pushes data to an operational data environment server using a known IP address and port. * Pedestrian Plugin – Creates a PSM using information obtained from nomadic devices (ex. cell phones) through a local webserver. -* Preemption Plugin – Calls a preemption table on a controller using NTCIP 1202 V3 commands to provide passage to an emergency vehicle upon request through BSMs +* Preemption Plugin – Calls a preemption table on a controller using NTCIP 1202 V3 commands to provide passage to an emergency vehicle upon request through BSMs * SPAT Logger Plugin – Logs V2X Hub generated, UPER-encoded SPAT messages in a .csv file along with a system timestamp * TIM Plugin – Creates and broadcasts a TIM message from an .xml file based on user input through GUI or local webserver * BSM Logger Plugin – Decodes and logs BSMs received by the Message Receiver Plugin to a .csv file diff --git a/configuration/amd64/docker-compose.yml b/configuration/amd64/docker-compose.yml index 7ed58d51f..13947dbb9 100755 --- a/configuration/amd64/docker-compose.yml +++ b/configuration/amd64/docker-compose.yml @@ -19,7 +19,7 @@ services: - ./mysql/port_drayage.sql:/docker-entrypoint-initdb.d/port_drayage.sql php: - image: usdotfhwaops/php:7.3.1 + image: usdotfhwaops/php:7.4.0 container_name: php network_mode: host depends_on: @@ -29,7 +29,7 @@ services: tty: true v2xhub: - image: usdotfhwaops/v2xhubamd:7.3.1 + image: usdotfhwaops/v2xhubamd:7.4.0 container_name: v2xhub network_mode: host restart: always @@ -43,7 +43,7 @@ services: - ./logs:/var/log/tmx - ./MAP:/var/www/plugins/MAP port_drayage_webservice: - image: usdotfhwaops/port-drayage-webservice:7.3.1 + image: usdotfhwaops/port-drayage-webservice:7.4.0 container_name: port_drayage_webservice network_mode: host secrets: diff --git a/configuration/amd64/mysql/localhost.sql b/configuration/amd64/mysql/localhost.sql index 06d9abcf4..0b3021989 100644 --- a/configuration/amd64/mysql/localhost.sql +++ b/configuration/amd64/mysql/localhost.sql @@ -41,14 +41,7 @@ CREATE TABLE `eventLog` ( ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1 COMMENT='This table records events generated by every IVP core component and plugin in the IVP platform. '; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `eventLog` --- -LOCK TABLES `eventLog` WRITE; -/*!40000 ALTER TABLE `eventLog` DISABLE KEYS */; -/*!40000 ALTER TABLE `eventLog` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `installedPlugin` @@ -72,15 +65,6 @@ CREATE TABLE `installedPlugin` ( ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `installedPlugin` --- - -LOCK TABLES `installedPlugin` WRITE; -/*!40000 ALTER TABLE `installedPlugin` DISABLE KEYS */; -INSERT INTO `installedPlugin` VALUES (1,1,'/var/www/plugins/CommandPlugin','/bin/CommandPlugin','manifest.json','',1,500000),(2,2,'/var/www/plugins/CswPlugin','/bin/CswPlugin','manifest.json','',0,500000),(3,3,'/var/www/plugins/DmsPlugin','/bin/DmsPlugin','manifest.json','',0,500000),(4,4,'/var/www/plugins/DsrcImmediateForwardPlugin','/bin/DsrcImmediateForwardPlugin','manifest.json','',0,500000),(5,5,'/var/www/plugins/LocationPlugin','/bin/LocationPlugin','manifest.json','',0,500000),(6,6,'/var/www/plugins/MapPlugin','/bin/MapPlugin','manifest.json','',0,500000),(7,7,'/var/www/plugins/MessageReceiverPlugin','/bin/MessageReceiverPlugin','manifest.json','',0,500000),(8,8,'/var/www/plugins/ODEPlugin','/bin/ODEPlugin','manifest.json','',0,500000),(9,9,'/var/www/plugins/RtcmPlugin','/bin/RtcmPlugin','manifest.json','',0,500000),(10,10,'/var/www/plugins/SpatPlugin','/bin/SpatPlugin','manifest.json','',0,500000),(11,11,'/var/www/plugins/PreemptionPlugin','/bin/PreemptionPlugin','manifest.json','',0,500000),(12,12,'/var/www/plugins/SPaTLoggerPlugin','/bin/SPaTLoggerPlugin','manifest.json','',0,500000),(13,13,'/var/www/plugins/MessageLoggerPlugin','/bin/MessageLoggerPlugin','manifest.json','',0,500000),(14,14,'/var/www/plugins/PedestrianPlugin','/bin/PedestrianPlugin','manifest.json','',0,500000),(15,15,'/var/www/plugins/TimPlugin','/bin/TimPlugin','manifest.json','',0,500000),(16,16,'/var/www/plugins/CARMACloudPlugin','/bin/CARMACloudPlugin','manifest.json','',0,500000),(17,17,'/var/www/plugins/PortDrayagePlugin','/bin/PortDrayagePlugin','manifest.json','',0,500000),(18,18,'/var/www/plugins/ODELoggerPlugin','/bin/ODELoggerPlugin','manifest.json','',0,500000); -/*!40000 ALTER TABLE `installedPlugin` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `messageActivity` @@ -105,14 +89,6 @@ CREATE TABLE `messageActivity` ( ) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=latin1 COMMENT='This table records the most recent message activity of each active plugin in the IVP system. The data in this table is updated by the IVP plugin monitor core component for every message the plugin monitor receives.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `messageActivity` --- - -LOCK TABLES `messageActivity` WRITE; -/*!40000 ALTER TABLE `messageActivity` DISABLE KEYS */; -/*!40000 ALTER TABLE `messageActivity` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `messageType` @@ -131,15 +107,6 @@ CREATE TABLE `messageType` ( ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1 COMMENT='This table lists the valid message types of every plugin loaded on the IVP platform.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `messageType` --- - -LOCK TABLES `messageType` WRITE; -/*!40000 ALTER TABLE `messageType` DISABLE KEYS */; -INSERT INTO `messageType` VALUES (1,'J2735','BSM','DSRC Basic Safety Message'),(2,'J2735','CSR','DSRC Common Safety Request'),(3,'J2735','EVA','DSRC Emergency Vehicle Alert'),(4,'J2735','IC','DSRC Intersection Collision'),(5,'J2735','MAP','DSRC Map Data'),(6,'J2735','NMEA','DSRC NMEA Corrections'),(7,'J2735','PDM','DSRC Probe Data Management'),(8,'J2735','PVD','DSRC Probe Vehicle Data'),(9,'J2735','RSA','DSRC Road Side Alert'),(10,'J2735','RTCM','DSRC RTCM Corrections'),(11,'J2735','SPAT','DSRC SPAT Message'),(12,'J2735','SRM','DSRC Signal Request Message'),(13,'J2735','SSM','DSRC Signal Status Message'),(14,'J2735','TIM','DSRC Traveler Information Message'),(15,'System','KeepAlive',''); -/*!40000 ALTER TABLE `messageType` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `plugin` @@ -158,16 +125,6 @@ CREATE TABLE `plugin` ( ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=latin1 COMMENT='This table lists the plugins loaded and available to run on the IVP platform.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `plugin` --- - -LOCK TABLES `plugin` WRITE; -/*!40000 ALTER TABLE `plugin` DISABLE KEYS */; -INSERT INTO `plugin` VALUES (0,'Plugin System','The global configuration for all TMX plugins','4.0'),(1,'CommandPlugin','Listens for websocket connections from the TMX admin portal and processes commands','5.0'),(2,'CSW','Provides Curve Speed Warning (CSW).','5.0'),(3,'DynamicMessageSign','Provides communication to a dynamic message sign.','5.0'),(4,'DSRCMessageManager','Plugin that listens for TMX messages and forwards them to the DSRC Radio (i.e. the RSU).','5.0'),(5,'Location','Plugin used to send out Location Messages using data from GPSD','5.0'),(6,'MAP','Plugin that reads intersection geometry from a configuration file and publishes a J2735 MAP message.','5.0'),(7,'MessageReceiver','Plugin to receive messages from an external DSRC radio or other source','5.0'),(8,'ODEPlugin','Plugin to forward messages to the Florida ODEPlugin network','5.0'),(9,'RTCM','Plugin to listen for RTCM messages from an NTRIP caster and route those messages over DSRC','5.0'),(10,'SPAT','Plugin that reads PTLM data from a configuration file, receives live data from the signal controller, and publishes a J2735 SPAT message.','5.0'),(11,'Preemption','Preemption plugin for the IVP system.','5.0'),(12,'SPaTLoggerPlugin','Listens for SPaT messages and logs them in a file in CSV format.','5.0'),(13,'MessageLoggerPlugin','Listens for J2735 messages and logs them in a file in JSON format.','5.0'),(14,'Pedestrian','Pedestrian plugin for the IVP system.','5.0'),(15,'TIM','Provides Traveller Information Message (TIM).','5.0'),(16,'CARMACloud','CARMA cloud plugin for making websocket connection with CARMA cloud .','3.0.0'),(17,'PortDrayagePlugin','PortDrayagePlugin for sending freight trucks automated actions in a port.','5.0'),(18,'ODELoggerPlugin','Listens for J2735 messages and realtime forwards them to ODE.','5.0'),(19,'ivpcore.PluginMonitor','Core element that is responsible for starting/stopping installed plugins and monitoring the status of the plugins','3.2.0'),(20,'ivpcore.MessageProfiler','Core element that is responsible for profiling the statistics of received messages','3.2.0'),(21,'ivpcore.HistoryManager','Core element that is responsible for purging old log and history data','3.2.0'); -/*!40000 ALTER TABLE `plugin` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `pluginActivity` -- @@ -190,15 +147,6 @@ CREATE TABLE `pluginActivity` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='This table records all message activity of each active plugin in the IVP system. The data in this table is updated by each Plugin as part of PluginClient base class implementation.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `pluginActivity` --- - -LOCK TABLES `pluginActivity` WRITE; -/*!40000 ALTER TABLE `pluginActivity` DISABLE KEYS */; -/*!40000 ALTER TABLE `pluginActivity` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `pluginConfigurationParameter` -- @@ -220,16 +168,6 @@ CREATE TABLE `pluginConfigurationParameter` ( ) ENGINE=InnoDB AUTO_INCREMENT=113 DEFAULT CHARSET=latin1 COMMENT='This table lists the IVP system configuration parameters used by both core components and plugins to control the behavior of the system.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `pluginConfigurationParameter` --- - -LOCK TABLES `pluginConfigurationParameter` WRITE; -/*!40000 ALTER TABLE `pluginConfigurationParameter` DISABLE KEYS */; -INSERT INTO `pluginConfigurationParameter` VALUES (1,1,'SleepMS','100','100','The length of milliseconds to sleep between processing all messages.'),(2,1,'SSLEnabled','true','true','Enable secure connection using SSL.'),(3,1,'SSLPath','/var/www/plugins/.ssl','/var/www/plugins/.ssl','The path to the directory containing the SSL key and certificate files.'),(4,1,'EventRowLimit','50','50','The maximum number of rows returned for the initial Event Log query.'),(5,1,'DownloadPath','/var/www/download','/var/www/download','The path to the directory where downloaded files will be saved.'),(6,1,'LogLevel','ERROR','ERROR','The log level for this plugin'),(7,2,'Frequency','1000','1000','The frequency to send the TIM in milliseconds.'),(8,2,'MapFile','IVP_GF_CSW.xml','IVP_GF_CSW.xml',''),(9,2,'Snap Interval','300','300','The interval in milliseconds to keep a vehicle within a zone before allowing it to transition out of all zones.'),(10,2,'Vehicle Timeout','2000','2000','Timeout in milliseconds when a vehicle is removed from all zones if a BSM has not been received.'),(11,3,'DMS IP Address','192.168.25.30','192.168.25.30','The IP address of the NTCIP Dynamic Message Sign.'),(12,3,'DMS Port','9090','9090','The port of the NTCIP Dynamic Message Sign.'),(13,3,'Enable DMS','True','True','If true all messages are sent to the Dynamic Message Sign using NTCIP 1203.'),(14,3,'Enable Sign Simulator','True','True','If true all messages are sent to the Sign Simulator using UDP.'),(15,3,'Force Message ID','-1','-1','Immediately activates the message ID specified, then resets back to -1.'),(16,3,'Message 01','','','The text to display on the sign for ID 01 with any formatting (see NTCIP 1203).'),(17,3,'Message 02','[jl3][pt15o0]25[np]MPH','[jl3][pt15o0]25[np]MPH','The text to display on the sign for ID 02 with any formatting (see NTCIP 1203).'),(18,3,'Message 03','[jl3][pt15o0]SLOW[np]DOWN','[jl3][pt15o0]SLOW[np]DOWN','The text to display on the sign for ID 03 with any formatting (see NTCIP 1203).'),(19,3,'Message 04','[jl3][pt15o0]CRVE[np]AHED','[jl3][pt15o0]CRVE[np]AHED','The text to display on the sign for ID 04 with any formatting (see NTCIP 1203).'),(20,3,'Sign Sim IP Address','192.168.25.31','192.168.25.31','The IP address of the Sign Simulator that is the receipient of UDP messages.'),(21,3,'Sign Sim Port','9090','9090','The UDP port of the Sign Simulator that is the receipient of UDP messages.'),(22,4,'Messages_Destination_1','{ \"Messages\": [ { \"TmxType\": \"SPAT-P\", \"SendType\": \"SPAT\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"MAP-P\", \"SendType\": \"MAP\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"PSM\", \"SendType\": \"PSM\", \"PSID\": \"0x8002\" } ,{ \"TmxType\": \"TMSG07\", \"SendType\": \"TMSG07\", \"PSID\": \"0x8002\" },{ \"TmxType\": \"TMSG03-P\", \"SendType\": \"TMSG03-P\", \"PSID\": \"0xBFEE\" }] }','{ \"Messages\": [ { \"TmxType\": \"SPAT-P\", \"SendType\": \"SPAT\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"MAP-P\", \"SendType\": \"MAP\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"PSM\", \"SendType\": \"PSM\", \"PSID\": \"0x8002\" } ,{ \"TmxType\": \"TMSG07\", \"SendType\": \"TMSG07\", \"PSID\": \"0x8002\" },{ \"TmxType\": \"TMSG03-P\", \"SendType\": \"TMSG03-P\", \"PSID\": \"0xBFEE\" }] }','JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 1.'),(23,4,'Messages_Destination_2','{ \"Messages\": [ ] }','{ \"Messages\": [ ] }','JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 2.'),(24,4,'Messages_Destination_3','{ \"Messages\": [ ] }','{ \"Messages\": [ ] }','JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 3.'),(25,4,'Messages_Destination_4','{ \"Messages\": [ ] }','{ \"Messages\": [ ] }','JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 4.'),(26,4,'Destination_1','127.0.0.1:1516','127.0.0.1:1516','The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_1.'),(27,4,'Destination_2','0','0','The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_2.'),(28,4,'Destination_3','0','0','The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_3.'),(29,4,'Destination_4','0','0','The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_4.'),(30,4,'Signature','False','False','True or False value indicating whether to sign the messages.'),(31,5,'Frequency','500','500','Rate to send Location Message in milliseconds'),(32,5,'LatchHeadingSpeed','2.5','2.5','Speed at which the heading parameter should be latched, in mph. Set to 0 to disable latching.'),(33,5,'GPSSource','localhost','localhost','Host where the GPSd is running'),(34,5,'SendRawNMEA','true','true','Route the raw NMEA strings from GPSd through TMX'),(35,6,'Frequency','1000','1000','The frequency to send the MAP message in milliseconds.'),(36,6,'MAP_Files','{ \"MapFiles\": [\n {\"Action\":0, \"FilePath\":\"GID_Telegraph-Twelve_Mile_withEgress.xml\"}\n] }','{ \"MapFiles\": [\n {\"Action\":0, \"FilePath\":\"GID_Telegraph-Twelve_Mile_withEgress.xml\"}\n] }','JSON data defining a list of map files. One map file for each action set specified by the TSC.'),(37,7,'IP','127.0.0.1','127.0.0.1','IP address for the incoming message network connection.'),(38,7,'Port','26789','26789','Port for the incoming message network connection.'),(39,7,'RouteDSRC','false','false','Set the flag to route a received J2735 message over DSRC.'),(40,7,'EnableSimulatedBSM','true','true','Accept and route incoming BSM messages from a V2I Hub simulator.'),(41,7,'EnableSimulatedSRM','true','true','Accept and route incoming SRM messages from a V2I Hub simulator.'),(42,7,'EnableSimulatedLocation','true','true','Accept and route incoming GPS location messages from a V2I Hub simulator.'),(43,8,'ODEIP','127.0.0.1','127.0.0.1','IP address for the ODE network connection.'),(44,8,'ODEPort','26789','26789','Port for the ODE network connection.'),(45,9,'Endpoint IP','156.63.133.118','156.63.133.118','NTRIP caster endpoint IP address'),(46,9,'Endpoint Port','2101','2101','NTRIP caster endpoint port'),(47,9,'Username','username','username','NTRIP caster authentication username'),(48,9,'Password','password','password','NTRIP caster authentication password'),(49,9,'Mountpoint','ODOT_RTCM23','ODOT_RTCM23','NTRIP caster mountpoint'),(50,9,'RTCM Version','Unknown','Unknown','Specify the expected RTCM message version (2.3 or 3.3) coming from the caster. Use Unknown to auto detect the version, which is done using trial and error, thus may be slow.'),(51,9,'Route RTCM','false','false','Route the RTCM messages created from NTRIP internally for use by other plugins.'),(52,10,'Intersection_Id','1','1','The intersection id for SPAT generated by this plugin.'),(53,10,'Intersection_Name','Intersection','Intersection','The intersection name for SPAT generated by this plugin.'),(54,10,'SignalGroupMapping','{\"SignalGroups\":[{\"SignalGroupId\":1,\"Phase\":1,\"Type\":\"vehicle\"},{\"SignalGroupId\":2,\"Phase\":2,\"Type\":\"vehicle\"},{\"SignalGroupId\":3,\"Phase\":3,\"Type\":\"vehicle\"},{\"SignalGroupId\":4,\"Phase\":4,\"Type\":\"vehicle\"},{\"SignalGroupId\":5,\"Phase\":5,\"Type\":\"vehicle\"},{\"SignalGroupId\":6,\"Phase\":6,\"Type\":\"vehicle\"},{\"SignalGroupId\":7,\"Phase\":7,\"Type\":\"vehicle\"},{\"SignalGroupId\":8,\"Phase\":8,\"Type\":\"vehicle\"},{\"SignalGroupId\":22,\"Phase\":2,\"Type\":\"pedestrian\"},{\"SignalGroupId\":24,\"Phase\":4,\"Type\":\"pedestrian\"},{\"SignalGroupId\":26,\"Phase\":6,\"Type\":\"pedestrian\"},{\"SignalGroupId\":28,\"Phase\":8,\"Type\":\"pedestrian\"}]}','{\"SignalGroups\":[{\"SignalGroupId\":1,\"Phase\":1,\"Type\":\"vehicle\"},{\"SignalGroupId\":2,\"Phase\":2,\"Type\":\"vehicle\"},{\"SignalGroupId\":3,\"Phase\":3,\"Type\":\"vehicle\"},{\"SignalGroupId\":4,\"Phase\":4,\"Type\":\"vehicle\"},{\"SignalGroupId\":5,\"Phase\":5,\"Type\":\"vehicle\"},{\"SignalGroupId\":6,\"Phase\":6,\"Type\":\"vehicle\"},{\"SignalGroupId\":7,\"Phase\":7,\"Type\":\"vehicle\"},{\"SignalGroupId\":8,\"Phase\":8,\"Type\":\"vehicle\"},{\"SignalGroupId\":22,\"Phase\":2,\"Type\":\"pedestrian\"},{\"SignalGroupId\":24,\"Phase\":4,\"Type\":\"pedestrian\"},{\"SignalGroupId\":26,\"Phase\":6,\"Type\":\"pedestrian\"},{\"SignalGroupId\":28,\"Phase\":8,\"Type\":\"pedestrian\"}]}','JSON data defining a list of SignalGroups and phases.'),(55,10,'Local_IP','','','The IPv4 address of the local computer for receiving Traffic Signal Controller Broadcast Messages.'),(56,10,'Local_UDP_Port','local port','local port','The local UDP port for reception of Traffic Signal Controller Broadcast Messages from the TSC.'),(57,10,'TSC_IP','','','The IPv4 address of the destination Traffic Signal Controller (TSC).'),(58,10,'TSC_Remote_SNMP_Port','','','The destination port on the Traffic Signal Controller (TSC) for SNMP NTCIP communication.'),(59,11,'Instance','0','0','The instance of Preemption plugin.'),(60,11,'BasePreemptionOid','.1.3.6.1.4.1.1206.4.2.1.6.3.1.2.','.1.3.6.1.4.1.1206.4.2.1.6.3.1.2.','The BasePreemptionOid of Preemption plugin.'),(61,11,'ipwithport',':',':','The ipwithport of Preemption plugin.'),(62,11,'snmp_community','public','public','The snmp_community of Preemption plugin.'),(63,11,'map_path','/geo.json','/geo.json','The map_path for Preemption plugin.'),(64,11,'allowedList','{\"validVehicles\":[\"292710445\",\"123456789\",\"2345678\"]}','{\"validVehicles\":[\"292710445\",\"123456789\",\"2345678\"]}','List of vehicles BSM id that are allowed'),(65,12,'File Size In MB','100','100','Maximum size of the SPaT log file in mb.'),(66,12,'Filename','spatTx','spatTx','Default name of the SPaT log file.'),(67,12,'File Location','/var/log/tmx','/var/log/tmx','The location where the log files are stored. DO NOT edit while using docker deployment of V2X-Hub!'),(68,13,'File Size In MB','100','100','Maximum size of the BSM log file in mb.'),(69,13,'Filename','bsmTx','bsmTx','Default name of the BSM log file.'),(70,13,'File Location','/var/log/tmx','/var/log/tmx','The location where the log files are stored. DO NOT edit while using docker deployment of V2X-Hub!'),(71,14,'Frequency','1000','1000','The frequency to send the PSM in milliseconds.'),(72,14,'Instance','0','0','The instance of Pedestrian plugin.'),(73,14,'WebServiceIP','127.0.0.1','127.0.0.1','IP address at which the web service exists'),(74,14,'WebServicePort','9000','9000','Port at which Web service exists'),(75,15,'Frequency','1000','1000','The frequency to send the TIM in milliseconds.'),(76,15,'MapFile','/var/www/plugins/MAP/IVP_GF_TIM.xml','/var/www/plugins/MAP/IVP_GF_TIM.xml',''),(77,15,'Start_Broadcast_Date','01-01-2019','01-01-2019','The Start Broadcast Date for the TIM message in the (mm-dd-YYYY) format.'),(78,15,'Stop_Broadcast_Date','12-31-2020','12-31-2020','The Stop Broadcast Date for the TIM message in the (mm-dd-YYYY) format.'),(79,15,'Start_Broadcast_Time','06:00:00','06:00:00','The Start Broadcast Time for the TIM message in the (HH:MM:SS) format.'),(80,15,'Stop_Broadcast_Time','21:00:00','21:00:00','The Start Broadcast Time for the TIM message in the (HH:MM:SS) format.'),(81,15,'WebServiceIP','127.0.0.1','127.0.0.1','IP address at which the web service exists'),(82,15,'WebServicePort','10000','10000','Port at which Web service exists'),(83,16,'Frequency','1000','1000','The frequency to send the TIM in milliseconds.'),(84,16,'Instance','0','0','The instance of this plugin.'),(85,16,'WebServiceIP','127.0.0.1','127.0.0.1','Server IP address for V2X hub'),(86,16,'WebServicePort','22222','22222','Server Port for V2X hub'),(87,17,'Database_IP','127.0.0.1','127.0.0.1','IP address of database'),(88,17,'Database_Port','3306','3306','Port of database'),(89,17,'Database_Username','root','root','Username for database'),(90,17,'Database_Password','ivp','ivp','Password for database'),(91,17,'Database_Name','PORT_DRAYAGE','PORT_DRAYAGE','Name of database'),(92,17,'LogLevel','INFO','INFO','The log level for this plugin'),(93,18,'instance','1','1','instance of the application'),(94,18,'schedule_frequency','1','1','sample of incoming messages to forward, 1 = forwards every message'),(95,18,'ForwardMSG','1','1','Enable Forwarding of BSM'),(96,18,'BSMKafkaTopic','topic.OdeRawEncodedBSMJson','topic.OdeRawEncodedBSMJson','(Cond: ForwardMSG == True) Topic to use for forwarding BSM'),(97,18,'SPaTKafkaTopic','topic.OdeRawEncodedSPATJson','topic.OdeRawEncodedSPATJson','(Cond: ForwardMSG == True) Topic to use for forwarding BSM'),(98,18,'KafkaBrokerIp','172.31.55.238','172.31.55.238','IP address to be used for KAFKA broker'),(99,18,'KafkaBrokerPort','9092','9092','Port number to be used for KAFKA broker'),(100,19,'Startup Delay (ms)','10000','10000','Delay in milliseconds before starting any plugins.'),(101,19,'Monitor Check Interval (ms)','5000','5000','Delay in milliseconds between monitor checks.'),(102,19,'Max Startup Time (ms)','15000','15000','Maximum allowed startup time of a plugin before it is rebooted.'),(103,20,'Database Refresh Interval (ms)','2000','2000','The interval (in milliseconds) between uploads of message statistics to the database.'),(104,20,'Message Averaging Window (ms)','20000','20000','The averaging window (in milliseconds) that the profiler measures average interval.'),(105,21,'Purge Intervals (sec)','120','120','Interval between purges of history items'),(106,21,'Max Event Log Size','2000','2000','Maximum number of event log entries to keep. A value of zero will result in no purging of event log entries'); -/*!40000 ALTER TABLE `pluginConfigurationParameter` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `pluginMessageMap` -- @@ -250,15 +188,6 @@ CREATE TABLE `pluginMessageMap` ( ) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=latin1 COMMENT='This table identifies the types of messages generated by each plugin.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `pluginMessageMap` --- - -LOCK TABLES `pluginMessageMap` WRITE; -/*!40000 ALTER TABLE `pluginMessageMap` DISABLE KEYS */; -INSERT INTO `pluginMessageMap` VALUES (1,1,15),(1361,7,1),(70,7,15),(75,13,15),(1538,15,14),(1435,17,30); -/*!40000 ALTER TABLE `pluginMessageMap` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `pluginStatus` @@ -279,14 +208,6 @@ CREATE TABLE `pluginStatus` ( ) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `pluginStatus` --- - -LOCK TABLES `pluginStatus` WRITE; -/*!40000 ALTER TABLE `pluginStatus` DISABLE KEYS */; -/*!40000 ALTER TABLE `pluginStatus` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `systemConfigurationParameter` @@ -305,16 +226,6 @@ CREATE TABLE `systemConfigurationParameter` ( ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 COMMENT='This table lists the IVP system configuration parameters used by both core components and plugins to control the behavior of the system.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `systemConfigurationParameter` --- - -LOCK TABLES `systemConfigurationParameter` WRITE; -/*!40000 ALTER TABLE `systemConfigurationParameter` DISABLE KEYS */; -INSERT INTO `systemConfigurationParameter` VALUES (1,'LOG_FILE_NAME','ivpcore.log','ivpcore.log'); -/*!40000 ALTER TABLE `systemConfigurationParameter` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `user` -- @@ -333,14 +244,7 @@ CREATE TABLE `user` ( ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1 COMMENT='The list of accounts that can access the IVP platform via the administrative portal is held in the users table.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `user` --- -LOCK TABLES `user` WRITE; -/*!40000 ALTER TABLE `user` DISABLE KEYS */; -/*!40000 ALTER TABLE `user` ENABLE KEYS */; -UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -351,4 +255,3 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2021-08-25 13:36:29 diff --git a/configuration/arm64/docker-compose.yml b/configuration/arm64/docker-compose.yml index 8522f715f..db4aa4b9d 100644 --- a/configuration/arm64/docker-compose.yml +++ b/configuration/arm64/docker-compose.yml @@ -19,7 +19,7 @@ services: - ./mysql/port_drayage.sql:/docker-entrypoint-initdb.d/port_drayage.sql php: - image: usdotfhwaops/php_arm:7.3.1 + image: usdotfhwaops/php_arm:7.4.0 container_name: php network_mode: host depends_on: @@ -29,7 +29,7 @@ services: tty: true v2xhub: - image: usdotfhwaops/v2xhubarm:7.3.1 + image: usdotfhwaops/v2xhubarm:7.4.0 container_name: v2xhub network_mode: host restart: always @@ -43,7 +43,7 @@ services: - ./logs:/var/log/tmx - ./MAP:/var/www/plugins/MAP port_drayage_webservice: - image: usdotfhwaops/port-drayage-webservice_arm:7.3.1 + image: usdotfhwaops/port-drayage-webservice_arm:7.4.0 container_name: port_drayage_webservice network_mode: host secrets: diff --git a/configuration/arm64/mysql/localhost.sql b/configuration/arm64/mysql/localhost.sql index 12b072cc7..d8c22bd11 100644 --- a/configuration/arm64/mysql/localhost.sql +++ b/configuration/arm64/mysql/localhost.sql @@ -41,15 +41,6 @@ CREATE TABLE `eventLog` ( ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1 COMMENT='This table records events generated by every IVP core component and plugin in the IVP platform. '; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `eventLog` --- - -LOCK TABLES `eventLog` WRITE; -/*!40000 ALTER TABLE `eventLog` DISABLE KEYS */; -/*!40000 ALTER TABLE `eventLog` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `installedPlugin` -- @@ -72,15 +63,6 @@ CREATE TABLE `installedPlugin` ( ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `installedPlugin` --- - -LOCK TABLES `installedPlugin` WRITE; -/*!40000 ALTER TABLE `installedPlugin` DISABLE KEYS */; -INSERT INTO `installedPlugin` VALUES (1,1,'/var/www/plugins/CommandPlugin','/bin/CommandPlugin','manifest.json','',1,500000),(2,2,'/var/www/plugins/CswPlugin','/bin/CswPlugin','manifest.json','',0,500000),(3,3,'/var/www/plugins/DmsPlugin','/bin/DmsPlugin','manifest.json','',0,500000),(4,4,'/var/www/plugins/DsrcImmediateForwardPlugin','/bin/DsrcImmediateForwardPlugin','manifest.json','',0,500000),(5,5,'/var/www/plugins/LocationPlugin','/bin/LocationPlugin','manifest.json','',0,500000),(6,6,'/var/www/plugins/MapPlugin','/bin/MapPlugin','manifest.json','',0,500000),(7,7,'/var/www/plugins/MessageReceiverPlugin','/bin/MessageReceiverPlugin','manifest.json','',0,500000),(8,8,'/var/www/plugins/ODEPlugin','/bin/ODEPlugin','manifest.json','',0,500000),(9,9,'/var/www/plugins/RtcmPlugin','/bin/RtcmPlugin','manifest.json','',0,500000),(10,10,'/var/www/plugins/SpatPlugin','/bin/SpatPlugin','manifest.json','',0,500000),(11,11,'/var/www/plugins/PreemptionPlugin','/bin/PreemptionPlugin','manifest.json','',0,500000),(12,12,'/var/www/plugins/SPaTLoggerPlugin','/bin/SPaTLoggerPlugin','manifest.json','',0,500000),(13,13,'/var/www/plugins/MessageLoggerPlugin','/bin/MessageLoggerPlugin','manifest.json','',0,500000),(14,14,'/var/www/plugins/PedestrianPlugin','/bin/PedestrianPlugin','manifest.json','',0,500000),(15,15,'/var/www/plugins/TimPlugin','/bin/TimPlugin','manifest.json','',0,500000),(16,16,'/var/www/plugins/CARMACloudPlugin','/bin/CARMACloudPlugin','manifest.json','',0,500000),(17,17,'/var/www/plugins/PortDrayagePlugin','/bin/PortDrayagePlugin','manifest.json','',0,500000),(18,18,'/var/www/plugins/ODELoggerPlugin','/bin/ODELoggerPlugin','manifest.json','',0,500000); -/*!40000 ALTER TABLE `installedPlugin` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `messageActivity` @@ -105,14 +87,6 @@ CREATE TABLE `messageActivity` ( ) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=latin1 COMMENT='This table records the most recent message activity of each active plugin in the IVP system. The data in this table is updated by the IVP plugin monitor core component for every message the plugin monitor receives.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `messageActivity` --- - -LOCK TABLES `messageActivity` WRITE; -/*!40000 ALTER TABLE `messageActivity` DISABLE KEYS */; -/*!40000 ALTER TABLE `messageActivity` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `messageType` @@ -131,15 +105,6 @@ CREATE TABLE `messageType` ( ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1 COMMENT='This table lists the valid message types of every plugin loaded on the IVP platform.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `messageType` --- - -LOCK TABLES `messageType` WRITE; -/*!40000 ALTER TABLE `messageType` DISABLE KEYS */; -INSERT INTO `messageType` VALUES (1,'J2735','BSM','DSRC Basic Safety Message'),(2,'J2735','CSR','DSRC Common Safety Request'),(3,'J2735','EVA','DSRC Emergency Vehicle Alert'),(4,'J2735','IC','DSRC Intersection Collision'),(5,'J2735','MAP','DSRC Map Data'),(6,'J2735','NMEA','DSRC NMEA Corrections'),(7,'J2735','PDM','DSRC Probe Data Management'),(8,'J2735','PVD','DSRC Probe Vehicle Data'),(9,'J2735','RSA','DSRC Road Side Alert'),(10,'J2735','RTCM','DSRC RTCM Corrections'),(11,'J2735','SPAT','DSRC SPAT Message'),(12,'J2735','SRM','DSRC Signal Request Message'),(13,'J2735','SSM','DSRC Signal Status Message'),(14,'J2735','TIM','DSRC Traveler Information Message'),(15,'System','KeepAlive',''); -/*!40000 ALTER TABLE `messageType` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `plugin` @@ -158,16 +123,6 @@ CREATE TABLE `plugin` ( ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=latin1 COMMENT='This table lists the plugins loaded and available to run on the IVP platform.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `plugin` --- - -LOCK TABLES `plugin` WRITE; -/*!40000 ALTER TABLE `plugin` DISABLE KEYS */; -INSERT INTO `plugin` VALUES (0,'Plugin System','The global configuration for all TMX plugins','4.0'),(1,'CommandPlugin','Listens for websocket connections from the TMX admin portal and processes commands','5.0'),(2,'CSW','Provides Curve Speed Warning (CSW).','5.0'),(3,'DynamicMessageSign','Provides communication to a dynamic message sign.','5.0'),(4,'DSRCMessageManager','Plugin that listens for TMX messages and forwards them to the DSRC Radio (i.e. the RSU).','5.0'),(5,'Location','Plugin used to send out Location Messages using data from GPSD','5.0'),(6,'MAP','Plugin that reads intersection geometry from a configuration file and publishes a J2735 MAP message.','5.0'),(7,'MessageReceiver','Plugin to receive messages from an external DSRC radio or other source','5.0'),(8,'ODEPlugin','Plugin to forward messages to the Florida ODEPlugin network','5.0'),(9,'RTCM','Plugin to listen for RTCM messages from an NTRIP caster and route those messages over DSRC','5.0'),(10,'SPAT','Plugin that reads PTLM data from a configuration file, receives live data from the signal controller, and publishes a J2735 SPAT message.','5.0'),(11,'Preemption','Preemption plugin for the IVP system.','5.0'),(12,'SPaTLoggerPlugin','Listens for SPaT messages and logs them in a file in CSV format.','5.0'),(13,'MessageLoggerPlugin','Listens for J2735 messages and logs them in a file in JSON format.','5.0'),(14,'Pedestrian','Pedestrian plugin for the IVP system.','5.0'),(15,'TIM','Provides Traveller Information Message (TIM).','5.0'),(16,'CARMACloud','CARMA cloud plugin for making websocket connection with CARMA cloud .','3.0.0'),(17,'PortDrayagePlugin','PortDrayagePlugin for sending freight trucks automated actions in a port.','5.0'),(18,'ODELoggerPlugin','Listens for J2735 messages and realtime forwards them to ODE.','5.0'),(19,'ivpcore.PluginMonitor','Core element that is responsible for starting/stopping installed plugins and monitoring the status of the plugins','3.2.0'),(20,'ivpcore.MessageProfiler','Core element that is responsible for profiling the statistics of received messages','3.2.0'),(21,'ivpcore.HistoryManager','Core element that is responsible for purging old log and history data','3.2.0'); -/*!40000 ALTER TABLE `plugin` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `pluginActivity` -- @@ -190,14 +145,6 @@ CREATE TABLE `pluginActivity` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='This table records all message activity of each active plugin in the IVP system. The data in this table is updated by each Plugin as part of PluginClient base class implementation.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `pluginActivity` --- - -LOCK TABLES `pluginActivity` WRITE; -/*!40000 ALTER TABLE `pluginActivity` DISABLE KEYS */; -/*!40000 ALTER TABLE `pluginActivity` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `pluginConfigurationParameter` @@ -220,16 +167,6 @@ CREATE TABLE `pluginConfigurationParameter` ( ) ENGINE=InnoDB AUTO_INCREMENT=113 DEFAULT CHARSET=latin1 COMMENT='This table lists the IVP system configuration parameters used by both core components and plugins to control the behavior of the system.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `pluginConfigurationParameter` --- - -LOCK TABLES `pluginConfigurationParameter` WRITE; -/*!40000 ALTER TABLE `pluginConfigurationParameter` DISABLE KEYS */; -INSERT INTO `pluginConfigurationParameter` VALUES (1,1,'SleepMS','100','100','The length of milliseconds to sleep between processing all messages.'),(2,1,'SSLEnabled','true','true','Enable secure connection using SSL.'),(3,1,'SSLPath','/var/www/plugins/.ssl','/var/www/plugins/.ssl','The path to the directory containing the SSL key and certificate files.'),(4,1,'EventRowLimit','50','50','The maximum number of rows returned for the initial Event Log query.'),(5,1,'DownloadPath','/var/www/download','/var/www/download','The path to the directory where downloaded files will be saved.'),(6,1,'LogLevel','ERROR','ERROR','The log level for this plugin'),(7,2,'Frequency','1000','1000','The frequency to send the TIM in milliseconds.'),(8,2,'MapFile','IVP_GF_CSW.xml','IVP_GF_CSW.xml',''),(9,2,'Snap Interval','300','300','The interval in milliseconds to keep a vehicle within a zone before allowing it to transition out of all zones.'),(10,2,'Vehicle Timeout','2000','2000','Timeout in milliseconds when a vehicle is removed from all zones if a BSM has not been received.'),(11,3,'DMS IP Address','192.168.25.30','192.168.25.30','The IP address of the NTCIP Dynamic Message Sign.'),(12,3,'DMS Port','9090','9090','The port of the NTCIP Dynamic Message Sign.'),(13,3,'Enable DMS','True','True','If true all messages are sent to the Dynamic Message Sign using NTCIP 1203.'),(14,3,'Enable Sign Simulator','True','True','If true all messages are sent to the Sign Simulator using UDP.'),(15,3,'Force Message ID','-1','-1','Immediately activates the message ID specified, then resets back to -1.'),(16,3,'Message 01','','','The text to display on the sign for ID 01 with any formatting (see NTCIP 1203).'),(17,3,'Message 02','[jl3][pt15o0]25[np]MPH','[jl3][pt15o0]25[np]MPH','The text to display on the sign for ID 02 with any formatting (see NTCIP 1203).'),(18,3,'Message 03','[jl3][pt15o0]SLOW[np]DOWN','[jl3][pt15o0]SLOW[np]DOWN','The text to display on the sign for ID 03 with any formatting (see NTCIP 1203).'),(19,3,'Message 04','[jl3][pt15o0]CRVE[np]AHED','[jl3][pt15o0]CRVE[np]AHED','The text to display on the sign for ID 04 with any formatting (see NTCIP 1203).'),(20,3,'Sign Sim IP Address','192.168.25.31','192.168.25.31','The IP address of the Sign Simulator that is the receipient of UDP messages.'),(21,3,'Sign Sim Port','9090','9090','The UDP port of the Sign Simulator that is the receipient of UDP messages.'),(22,4,'Messages_Destination_1','{ \"Messages\": [ { \"TmxType\": \"SPAT-P\", \"SendType\": \"SPAT\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"MAP-P\", \"SendType\": \"MAP\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"PSM\", \"SendType\": \"PSM\", \"PSID\": \"0x8002\" } ,{ \"TmxType\": \"TMSG07\", \"SendType\": \"TMSG07\", \"PSID\": \"0x8002\" }] }','{ \"Messages\": [ { \"TmxType\": \"SPAT-P\", \"SendType\": \"SPAT\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"MAP-P\", \"SendType\": \"MAP\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"PSM\", \"SendType\": \"PSM\", \"PSID\": \"0x8002\" } ,{ \"TmxType\": \"TMSG07\", \"SendType\": \"TMSG07\", \"PSID\": \"0x8002\" }] }','JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 1.'),(23,4,'Messages_Destination_2','{ \"Messages\": [ ] }','{ \"Messages\": [ ] }','JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 2.'),(24,4,'Messages_Destination_3','{ \"Messages\": [ ] }','{ \"Messages\": [ ] }','JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 3.'),(25,4,'Messages_Destination_4','{ \"Messages\": [ ] }','{ \"Messages\": [ ] }','JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 4.'),(26,4,'Destination_1','127.0.0.1:1516','127.0.0.1:1516','The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_1.'),(27,4,'Destination_2','0','0','The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_2.'),(28,4,'Destination_3','0','0','The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_3.'),(29,4,'Destination_4','0','0','The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_4.'),(30,4,'Signature','False','False','True or False value indicating whether to sign the messages.'),(31,5,'Frequency','500','500','Rate to send Location Message in milliseconds'),(32,5,'LatchHeadingSpeed','2.5','2.5','Speed at which the heading parameter should be latched, in mph. Set to 0 to disable latching.'),(33,5,'GPSSource','localhost','localhost','Host where the GPSd is running'),(34,5,'SendRawNMEA','true','true','Route the raw NMEA strings from GPSd through TMX'),(35,6,'Frequency','1000','1000','The frequency to send the MAP message in milliseconds.'),(36,6,'MAP_Files','{ \"MapFiles\": [\n {\"Action\":0, \"FilePath\":\"GID_Telegraph-Twelve_Mile_withEgress.xml\"}\n] }','{ \"MapFiles\": [\n {\"Action\":0, \"FilePath\":\"GID_Telegraph-Twelve_Mile_withEgress.xml\"}\n] }','JSON data defining a list of map files. One map file for each action set specified by the TSC.'),(37,7,'IP','127.0.0.1','127.0.0.1','IP address for the incoming message network connection.'),(38,7,'Port','26789','26789','Port for the incoming message network connection.'),(39,7,'RouteDSRC','false','false','Set the flag to route a received J2735 message over DSRC.'),(40,7,'EnableSimulatedBSM','true','true','Accept and route incoming BSM messages from a V2I Hub simulator.'),(41,7,'EnableSimulatedSRM','true','true','Accept and route incoming SRM messages from a V2I Hub simulator.'),(42,7,'EnableSimulatedLocation','true','true','Accept and route incoming GPS location messages from a V2I Hub simulator.'),(43,8,'ODEIP','127.0.0.1','127.0.0.1','IP address for the ODE network connection.'),(44,8,'ODEPort','26789','26789','Port for the ODE network connection.'),(45,9,'Endpoint IP','156.63.133.118','156.63.133.118','NTRIP caster endpoint IP address'),(46,9,'Endpoint Port','2101','2101','NTRIP caster endpoint port'),(47,9,'Username','username','username','NTRIP caster authentication username'),(48,9,'Password','password','password','NTRIP caster authentication password'),(49,9,'Mountpoint','ODOT_RTCM23','ODOT_RTCM23','NTRIP caster mountpoint'),(50,9,'RTCM Version','Unknown','Unknown','Specify the expected RTCM message version (2.3 or 3.3) coming from the caster. Use Unknown to auto detect the version, which is done using trial and error, thus may be slow.'),(51,9,'Route RTCM','false','false','Route the RTCM messages created from NTRIP internally for use by other plugins.'),(52,10,'Intersection_Id','1','1','The intersection id for SPAT generated by this plugin.'),(53,10,'Intersection_Name','Intersection','Intersection','The intersection name for SPAT generated by this plugin.'),(54,10,'SignalGroupMapping','{\"SignalGroups\":[{\"SignalGroupId\":1,\"Phase\":1,\"Type\":\"vehicle\"},{\"SignalGroupId\":2,\"Phase\":2,\"Type\":\"vehicle\"},{\"SignalGroupId\":3,\"Phase\":3,\"Type\":\"vehicle\"},{\"SignalGroupId\":4,\"Phase\":4,\"Type\":\"vehicle\"},{\"SignalGroupId\":5,\"Phase\":5,\"Type\":\"vehicle\"},{\"SignalGroupId\":6,\"Phase\":6,\"Type\":\"vehicle\"},{\"SignalGroupId\":7,\"Phase\":7,\"Type\":\"vehicle\"},{\"SignalGroupId\":8,\"Phase\":8,\"Type\":\"vehicle\"},{\"SignalGroupId\":22,\"Phase\":2,\"Type\":\"pedestrian\"},{\"SignalGroupId\":24,\"Phase\":4,\"Type\":\"pedestrian\"},{\"SignalGroupId\":26,\"Phase\":6,\"Type\":\"pedestrian\"},{\"SignalGroupId\":28,\"Phase\":8,\"Type\":\"pedestrian\"}]}','{\"SignalGroups\":[{\"SignalGroupId\":1,\"Phase\":1,\"Type\":\"vehicle\"},{\"SignalGroupId\":2,\"Phase\":2,\"Type\":\"vehicle\"},{\"SignalGroupId\":3,\"Phase\":3,\"Type\":\"vehicle\"},{\"SignalGroupId\":4,\"Phase\":4,\"Type\":\"vehicle\"},{\"SignalGroupId\":5,\"Phase\":5,\"Type\":\"vehicle\"},{\"SignalGroupId\":6,\"Phase\":6,\"Type\":\"vehicle\"},{\"SignalGroupId\":7,\"Phase\":7,\"Type\":\"vehicle\"},{\"SignalGroupId\":8,\"Phase\":8,\"Type\":\"vehicle\"},{\"SignalGroupId\":22,\"Phase\":2,\"Type\":\"pedestrian\"},{\"SignalGroupId\":24,\"Phase\":4,\"Type\":\"pedestrian\"},{\"SignalGroupId\":26,\"Phase\":6,\"Type\":\"pedestrian\"},{\"SignalGroupId\":28,\"Phase\":8,\"Type\":\"pedestrian\"}]}','JSON data defining a list of SignalGroups and phases.'),(55,10,'Local_IP','','','The IPv4 address of the local computer for receiving Traffic Signal Controller Broadcast Messages.'),(56,10,'Local_UDP_Port','local port','local port','The local UDP port for reception of Traffic Signal Controller Broadcast Messages from the TSC.'),(57,10,'TSC_IP','','','The IPv4 address of the destination Traffic Signal Controller (TSC).'),(58,10,'TSC_Remote_SNMP_Port','','','The destination port on the Traffic Signal Controller (TSC) for SNMP NTCIP communication.'),(59,11,'Instance','0','0','The instance of Preemption plugin.'),(60,11,'BasePreemptionOid','.1.3.6.1.4.1.1206.4.2.1.6.3.1.2.','.1.3.6.1.4.1.1206.4.2.1.6.3.1.2.','The BasePreemptionOid of Preemption plugin.'),(61,11,'ipwithport',':',':','The ipwithport of Preemption plugin.'),(62,11,'snmp_community','public','public','The snmp_community of Preemption plugin.'),(63,11,'map_path','/geo.json','/geo.json','The map_path for Preemption plugin.'),(64,11,'allowedList','{\"validVehicles\":[\"292710445\",\"123456789\",\"2345678\"]}','{\"validVehicles\":[\"292710445\",\"123456789\",\"2345678\"]}','List of vehicles BSM id that are allowed'),(65,12,'File Size In MB','100','100','Maximum size of the SPaT log file in mb.'),(66,12,'Filename','spatTx','spatTx','Default name of the SPaT log file.'),(67,12,'File Location','/var/log/tmx','/var/log/tmx','The location where the log files are stored. DO NOT edit while using docker deployment of V2X-Hub!'),(68,13,'File Size In MB','100','100','Maximum size of the BSM log file in mb.'),(69,13,'Filename','bsmTx','bsmTx','Default name of the BSM log file.'),(70,13,'File Location','/var/log/tmx','/var/log/tmx','The location where the log files are stored. DO NOT edit while using docker deployment of V2X-Hub!'),(71,14,'Frequency','1000','1000','The frequency to send the PSM in milliseconds.'),(72,14,'Instance','0','0','The instance of Pedestrian plugin.'),(73,14,'WebServiceIP','127.0.0.1','127.0.0.1','IP address at which the web service exists'),(74,14,'WebServicePort','9000','9000','Port at which Web service exists'),(75,15,'Frequency','1000','1000','The frequency to send the TIM in milliseconds.'),(76,15,'MapFile','/var/www/plugins/MAP/IVP_GF_TIM.xml','/var/www/plugins/MAP/IVP_GF_TIM.xml',''),(77,15,'Start_Broadcast_Date','01-01-2019','01-01-2019','The Start Broadcast Date for the TIM message in the (mm-dd-YYYY) format.'),(78,15,'Stop_Broadcast_Date','12-31-2020','12-31-2020','The Stop Broadcast Date for the TIM message in the (mm-dd-YYYY) format.'),(79,15,'Start_Broadcast_Time','06:00:00','06:00:00','The Start Broadcast Time for the TIM message in the (HH:MM:SS) format.'),(80,15,'Stop_Broadcast_Time','21:00:00','21:00:00','The Start Broadcast Time for the TIM message in the (HH:MM:SS) format.'),(81,15,'WebServiceIP','127.0.0.1','127.0.0.1','IP address at which the web service exists'),(82,15,'WebServicePort','10000','10000','Port at which Web service exists'),(83,16,'Frequency','1000','1000','The frequency to send the TIM in milliseconds.'),(84,16,'Instance','0','0','The instance of this plugin.'),(85,16,'WebServiceIP','127.0.0.1','127.0.0.1','Server IP address for V2X hub'),(86,16,'WebServicePort','22222','22222','Server Port for V2X hub'),(87,17,'Database_IP','127.0.0.1','127.0.0.1','IP address of database'),(88,17,'Database_Port','3306','3306','Port of database'),(89,17,'Database_Username','root','root','Username for database'),(90,17,'Database_Password','ivp','ivp','Password for database'),(91,17,'Database_Name','PORT_DRAYAGE','PORT_DRAYAGE','Name of database'),(92,17,'LogLevel','INFO','INFO','The log level for this plugin'),(93,18,'instance','1','1','instance of the application'),(94,18,'schedule_frequency','1','1','sample of incoming messages to forward, 1 = forwards every message'),(95,18,'ForwardMSG','1','1','Enable Forwarding of BSM'),(96,18,'BSMKafkaTopic','topic.OdeRawEncodedBSMJson','topic.OdeRawEncodedBSMJson','(Cond: ForwardMSG == True) Topic to use for forwarding BSM'),(97,18,'SPaTKafkaTopic','topic.OdeRawEncodedSPATJson','topic.OdeRawEncodedSPATJson','(Cond: ForwardMSG == True) Topic to use for forwarding BSM'),(98,18,'KafkaBrokerIp','172.31.55.238','172.31.55.238','IP address to be used for KAFKA broker'),(99,18,'KafkaBrokerPort','9092','9092','Port number to be used for KAFKA broker'),(100,19,'Startup Delay (ms)','10000','10000','Delay in milliseconds before starting any plugins.'),(101,19,'Monitor Check Interval (ms)','5000','5000','Delay in milliseconds between monitor checks.'),(102,19,'Max Startup Time (ms)','15000','15000','Maximum allowed startup time of a plugin before it is rebooted.'),(103,20,'Database Refresh Interval (ms)','2000','2000','The interval (in milliseconds) between uploads of message statistics to the database.'),(104,20,'Message Averaging Window (ms)','20000','20000','The averaging window (in milliseconds) that the profiler measures average interval.'),(105,21,'Purge Intervals (sec)','120','120','Interval between purges of history items'),(106,21,'Max Event Log Size','2000','2000','Maximum number of event log entries to keep. A value of zero will result in no purging of event log entries'); -/*!40000 ALTER TABLE `pluginConfigurationParameter` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `pluginMessageMap` -- @@ -250,15 +187,6 @@ CREATE TABLE `pluginMessageMap` ( ) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=latin1 COMMENT='This table identifies the types of messages generated by each plugin.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `pluginMessageMap` --- - -LOCK TABLES `pluginMessageMap` WRITE; -/*!40000 ALTER TABLE `pluginMessageMap` DISABLE KEYS */; -INSERT INTO `pluginMessageMap` VALUES (1,1,15),(1361,7,1),(70,7,15),(75,13,15),(1538,15,14),(1435,17,30); -/*!40000 ALTER TABLE `pluginMessageMap` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `pluginStatus` @@ -279,14 +207,6 @@ CREATE TABLE `pluginStatus` ( ) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `pluginStatus` --- - -LOCK TABLES `pluginStatus` WRITE; -/*!40000 ALTER TABLE `pluginStatus` DISABLE KEYS */; -/*!40000 ALTER TABLE `pluginStatus` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `systemConfigurationParameter` @@ -305,15 +225,6 @@ CREATE TABLE `systemConfigurationParameter` ( ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 COMMENT='This table lists the IVP system configuration parameters used by both core components and plugins to control the behavior of the system.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `systemConfigurationParameter` --- - -LOCK TABLES `systemConfigurationParameter` WRITE; -/*!40000 ALTER TABLE `systemConfigurationParameter` DISABLE KEYS */; -INSERT INTO `systemConfigurationParameter` VALUES (1,'LOG_FILE_NAME','ivpcore.log','ivpcore.log'); -/*!40000 ALTER TABLE `systemConfigurationParameter` ENABLE KEYS */; -UNLOCK TABLES; -- -- Table structure for table `user` @@ -333,14 +244,6 @@ CREATE TABLE `user` ( ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1 COMMENT='The list of accounts that can access the IVP platform via the administrative portal is held in the users table.'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Dumping data for table `user` --- - -LOCK TABLES `user` WRITE; -/*!40000 ALTER TABLE `user` DISABLE KEYS */; -/*!40000 ALTER TABLE `user` ENABLE KEYS */; -UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -350,5 +253,3 @@ UNLOCK TABLES; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2021-08-25 13:36:29 diff --git a/docker/Dockerfile-depl b/docker/Dockerfile-depl index be777bccb..37d79bdee 100644 --- a/docker/Dockerfile-depl +++ b/docker/Dockerfile-depl @@ -2,8 +2,8 @@ FROM ubuntu:focal-20220113 AS install_dependencies ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y cmake git build-essential libgtest-dev libssl-dev qtbase5-dev \ - zip libmysqlcppconn-dev libboost1.71-all-dev libmysqlclient-dev uuid-dev libxerces-c-dev qtbase5-dev \ - libcurl4-openssl-dev libgps-dev libsnmp-dev librdkafka-dev libjsoncpp-dev libev-dev libuv1-dev libcpprest-dev + zip libmysqlcppconn-dev libboost1.71-all-dev libmysqlclient-dev uuid-dev zlib1g libxerces-c-dev qtbase5-dev \ + libcurl4-openssl-dev libgps-dev libsnmp-dev librdkafka-dev libjsoncpp-dev libev-dev libuv1-dev libcpprest-dev wget # Build and install GTest WORKDIR cd /usr/src/googletest/googletest RUN mkdir ~/build @@ -44,11 +44,13 @@ RUN make RUN make install WORKDIR /home/V2X-Hub/ext -RUN git clone https://github.com/usdot-fhwa-OPS/qhttpengine.git -WORKDIR /home/V2X-Hub/ext/qhttpengine -RUN cmake . -RUN make -RUN make install +RUN QHTTPENGINE_VERSION=1.0.1 && \ + wget -O qhttpengine-${QHTTPENGINE_VERSION}.tar.gz https://github.com/nitroshare/qhttpengine/archive/refs/tags/${QHTTPENGINE_VERSION}.tar.gz && \ + tar xvf qhttpengine-${QHTTPENGINE_VERSION}.tar.gz && \ + cd qhttpengine-${QHTTPENGINE_VERSION}/ && \ + cmake . && \ + make -j && \ + make install WORKDIR /home/V2X-Hub/ext/ RUN git clone https://github.com/HowardHinnant/date.git diff --git a/docs/Release_notes.md b/docs/Release_notes.md index cde93e7bb..0c8f80de1 100644 --- a/docs/Release_notes.md +++ b/docs/Release_notes.md @@ -1,15 +1,53 @@ V2X-Hub Release Notes --------------------------------- +Version 7.4.0, released Feb 9th, 2023 +-------------------------------------------------------- + +**Summary:** +V2X Hub release 7.4.0 includes added functionality changes for CARMA-Streets plugin to broadcast Spat movement event list and updated UC1 and UC3 scheduling messages logic. The MAP Plugin functionality to process with new ‘.uper’ extension and supports other formats of MAP messages. Updated V2Xhub plugin names in UI. V2xhub Core to include BSM Part II with extension that has destination points. Along with the above enhancements, several bug fixes and CI related enhancements are included in this release. + +Enhancements in this release: +- Issue 398: Added functionality to Map Plugin to process files with extension '.uper' which will expect hex encoded MAP messages including the message frame. Also resolves some issues encountered with processing other formats of MAP messages. +- Issue 407: Updated CARMA-Streets plugin to broadcast SPaT include MovementEventList which consume modified spat JSON data from the Carma-streets traffic signal controller service and encode the streets internal spat JSON into J2735 SPAT message. +- Issue 412: Updated CARMA-Streets Plugin to consume UC 3 scheduling messages that only include ET (entering time) and read intersection type from scheduling message. Also updated UC3 and UC1 scheduling messages to include intersection ID in Mobility Header. +- Issue 422: Updated V2X-Hub Plugin names in UI as below: + 1. DSRCImmediateForwardPlugin -> ImmediateForwardPlugin + 2. ODELoggerPlugin -> ODEForwardPlugin +- Issue 423&425: Updated V2X-Hub Class names as below: + 1. DSRCImmediateForwardPlugin -> ImmediateForwardPlugin + 2. ODEForwardPlugin -> ODELoggerPlugin + 3. MessageLoggerPlugin -> MessageLoggerPlugin +- Issue 427: Updated plugins to allow different channels for message file format and this channel configuration covers all messages being generated by V2X Hub. +- Issue 439: Updated V2xhub Core to include BSM Part II with extension that has destination points, and PARTII content that has the sirenUse and LightBarUse information. +- Issue 444: Updated Docker compose configuration files to allow MySQL data persistence across restarts to avoid data is lost. + +Fixes in this release: +- Issue 351: Fixed PHP UI missing Configuration parameters due to the configuration parameter values stored in the localhost.sql files. +- Issue 415: Fixed CARMA-Streets Plugin Incorrectly translates BSM IDs with leading zeros which attempts to translate each byte in byte array to a hex resulting hex number with zeros to make it 4 bytes long. +- Issue 420: Fixed CARMA-Streets Plugin failed to encode SPaT as it should process valid SPaT messages from CARMA-Streets. For invalid messages, the plugin should print a warning or error log statement and continue with the next incoming message. +- Issue 424: Update V2X-Hub UI Version numbers with most recent numbers. +- Issue 432: Fixed libwebsockets which does not build on Ubuntu 22.04 +- Issue 434: Fixed SCSM Security Issues as below: + 1. HSM Location configuration parameter inside Message Receiver is never used and can be removed. + 2. Message Receiver does not have a configuration parameter for plugin log level. + 3. ImmediateForward plugin has a duplicate signature parameter. + 4. Signature and sign Message + 5. ImmediateForward plugin does not have a configuration parameter for plugin log level. + 6. V2X-Hub ARM image currently has segmentation fault on message signature attempts likely related to sh: 1: curl: not found. + 7. ImmediateForward plugin throws segmentation fault with receiving HTTP 500 response for message signature request +- Issue 442: Fixed DB connection pool file read errors are hidden and error message is not shown if the password file cannot be read to troubleshoot the root cause. +- Issue 446: Fixed Spat Plugin Socket Handling where spat plugin after it times out the messages are never received again. +- Issue 450: Support CI builds for forked pull requests +- Issue 451: Unit tests are failing but they're not failing the CI as they should cause build failures with unit test failures. +- Issue 467: ERV Cloud Forwarding Plugin RSU Request misses ending tag it nees to send correct format XML request. + Version 7.3.1, released July 29th, 2022 -------------------------------------------------------- **Summary:** V2X Hub release version 7.3.1 is a hotfix release for 7.3.0. The fixes primarily occurred during the Implementation of IHP2 Speed Harmonization algorithm in Carma-cloud application. -Enhancements in this release: - - Issue 262: Updated CARMA Streets plugin to receive and decode Mobility Path messages into JSON through Kafka. Bug fixes in this release: - Issue 392: Fixed Large latencies experienced between V2XHub receiving a Traffic Control Request (TCR) and broadcasting corresponding Traffic Control Messages (TCMs). - - Issue 394: Fixed V2X Hub TCMs are broadcasted more than the configured maximum quantity, and are broadcasted after an acknowledgement is received. - Issue 404: Fixed V2xhub cannot encode the TCM if the package detail has minplatoonhdwy tag. diff --git a/examples/tmx-exampleapps/SampleBSMPlugin/src/SampleBSMPlugin.cpp b/examples/tmx-exampleapps/SampleBSMPlugin/src/SampleBSMPlugin.cpp index abef1281f..8463b3f5a 100644 --- a/examples/tmx-exampleapps/SampleBSMPlugin/src/SampleBSMPlugin.cpp +++ b/examples/tmx-exampleapps/SampleBSMPlugin/src/SampleBSMPlugin.cpp @@ -26,7 +26,7 @@ namespace SampleBSMPluginNS MessageFrameMessage frame_msg(bsmMessage->get_j2735_data()); bsmEncodeMessage.set_data(TmxJ2735EncodedMessage::encode_j2735_message>(frame_msg)); bsmEncodeMessage.set_flags(IvpMsgFlags_RouteDSRC); - bsmEncodeMessage.addDsrcMetadata(172, 0x20); + bsmEncodeMessage.addDsrcMetadata(0x20); bsmEncodeMessage.refresh_timestamp(); routeable_message *rMsg = dynamic_cast(&bsmEncodeMessage); @@ -59,7 +59,7 @@ namespace SampleBSMPluginNS //Broadcast BSM bsmEncoded.set_flags(IvpMsgFlags_RouteDSRC); - bsmEncoded.addDsrcMetadata(172, 0x20); + bsmEncoded.addDsrcMetadata(0x20); bsmEncoded.refresh_timestamp(); routeable_message *rMsg = dynamic_cast(&bsmEncoded); BroadcastMessage(*rMsg); diff --git a/ext/ccserver/src/CMakeLists.txt b/ext/ccserver/src/CMakeLists.txt index e49336a49..d5f805938 100644 --- a/ext/ccserver/src/CMakeLists.txt +++ b/ext/ccserver/src/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.2 FATAL_ERROR) - +find_package(qhttpengine REQUIRED) set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) diff --git a/src/tmx/Asn_J2735/include/asn_j2735_r63/TrafficControlGeometry.h b/src/tmx/Asn_J2735/include/asn_j2735_r63/TrafficControlGeometry.h index 878ae762c..587288aed 100644 --- a/src/tmx/Asn_J2735/include/asn_j2735_r63/TrafficControlGeometry.h +++ b/src/tmx/Asn_J2735/include/asn_j2735_r63/TrafficControlGeometry.h @@ -37,7 +37,7 @@ typedef struct TrafficControlGeometry { Longitude_t reflon; Latitude_t reflat; DSRC_Elevation_t refelv; - long refwidth; + long *refwidth /* OPTIONAL */; long heading; struct TrafficControlGeometry__nodes { A_SEQUENCE_OF(struct PathNode) list; diff --git a/src/tmx/Asn_J2735/src/r63/TrafficControlGeometry.c b/src/tmx/Asn_J2735/src/r63/TrafficControlGeometry.c index 14b3466db..53f9c587f 100644 --- a/src/tmx/Asn_J2735/src/r63/TrafficControlGeometry.c +++ b/src/tmx/Asn_J2735/src/r63/TrafficControlGeometry.c @@ -101,7 +101,7 @@ memb_refwidth_constraint_1(const asn_TYPE_descriptor_t *td, const void *sptr, value = *(const long *)sptr; - if((value >= 0 && value <= 32767)) { + if((value >= 0 && value <= 32767)) { /* Constraint check succeeded */ return 0; } else { @@ -154,7 +154,7 @@ memb_nodes_constraint_1(const asn_TYPE_descriptor_t *td, const void *sptr, if((size >= 1 && size <= 255)) { /* Perform validation of the inner elements */ - return td->encoding_constraints.general_constraints(td, sptr, ctfailcb, app_key); + return SEQUENCE_OF_constraint(td, sptr, ctfailcb, app_key); } else { ASN__CTFAIL(app_key, td, sptr, "%s: constraint failed (%s:%d)", @@ -163,10 +163,10 @@ memb_nodes_constraint_1(const asn_TYPE_descriptor_t *td, const void *sptr, } } -static asn_oer_constraints_t asn_OER_type_nodes_constr_9 CC_NOTUSED = { +static asn_oer_constraints_t asn_OER_type_nodes_constr_10 CC_NOTUSED = { { 0, 0 }, -1 /* (SIZE(1..255)) */}; -static asn_per_constraints_t asn_PER_type_nodes_constr_9 CC_NOTUSED = { +static asn_per_constraints_t asn_PER_type_nodes_constr_10 CC_NOTUSED = { { APC_UNCONSTRAINED, -1, -1, 0, 0 }, { APC_CONSTRAINED, 8, 8, 1, 255 } /* (SIZE(1..255)) */, 0, 0 /* No PER value map */ @@ -195,23 +195,23 @@ static asn_per_constraints_t asn_PER_memb_refwidth_constr_8 CC_NOTUSED = { { APC_UNCONSTRAINED, -1, -1, 0, 0 }, 0, 0 /* No PER value map */ }; -static asn_oer_constraints_t asn_OER_memb_heading_constr_8 CC_NOTUSED = { +static asn_oer_constraints_t asn_OER_memb_heading_constr_9 CC_NOTUSED = { { 2, 1 } /* (0..3599) */, -1}; -static asn_per_constraints_t asn_PER_memb_heading_constr_8 CC_NOTUSED = { +static asn_per_constraints_t asn_PER_memb_heading_constr_9 CC_NOTUSED = { { APC_CONSTRAINED, 12, 12, 0, 3599 } /* (0..3599) */, { APC_UNCONSTRAINED, -1, -1, 0, 0 }, 0, 0 /* No PER value map */ }; -static asn_oer_constraints_t asn_OER_memb_nodes_constr_9 CC_NOTUSED = { +static asn_oer_constraints_t asn_OER_memb_nodes_constr_10 CC_NOTUSED = { { 0, 0 }, -1 /* (SIZE(1..255)) */}; -static asn_per_constraints_t asn_PER_memb_nodes_constr_9 CC_NOTUSED = { +static asn_per_constraints_t asn_PER_memb_nodes_constr_10 CC_NOTUSED = { { APC_UNCONSTRAINED, -1, -1, 0, 0 }, { APC_CONSTRAINED, 8, 8, 1, 255 } /* (SIZE(1..255)) */, 0, 0 /* No PER value map */ }; -static asn_TYPE_member_t asn_MBR_nodes_9[] = { +static asn_TYPE_member_t asn_MBR_nodes_10[] = { { ATF_POINTER, 0, 0, (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), 0, @@ -222,30 +222,30 @@ static asn_TYPE_member_t asn_MBR_nodes_9[] = { "" }, }; -static const ber_tlv_tag_t asn_DEF_nodes_tags_9[] = { +static const ber_tlv_tag_t asn_DEF_nodes_tags_10[] = { (ASN_TAG_CLASS_CONTEXT | (8 << 2)), (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) }; -static asn_SET_OF_specifics_t asn_SPC_nodes_specs_9 = { +static asn_SET_OF_specifics_t asn_SPC_nodes_specs_10 = { sizeof(struct TrafficControlGeometry__nodes), offsetof(struct TrafficControlGeometry__nodes, _asn_ctx), 0, /* XER encoding is XMLDelimitedItemList */ }; static /* Use -fall-defs-global to expose */ -asn_TYPE_descriptor_t asn_DEF_nodes_9 = { +asn_TYPE_descriptor_t asn_DEF_nodes_10 = { "nodes", "nodes", &asn_OP_SEQUENCE_OF, - asn_DEF_nodes_tags_9, - sizeof(asn_DEF_nodes_tags_9) - /sizeof(asn_DEF_nodes_tags_9[0]) - 1, /* 1 */ - asn_DEF_nodes_tags_9, /* Same as above */ - sizeof(asn_DEF_nodes_tags_9) - /sizeof(asn_DEF_nodes_tags_9[0]), /* 2 */ - { &asn_OER_type_nodes_constr_9, &asn_PER_type_nodes_constr_9, SEQUENCE_OF_constraint }, - asn_MBR_nodes_9, + asn_DEF_nodes_tags_10, + sizeof(asn_DEF_nodes_tags_10) + /sizeof(asn_DEF_nodes_tags_10[0]) - 1, /* 1 */ + asn_DEF_nodes_tags_10, /* Same as above */ + sizeof(asn_DEF_nodes_tags_10) + /sizeof(asn_DEF_nodes_tags_10[0]), /* 2 */ + { &asn_OER_type_nodes_constr_10, &asn_PER_type_nodes_constr_10, SEQUENCE_OF_constraint }, + asn_MBR_nodes_10, 1, /* Single element */ - &asn_SPC_nodes_specs_9 /* Additional specs */ + &asn_SPC_nodes_specs_10 /* Additional specs */ }; asn_TYPE_member_t asn_MBR_TrafficControlGeometry_1[] = { @@ -303,7 +303,7 @@ asn_TYPE_member_t asn_MBR_TrafficControlGeometry_1[] = { 0, 0, /* No default value */ "refelv" }, - { ATF_NOFLAGS, 0, offsetof(struct TrafficControlGeometry, refwidth), + { ATF_POINTER, 1, offsetof(struct TrafficControlGeometry, refwidth), (ASN_TAG_CLASS_CONTEXT | (6 << 2)), -1, /* IMPLICIT tag at current level */ &asn_DEF_NativeInteger, @@ -317,20 +317,21 @@ asn_TYPE_member_t asn_MBR_TrafficControlGeometry_1[] = { -1, /* IMPLICIT tag at current level */ &asn_DEF_NativeInteger, 0, - { &asn_OER_memb_heading_constr_8, &asn_PER_memb_heading_constr_8, memb_heading_constraint_1 }, + { &asn_OER_memb_heading_constr_9, &asn_PER_memb_heading_constr_9, memb_heading_constraint_1 }, 0, 0, /* No default value */ "heading" }, { ATF_NOFLAGS, 0, offsetof(struct TrafficControlGeometry, nodes), (ASN_TAG_CLASS_CONTEXT | (8 << 2)), 0, - &asn_DEF_nodes_9, + &asn_DEF_nodes_10, 0, - { &asn_OER_memb_nodes_constr_9, &asn_PER_memb_nodes_constr_9, memb_nodes_constraint_1 }, + { &asn_OER_memb_nodes_constr_10, &asn_PER_memb_nodes_constr_10, memb_nodes_constraint_1 }, 0, 0, /* No default value */ "nodes" }, }; +static const int asn_MAP_TrafficControlGeometry_oms_1[] = { 6 }; static const ber_tlv_tag_t asn_DEF_TrafficControlGeometry_tags_1[] = { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) }; @@ -350,7 +351,8 @@ asn_SEQUENCE_specifics_t asn_SPC_TrafficControlGeometry_specs_1 = { offsetof(struct TrafficControlGeometry, _asn_ctx), asn_MAP_TrafficControlGeometry_tag2el_1, 9, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ + asn_MAP_TrafficControlGeometry_oms_1, /* Optional members */ + 1, 0, /* Root/Additions */ -1, /* First extension addition */ }; asn_TYPE_descriptor_t asn_DEF_TrafficControlGeometry = { @@ -368,4 +370,3 @@ asn_TYPE_descriptor_t asn_DEF_TrafficControlGeometry = { 9, /* Elements count */ &asn_SPC_TrafficControlGeometry_specs_1 /* Additional specs */ }; - diff --git a/src/tmx/TmxApi/tmx/IvpMessage.c b/src/tmx/TmxApi/tmx/IvpMessage.c index e7b17b7e8..f94c852f9 100644 --- a/src/tmx/TmxApi/tmx/IvpMessage.c +++ b/src/tmx/TmxApi/tmx/IvpMessage.c @@ -53,7 +53,7 @@ IvpMessage *ivpMsg_create(const char *type, const char *subtype, const char *enc return newIvpMessage; } -IvpMessage *ivpMsg_addDsrcMetadata(IvpMessage *msg, int channel, int psid) +IvpMessage *ivpMsg_addDsrcMetadata(IvpMessage *msg, int psid, int channel) { assert(msg != NULL); if (msg == NULL) diff --git a/src/tmx/TmxApi/tmx/messages/routeable_message.hpp b/src/tmx/TmxApi/tmx/messages/routeable_message.hpp index d03ee1a9d..0c692898a 100644 --- a/src/tmx/TmxApi/tmx/messages/routeable_message.hpp +++ b/src/tmx/TmxApi/tmx/messages/routeable_message.hpp @@ -452,12 +452,12 @@ class tmx_routeable_message: public tmx_message /** * Add DSRC metadata attributes - * @param channel The DSRC channel - * @param psid The DSRC psid + * @param channel The V2X channel, default set to 172. Configurable in Immediate Forward Plugin. + * @param psid The V2X psid */ - void addDsrcMetadata(int channel, int psid) + void addDsrcMetadata(int psid, int channel = 172) { - ivpMsg_addDsrcMetadata(ivpMsg, channel, psid); + ivpMsg_addDsrcMetadata(ivpMsg, psid, channel); _dsrcChannel.bind(ivpMsg->dsrcMetadata->channel); _dsrcPsid.bind(ivpMsg->dsrcMetadata->psid); } diff --git a/src/tmx/TmxUtils/test/J2735MessageTest.cpp b/src/tmx/TmxUtils/test/J2735MessageTest.cpp index a8425da69..31510bbb2 100644 --- a/src/tmx/TmxUtils/test/J2735MessageTest.cpp +++ b/src/tmx/TmxUtils/test/J2735MessageTest.cpp @@ -572,6 +572,7 @@ TEST_F(J2735MessageTest, EncodeTrafficControlRequest){ TEST_F(J2735MessageTest, EncodeTrafficControlMessage){ + //Has tag in TCM string tsm5str=" 30642B129B984162 0 9 9 0034b8d88d084ffdaf23837926031658 0 0034b8d88d084ffdaf23837926031658 27506547 153722867280912 1111111 epsg:3785 WGS84 27506547 -818331529 281182119 0 424 3403 000 -2037220 -2037220 -2037220 -2037210 -2037220 -2037220 -2047222 -2037220 -203722-2 -2037210 -2037220 -2037220 -2037220 -2037220 -13460 "; std::stringstream ss; tsm5Message tsm5msg; @@ -584,7 +585,14 @@ TEST_F(J2735MessageTest, EncodeTrafficControlMessage){ std::cout << tsm5Enc.get_payload_str()< tag in TCM + tsm5str="D0E0C6E650394C06011002740591d261d2e99e477df0a82db260002740591d261d2e99e477df0a82db26277773121537228672809121111111epsg:3785WGS8427777312-77148351938954910903312100-1498-262-1497457-14979111-370342"; + ss<(ss); + tsm5msg.set_contents(container.get_storage().get_tree()); + tsm5Enc.encode_j2735_message(tsm5msg); + std::cout << tsm5Enc.get_payload_str()<%s%ld%ld%s",reqid, reqseq,scale,bounds_str); + sprintf(xml_str,"%s%ld%ld%s",std::to_string(webport).c_str(),list_tcm.c_str(),reqid, reqseq,scale,bounds_str); PLOG(logINFO) << "Sent TCR to cloud: "<< xml_str<bytesAvailable()>0) { - st.append(socket->readAll()); + auto readBytes = socket->readAll(); + if (socket->headers().keys().contains(CONTENT_ENCODING_KEY) && std::string(socket->headers().constFind(CONTENT_ENCODING_KEY).value().data()) == CONTENT_ENCODING_VALUE) + { + //readBytes is compressed in gzip format + st.append(UncompressBytes(readBytes)); + }else{ + st.append(readBytes); + } } QByteArray array = st.toLocal8Bit(); @@ -224,43 +231,83 @@ void CARMACloudPlugin::CARMAResponseHandler(QHttpEngine::Socket *socket) PLOG(logERROR) << "Received TCM length is zero, and skipped." << std::endl; return; } - // new updateTags section + + //Transform carma-cloud TCM XML to J2735 compatible TCM XML by updating tags tcm=updateTags(tcm,"",""); tcm=updateTags(tcm,"",""); tcm=updateTags(tcm,"TrafficControlParams","params"); tcm=updateTags(tcm,"TrafficControlGeometry","geometry"); tcm=updateTags(tcm,"TrafficControlPackage","package"); - tsm5Message tsm5message; - tsm5EncodedMessage tsm5ENC; - tmx::message_container_type container; + //List of tcm in string format + std::list tcm_sl = FilterTCMs(tcm); + for(const auto tcm_s: tcm_sl) + { + tsm5Message tsm5message; + tsm5EncodedMessage tsm5ENC; + tmx::message_container_type container; - std::stringstream ss; - ss << tcm; // updated _cloudUpdate tags, using updateTags - container.load(ss); - tsm5message.set_contents(container.get_storage().get_tree()); - tsm5ENC.encode_j2735_message(tsm5message); - BroadcastTCM(tsm5ENC); - PLOG(logINFO) << " CARMACloud Plugin :: Broadcast tsm5:: " << tsm5ENC.get_payload_str(); + std::stringstream ss; + ss << tcm_s; - //Get TCM id - Id64b_t tcmv01_req_id = tsm5message.get_j2735_data()->body.choice.tcmV01.reqid; - - ss.str(""); - for(size_t i=0; i < tcmv01_req_id.size; i++) + container.load(ss); + tsm5message.set_contents(container.get_storage().get_tree()); + tsm5ENC.encode_j2735_message(tsm5message); + BroadcastTCM(tsm5ENC); + PLOG(logINFO) << " CARMACloud Plugin :: Broadcast tsm5:: " << tsm5ENC.get_payload_str(); + + //Get TCM id + Id64b_t tcmv01_req_id = tsm5message.get_j2735_data()->body.choice.tcmV01.reqid; + //Translate TCM request id to hex string + ss.str(""); + for(size_t i=0; i < tcmv01_req_id.size; i++) + { + ss << std::setfill('0') << std::setw(2) << std::hex << (unsigned) tcmv01_req_id.buf[i]; + } + string tcmv01_req_id_hex = ss.str(); + //Transform all hex to lower case + std::transform(tcmv01_req_id_hex.begin(), tcmv01_req_id_hex.end(), tcmv01_req_id_hex.begin(), ::tolower ); + if(tcmv01_req_id_hex.length() > 0) + { + //Update map of tcm request id hex and tcm hex + std::lock_guard lock(_not_ACK_TCMs_mutex); + _not_ACK_TCMs->insert({tcmv01_req_id_hex, tsm5ENC}); + } + } +} + +std::list CARMACloudPlugin::FilterTCMs(const std::string& tcm_response) const +{ + std::list tcm_sl = {}; + try { - ss << std::setfill('0') << std::setw(2) << std::hex << (unsigned) tcmv01_req_id.buf[i]; + std::stringstream iss; + iss << tcm_response; + boost::property_tree::ptree parent_node; + boost::property_tree::read_xml(iss, parent_node); + auto child_nodes = parent_node.get_child_optional("TrafficControlMessageList"); + //The tcm response is a list of TCM + if (child_nodes) + { + for (const auto &p : child_nodes.get()) + { + boost::property_tree::ptree tcm_node; + tcm_node.put_child(p.first, p.second); + std::ostringstream oss; + boost::property_tree::write_xml(oss, tcm_node); + tcm_sl.push_back(oss.str()); + } + }else{ + tcm_sl.push_back(iss.str()); + } } - string tcmv01_req_id_hex = ss.str(); - - std::transform(tcmv01_req_id_hex.begin(), tcmv01_req_id_hex.end(), tcmv01_req_id_hex.begin(), ::tolower ); - if(tcmv01_req_id_hex.length() > 0) - { - std::lock_guard lock(_not_ACK_TCMs_mutex); - _not_ACK_TCMs->insert({tcmv01_req_id_hex, tsm5ENC}); - } + catch (const boost::property_tree::xml_parser_error &e) + { + PLOG(logERROR) << "Failed to parse the xml string." << e.what(); + } + return tcm_sl; } void CARMACloudPlugin::TCMAckCheckAndRebroadcastTCM() @@ -347,7 +394,7 @@ void CARMACloudPlugin::BroadcastTCM(tsm5EncodedMessage& tsm5ENC) { msg->set_payload(tsm5ENC.get_payload_str()); msg->set_encoding(enc); msg->set_flags(IvpMsgFlags_RouteDSRC); - msg->addDsrcMetadata(172, 0x8003); + msg->addDsrcMetadata(0x8003); msg->refresh_timestamp(); routeable_message *rMsg = dynamic_cast(msg.get()); BroadcastMessage(*rMsg); @@ -448,6 +495,8 @@ void CARMACloudPlugin::UpdateConfigSettings() { GetConfigValue("TCMNOAcknowledgementDescription", _TCMNOAcknowledgementDescription); GetConfigValue("TCMRepeatedlyBroadCastTotalTimes", _TCMRepeatedlyBroadCastTotalTimes); GetConfigValue("TCMRepeatedlyBroadcastSleep", _TCMRepeatedlyBroadcastSleep); + GetConfigValue("listTCM",list_tcm); + } @@ -548,25 +597,51 @@ void CARMACloudPlugin::ConvertString2Pair(std::pair &str_pair, co str_pair = std::make_pair(key, value); } +QByteArray CARMACloudPlugin::UncompressBytes(const QByteArray compressedBytes) const +{ + z_stream strm; + strm.zalloc = nullptr;//Refer to zlib docs (https://zlib.net/zlib_how.html) + strm.zfree = nullptr; + strm.opaque = nullptr; + strm.avail_in = compressedBytes.size(); + strm.next_in = (Byte *)compressedBytes.data(); + //checking input z_stream to see if there is any error, eg: invalid data etc. + auto err = inflateInit2(&strm, MAX_WBITS + 16); // gzip input + QByteArray outBuf; + //MAX numbers of bytes stored in a buffer + const int BUFFER_SIZE = 4092; + //There is successful, starting to decompress data + if (err == Z_OK) + { + int isDone = 0; + do + { + char buffer[BUFFER_SIZE] = {0}; + strm.avail_out = BUFFER_SIZE; + strm.next_out = (Byte *)buffer; + //Uncompress finished + isDone = inflate(&strm, Z_FINISH); + outBuf.append(buffer); + } while (Z_STREAM_END != isDone); //Reach the end of stream to be uncompressed + }else{ + PLOG(logWARNING) << "Error initalize stream. Err code = " << err << std::endl; + } + //Finished decompress data stream + inflateEnd(&strm); + return outBuf; +} + int CARMACloudPlugin::Main() { - FILE_LOG(logINFO) << "Starting plugin."; - - //std::string msg = "0.19901584057600000-7715215583895042791020100500500"; - //std::string url ="http://127.0.0.1:22222"; - //std::string base = "/carmacloud/v2xhub"; - //std::string method = "POST"; - + FILE_LOG(logINFO) << "Starting plugin."; while (_plugin->state != IvpPluginState_error) { if (IsPluginState(IvpPluginState_registered)) { - //CloudSend(msg, url, base, method); this_thread::sleep_for(chrono::milliseconds(5000)); } - } return (EXIT_SUCCESS); diff --git a/src/v2i-hub/CARMACloudPlugin/src/CARMACloudPlugin.h b/src/v2i-hub/CARMACloudPlugin/src/CARMACloudPlugin.h index 8876ade07..1cc6f1819 100644 --- a/src/v2i-hub/CARMACloudPlugin/src/CARMACloudPlugin.h +++ b/src/v2i-hub/CARMACloudPlugin/src/CARMACloudPlugin.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "PluginUtil.h" @@ -163,6 +164,19 @@ class CARMACloudPlugin: public PluginClient { * **/ bool IsSkipBroadcastCurTCM(const string & tcmv01_req_id_hex, const string & tcm_hex_payload ) const; + /** + * @brief Uncompress input source buffer + * @param compressedBytes Uncompressed source buffer + * @return QByteArray uncompressed destination buffer + */ + QByteArray UncompressBytes(const QByteArray compressedBytes) const; + /*** + * @brief Filter each individual TCM from the tcm response. + * @param tcm_response string in XML format. The TCM response string can be either a list of TCMs or one TCM. + * @return A list of TCM in XML format + */ + std::list FilterTCMs(const std::string& tcm_response) const; + private: pthread_mutex_t _settingsMutex = PTHREAD_MUTEX_INITIALIZER; @@ -202,6 +216,9 @@ class CARMACloudPlugin: public PluginClient { const string _TCMAcknowledgementStrategy = "carma3/geofence_acknowledgement"; int _TCMRepeatedlyBroadcastSleep = 100; + const char *CONTENT_ENCODING_KEY = "Content-Encoding"; + const char *CONTENT_ENCODING_VALUE = "gzip"; + std::string list_tcm = "true"; }; std::mutex _cfgLock; diff --git a/src/v2i-hub/CARMAStreetsPlugin/CMakeLists.txt b/src/v2i-hub/CARMAStreetsPlugin/CMakeLists.txt index 51c7f34d2..c9a2a11ee 100644 --- a/src/v2i-hub/CARMAStreetsPlugin/CMakeLists.txt +++ b/src/v2i-hub/CARMAStreetsPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( CARMAStreetsPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( CARMAStreetsPlugin VERSION 7.4.0 LANGUAGES CXX ) BuildTmxPlugin ( ) @@ -9,7 +9,7 @@ TARGET_LINK_LIBRARIES (${PROJECT_NAME} tmxutils rdkafka++ jsoncpp) ############# enable_testing() include_directories(${PROJECT_SOURCE_DIR}/src) -add_library(${PROJECT_NAME}_lib src/J2735MapToJsonConverter.cpp) +add_library(${PROJECT_NAME}_lib src/J2735MapToJsonConverter.cpp src/JsonToJ2735SpatConverter.cpp) target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${TMXAPI_LIBRARIES} ${ASN_J2735_LIBRARIES} ${MYSQL_LIBRARIES} diff --git a/src/v2i-hub/CARMAStreetsPlugin/manifest.json b/src/v2i-hub/CARMAStreetsPlugin/manifest.json index b870105bd..634421f62 100644 --- a/src/v2i-hub/CARMAStreetsPlugin/manifest.json +++ b/src/v2i-hub/CARMAStreetsPlugin/manifest.json @@ -19,62 +19,84 @@ "type": "J2735", "subtype": "BSM", "description": "Basic Safety Message" - }], + }, + { + "type":"J2735", + "subtype":"MAP-P", + "description":"Full geometric layout of the intersection." + }, + { + "type":"J2735", + "subtype":"SPAT-P", + "description":"Signal Phase and Timing (SPAT) status for the signalized intersection." + } + ], "configuration": [ { - "key": "transmitMobilityOperationTopic", - "default": "v2xhub_mobility_operation_in", - "description": "Apache Kafka topic plugin will transmit message to." + "key": "LogLevel", + "default": "INFO", + "description": "The log level for this plugin" }, { - "key": "transmitBSMTopic", - "default": "v2xhub_bsm_in", - "description": "Apache Kafka topic plugin will transmit message to." + "key": "IntersectionId", + "default": "9945", + "description": "The id of intersection." }, { - "key": "transmitMapTopic", - "default": "v2xhub_map_msg_in", - "description": "Apache Kafka topic plugin will transmit message to." + "key": "KafkaBrokerIp", + "default": "127.0.0.1", + "description": "IP of Apache Kafka broker." }, { - "key": "runKafkaConsumer", - "default": "1", - "description": "indicator for consuming kafka messages." + "key": "KafkaBrokerPort", + "default": "9092", + "description": "Port of Apache Kafka broker." }, { - "key": "subscribeToSchedulingPlanTopic", - "default": "v2xhub_scheduling_plan_sub", + "key": "MobilityOperationStrategies", + "default": "Carma/stop_controlled_intersection,Carma/signalized_intersection", + "description": "A comma separated list of strategies of MobilityOperation messages to send to CARMA Streets" + }, + { + "key": "MobilityOperationTopic", + "default": "v2xhub_mobility_operation_in", "description": "Apache Kafka topic plugin will transmit message to." }, { - "key": "transmitMobilityPathTopic", + "key": "MobilityPathTopic", "default": "v2xhub_mobility_path_in", "description": "Apache Kafka topic plugin will transmit message to." + }, + { + "key": "BsmTopic", + "default": "v2xhub_bsm_in", + "description": "Apache Kafka topic plugin will transmit message to." }, { - "key": "intersectionType", - "default": "Carma/stop_controlled_intersection", - "description": "The type of intersection" + "key": "MapTopic", + "default": "v2xhub_map_msg_in", + "description": "Apache Kafka topic plugin will transmit message to." }, { - "key": "KafkaBrokerIp", - "default": "127.0.0.1", - "description": "IP of Apache Kafka broker." + "key": "SchedulingPlanTopic", + "default": "v2xhub_scheduling_plan_sub", + "description": "Apache Kafka topic plugin will transmit message to." }, { - "key": "KafkaBrokerPort", - "default": "9092", - "description": "Port of Apache Kafka broker." + "key": "SchedulingPlanConsumerGroupId", + "default": "v2xhub_scheduling_plan", + "description": "Apache Kafka consumer group ID for scheduling plan consumer." }, { - "key": "MobilityOperationStrategies", - "default": "Carma/stop_controlled_intersection", - "description": "A comma separated list of strategies of MobilityOperation messages to send to CARMA Streets" + "key": "SpatTopic", + "default": "modified_spat", + "description": "Apache Kafka topic plugin will transmit message to." }, { - "key": "LogLevel", - "default": "INFO", - "description": "The log level for this plugin" + "key": "SpatConsumerGroupId", + "default": "v2xhub_spat", + "description": "Apache Kafka consumer group ID for spat consumer." } + ] } \ No newline at end of file diff --git a/src/v2i-hub/CARMAStreetsPlugin/src/CARMAStreetsPlugin.cpp b/src/v2i-hub/CARMAStreetsPlugin/src/CARMAStreetsPlugin.cpp index 8cefdd585..30545e6a8 100644 --- a/src/v2i-hub/CARMAStreetsPlugin/src/CARMAStreetsPlugin.cpp +++ b/src/v2i-hub/CARMAStreetsPlugin/src/CARMAStreetsPlugin.cpp @@ -36,16 +36,20 @@ CARMAStreetsPlugin::~CARMAStreetsPlugin() { void CARMAStreetsPlugin::UpdateConfigSettings() { lock_guard lock(_cfgLock); - GetConfigValue("receiveTopic", _receiveTopic); - GetConfigValue("transmitMobilityOperationTopic", _transmitMobilityOperationTopic); - GetConfigValue("transmitMobilityPathTopic", _transmitMobilityPathTopic); - GetConfigValue("transmitMapTopic", _transmitMAPTopic); + // Populate Header Information for outgoing mobility operation messages and filter Header for incoming mobility operation messages + GetConfigValue("IntersectionId", _intersectionId); + // Kafka broker configuration GetConfigValue("KafkaBrokerIp", _kafkaBrokerIp); GetConfigValue("KafkaBrokerPort", _kafkaBrokerPort); - GetConfigValue("runKafkaConsumer", _run_kafka_consumer); - GetConfigValue("subscribeToSchedulingPlanTopic", _subscribeToSchedulingPlanTopic); - GetConfigValue("transmitBSMTopic", _transmitBSMTopic); - GetConfigValue("intersectionType", _intersectionType); + // + GetConfigValue("SchedulingPlanTopic", _subscribeToSchedulingPlanTopic); + GetConfigValue("SchedulingPlanConsumerGroupId", _subscribeToSchedulingPlanConsumerGroupId); + GetConfigValue("SpatTopic", _subscribeToSpatTopic); + GetConfigValue("SpatConsumerGroupId", _subscribeToSpatConsumerGroupId); + GetConfigValue("BsmTopic", _transmitBSMTopic); + GetConfigValue("MobilityOperationTopic", _transmitMobilityOperationTopic); + GetConfigValue("MobilityPathTopic", _transmitMobilityPathTopic); + GetConfigValue("MapTopic", _transmitMAPTopic); // Populate strategies config string config; GetConfigValue("MobilityOperationStrategies", config); @@ -60,7 +64,8 @@ void CARMAStreetsPlugin::UpdateConfigSettings() { std::string error_string; kafkaConnectString = _kafkaBrokerIp + ':' + _kafkaBrokerPort; kafka_conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); - kafka_conf_consumer = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); + kafka_conf_sp_consumer = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); + kafka_conf_spat_consumer = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); PLOG(logDEBUG) <<"Attempting to connect to " << kafkaConnectString; if ((kafka_conf->set("bootstrap.servers", kafkaConnectString, error_string) != RdKafka::Conf::CONF_OK)) { @@ -77,39 +82,56 @@ void CARMAStreetsPlugin::UpdateConfigSettings() { } PLOG(logDEBUG) <<"Kafka producer created"; - if (kafka_conf_consumer->set("bootstrap.servers", kafkaConnectString, error_string) != RdKafka::Conf::CONF_OK || (kafka_conf_consumer->set("group.id", "streets_group", error_string) != RdKafka::Conf::CONF_OK)) { + if (kafka_conf_sp_consumer->set("bootstrap.servers", kafkaConnectString, error_string) != RdKafka::Conf::CONF_OK + || (kafka_conf_sp_consumer->set("group.id", _subscribeToSchedulingPlanConsumerGroupId, error_string) != RdKafka::Conf::CONF_OK) + || (kafka_conf_spat_consumer->set("bootstrap.servers", kafkaConnectString, error_string) != RdKafka::Conf::CONF_OK) + || (kafka_conf_spat_consumer->set("group.id", _subscribeToSpatConsumerGroupId, error_string) != RdKafka::Conf::CONF_OK)) { PLOG(logERROR) <<"Setting kafka config group.id options failed with error:" << error_string << "\n" <<"Exiting with exit code 1"; exit(1); } else { PLOG(logDEBUG) <<"Kafka config group.id options set successfully"; } - kafka_conf_consumer->set("enable.partition.eof", "true", error_string); + kafka_conf_sp_consumer->set("enable.partition.eof", "true", error_string); + kafka_conf_spat_consumer->set("enable.partition.eof", "true", error_string); - kafka_consumer = RdKafka::KafkaConsumer::create(kafka_conf_consumer, error_string); - if ( !kafka_consumer ) { - PLOG(logERROR) << "Failed to create Kafka consumer: " << error_string << std::endl; + _scheduing_plan_kafka_consumer = RdKafka::KafkaConsumer::create(kafka_conf_sp_consumer, error_string); + _spat_kafka_consumer = RdKafka::KafkaConsumer::create(kafka_conf_spat_consumer, error_string); + + if ( !_scheduing_plan_kafka_consumer || !_spat_kafka_consumer) { + PLOG(logERROR) << "Failed to create Kafka consumers: " << error_string << std::endl; exit(1); } - PLOG(logDEBUG) << "Created consumer " << kafka_consumer->name() << std::endl; + PLOG(logDEBUG) << "Created consumer " << _scheduing_plan_kafka_consumer->name() << std::endl; + PLOG(logDEBUG) << "Created consumer " << _spat_kafka_consumer->name() << std::endl; - //create kafka topic - RdKafka::Conf *tconf = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC); - if(!tconf) + //create kafka topics + RdKafka::Conf *tconf_spat = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC); + RdKafka::Conf *tconf_sp = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC); + if(!tconf_spat && !tconf_sp) { PLOG(logERROR) << "RDKafka create topic conf failed "; return; } - _topic = RdKafka::Topic::create(kafka_consumer,_subscribeToSchedulingPlanTopic,tconf,error_string); - if(!_topic) + _scheduing_plan_topic = RdKafka::Topic::create(_scheduing_plan_kafka_consumer,_subscribeToSchedulingPlanTopic,tconf_sp,error_string); + if(!_scheduing_plan_topic) + { + PLOG(logERROR) << "RDKafka create scheduing plan topic failed:" << error_string; + return ; + } + + _spat_topic = RdKafka::Topic::create(_spat_kafka_consumer,_subscribeToSpatTopic,tconf_spat,error_string); + if(!_spat_topic) { - PLOG(logERROR) << "RDKafka create topic failed:" << error_string; + PLOG(logERROR) << "RDKafka create SPAT topic failed:" << error_string; return ; } - delete tconf; + delete tconf_sp; + delete tconf_spat; - boost::thread thr(&CARMAStreetsPlugin::SubscribeKafkaTopics, this); + boost::thread thread_schpl(&CARMAStreetsPlugin::SubscribeSchedulingPlanKafkaTopic, this); + boost::thread thread_spat(&CARMAStreetsPlugin::SubscribeSpatKafkaTopic, this); } void CARMAStreetsPlugin::OnConfigChanged(const char *key, const char *value) { @@ -121,7 +143,7 @@ void CARMAStreetsPlugin::HandleMobilityOperationMessage(tsm3Message &msg, routea try { auto mobilityOperation = msg.get_j2735_data(); - PLOG(logINFO) << "Body OperationParams : " << mobilityOperation->body.operationParams.buf << "\n" + PLOG(logDEBUG) << "Body OperationParams : " << mobilityOperation->body.operationParams.buf << "\n" << "Body Strategy : " << mobilityOperation->body.strategy.buf<< "\n" <<"Queueing kafka message:topic:" << _transmitMobilityOperationTopic << " " << kafka_producer->outq_len() <<"messages already in queue"; @@ -134,6 +156,7 @@ void CARMAStreetsPlugin::HandleMobilityOperationMessage(tsm3Message &msg, routea payload << mobilityOperation->body.operationParams.buf; std::string strategy_params; std::string strategy = strat.str(); + // TODO: Filter vehicle mobility operation messages based on Mobility Header host id == intersection id if ( std::find( _strategies.begin(), _strategies.end(), strategy) != _strategies.end() ) { strategy_params = payload.str(); @@ -172,6 +195,8 @@ void CARMAStreetsPlugin::HandleMobilityOperationMessage(tsm3Message &msg, routea } catch (TmxException &ex) { PLOG(logERROR) << "Failed to decode message : " << ex.what(); + SetStatus(Key_MobilityOperationMessageSkipped, ++_mobilityOperationMessageSkipped); + } @@ -256,6 +281,7 @@ void CARMAStreetsPlugin::HandleMobilityPathMessage(tsm2Message &msg, routeable_m catch (TmxException &ex) { PLOG(logERROR) << "Failed to decode message : " << ex.what(); + SetStatus(Key_MobilityPathMessageSkipped, ++_mobilityPathMessageSkipped); } } @@ -304,13 +330,13 @@ void CARMAStreetsPlugin::HandleBasicSafetyMessage(BsmMessage &msg, routeable_mes coreData["sec_mark"] = secMark.str(); auto id_len = bsm->coreData.id.size; - std::stringstream id_ss; + unsigned long id_num = 0; for(auto i = 0; i < id_len; i++) { - id_ss<(bsm->coreData.id.buf[i]); + id_num = (id_num << 8) | bsm->coreData.id.buf[i]; } std::stringstream id_fill_ss; - id_fill_ss << std::setfill('0') << std::setw(8) << id_ss.str(); + id_fill_ss << std::setfill('0') << std::setw(8) <(Key_BSMMessageSkipped, ++_bsmMessageSkipped); + } } @@ -463,27 +491,27 @@ void CARMAStreetsPlugin::OnStateChange(IvpPluginState state) { } } -void CARMAStreetsPlugin::SubscribeKafkaTopics() +void CARMAStreetsPlugin::SubscribeSchedulingPlanKafkaTopic() { if(_subscribeToSchedulingPlanTopic.length() > 0) { - PLOG(logDEBUG) << "SubscribeKafkaTopics:" <<_subscribeToSchedulingPlanTopic << std::endl; + PLOG(logDEBUG) << "SubscribeSchedulingPlanKafkaTopics:" <<_subscribeToSchedulingPlanTopic << std::endl; std::vector topics; - topics.push_back(std::string(_subscribeToSchedulingPlanTopic)); + topics.emplace_back(_subscribeToSchedulingPlanTopic); - RdKafka::ErrorCode err = kafka_consumer->subscribe(topics); + RdKafka::ErrorCode err = _scheduing_plan_kafka_consumer->subscribe(topics); if (err) { PLOG(logERROR) << "Failed to subscribe to " << topics.size() << " topics: " << RdKafka::err2str(err) << std::endl; return; } - while (_run_kafka_consumer) + while (true) { - RdKafka::Message *msg = kafka_consumer->consume( 500 ); + auto msg = _scheduing_plan_kafka_consumer->consume( 500 ); if( msg->err() == RdKafka::ERR_NO_ERROR ) { - const char * payload_str = static_cast( msg->payload() ); + auto payload_str = static_cast( msg->payload() ); if(msg->len() > 0) { PLOG(logDEBUG) << "consumed message payload: " << payload_str <(Key_ScheduleMessageSkipped, ++_scheduleMessageSkipped); continue; } @@ -507,7 +536,7 @@ void CARMAStreetsPlugin::SubscribeKafkaTopics() if( getEncodedtsm3 (&tsm3EncodedMsgs, metadata, payload_json) ) { tsm3EncodedMsgs.set_flags( IvpMsgFlags_RouteDSRC ); - tsm3EncodedMsgs.addDsrcMetadata( 172, 0xBFEE ); + tsm3EncodedMsgs.addDsrcMetadata(0xBFEE ); PLOG(logDEBUG) << "tsm3EncodedMsgs: " << tsm3EncodedMsgs; BroadcastMessage(static_cast( tsm3EncodedMsgs )); } @@ -520,7 +549,7 @@ void CARMAStreetsPlugin::SubscribeKafkaTopics() if( getEncodedtsm3 (&tsm3EncodedMsgs, metadata, payload_json) ) { tsm3EncodedMsgs.set_flags( IvpMsgFlags_RouteDSRC ); - tsm3EncodedMsgs.addDsrcMetadata( 172, 0xBFEE ); + tsm3EncodedMsgs.addDsrcMetadata(0xBFEE); PLOG(logDEBUG) << "tsm3EncodedMsgs: " << tsm3EncodedMsgs; BroadcastMessage(static_cast( tsm3EncodedMsgs )); } @@ -533,26 +562,92 @@ void CARMAStreetsPlugin::SubscribeKafkaTopics() } } +void CARMAStreetsPlugin::SubscribeSpatKafkaTopic(){ + if(_subscribeToSpatTopic.length() > 0) + { + PLOG(logDEBUG) << "SubscribeSpatKafkaTopics:" <<_subscribeToSpatTopic << std::endl; + std::vector topics; + topics.emplace_back(_subscribeToSpatTopic); + + RdKafka::ErrorCode err = _spat_kafka_consumer->subscribe(topics); + if (err) + { + PLOG(logERROR) << "Failed to subscribe to " << topics.size() << " topics: " << RdKafka::err2str(err) << std::endl; + return; + } + //Initialize Json to J2735 Spat convertor + JsonToJ2735SpatConverter spat_convertor; + while (true) + { + auto msg = _spat_kafka_consumer->consume( 500 ); + if( msg->err() == RdKafka::ERR_NO_ERROR ) + { + auto payload_str = static_cast( msg->payload() ); + if(msg->len() > 0) + { + PLOG(logDEBUG) << "consumed message payload: " << payload_str <(Key_SPATMessageSkipped, ++_spatMessageSkipped); + continue; + } + //Convert the SPAT JSON string into J2735 SPAT message and encode it. + auto spat_ptr = std::make_shared(); + spat_convertor.convertJson2Spat(payload_root, spat_ptr.get()); + tmx::messages::SpatEncodedMessage spatEncodedMsg; + try + { + spat_convertor.encodeSpat(spat_ptr, spatEncodedMsg); + } + catch (TmxException &ex) + { + // Skip messages that fail to encode. + PLOG(logERROR) << "Failed to encoded SPAT message : \n" << payload_str << std::endl << "Exception encountered: " + << ex.what() << std::endl; + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SPAT, spat_ptr.get()); + SetStatus(Key_SPATMessageSkipped, ++_spatMessageSkipped); + + continue; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SPAT, spat_ptr.get()); + PLOG(logDEBUG) << "SpatEncodedMessage: " << spatEncodedMsg; + + //Broadcast the encoded SPAT message + spatEncodedMsg.set_flags(IvpMsgFlags_RouteDSRC); + spatEncodedMsg.addDsrcMetadata(0x8002); + BroadcastMessage(static_cast(spatEncodedMsg)); + } + } + delete msg; + } + } +} + bool CARMAStreetsPlugin::getEncodedtsm3( tsm3EncodedMessage *tsm3EncodedMsg, Json::Value metadata, Json::Value payload_json ) { try { std::lock_guard lock(data_lock); TestMessage03* mobilityOperation = (TestMessage03 *) calloc(1, sizeof(TestMessage03)); - std::string sender_id = "UNSET"; + std::string sender_id = _intersectionId; std::string recipient_id_str = payload_json != Json::nullValue && payload_json.isMember("v_id") ? payload_json["v_id"].asString(): "UNSET"; std::string sender_bsm_id_str = "00000000"; std::string plan_id_str = "00000000-0000-0000-0000-000000000000"; - std::string strategy_str = _intersectionType; + std::string strategy_str = metadata != Json::nullValue && metadata.isMember("intersection_type")? metadata["intersection_type"].asString(): "UNSET"; std::string strategy_params_str = "null"; if( payload_json != Json::nullValue && !payload_json.empty()) { - strategy_params_str = "st:" + (payload_json.isMember("st") ? std::to_string(payload_json["st"].asUInt64()) : "0") - + ",et:" + (payload_json.isMember("et") ? std::to_string(payload_json["et"].asUInt64()) : "0") - + ",dt:" + (payload_json.isMember("dt") ? std::to_string(payload_json["dt"].asUInt64()) : "0") - + ",dp:" + (payload_json.isMember("dp") ? std::to_string(payload_json["dp"].asUInt64()) : "0") - + ",access:" + (payload_json.isMember("dp") ? std::to_string(payload_json["access"].asUInt64()): "0"); + strategy_params_str = (payload_json.isMember("st") ? "st:" + std::to_string(payload_json["st"].asUInt64()) + "," : "") + + (payload_json.isMember("et") ? "et:" + std::to_string(payload_json["et"].asUInt64())+ "," : "") + + (payload_json.isMember("dt") ? "dt:" + std::to_string(payload_json["dt"].asUInt64())+ "," : "") + + (payload_json.isMember("dp") ? "dp:" + std::to_string(payload_json["dp"].asUInt64())+ "," : "") + + (payload_json.isMember("access") ? "access:" + std::to_string(payload_json["access"].asUInt64()) : ""); } @@ -645,9 +740,10 @@ bool CARMAStreetsPlugin::getEncodedtsm3( tsm3EncodedMessage *tsm3EncodedMsg, Js free(mobilityOperation); return true; } - catch(...) + catch(const std::runtime_error &e ) { - PLOG(logERROR) << "Failed to encoded MobilityOperation message" <(Key_ScheduleMessageSkipped, ++_scheduleMessageSkipped); return false; } } diff --git a/src/v2i-hub/CARMAStreetsPlugin/src/CARMAStreetsPlugin.h b/src/v2i-hub/CARMAStreetsPlugin/src/CARMAStreetsPlugin.h index 392d2cfa2..01856cbf4 100644 --- a/src/v2i-hub/CARMAStreetsPlugin/src/CARMAStreetsPlugin.h +++ b/src/v2i-hub/CARMAStreetsPlugin/src/CARMAStreetsPlugin.h @@ -9,11 +9,13 @@ #include #include #include +#include #include "jsoncpp/json/json.h" #include #include #include #include "J2735MapToJsonConverter.h" +#include "JsonToJ2735SpatConverter.h" @@ -47,7 +49,15 @@ class CARMAStreetsPlugin: public PluginClient { * @param routeableMsg */ void HandleMapMessage(MapDataMessage &msg, routeable_message &routeableMsg); - void SubscribeKafkaTopics(); + /** + * @brief Subcribe to scheduling plan Kafka topic created by carma-streets + */ + void SubscribeSchedulingPlanKafkaTopic(); + /** + * @brief Subcribe to SPAT Kafka topic created by carma-streets + */ + void SubscribeSpatKafkaTopic(); + bool getEncodedtsm3(tsm3EncodedMessage *tsm3EncodedMsg, Json::Value metadata, Json::Value payload_json); /** * @brief Produce message to a kafka topic @@ -58,29 +68,93 @@ class CARMAStreetsPlugin: public PluginClient { private: + tmx::messages::J2735MessageFactory factory; std::string _receiveTopic; std::string _transmitMobilityOperationTopic; - std::string _subscribeToSchedulingPlanTopic = ""; + std::string _subscribeToSchedulingPlanTopic; + std::string _subscribeToSchedulingPlanConsumerGroupId; + std::string _subscribeToSpatTopic; + std::string _subscribeToSpatConsumerGroupId; std::string _transmitMobilityPathTopic; std::string _transmitBSMTopic; std::string _transmitMAPTopic; std::string _kafkaBrokerIp; std::string _kafkaBrokerPort; RdKafka::Conf *kafka_conf; - RdKafka::Conf *kafka_conf_consumer; + RdKafka::Conf *kafka_conf_spat_consumer; + RdKafka::Conf *kafka_conf_sp_consumer; RdKafka::Producer *kafka_producer; - RdKafka::KafkaConsumer *kafka_consumer; - RdKafka::Topic *_topic; + RdKafka::KafkaConsumer *_scheduing_plan_kafka_consumer; + RdKafka::KafkaConsumer *_spat_kafka_consumer; + RdKafka::Topic *_scheduing_plan_topic; + RdKafka::Topic *_spat_topic; std::vector _strategies; tmx::messages::tsm3Message *_tsm3Message{NULL}; std::mutex data_lock; + + /** + * @brief Status label for SPAT messages skipped due to errors. + */ + const char* Key_SPATMessageSkipped = "SPAT messages skipped due to errors."; + /** + * @brief Count for SPAT messages skipped due to errors. + */ + uint _spatMessageSkipped = 0; + + /** + * @brief Status label for Intersection Schedule messages skipped due to errors. + */ + const char* Key_ScheduleMessageSkipped = "Intersection Schedule messages skipped due to errors."; + + /** + * @brief Count for Intersection Schedule messages skipped due to errors. + */ + uint _scheduleMessageSkipped = 0; + + /** + * @brief Status label for MAP messages skipped due to errors. + */ + const char* Key_MAPMessageSkipped = "MAP messages skipped due to errors."; + + /** + * @brief Count for MAP messages skipped due to errors. + */ + uint _mapMessageSkipped = 0; + + /** + * @brief Status label for Mobility Operation messages skipped due to errors. + */ + const char* Key_MobilityOperationMessageSkipped = "Mobility Operation messages skipped due to errors."; + + /** + * @brief Count for Mobility Operation messages skipped due to errors. + */ + uint _mobilityOperationMessageSkipped = 0; + + /** + * @brief Status label for Mobility Path messages skipped due to errors. + */ + const char* Key_MobilityPathMessageSkipped = "Mobility Path messages skipped due to errors."; + + /** + * @brief Count for Mobility Path messages skipped due to errors. + */ + uint _mobilityPathMessageSkipped = 0; + + /** + * @brief Status label for BSM messages skipped due to errors. + */ + const char* Key_BSMMessageSkipped = "BSM messages skipped due to errors."; + + /** + * @brief Count for BSM messages skipped due to errors. + */ + uint _bsmMessageSkipped = 0; - /*** - * Configurable indicator to run consumer and consume messages from kafka topics - * run the consumer if it equals = 1; otherwise = 0 - **/ - int _run_kafka_consumer = 0; - std::string _intersectionType = "NA"; + /** + * @brief Intersection Id for intersection + */ + std::string _intersectionId = "UNSET"; }; std::mutex _cfgLock; diff --git a/src/v2i-hub/CARMAStreetsPlugin/src/JsonToJ2735SpatConverter.cpp b/src/v2i-hub/CARMAStreetsPlugin/src/JsonToJ2735SpatConverter.cpp new file mode 100644 index 000000000..999be321d --- /dev/null +++ b/src/v2i-hub/CARMAStreetsPlugin/src/JsonToJ2735SpatConverter.cpp @@ -0,0 +1,225 @@ +#include "JsonToJ2735SpatConverter.h" + +namespace CARMAStreetsPlugin +{ + void JsonToJ2735SpatConverter::convertJson2Spat(const Json::Value &spat_json, SPAT *spat) const + { + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SPAT, spat); + + // Parse spat name field + if (spat_json.isMember("name") && spat_json["name"].asString().length() != 0) + { + std::string name = spat_json["name"].asString(); + spat->name = (DescriptiveName_t *)calloc(1, sizeof(DescriptiveName_t)); + spat->name->buf = (uint8_t *)calloc(1, name.length()); + spat->name->size = name.length(); + memcpy(spat->name->buf, name.c_str(), name.length()); + } + + if (spat_json.isMember("time_stamp")) + { + int32_t time_stamp = spat_json["time_stamp"].asInt(); + spat->timeStamp = (MinuteOfTheYear_t *)calloc(1, sizeof(MinuteOfTheYear_t)); + *spat->timeStamp = time_stamp; + } + + // Parse intersections + if (spat_json["intersections"].isArray()) + { + convertJson2IntersectionStateList(spat_json["intersections"], &spat->intersections); + } + } + + void JsonToJ2735SpatConverter::convertJson2IntersectionStateList(const Json::Value &intersections_json, IntersectionStateList *intersections) const + { + for (const auto &int_json : intersections_json) + { + auto intersection = (IntersectionState_t *)calloc(1, sizeof(IntersectionState_t)); + // intersection name + auto name = int_json["name"].asString(); + auto intersection_name = (DescriptiveName_t *)calloc(1, sizeof(DescriptiveName_t)); + intersection_name->size = name.length(); + intersection_name->buf = (uint8_t *)calloc(1, name.length()); + memcpy(intersection_name->buf, name.c_str(), name.length()); + + // intersection id + auto id = int_json["id"].asInt(); + intersection->id.id = id; + intersection->name = intersection_name; + + // revision + auto revision = int_json["revision"].asInt(); + intersection->revision = revision; + + // moy + auto moy_int = int_json["moy"].asInt(); + intersection->moy = (MinuteOfTheYear_t *)calloc(1, sizeof(MinuteOfTheYear_t)); + *intersection->moy = moy_int; + + // timestamp + intersection->timeStamp = (DSecond_t *)calloc(1, sizeof(DSecond_t)); + *intersection->timeStamp = int_json["time_stamp"].asInt(); + + // status + auto status = static_cast(int_json["status"].asInt()); + intersection->status.buf = (uint8_t *)calloc(2, sizeof(uint8_t)); + intersection->status.size = 2 * sizeof(uint8_t); + intersection->status.bits_unused = 0; + intersection->status.buf[1] = static_cast(status); + intersection->status.buf[0] = (status >> 8); + + // enabled_lanes + const auto &enabled_lanes_json = int_json["enabled_lanes"]; + if (enabled_lanes_json.isArray()) + { + intersection->enabledLanes = (EnabledLaneList_t *)calloc(1, sizeof(EnabledLaneList_t)); + for (const auto &laneId : enabled_lanes_json) + { + auto lane = (LaneID_t *)calloc(1, sizeof(LaneID_t)); + *lane = laneId.asInt(); + ASN_SEQUENCE_ADD(&intersection->enabledLanes->list, lane); + } + } + + // Movements + if (int_json["states"].isArray()) + { + convertJson2MovementList(int_json["states"], &intersection->states); + } + + // Manuever Assist List + if (int_json["maneuver_assist_list"].isArray()) + { + intersection->maneuverAssistList = (ManeuverAssistList_t *)calloc(1, sizeof(ManeuverAssistList_t)); + convertJson2ManeuverAssistList(int_json["maneuver_assist_list"], intersection->maneuverAssistList); + } + ASN_SEQUENCE_ADD(&intersections->list, intersection); + } + } + void JsonToJ2735SpatConverter::convertJson2MovementList(const Json::Value &movements_json, MovementList *states) const + { + for (const auto &movement_json : movements_json) + { + auto state = (MovementState_t *)calloc(1, sizeof(MovementState_t)); + if (movement_json.isMember("movement_name") && movement_json["movement_name"].asString().length() != 0) + { + auto movement_name_str = movement_json["movement_name"].asString(); + state->movementName = (DescriptiveName_t *)calloc(1, sizeof(DescriptiveName_t)); + state->movementName->size = movement_name_str.length(); + state->movementName->buf = (uint8_t *)calloc(1, movement_name_str.length()); + memcpy(state->movementName->buf, movement_name_str.c_str(), movement_name_str.length()); + } + + state->signalGroup = movement_json["signal_group"].asInt(); + + if (movement_json["state_time_speed"].isArray()) + { + convertJson2MovementEventList(movement_json["state_time_speed"], &state->state_time_speed); + } + + if (movement_json["maneuver_assist_list"].isArray()) + { + state->maneuverAssistList = (ManeuverAssistList_t *)calloc(1, sizeof(ManeuverAssistList_t)); + convertJson2ManeuverAssistList(movement_json["maneuver_assist_list"], state->maneuverAssistList); + } + ASN_SEQUENCE_ADD(&states->list, state); + } + } + + void JsonToJ2735SpatConverter::convertJson2MovementEventList(const Json::Value &movement_event_list_json, MovementEventList *state_time_speed) const + { + for (const auto &m_event : movement_event_list_json) + { + auto movement_event = (MovementEvent_t *)calloc(1, sizeof(MovementEvent_t)); + movement_event->eventState = m_event["event_state"].asInt(); + + // Timing + const auto &timing_json = m_event["timing"]; + movement_event->timing = (TimeChangeDetails_t *)calloc(1, sizeof(TimeChangeDetails_t)); + convertJson2TimeChangeDetail(timing_json, movement_event->timing); + + // speeds + const auto &speeds_json = m_event["speeds"]; + if (speeds_json.isArray()) + { + movement_event->speeds = (AdvisorySpeedList_t *)calloc(1, sizeof(AdvisorySpeedList_t)); + convertJson2AdvisorySpeed(speeds_json, movement_event->speeds); + } + + ASN_SEQUENCE_ADD(&state_time_speed->list, movement_event); + } + } + + void JsonToJ2735SpatConverter::convertJson2TimeChangeDetail(const Json::Value &time_change_detail_json, TimeChangeDetails_t *timing) const + { + timing->startTime = (DSRC_TimeMark_t *)calloc(1, sizeof(DSRC_TimeMark_t)); + *timing->startTime = time_change_detail_json["start_time"].asInt(); + + timing->minEndTime = time_change_detail_json["min_end_time"].asInt(); + + timing->maxEndTime = (DSRC_TimeMark_t *)calloc(1, sizeof(DSRC_TimeMark_t)); + *timing->maxEndTime = time_change_detail_json["max_end_time"].asInt(); + + timing->likelyTime = (DSRC_TimeMark_t *)calloc(1, sizeof(DSRC_TimeMark_t)); + *timing->likelyTime = time_change_detail_json["likely_time"].asInt(); + + timing->nextTime = (DSRC_TimeMark_t *)calloc(1, sizeof(DSRC_TimeMark_t)); + *timing->nextTime = time_change_detail_json["next_time"].asInt(); + + timing->confidence = (TimeIntervalConfidence_t *)calloc(1, sizeof(TimeIntervalConfidence_t)); + *timing->confidence = time_change_detail_json["confidence"].asInt(); + } + + void JsonToJ2735SpatConverter::convertJson2AdvisorySpeed(const Json::Value &speeds_json, AdvisorySpeedList_t *speeds) const + { + for (const auto &speed_json : speeds_json) + { + auto speed = (AdvisorySpeed_t *)calloc(1, sizeof(AdvisorySpeed_t)); + speed->type = speed_json["type"].asInt(); + + speed->speed = (SpeedAdvice_t *)calloc(1, sizeof(SpeedAdvice_t)); + *speed->speed = speed_json["speed_limit"].asInt(); + + speed->confidence = (SpeedConfidence_t *)calloc(1, sizeof(SpeedConfidence_t)); + *speed->confidence = speed_json["speed_confidence"].asInt(); + + speed->Class = (RestrictionClassID_t *)calloc(1, sizeof(RestrictionClassID_t)); + *speed->Class = speed_json["class"].asInt(); + + speed->distance = (ZoneLength_t *)calloc(1, sizeof(ZoneLength_t)); + *speed->distance = speed_json["distance"].asInt(); + + ASN_SEQUENCE_ADD(&speeds->list, speed); + } + } + + void JsonToJ2735SpatConverter::convertJson2ManeuverAssistList(const Json::Value &maneuver_assist_list_json, ManeuverAssistList_t *maneuver_assist_list) const + { + for (const auto &masst : maneuver_assist_list_json) + { + auto maneuver_assist = (ConnectionManeuverAssist_t *)calloc(1, sizeof(ConnectionManeuverAssist_t)); + maneuver_assist->connectionID = masst["connection_id"].asInt(); + + maneuver_assist->queueLength = (ZoneLength_t *)calloc(1, sizeof(ZoneLength_t)); + *maneuver_assist->queueLength = masst["queue_length"].asInt(); + + maneuver_assist->availableStorageLength = (ZoneLength_t *)calloc(1, sizeof(ZoneLength_t)); + *maneuver_assist->availableStorageLength = masst["available_storage_length"].asInt(); + + maneuver_assist->waitOnStop = (WaitOnStopline_t *)calloc(1, sizeof(WaitOnStopline_t)); + *maneuver_assist->waitOnStop = masst["wait_on_stop"].asBool() ? 1 : 0; + + maneuver_assist->pedBicycleDetect = (PedestrianBicycleDetect_t *)calloc(1, sizeof(PedestrianBicycleDetect_t)); + *maneuver_assist->pedBicycleDetect = masst["ped_bicycle_detect"].asBool() ? 1 : 0; + + ASN_SEQUENCE_ADD(&maneuver_assist_list->list, maneuver_assist); + } + } + + void JsonToJ2735SpatConverter::encodeSpat(const std::shared_ptr &spat_ptr, tmx::messages::SpatEncodedMessage &encodedSpat) const + { + tmx::messages::MessageFrameMessage frame(spat_ptr); + encodedSpat.set_data(tmx::messages::TmxJ2735EncodedMessage::encode_j2735_message>(frame)); + free(frame.get_j2735_data().get()); + } +} \ No newline at end of file diff --git a/src/v2i-hub/CARMAStreetsPlugin/src/JsonToJ2735SpatConverter.h b/src/v2i-hub/CARMAStreetsPlugin/src/JsonToJ2735SpatConverter.h new file mode 100644 index 000000000..80c599c18 --- /dev/null +++ b/src/v2i-hub/CARMAStreetsPlugin/src/JsonToJ2735SpatConverter.h @@ -0,0 +1,74 @@ + +#include "jsoncpp/json/json.h" +#include +#include +#include +#include +#include +#include + +namespace CARMAStreetsPlugin +{ + class JsonToJ2735SpatConverter + { + public: + JsonToJ2735SpatConverter()= default; + /** + * @brief Convert the Json value with spat information info tmx SPAT object. + * @param json Incoming Json value with spat information that is consumed from a Kafka topic. + * @param spat Outgoing J2735 spat object that is populated by the json value. + */ + void convertJson2Spat(const Json::Value& spat_json, SPAT *spat) const; + + /** + * @brief Convert the Json value with intersection information info J2735 IntersectionStateList object. + * @param json Incoming Json value with spat information that is consumed from a Kafka topic. + * @param intersections Outgoing J2735 IntersectionStateList object that is populated by the json value. + */ + void convertJson2IntersectionStateList(const Json::Value& intersections_json, IntersectionStateList *intersections) const; + + /** + * @brief Convert the Json value with MovementList information info J2735 MovementList object. + * @param json Incoming Json value with MovementList information that is consumed from a Kafka topic. + * @param states Outgoing J2735 MovementList object that is populated by the json value. + */ + void convertJson2MovementList(const Json::Value& movements_json, MovementList *states) const; + + /** + * @brief Convert the Json value with MovementEventList information info J2735 MovementEventList object. + * @param json Incoming Json value with MovementEventList information that is consumed from a Kafka topic. + * @param state_time_speed Outgoing J2735 MovementEventList object that is populated by the json value. + */ + void convertJson2MovementEventList(const Json::Value& movement_events_json, MovementEventList *state_time_speed) const; + + /** + * @brief Convert the Json value with TimeChangeDetails information info J2735 TimeChangeDetails object. + * @param json Incoming Json value with TimeChangeDetails information that is consumed from a Kafka topic. + * @param time_change_detail_json Outgoing J2735 TimeChangeDetails object that is populated by the json value. + */ + void convertJson2TimeChangeDetail(const Json::Value& time_change_detail_json, TimeChangeDetails_t *timing) const; + + /** + * @brief Convert the Json value with ManeuverAssistList information info J2735 ManeuverAssistList object. + * @param json Incoming Json value with ManeuverAssistList information that is consumed from a Kafka topic. + * @param maneuver_assist_list Outgoing J2735 ManeuverAssistList object that is populated by the json value. + */ + void convertJson2ManeuverAssistList(const Json::Value& maneuver_assist_list_json, ManeuverAssistList *maneuver_assist_list) const; + + /** + * @brief Convert the Json value with AdvisorySpeedList information info J2735 AdvisorySpeedList object. + * @param json Incoming Json value with AdvisorySpeedList information that is consumed from a Kafka topic. + * @param maneuver_assist_list Outgoing J2735 AdvisorySpeedList object that is populated by the json value. + */ + void convertJson2AdvisorySpeed(const Json::Value& speeds_json, AdvisorySpeedList_t *speeds) const; + + /** + * @brief Encode the J2735 SPAT object + * @param spat Incoming J2735 SPAT object. + * @param encodedSpat Outgoing encoded SPAT object populated by the Incoming SPAT object. + */ + void encodeSpat(const std::shared_ptr &spat_ptr, tmx::messages::SpatEncodedMessage &encodedSpat) const; + + ~JsonToJ2735SpatConverter() = default; + }; +} \ No newline at end of file diff --git a/src/v2i-hub/CARMAStreetsPlugin/test/test_JsonToJ2735SpatConverter.cpp b/src/v2i-hub/CARMAStreetsPlugin/test/test_JsonToJ2735SpatConverter.cpp new file mode 100644 index 000000000..584c246af --- /dev/null +++ b/src/v2i-hub/CARMAStreetsPlugin/test/test_JsonToJ2735SpatConverter.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include "jsoncpp/json/json.h" +#include "JsonToJ2735SpatConverter.h" + +namespace CARMAStreetsPlugin +{ + class test_JsonToJ2735SpatConverter : public ::testing::Test + { + public: + Json::Value spat_json; + Json::Value movement_list_json; + Json::Value manuever_assist_list_json; + Json::Value movement_events_json; + + protected: + void SetUp() override + { + std::string spat_json_str="{\"time_stamp\":316554,\"name\":\"\",\"intersections\":[{\"name\":\"WestIntersection\",\"id\":9001,\"revision\":120,\"status\":0,\"moy\":316554,\"time_stamp\":8609,\"states\":[{\"movement_name\":\"\",\"signal_group\":8,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":32486,\"min_end_time\":32558,\"max_end_time\":32558,\"confidence\":0}}]},{\"movement_name\":\"\",\"signal_group\":7,\"state_time_speed\":[{\"event_state\":6,\"timing\":{\"start_time\":32486,\"min_end_time\":32518,\"max_end_time\":32518,\"confidence\":0}}]},{\"movement_name\":\"\",\"signal_group\":2,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":32486,\"min_end_time\":32838,\"max_end_time\":32838,\"confidence\":0}}]},{\"movement_name\":\"\",\"signal_group\":1,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":32486,\"min_end_time\":32698,\"max_end_time\":32698,\"confidence\":0}}]},{\"movement_name\":\"\",\"signal_group\":3,\"state_time_speed\":[{\"event_state\":6,\"timing\":{\"start_time\":32486,\"min_end_time\":32518,\"max_end_time\":32518,\"confidence\":0}}]},{\"movement_name\":\"\",\"signal_group\":4,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":32486,\"min_end_time\":32558,\"max_end_time\":32558,\"confidence\":0}}]},{\"movement_name\":\"\",\"signal_group\":5,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":32486,\"min_end_time\":32698,\"max_end_time\":32698,\"confidence\":0}}]},{\"movement_name\":\"\",\"signal_group\":6,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":32486,\"min_end_time\":32838,\"max_end_time\":32838,\"confidence\":0}}]}]}]}"; + Json::Reader reader; + auto parse_success = reader.parse(spat_json_str, spat_json, true); + if (!parse_success) + { + std::cout << "Failed to parse spat json" << std::endl; + } + + std::string movement_list_str = "{\"states\":[{\"movement_name\":\"RightTurn\",\"signal_group\":4,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":0,\"min_end_time\":0,\"max_end_time\":0,\"likely_time\":0,\"confidence\":0},\"speeds\":[{\"type\":0,\"speed_limit\":4,\"speed_confidence\":1,\"distance\":5,\"class\":5}]}],\"maneuver_assist_list\":[{\"connection_id\":7,\"queue_length\":4,\"available_storage_length\":8,\"wait_on_stop\":true,\"ped_bicycle_detect\":false}]}]}"; + parse_success = reader.parse(movement_list_str, movement_list_json, true); + if (!parse_success) + { + std::cout << "Failed to parse movement list json" << std::endl; + } + + std::string movement_events_str = "{\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":0,\"min_end_time\":0,\"max_end_time\":0,\"likely_time\":0,\"confidence\":0},\"speeds\":[{\"type\":0,\"speed_limit\":4,\"speed_confidence\":1,\"distance\":5,\"class\":5}]}]}"; + parse_success = reader.parse(movement_events_str, movement_events_json, true); + if (!parse_success) + { + std::cout << "Failed to parse movement events json" << std::endl; + } + + std::string manuever_assist_list_str = "{\"maneuver_assist_list\":[{\"connection_id\":7,\"queue_length\":4,\"available_storage_length\":8,\"wait_on_stop\":true,\"ped_bicycle_detect\":false}]}"; + parse_success = reader.parse(manuever_assist_list_str, manuever_assist_list_json, true); + if (!parse_success) + { + std::cout << "Failed to parse manuever assist list json" << std::endl; + } + } + }; + + TEST_F(test_JsonToJ2735SpatConverter, convertJson2Spat) + { + auto spat_ptr = std::make_shared(); + JsonToJ2735SpatConverter converter; + ASSERT_EQ(spat_ptr->intersections.list.count, 0); + converter.convertJson2Spat(spat_json, spat_ptr.get()); + ASSERT_EQ(spat_ptr->intersections.list.count, 1); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SPAT, spat_ptr.get()); + } + + TEST_F(test_JsonToJ2735SpatConverter, convertJson2IntersectionStateList) + { + if (spat_json["intersections"].isArray()) + { + auto intersections = (IntersectionStateList *)calloc(1, sizeof(IntersectionStateList)); + JsonToJ2735SpatConverter converter; + ASSERT_EQ(intersections->list.count, 0); + converter.convertJson2IntersectionStateList(spat_json["intersections"], intersections); + ASSERT_EQ(intersections->list.count, 1); + free(intersections); + } + } + + TEST_F(test_JsonToJ2735SpatConverter, convertJson2MovementList) + { + if (movement_list_json["states"].isArray()) + { + auto states = (MovementList_t *)calloc(1, sizeof(MovementList_t)); + JsonToJ2735SpatConverter converter; + ASSERT_EQ(states->list.count, 0); + converter.convertJson2MovementList(movement_list_json["states"], states); + ASSERT_EQ(states->list.count, 1); + free(states); + } + } + + TEST_F(test_JsonToJ2735SpatConverter, convertJson2MovementEventList) + { + if (movement_events_json["state_time_speed"].isArray()) + { + auto state_time_speed = (MovementEventList_t *)calloc(1, sizeof(MovementEventList_t)); + JsonToJ2735SpatConverter converter; + ASSERT_EQ(state_time_speed->list.count, 0); + converter.convertJson2MovementEventList(movement_events_json["state_time_speed"], state_time_speed); + ASSERT_EQ(state_time_speed->list.count, 1); + free(state_time_speed->list.array[0]->speeds); + free(state_time_speed->list.array[0]->timing); + free(state_time_speed); + } + } + + TEST_F(test_JsonToJ2735SpatConverter, convertJson2ManeuverAssistList) + { + if (manuever_assist_list_json["maneuver_assist_list"].isArray()) + { + auto maneuver_assist_list = (ManeuverAssistList_t *)calloc(1, sizeof(ManeuverAssistList_t)); + JsonToJ2735SpatConverter converter; + ASSERT_EQ(maneuver_assist_list->list.count, 0); + converter.convertJson2ManeuverAssistList(manuever_assist_list_json["maneuver_assist_list"], maneuver_assist_list); + ASSERT_EQ(maneuver_assist_list->list.count, 1); + free(maneuver_assist_list); + } + } + + TEST_F(test_JsonToJ2735SpatConverter, encodeSpat) + { + auto spat_ptr = std::make_shared(); + JsonToJ2735SpatConverter converter; + converter.convertJson2Spat(spat_json, spat_ptr.get()); + + tmx::messages::SpatEncodedMessage encodedSpat; + converter.encodeSpat(spat_ptr, encodedSpat); + std::string encoded_spat_str = "0013808f44d48a0383ebe5e7d24eee997973cb8fa69dfb84653e000013522886841c02010fefdccfe5cfe5c00000000000e08df7ee67f067f06000000000002043fbf7340234023000000000000821fdfb99fee9fee800000000000c11befdccfe0cfe0c000000000008087f7ee67f2e7f2e000000000005043fbf733fdd3fdd000000000003021fdfb9a011a0118000000000"; + ASSERT_EQ(encoded_spat_str, encodedSpat.get_payload_str()); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SPAT, spat_ptr.get()); + } + + /** + * @brief Unit test to ensure encodeSpat will throw and exception attempting to encode timing + * data that exceeds max value of 36001 (see ASN1 documentation for TimeMark). + * + */ + TEST_F(test_JsonToJ2735SpatConverter, time_mark_over_max_value) { + std::string spat_json_string = "{\"time_stamp\":387178,\"name\":\"\",\"intersections\":[{\"name\":\"East Intersection\",\"id\":9945,\"revision\":1,\"status\":0,\"moy\":387178,\"time_stamp\":32248,\"states\":[" + "{\"movement_name\":\"\",\"signal_group\":8,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":34975,\"min_end_time\":35405,\"max_end_time\":35405,\"confidence\":0}},{\"event_state\":6,\"timing\":{\"start_time\":35405,\"min_end_time\":35505,\"max_end_time\":35505,\"confidence\":0}},{\"event_state\":8,\"timing\":{\"start_time\":35505,\"min_end_time\":35535,\"max_end_time\":35535,\"confidence\":0}},{\"event_state\":3,\"timing\":{\"start_time\":35535,\"min_end_time\":35965,\"max_end_time\":35965,\"confidence\":0}}]}," + "{\"movement_name\":\"\",\"signal_group\":2,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":34695,\"min_end_time\":35125,\"max_end_time\":35125,\"confidence\":0}},{\"event_state\":6,\"timing\":{\"start_time\":35125,\"min_end_time\":35225,\"max_end_time\":35225,\"confidence\":0}},{\"event_state\":8,\"timing\":{\"start_time\":35225,\"min_end_time\":35255,\"max_end_time\":35255,\"confidence\":0}},{\"event_state\":3,\"timing\":{\"start_time\":35255,\"min_end_time\":35685,\"max_end_time\":35685,\"confidence\":0}}]}," + "{\"movement_name\":\"\",\"signal_group\":1,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":35115,\"min_end_time\":35545,\"max_end_time\":35545,\"confidence\":0}},{\"event_state\":6,\"timing\":{\"start_time\":35545,\"min_end_time\":35645,\"max_end_time\":35645,\"confidence\":0}},{\"event_state\":8,\"timing\":{\"start_time\":35645,\"min_end_time\":35675,\"max_end_time\":35675,\"confidence\":0}},{\"event_state\":3,\"timing\":{\"start_time\":35675,\"min_end_time\":36105,\"max_end_time\":36105,\"confidence\":0}}]}," + "{\"movement_name\":\"\",\"signal_group\":3,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":34835,\"min_end_time\":35265,\"max_end_time\":35265,\"confidence\":0}},{\"event_state\":6,\"timing\":{\"start_time\":35265,\"min_end_time\":35365,\"max_end_time\":35365,\"confidence\":0}},{\"event_state\":8,\"timing\":{\"start_time\":35365,\"min_end_time\":35395,\"max_end_time\":35395,\"confidence\":0}},{\"event_state\":3,\"timing\":{\"start_time\":35395,\"min_end_time\":35825,\"max_end_time\":35825,\"confidence\":0}}]}," + "{\"movement_name\":\"\",\"signal_group\":4,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":34975,\"min_end_time\":35405,\"max_end_time\":35405,\"confidence\":0}},{\"event_state\":6,\"timing\":{\"start_time\":35405,\"min_end_time\":35505,\"max_end_time\":35505,\"confidence\":0}},{\"event_state\":8,\"timing\":{\"start_time\":35505,\"min_end_time\":35535,\"max_end_time\":35535,\"confidence\":0}},{\"event_state\":3,\"timing\":{\"start_time\":35535,\"min_end_time\":35965,\"max_end_time\":35965,\"confidence\":0}}]}," + "{\"movement_name\":\"\",\"signal_group\":5,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":35115,\"min_end_time\":35545,\"max_end_time\":35545,\"confidence\":0}},{\"event_state\":6,\"timing\":{\"start_time\":35545,\"min_end_time\":35645,\"max_end_time\":35645,\"confidence\":0}},{\"event_state\":8,\"timing\":{\"start_time\":35645,\"min_end_time\":35675,\"max_end_time\":35675,\"confidence\":0}},{\"event_state\":3,\"timing\":{\"start_time\":35675,\"min_end_time\":36105,\"max_end_time\":36105,\"confidence\":0}}]}," + "{\"movement_name\":\"\",\"signal_group\":6,\"state_time_speed\":[{\"event_state\":3,\"timing\":{\"start_time\":34695,\"min_end_time\":35125,\"max_end_time\":35125,\"confidence\":0}},{\"event_state\":6,\"timing\":{\"start_time\":35125,\"min_end_time\":35225,\"max_end_time\":35225,\"confidence\":0}},{\"event_state\":8,\"timing\":{\"start_time\":35225,\"min_end_time\":35255,\"max_end_time\":35255,\"confidence\":0}},{\"event_state\":3,\"timing\":{\"start_time\":35255,\"min_end_time\":35685,\"max_end_time\":35685,\"confidence\":0}}]}]}]}"; + Json::Reader reader; + auto spat_ptr = std::make_shared(); + auto parse_success = reader.parse(spat_json_string, spat_json, true); + JsonToJ2735SpatConverter converter; + converter.convertJson2Spat(spat_json, spat_ptr.get()); + tmx::messages::SpatEncodedMessage encodedSpat; + + ASSERT_THROW( converter.encodeSpat(spat_ptr, encodedSpat), tmx::TmxException ); + + + + } + +} \ No newline at end of file diff --git a/src/v2i-hub/CommandPlugin/CMakeLists.txt b/src/v2i-hub/CommandPlugin/CMakeLists.txt index 3fc587303..54439baac 100644 --- a/src/v2i-hub/CommandPlugin/CMakeLists.txt +++ b/src/v2i-hub/CommandPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( CommandPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( CommandPlugin VERSION 7.4.0 LANGUAGES CXX ) FIND_PACKAGE (OpenSSL REQUIRED) diff --git a/src/v2i-hub/CswPlugin/CMakeLists.txt b/src/v2i-hub/CswPlugin/CMakeLists.txt index 99da1564e..607a1b32c 100644 --- a/src/v2i-hub/CswPlugin/CMakeLists.txt +++ b/src/v2i-hub/CswPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( CswPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( CswPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "CSW") diff --git a/src/v2i-hub/CswPlugin/src/CswPlugin.cpp b/src/v2i-hub/CswPlugin/src/CswPlugin.cpp index 8816d7efa..b4bc65e88 100644 --- a/src/v2i-hub/CswPlugin/src/CswPlugin.cpp +++ b/src/v2i-hub/CswPlugin/src/CswPlugin.cpp @@ -338,7 +338,7 @@ int CswPlugin::Main() { timEncMsg.initialize(timMsg); timEncMsg.set_flags(IvpMsgFlags_RouteDSRC); - timEncMsg.addDsrcMetadata(172, 0x8003); + timEncMsg.addDsrcMetadata(0x8003); routeable_message *rMsg = dynamic_cast(&timEncMsg); if (rMsg) BroadcastMessage(*rMsg); diff --git a/src/v2i-hub/DmsPlugin/CMakeLists.txt b/src/v2i-hub/DmsPlugin/CMakeLists.txt index 23e7ffde3..ac2960b0e 100644 --- a/src/v2i-hub/DmsPlugin/CMakeLists.txt +++ b/src/v2i-hub/DmsPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( DmsPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( DmsPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "Dynamic Message Sign") diff --git a/src/v2i-hub/DsrcImmediateForwardPlugin/CMakeLists.txt b/src/v2i-hub/DsrcImmediateForwardPlugin/CMakeLists.txt index 2d383eedd..0a6e4f480 100644 --- a/src/v2i-hub/DsrcImmediateForwardPlugin/CMakeLists.txt +++ b/src/v2i-hub/DsrcImmediateForwardPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( DsrcImmediateForwardPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( DsrcImmediateForwardPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "DSRC Message Manager") diff --git a/src/v2i-hub/DsrcImmediateForwardPlugin/manifest.json b/src/v2i-hub/DsrcImmediateForwardPlugin/manifest.json index a41ddf97a..2d67b3c21 100644 --- a/src/v2i-hub/DsrcImmediateForwardPlugin/manifest.json +++ b/src/v2i-hub/DsrcImmediateForwardPlugin/manifest.json @@ -1,7 +1,7 @@ { - "name": "DSRCMessageManager", - "description": "Plugin that listens for TMX messages and forwards them to the DSRC Radio (i.e. the RSU).", - "version": "5.0", + "name": "ImmediateForward", + "description": "Plugin that listens for TMX messages and forwards them to the V2X Radio (i.e. the RSU).", + "version": "@PROJECT_VERSION@", "exeLocation": "/bin/DsrcImmediateForwardPlugin", "coreIpAddr": "127.0.0.1", "corePort": 24601, @@ -9,43 +9,43 @@ "configuration": [ { "key": "Messages_Destination_1", - "default": "{ \"Messages\": [ { \"TmxType\": \"SPAT-P\", \"SendType\": \"SPAT\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"MAP-P\", \"SendType\": \"MAP\", \"PSID\": \"0x8002\" }, { \"TmxType\": \"PSM\", \"SendType\": \"PSM\", \"PSID\": \"0x8002\" } ,{ \"TmxType\": \"TMSG07\", \"SendType\": \"TMSG07\", \"PSID\": \"0x8002\" },{ \"TmxType\": \"TMSG03-P\", \"SendType\": \"TMSG03-P\", \"PSID\": \"0xBFEE\" }] }", - "description": "JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 1." + "default": "{ \"Messages\": [ { \"TmxType\": \"SPAT-P\", \"SendType\": \"SPAT\", \"PSID\": \"0x8002\", \"Channel\": \"172\" }, { \"TmxType\": \"MAP-P\", \"SendType\": \"MAP\", \"PSID\": \"0x8002\", \"Channel\": \"172\" }, { \"TmxType\": \"PSM\", \"SendType\": \"PSM\", \"PSID\": \"0x8002\", \"Channel\": \"172\" } ,{ \"TmxType\": \"TMSG07\", \"SendType\": \"TMSG07\", \"PSID\": \"0x8002\", \"Channel\": \"172\" },{ \"TmxType\": \"TMSG03-P\", \"SendType\": \"TMSG03-P\", \"PSID\": \"0xBFEE\", \"Channel\": \"172\" }] }", + "description": "JSON data defining the message types, PSIDs, and channel number for messages forwarded to the V2X radio at destination 1." }, { "key": "Messages_Destination_2", "default": "{ \"Messages\": [ ] }", - "description": "JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 2." + "description": "JSON data defining the message types, PSIDs, and channel number for messages forwarded to the V2X radio at destination 2." }, { "key": "Messages_Destination_3", "default": "{ \"Messages\": [ ] }", - "description": "JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 3." + "description": "JSON data defining the message types, PSIDs, and channel number for messages forwarded to the V2X radio at destination 3." }, { "key": "Messages_Destination_4", "default": "{ \"Messages\": [ ] }", - "description": "JSON data defining the message types and PSIDs for messages forwarded to the DSRC radio at destination 4." + "description": "JSON data defining the message types, PSIDs, and channel number for messages forwarded to the V2X radio at destination 4." }, { "key": "Destination_1", "default": "127.0.0.1:1516", - "description": "The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_1." + "description": "The destination UDP server(s) and port number(s) on the V2X radio for all messages specified by Messages_Destination_1." }, { "key": "Destination_2", "default": "0", - "description": "The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_2." + "description": "The destination UDP server(s) and port number(s) on the V2X radio for all messages specified by Messages_Destination_2." }, { "key": "Destination_3", "default": "0", - "description": "The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_3." + "description": "The destination UDP server(s) and port number(s) on the V2X radio for all messages specified by Messages_Destination_3." }, { "key": "Destination_4", "default": "0", - "description": "The destination UDP server(s) and port number(s) on the DSRC radio for all messages specified by Messages_Destination_4." + "description": "The destination UDP server(s) and port number(s) on the V2X radio for all messages specified by Messages_Destination_4." }, { "key": "Signature", @@ -65,4 +65,4 @@ ] -} +} \ No newline at end of file diff --git a/src/v2i-hub/DsrcImmediateForwardPlugin/src/DsrcMessageManagerPlugin.cpp b/src/v2i-hub/DsrcImmediateForwardPlugin/src/DsrcMessageManagerPlugin.cpp index 2b90bc9d5..1368b75ad 100644 --- a/src/v2i-hub/DsrcImmediateForwardPlugin/src/DsrcMessageManagerPlugin.cpp +++ b/src/v2i-hub/DsrcImmediateForwardPlugin/src/DsrcMessageManagerPlugin.cpp @@ -390,7 +390,7 @@ void DsrcMessageManagerPlugin::SendMessageToRadio(IvpMessage *msg) else os << "Priority=7" << "\n" << "TxMode=CONT" << "\n" << "TxChannel=" << _messageConfigMap[configIndex].Channel << "\n"; os << "TxInterval=0" << "\n" << "DeliveryStart=\n" << "DeliveryStop=\n"; - os << "Signature= "<< _signature << "\n" << "Encryption=False\n"; + os << "Signature="<< _signature << "\n" << "Encryption=False\n"; os << "Payload=" << payloadbyte << "\n"; string message = os.str(); diff --git a/src/v2i-hub/LocationPlugin/CMakeLists.txt b/src/v2i-hub/LocationPlugin/CMakeLists.txt index fb1c54ce3..4ec30bd65 100644 --- a/src/v2i-hub/LocationPlugin/CMakeLists.txt +++ b/src/v2i-hub/LocationPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -project( LocationPlugin VERSION 5.0 LANGUAGES CXX ) +project( LocationPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME Location) diff --git a/src/v2i-hub/MapPlugin/CMakeLists.txt b/src/v2i-hub/MapPlugin/CMakeLists.txt index fe1f3bd6a..e85e0ab8f 100644 --- a/src/v2i-hub/MapPlugin/CMakeLists.txt +++ b/src/v2i-hub/MapPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( MapPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( MapPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "MAP") diff --git a/src/v2i-hub/MapPlugin/manifest.json b/src/v2i-hub/MapPlugin/manifest.json index 6c53a6b6a..3bd5abac6 100644 --- a/src/v2i-hub/MapPlugin/manifest.json +++ b/src/v2i-hub/MapPlugin/manifest.json @@ -1,7 +1,7 @@ { "name": "MAP", "description": "Plugin that reads intersection geometry from a configuration file and publishes a J2735 MAP message.", - "version": "@PROJECT_VERSION@", + "version":"@PROJECT_VERSION@", "exeLocation":"/bin/MapPlugin", "coreIpAddr":"127.0.0.1", "corePort":24601, @@ -18,9 +18,14 @@ "default":"1000", "description":"The frequency to send the MAP message in milliseconds." }, + { + "key":"LogLevel", + "default":"INFO", + "description": "Map Plugin Log Level controls which log statements are printed to the terminal." + }, { "key":"MAP_Files", - "default":"{ \"MapFiles\": [\n {\"Action\":0, \"FilePath\":\"GID_Telegraph-Twelve_Mile_withEgress.xml\"}\n] }", + "default":"{ \"MapFiles\": [ {\"Action\":0, \"FilePath\":\"/var/www/plugins/MAP/MAP_9709_UPER.txt\"}] }", "description":"JSON data defining a list of map files. One map file for each action set specified by the TSC." } ] diff --git a/src/v2i-hub/MapPlugin/src/MapPlugin.cpp b/src/v2i-hub/MapPlugin/src/MapPlugin.cpp index 81b5a3bf4..2cf0b5666 100644 --- a/src/v2i-hub/MapPlugin/src/MapPlugin.cpp +++ b/src/v2i-hub/MapPlugin/src/MapPlugin.cpp @@ -272,7 +272,7 @@ int MapPlugin::Main() { msg->set_payload(byteStr); msg->set_encoding(enc); msg->set_flags(IvpMsgFlags_RouteDSRC); - msg->addDsrcMetadata(172, 0x8002); + msg->addDsrcMetadata(0x8002); activeAction = temp; PLOG(logINFO) << "Map for action " << activeAction << " will be sent"; @@ -325,6 +325,8 @@ bool MapPlugin::LoadMapFiles() inType = "ISD"; else if (fn.substr(fn.size() - 4) == ".txt") inType = "TXT"; + else if (fn.substr(fn.size()- 5) == ".uper") + inType ="UPER"; else inType = "XML"; @@ -354,6 +356,29 @@ bool MapPlugin::LoadMapFiles() PLOG(logINFO) << fn << " J2735 message bytes encoded as " << mapFile.get_Bytes(); } } + else if (inType == "UPER") + { + PLOG(logDEBUG) << "Reading MAP file as UPER encoded hex bytes including MessageFrame." << std::endl; + std::ifstream in; + try { + in.open(fn, std::ios::in | std::ios::binary ); + if (in.is_open()) { + in.seekg(0, std::ios::end); + int fileSize = in.tellg(); + in.seekg(0, std::ios::beg); + PLOG(logDEBUG) << "File size is " << fileSize <(in)), std::istreambuf_iterator()); + PLOG(logDEBUG) << "File contents : " << bytes_string << std::endl; + mapFile.set_Bytes(bytes_string); + } + else { + PLOG(logERROR) << "Failed to open file " << fn << "." << std::endl; + } + } + catch( const ios_base::failure &e) { + PLOG(logERROR) << "Exception Encountered : \n" << e.what(); + } + } else if (inType == "XML") { tmx::message_container_type container; diff --git a/src/v2i-hub/MessageLoggerPlugin/CMakeLists.txt b/src/v2i-hub/MessageLoggerPlugin/CMakeLists.txt index 00adfa23f..7430eef0b 100644 --- a/src/v2i-hub/MessageLoggerPlugin/CMakeLists.txt +++ b/src/v2i-hub/MessageLoggerPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( MessageLoggerPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( MessageLoggerPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "MessageLoggerPlugin") diff --git a/src/v2i-hub/MessageReceiverPlugin/CMakeLists.txt b/src/v2i-hub/MessageReceiverPlugin/CMakeLists.txt index 554c138c5..d57b4835e 100644 --- a/src/v2i-hub/MessageReceiverPlugin/CMakeLists.txt +++ b/src/v2i-hub/MessageReceiverPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( MessageReceiverPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( MessageReceiverPlugin VERSION 7.4.0 LANGUAGES CXX ) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/src/v2i-hub/MessageReceiverPlugin/manifest.json b/src/v2i-hub/MessageReceiverPlugin/manifest.json index 58669fbc3..3682dfbdb 100644 --- a/src/v2i-hub/MessageReceiverPlugin/manifest.json +++ b/src/v2i-hub/MessageReceiverPlugin/manifest.json @@ -1,7 +1,7 @@ { "name":"MessageReceiver", - "description":"Plugin to receive messages from an external DSRC radio or other source", - "version":"5.0", + "description":"Plugin to receive messages from an external V2X radio or other source", + "version":"@PROJECT_VERSION@", "exeLocation":"/bin/MessageReceiverPlugin", "coreIpAddr":"127.0.0.1", "corePort":24601, @@ -26,22 +26,22 @@ { "key":"RouteDSRC", "default":"false", - "description":"Set the flag to route a received J2735 message over DSRC." + "description":"Set the flag to route a received J2735 message." }, { "key":"EnableSimulatedBSM", "default":"true", - "description":"Accept and route incoming BSM messages from a V2I Hub simulator." + "description":"Accept and route incoming BSM messages from a V2X Hub simulator." }, { "key":"EnableSimulatedSRM", "default":"true", - "description":"Accept and route incoming SRM messages from a V2I Hub simulator." + "description":"Accept and route incoming SRM messages from a V2X Hub simulator." }, { "key":"EnableSimulatedLocation", "default":"true", - "description":"Accept and route incoming GPS location messages from a V2I Hub simulator." + "description":"Accept and route incoming GPS location messages from a V2X Hub simulator." }, { "key":"EnableVerification", diff --git a/src/v2i-hub/ODELoggerPlugin/CMakeLists.txt b/src/v2i-hub/ODELoggerPlugin/CMakeLists.txt index 2b76c78f5..bbcbcaac0 100644 --- a/src/v2i-hub/ODELoggerPlugin/CMakeLists.txt +++ b/src/v2i-hub/ODELoggerPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( ODELoggerPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( ODELoggerPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "ODELoggerPlugin") diff --git a/src/v2i-hub/ODELoggerPlugin/manifest.json b/src/v2i-hub/ODELoggerPlugin/manifest.json index ed34151e4..105dc3380 100644 --- a/src/v2i-hub/ODELoggerPlugin/manifest.json +++ b/src/v2i-hub/ODELoggerPlugin/manifest.json @@ -1,5 +1,5 @@ { - "name":"ODELoggerPlugin", + "name":"ODEForwardPlugin", "description":"Listens for J2735 messages and realtime forwards them to ODE.", "version":"@PROJECT_VERSION@", "exeLocation":"/bin/ODELoggerPlugin", diff --git a/src/v2i-hub/ODEPlugin/CMakeLists.txt b/src/v2i-hub/ODEPlugin/CMakeLists.txt index 177eb86e1..3a16f4bf7 100644 --- a/src/v2i-hub/ODEPlugin/CMakeLists.txt +++ b/src/v2i-hub/ODEPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( ODEPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( ODEPlugin VERSION 7.4.0 LANGUAGES CXX ) BuildTmxPlugin () diff --git a/src/v2i-hub/PedestrianPlugin/CMakeLists.txt b/src/v2i-hub/PedestrianPlugin/CMakeLists.txt index 8783a975c..a369271a0 100755 --- a/src/v2i-hub/PedestrianPlugin/CMakeLists.txt +++ b/src/v2i-hub/PedestrianPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( PedestrianPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( PedestrianPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "Pedestrian") add_compile_options(-fPIC) diff --git a/src/v2i-hub/PedestrianPlugin/src/PedestrianPlugin.cpp b/src/v2i-hub/PedestrianPlugin/src/PedestrianPlugin.cpp index ee1a6330e..42eec818c 100644 --- a/src/v2i-hub/PedestrianPlugin/src/PedestrianPlugin.cpp +++ b/src/v2i-hub/PedestrianPlugin/src/PedestrianPlugin.cpp @@ -264,7 +264,7 @@ void PedestrianPlugin::BroadcastPsm(char * psmJson) { //overloaded msg->set_payload(psmENC.get_payload_str()); msg->set_encoding(enc); msg->set_flags(IvpMsgFlags_RouteDSRC); - msg->addDsrcMetadata(172, 0x8002); + msg->addDsrcMetadata(0x8002); msg->refresh_timestamp(); routeable_message *rMsg = dynamic_cast(msg.get()); diff --git a/src/v2i-hub/PortDrayagePlugin/CMakeLists.txt b/src/v2i-hub/PortDrayagePlugin/CMakeLists.txt index 8a8883b35..d77924238 100644 --- a/src/v2i-hub/PortDrayagePlugin/CMakeLists.txt +++ b/src/v2i-hub/PortDrayagePlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( PortDrayagePlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( PortDrayagePlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "PortDrayage") set(CMAKE_AUTOMOC ON) diff --git a/src/v2i-hub/PortDrayagePlugin/src/PortDrayagePlugin.cpp b/src/v2i-hub/PortDrayagePlugin/src/PortDrayagePlugin.cpp index da15930d0..e07b04d13 100644 --- a/src/v2i-hub/PortDrayagePlugin/src/PortDrayagePlugin.cpp +++ b/src/v2i-hub/PortDrayagePlugin/src/PortDrayagePlugin.cpp @@ -206,7 +206,7 @@ void PortDrayagePlugin::HandleMobilityOperationMessage(tsm3Message &msg, routeab msg->set_payload(mobilityENC.get_payload_str()); msg->set_encoding(enc); msg->set_flags(IvpMsgFlags_RouteDSRC); - msg->addDsrcMetadata(172,0xBFEE); + msg->addDsrcMetadata(0xBFEE); msg->refresh_timestamp(); routeable_message *rMsg = dynamic_cast(msg.get()); BroadcastMessage(*rMsg); diff --git a/src/v2i-hub/PreemptionPlugin/CMakeLists.txt b/src/v2i-hub/PreemptionPlugin/CMakeLists.txt index aad0690f8..2acc89e2a 100644 --- a/src/v2i-hub/PreemptionPlugin/CMakeLists.txt +++ b/src/v2i-hub/PreemptionPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( PreemptionPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( PreemptionPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "Preemption") diff --git a/src/v2i-hub/RtcmPlugin/CMakeLists.txt b/src/v2i-hub/RtcmPlugin/CMakeLists.txt index 2403c9436..adf1ba654 100644 --- a/src/v2i-hub/RtcmPlugin/CMakeLists.txt +++ b/src/v2i-hub/RtcmPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( RtcmPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( RtcmPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "RTCM") diff --git a/src/v2i-hub/RtcmPlugin/manifest.json b/src/v2i-hub/RtcmPlugin/manifest.json index ad38a7768..85eca5713 100644 --- a/src/v2i-hub/RtcmPlugin/manifest.json +++ b/src/v2i-hub/RtcmPlugin/manifest.json @@ -1,6 +1,6 @@ { "name":"RTCM", - "description":"Plugin to listen for RTCM messages from an NTRIP caster and route those messages over DSRC", + "description":"Plugin to listen for RTCM messages from an NTRIP caster and route those messages over a V2X radio", "version":"@PROJECT_VERSION@", "exeLocation":"/bin/RtcmPlugin", "coreIpAddr":"127.0.0.1", diff --git a/src/v2i-hub/RtcmPlugin/src/RtcmPlugin.cpp b/src/v2i-hub/RtcmPlugin/src/RtcmPlugin.cpp index 6e58da66b..ac085dca9 100644 --- a/src/v2i-hub/RtcmPlugin/src/RtcmPlugin.cpp +++ b/src/v2i-hub/RtcmPlugin/src/RtcmPlugin.cpp @@ -116,7 +116,7 @@ void RtcmPlugin::BroadcastRTCMMessage(TmxRtcmMessage &msg, routeable_message &ro RtcmMessage rtcm = msg.get_RtcmMessage(); RtcmEncodedMessage encMsg; encMsg.initialize(rtcm, "", 0, IvpMsgFlags_RouteDSRC); - encMsg.addDsrcMetadata(172, 0x8000); + encMsg.addDsrcMetadata(0x8000); const routeable_message &rMsg = encMsg; this->BroadcastMessage(rMsg); diff --git a/src/v2i-hub/SPaTLoggerPlugin/CMakeLists.txt b/src/v2i-hub/SPaTLoggerPlugin/CMakeLists.txt index f8ea64bd4..60510405b 100644 --- a/src/v2i-hub/SPaTLoggerPlugin/CMakeLists.txt +++ b/src/v2i-hub/SPaTLoggerPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( SPaTLoggerPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( SPaTLoggerPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "SPaTLoggerPlugin") diff --git a/src/v2i-hub/SpatPlugin/CMakeLists.txt b/src/v2i-hub/SpatPlugin/CMakeLists.txt index a9076ef03..001b0ce7b 100644 --- a/src/v2i-hub/SpatPlugin/CMakeLists.txt +++ b/src/v2i-hub/SpatPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( SpatPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( SpatPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "SPAT") diff --git a/src/v2i-hub/SpatPlugin/src/SpatPlugin.cpp b/src/v2i-hub/SpatPlugin/src/SpatPlugin.cpp index 8604905c5..737990be8 100644 --- a/src/v2i-hub/SpatPlugin/src/SpatPlugin.cpp +++ b/src/v2i-hub/SpatPlugin/src/SpatPlugin.cpp @@ -142,7 +142,7 @@ int SpatPlugin::Main() { sc.getEncodedSpat(&spatEncodedMsg, pedZones); spatEncodedMsg.set_flags(IvpMsgFlags_RouteDSRC); - spatEncodedMsg.addDsrcMetadata(172, 0x8002); + spatEncodedMsg.addDsrcMetadata(0x8002); //PLOG(logDEBUG) << spatEncodedMsg; diff --git a/src/v2i-hub/TimPlugin/CMakeLists.txt b/src/v2i-hub/TimPlugin/CMakeLists.txt index c019f9f7c..5eb9c7af6 100644 --- a/src/v2i-hub/TimPlugin/CMakeLists.txt +++ b/src/v2i-hub/TimPlugin/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT ( TimPlugin VERSION 5.0 LANGUAGES CXX ) +PROJECT ( TimPlugin VERSION 7.4.0 LANGUAGES CXX ) SET (TMX_PLUGIN_NAME "TIM") add_compile_options(-fPIC) diff --git a/src/v2i-hub/TimPlugin/src/TimPlugin.cpp b/src/v2i-hub/TimPlugin/src/TimPlugin.cpp index afb87ac3b..7ebe0ad9a 100644 --- a/src/v2i-hub/TimPlugin/src/TimPlugin.cpp +++ b/src/v2i-hub/TimPlugin/src/TimPlugin.cpp @@ -322,7 +322,7 @@ int TimPlugin::Main() { //PLOG(logERROR) <<"encoded timEncMsg..."<< timEncMsg<(&timEncMsg); if (rMsg) BroadcastMessage(*rMsg); diff --git a/tools/v2i-hub-simulator/V2IHubSimulator/packages.config b/tools/v2i-hub-simulator/V2IHubSimulator/packages.config index 8bba82852..53e2ea918 100644 --- a/tools/v2i-hub-simulator/V2IHubSimulator/packages.config +++ b/tools/v2i-hub-simulator/V2IHubSimulator/packages.config @@ -3,7 +3,7 @@ - + \ No newline at end of file diff --git a/tools/validation-tool/requirements.txt b/tools/validation-tool/requirements.txt index a9c19b3a9..288d694b3 100644 --- a/tools/validation-tool/requirements.txt +++ b/tools/validation-tool/requirements.txt @@ -2,4 +2,4 @@ appJar==0.94.0 json5==0.9.5 pandas==0.25.1 scp==0.13.3 -paramiko==2.7.2 +paramiko==2.10.1 diff --git a/web/admin/admin.html b/web/admin/admin.html index 25b78db1f..735c9b63a 100644 --- a/web/admin/admin.html +++ b/web/admin/admin.html @@ -49,7 +49,7 @@
-
3.2.0
+
7.4.0