Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-du-car committed Nov 8, 2023
1 parent 25cf9fc commit 0577b21
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 61 deletions.
5 changes: 4 additions & 1 deletion src/tmx/TmxUtils/src/SNMPClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ namespace tmx::utils {
}
}

PLOG(logERROR) << "Created OID for input: " << input_oid;
PLOG(logINFO) << "Created OID for input: " << input_oid;
}
// Send the request
int status = snmp_synch_response(ss, pdu, &response);
Expand All @@ -183,6 +183,7 @@ namespace tmx::utils {
PLOG(logDEBUG1) << "Integer value in object: " << val.val_int;
}
else{
snmp_free_pdu(response);
PLOG(logERROR) << "Response specifies type integer, but no integer value found";
return false;
}
Expand All @@ -199,11 +200,13 @@ namespace tmx::utils {

}
else{
snmp_free_pdu(response);
PLOG(logERROR) << "Response specifies type string, but no string value found";
return false;
}
}
else{
snmp_free_pdu(response);
PLOG(logERROR) << "Received a message type which isn't an integer or string";
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ find_library(libasn1c .)
BuildTmxPlugin()

TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC ${NETSNMP_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC tmxutils ${NETSNMPAGENT} ${NETSNMPMIBS} ${NETSNMP} ${NETSNMP_LIBRARIES} jsoncpp)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC tmxutils ${NETSNMPAGENT} ${NETSNMPMIBS} ${NETSNMP} ${NETSNMP_LIBRARIES} jsoncpp NemaTode)
2 changes: 1 addition & 1 deletion src/v2i-hub/RSUHealthMonitorPlugin/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
},
{
"key":"RSUOIDConfigMap",
"default":"{\"RSUOIDConfig\":[{\"RsuField\":\"rsuGpsOutputString\",\"OID\":\"iso.0.15628.4.1.8.5.0\"},{\"RsuField\":\"rsuID\",\"OID\":\"iso.0.15628.4.1.17.4.0\"},{\"RsuField\":\"rsuMibVersion\",\"OID\":\"iso.0.15628.4.1.17.1.0\"},{\"RsuField\":\"rsuFirmwareVersion\",\"OID\":\"iso.0.15628.4.1.17.2.0 \"},{\"RsuField\":\"rsuManufacturer\",\"OID\":\"iso.0.15628.4.1.17.5.0\"},{\"RsuField\":\"rsuIFMIndex\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMPsid\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMDsrcMsgId\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMTxMode\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMTxChannel\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMEnable\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMStatus\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuMode\",\"OID\":\"iso.0.15628.4.1.99.0\"}]}",
"default":"{\"RSUOIDConfig\":[{\"RsuField\":\"rsuGpsOutputString\",\"OID\":\"iso.0.15628.4.1.8.5.0\",\"Required\":false},{\"RsuField\":\"rsuID\",\"OID\":\"iso.0.15628.4.1.17.4.0\",\"Required\":false},{\"RsuField\":\"rsuMibVersion\",\"OID\":\"iso.0.15628.4.1.17.1.0\",\"Required\":false},{\"RsuField\":\"rsuFirmwareVersion\",\"OID\":\"iso.0.15628.4.1.17.2.0 \",\"Required\":false},{\"RsuField\":\"rsuManufacturer\",\"OID\":\"iso.0.15628.4.1.17.5.0\",\"Required\":false},{\"RsuField\":\"rsuIFMIndex\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMPsid\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMDsrcMsgId\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMTxMode\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMTxChannel\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMEnable\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMStatus\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuMode\",\"OID\":\"iso.0.15628.4.1.99.0\",\"Required\":false}]}",
"description":"OID (Object Identifier) uniquely identify managed objects in a MIB database."
}
]
Expand Down
148 changes: 92 additions & 56 deletions src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,6 @@ namespace RSUHealthMonitor
string rsuOIDMapJsonStr;
GetConfigValue<string>("RSUOIDConfigMap", rsuOIDMapJsonStr);
UpdateRSUOIDConfig(rsuOIDMapJsonStr);

// Create SNMP client and use SNMP V3 protocol
try
{
_snmpClientPtr = std::make_shared<snmp_client>(_rsuIp, _snmpPort, "", _securityUser, "authNoPriv", _authPassPhrase, 3);
PLOG(logINFO) << "Updated SNMP client call: RSU IP: " << _rsuIp << ", RSU port: " << _snmpPort << ", User: " << _securityUser << ", auth pass phrase: " << _authPassPhrase << ", security level: "
<< "authNoPriv";
}
catch (std::exception &ex)
{
PLOG(logERROR) << "Cannot create SNMP client due to an error. The error message is: " << ex.what();
}
}

void RSUHealthMonitorPlugin::UpdateRSUOIDConfig(string &json_str)
Expand All @@ -67,7 +55,7 @@ namespace RSUHealthMonitor
RSUOIDConfig config;
config.field = child.second.get<string>("RsuField");
config.oid = child.second.get<string>("OID");
PLOG(logINFO) << "RSU OID Config: Field: " << config.field << ", OID: " << config.oid;
config.required = child.second.get<bool>("Required");
// Add RSU OID to the map
_rsuOIDConfigMap.push_back(config);
}
Expand All @@ -88,63 +76,112 @@ namespace RSUHealthMonitor
{
while (true)
{
PLOG(logDEBUG) << "RSU status update call at every " << _interval << "seconds!";

// Broadcast the RSU status info when there are any RSU responses.
string json_str = getRSUstatus();
if (json_str.length() > 0)
try
{
tmx::messages::RSUStatusMessage sendRsuStatusMsg;
sendRsuStatusMsg.set_contents(json_str);
BroadcastMessage(sendRsuStatusMsg);
auto rsuStatusJson = getRSUstatus();

if (!rsuStatusJson.empty())
{
vector<string> rsuStatusFields;
for (auto const &field : rsuStatusJson.getMemberNames())
{
rsuStatusFields.push_back(field);
}
// Only broadcast RSU status when all required fields are present.
if (isAllRequiredFieldsPresent(rsuStatusFields))
{
Json::FastWriter fasterWirter;
string json_str = fasterWirter.write(rsuStatusJson);
tmx::messages::RSUStatusMessage sendRsuStatusMsg;
sendRsuStatusMsg.set_contents(json_str);
BroadcastMessage(sendRsuStatusMsg);
PLOG(logINFO) << "Broadcast RSU status: " << json_str;
}
}
}
catch (std::exception &ex)
{
PLOG(logERROR) << ex.what();
}
this_thread::sleep_for(chrono::seconds(_interval));
}
}

string RSUHealthMonitorPlugin::getRSUstatus()
Json::Value RSUHealthMonitorPlugin::getRSUstatus()
{
if (_rsuOIDConfigMap.size() == 0)
{
PLOG(logERROR) << "RSU status update call failed due to RSUOIDConfigMap is empty!";
return Json::nullValue;
}
PLOG(logDEBUG) << "RSU status update call at every " << _interval << " seconds!\n";

// Create SNMP client and use SNMP V3 protocol
auto _snmpClientPtr = std::make_unique<snmp_client>(_rsuIp, _snmpPort, "", _securityUser, "authNoPriv", _authPassPhrase, 3);
PLOG(logINFO) << "Updated SNMP client call: RSU IP: " << _rsuIp << ", RSU port: " << _snmpPort << ", User: " << _securityUser << ", auth pass phrase: " << _authPassPhrase << ", security level: "
<< "authNoPriv";
if (_snmpClientPtr == nullptr)
{
PLOG(logERROR) << "Error creating SNMP client!";
return Json::nullValue;
}

Json::Value rsuStatuJson;
// Sending RSU SNMP call for each field as each field has its own OID.
for_each(_rsuOIDConfigMap.begin(), _rsuOIDConfigMap.end(), [this, &rsuStatuJson](RSUOIDConfig &config)
{
try
for (auto &config : _rsuOIDConfigMap)
{
try
{
PLOG(logINFO) << "SNMP RSU status call for field:" << config.field << ", OID: " << config.oid;
snmp_response_obj responseVal;
auto success = _snmpClientPtr->process_snmp_request(config.oid, request_type::GET, responseVal);
if (!success)
{
// If any snmp request failed, stop any furthur snmp requests using the same current snmp session as the next OID will not be created.
break;
}
else if (success && responseVal.type == snmp_response_obj::response_type::INTEGER)
{
rsuStatuJson[config.field] = responseVal.val_int;
}
else if (success && responseVal.type == snmp_response_obj::response_type::STRING)
{
string response_str(responseVal.val_string.begin(), responseVal.val_string.end());
PLOG(logDEBUG) << "String value in response: " << response_str;
// Proess GPS nmea string
if (boost::iequals("rsuGpsOutputString", config.field))
{
PLOG(logINFO) << "SNMP RSU status call for field:"<< config.field << ", OID: " << config.oid;
snmp_response_obj responseVal;
if(_snmpClientPtr != nullptr)
{
_snmpClientPtr->process_snmp_request(config.oid, request_type::GET, responseVal);
if(responseVal.type == snmp_response_obj::response_type::INTEGER)
{
rsuStatuJson[config.field] = responseVal.val_int;
}
else if(responseVal.type == snmp_response_obj::response_type::STRING)
{
string response_str(responseVal.val_string.begin(), responseVal.val_string.end());
if(boost::iequals("rsuGpsOutputString", config.field))
{
auto gps = ParseGPS(response_str);
rsuStatuJson["rsuGpsOutputStringLatitude"] = gps[0];
rsuStatuJson["rsuGpsOutputStringLongitude"] = gps[1];
}else{
rsuStatuJson[config.field] = response_str;
}
}
}
auto gps = ParseGPS(response_str);
rsuStatuJson["rsuGpsOutputStringLatitude"] = gps[0];
rsuStatuJson["rsuGpsOutputStringLongitude"] = gps[1];
}
catch (std::exception &ex)
else
{
PLOG(logERROR) << "SNMP call failure due to: " << ex.what();
} });
rsuStatuJson[config.field] = response_str;
}
}
}
catch (std::exception &ex)
{
PLOG(logERROR) << "SNMP call failure due to: " << ex.what();
}
}
return rsuStatuJson;
}

if (!rsuStatuJson.empty())
bool RSUHealthMonitorPlugin::isAllRequiredFieldsPresent(vector<string> fields)
{
bool isAllPresent = true;
for (auto &config : _rsuOIDConfigMap)
{
Json::FastWriter fasterWirter;
string json_str = fasterWirter.write(rsuStatuJson);
return json_str;
if (config.required && std::find(fields.begin(), fields.end(), config.field) == fields.end())
{
isAllPresent = false;
PLOG(logWARNING) << "No broadcast as required field " << config.field << " is not present!";
}
}
return "";
return isAllPresent;
}

std::map<long, long> RSUHealthMonitorPlugin::ParseGPS(const std::string &gps_nmea_data)
Expand All @@ -161,9 +198,8 @@ namespace RSUHealthMonitor
std::stringstream sss;
sss << std::setprecision(8) << std::fixed << gps.fix.longitude << std::endl;
auto longitude_str = sss.str();
boost::erase_all(longitude_str, ".");
boost::erase_all(latitude_str, ".");
result.insert({std::stol(latitude_str), std::stol(longitude_str)});
PLOG(logDEBUG) << "Parse GPS NMEA string: " << gps_nmea_data << ". Result (Latitude, Longitude): (" << latitude_str << "," << longitude_str << ")";
}
catch (nmea::NMEAParseError &e)
{
Expand Down
10 changes: 8 additions & 2 deletions src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <jsoncpp/json/json.h>
#include "RSUStatusMessage.h"
#include <nmeaparse/nmea.h>
#include <algorithm>

using namespace tmx::utils;
using namespace std;
Expand All @@ -23,6 +24,7 @@ namespace RSUHealthMonitor
{
string field;
string oid;
bool required; // Indicate whether this field is required to before broadcasting the RSU status.
};

class RSUHealthMonitorPlugin : public PluginClient
Expand All @@ -35,7 +37,7 @@ namespace RSUHealthMonitor
string _authPassPhrase;
string _securityUser;
vector<RSUOIDConfig> _rsuOIDConfigMap;
std::shared_ptr<snmp_client> _snmpClientPtr;
// std::shared_ptr<snmp_client> _snmpClientPtr;
/**
* @brief Update RSU OID configuration map with input JSON string.
* @param JSON string with RSU OID configuration.
Expand All @@ -48,13 +50,17 @@ namespace RSUHealthMonitor
/**
* @brief Sending SNMP requests to get info for each field in the _rsuOIDConfigMap, and return the RSU status in JSON string
*/
string getRSUstatus();
Json::Value getRSUstatus();
/**
* @brief Parse NMEA GPS sentense and return GPS related data
* @param gps_nmea_data NMEA GPS sentense
* @return map<long, long> A map of latitude and longitude
*/
std::map<long, long> ParseGPS(const std::string &gps_nmea_data);
/**
* @brief determine if all required fields in the RSU config map _rsuOIDConfigMap present in the input fields
*/
bool isAllRequiredFieldsPresent(vector<string> fields);

public:
RSUHealthMonitorPlugin(std::string name);
Expand Down

0 comments on commit 0577b21

Please sign in to comment.