module ItsRSUsSimulator_Functions { // LibCommon import from LibCommon_BasicTypesAndValues all; import from LibCommon_DataStrings all; import from LibCommon_VerdictControl all; import from LibCommon_Sync all; import from LibCommon_Time all; // LibIts import from ITS_Container language "ASN.1:1997" all; import from CAM_PDU_Descriptions language "ASN.1:1997" all; import from DENM_PDU_Descriptions language "ASN.1:1997" all; import from MAPEM_PDU_Descriptions language "ASN.1:1997" all; import from SPATEM_PDU_Descriptions language "ASN.1:1997" all; import from IVIM_PDU_Descriptions language "ASN.1:1997" all; //import from EVCSN_PDU_Descriptions language "ASN.1:1997" all; import from SREM_PDU_Descriptions language "ASN.1:1997" all; import from SSEM_PDU_Descriptions language "ASN.1:1997" all; import from DSRC language "ASN.1:1997" all; import from IEEE1609dot2BaseTypes language "ASN.1:1997" all; import from IEEE1609dot2 language "ASN.1:1997" all; import from EtsiTs102941BaseTypes language "ASN.1:1997" all; import from EtsiTs102941TypesEnrolment language "ASN.1:1997" all; import from EtsiTs102941TypesAuthorization language "ASN.1:1997" all; import from EtsiTs102941TypesAuthorizationValidation language "ASN.1:1997" all; import from EtsiTs102941MessagesCa language "ASN.1:1997" all; import from EtsiTs103097Module language "ASN.1:1997" all; // LibItsCommon import from LibItsCommon_Functions all; // LibItsBtp import from LibItsBtp_TypesAndValues all; import from LibItsBtp_Templates all; // LibItsCam import from LibItsCam_TypesAndValues all; import from LibItsCam_Templates all; // LibItsDenm import from LibItsDenm_TypesAndValues all; import from LibItsDenm_Templates all; // LibItsMapemSpatemm import from LibItsMapemSpatem_Templates all; // LibItsMapemSpatemm import from LibItsIvim_Templates all; // LibItsMapemSpatemm import from LibItsSremSsem_Templates all; // LibItsGeoNetworking import from LibItsGeoNetworking_TestSystem all; import from LibItsGeoNetworking_Functions all; import from LibItsGeoNetworking_Templates all; import from LibItsGeoNetworking_TypesAndValues all; import from LibItsGeoNetworking_Pixits all; // LibItsSecurity import from LibItsSecurity_TypesAndValues all; import from LibItsSecurity_Functions all; import from LibItsSecurity_Templates all; // LibItsHttp import from LibItsHttp_TypesAndValues all; import from LibItsHttp_Templates all; import from LibItsHttp_BinaryTemplates all; import from LibItsHttp_Functions all; import from LibItsHttp_TestSystem all; // LibItsPki import from LibItsPki_TypesAndValues all; import from LibItsPki_Templates all; import from LibItsPki_Functions all; import from LibItsPki_TestSystem all; import from LibItsPki_Pics all; import from LibItsPki_Pixits all; // AtsRSUsSimulator import from ItsRSUsSimulator_TypesAndValues all; import from ItsRSUsSimulator_TestSystem all; import from ItsRSUsSimulator_Templates all; import from ItsRSUsSimulator_PicsInitConsts all; import from ItsRSUsSimulator_Pics all; import from ItsRSUsSimulator_Pixits all; group externalFunctions { /** * @desc External function to compute a position using a reference position, a distance and an orientation * @param p_refLongPosVector Vehicle reference position * @param p_cenLongPosVector Collision point position * @param p_rotation Rotation angle in 1/10 of degrees (from North) * @param p_latitude Computed position's latitude * @param p_longitude Computed position's longitude * @remark See http://www.movable-type.co.uk/scripts/latlong.html */ external function fx_computePositionFromRotation( in Int32 p_refLatitude, in Int32 p_refLongitude, in Int32 p_cenLatitude, in Int32 p_cenLongitude, in Int32 p_rotation, out Int32 p_latitude, out Int32 p_longitude ); } // End of group externalFunctions group rsuConfigurationFunctions { /** * @desc This configuration features: * - one ITS node (IUT) * - two ITS nodes (nodeA, nodeB) * - Area1 which only includes NodeB and IUT * - Area2 which only includes NodeB * NodeB being close to the area center */ function f_cf01Up() runs on ItsRSUsSimulator { // Local variables // Map map(self:acPort, system:acPort); map(self:cfPort, system:cfPort); map(self:geoNetworkingPort, system:geoNetworkingPort); // Connect f_connect4SelfOrClientSync(); activate(a_cf01Down()); // Initialise secured mode LibItsGeoNetworking_Functions.f_initialiseSecuredMode(); //Initialze the Config module //cfPort.send(CfInitialize:{}); // Initialisations f_setup_rsu(vc_rsu_id); if (vc_pki == true) { // TODO LibItsPki_Function.f_cf01(); } } // End of function f_cf01Up function f_cf01Down() runs on ItsRSUsSimulator { vc_rsuMessagesValueList := {}; LibItsGeoNetworking_Functions.f_uninitialiseSecuredMode(); // Unmap unmap(self:acPort, system:acPort); unmap(self:cfPort, system:cfPort); unmap(self:geoNetworkingPort, system:geoNetworkingPort); // Disconnect f_disconnect4SelfOrClientSync(); deactivate; } // End of function f_cf01Down /** * @desc Default handling cf01 de-initialisation. */ altstep a_cf01Down() runs on ItsRSUsSimulator { [] a_shutdown() { f_poDefault(); f_cf01Down(); log("*** a_cf01Down: INFO: TEST COMPONENT NOW STOPPING ITSELF! ***"); stop; } } // End of altstep a_cf01Down } // End of group rsuConfigurationFunctions group usecase6 { function f_initialiseVehicleSimulatorComponent( in ItsRSUsSimulator p_component, in integer p_vehicleIndex, out template (omit) CAM p_cam ) runs on ItsRSUsSimulator { p_cam := m_camMsg_vehicle( f_getTsStationId() + p_vehicleIndex, f_getCurrentTime() mod 65536, // Shall be updated in function f_prepare_vehicle_cam m_rsuPosition( 0, // Shall be computed 0 // Shall be computed ) ); map(p_component:geoNetworkingPort, system:geoNetworkingPort); } // End of function f_initialiseVehicleSimulatorComponent function f_uninitialiseVehicleSimulatorComponent( in ItsRSUsSimulator p_component ) runs on ItsRSUsSimulator { p_component.done; unmap(p_component:geoNetworkingPort, system:geoNetworkingPort); } // End of function f_uninitialiseVehicleSimulatorComponent } // End of group usecase6 function f_setup_rsu( in integer p_rsu_id ) runs on ItsRSUsSimulator { // Local variables var template (value) DenmParmContainers v_denmParmContainers; var template (omit) octetstring v_beacon := omit; var template (omit) DENMs v_denms := omit; var template (omit) CAM v_cam := omit; var template (omit) MAPEM v_mapem := omit; var template (omit) SPATEMs v_spatems := omit; var template (omit) IVIM v_ivim := omit; //var template (omit) EvcsnPdu v_evcsn := omit; var template (omit) SSEM v_ssem := omit; var integer v_counter; vc_longPosVectorRsu := PICS_RSU_PARAMS[p_rsu_id].longPosVector; // MAPEM, only if PX_ETSI_USE_CASE_ID is set to 3 if ((vc_mapem == true) and (PX_ETSI_USE_CASE_ID == 3) and ispresent(PICS_MAPEM_PARMS_RSUs[p_rsu_id].intersections)) { // Build the list of the MAPEM events v_mapem := m_mapemParm( PICS_RSU_PARAMS[vc_rsu_id].stationID, m_mapem( f_getMsgIssueRevision(), PICS_MAPEM_PARMS_RSUs[p_rsu_id].intersections, PICS_MAPEM_PARMS_RSUs[p_rsu_id].roadSegments )); // Update revision fields v_mapem.map_.intersections[0].revision := f_incMsgIssueRevision(); // TODO Add more? } else { vc_mapem := false; } // SPATEM, only if PX_ETSI_USE_CASE_ID is set to 3 if ((vc_spatem == true) and (PX_ETSI_USE_CASE_ID == 3) and (lengthof(PICS_SPATEM_PARMS_RSUs[p_rsu_id]) != 0)) { // Reset counter vc_currentPhaseStartTime := 36001; vc_endPhaseStartTime := 0; vc_spatemStatesId := 0; // Build the list of the SPATEM events for (v_counter := 0; v_counter < lengthof(PICS_SPATEM_PARMS_RSUs[p_rsu_id]); v_counter := v_counter + 1) { v_spatems[v_counter] := m_spatemParm( PICS_RSU_PARAMS[p_rsu_id].stationID, m_spatem( PICS_SPATEM_PARMS_RSUs[p_rsu_id][v_counter].intersections, "SignalGroupID #" & int2str(PICS_SPATEM_PARMS_RSUs[p_rsu_id][v_counter].signalGroupID) )); for (var integer v_intersection := 0; v_intersection < lengthof(v_spatems[v_counter].spat.intersections); v_intersection := v_intersection + 1) { vc_states[v_counter][v_intersection] := v_spatems[v_counter].spat.intersections[v_intersection].states; } // End of 'for' statement // TODO Build SPATEM with dynamic values } // End of 'for' statement // TODO Build SPATEM with dynamic values } else { vc_spatem := false; } // IVIM, only if PX_ETSI_USE_CASE_ID is set to 5 if ((vc_ivim == true) and (PX_ETSI_USE_CASE_ID == 5) and ispresent(PICS_IVIM_PARMS_RSUs[p_rsu_id].provider)) { // Build the list of the IVIM events v_ivim := m_ivimParm( PICS_RSU_PARAMS[p_rsu_id].stationID, m_ivimStructure( m_iviManagementContainer( PICS_IVIM_PARMS_RSUs[p_rsu_id].provider, PICS_IVIM_PARMS_RSUs[p_rsu_id].iviIdentificationNumber, 0//IviStatus_new_ ), PICS_IVIM_PARMS_RSUs[p_rsu_id].iviContainers )); // Update ivi status v_ivim.ivi.mandatory.validFrom := f_getCurrentTime(); v_ivim.ivi.mandatory.validTo := valueof(v_ivim.ivi.mandatory.validFrom) + 43200000; // 12hours } else { vc_ivim := false; } /* // EVCSN, only if PX_ETSI_USE_CASE_ID is set to 8 */ /* if ((vc_evcsn == true) and (PX_ETSI_USE_CASE_ID == 8)) { */ /* // Build the list of the EVCSN events */ /* v_evcsn := */ /* m_evcsnParm( */ /* PICS_RSU_PARAMS[p_rsu_id].stationID, */ /* m_evcsn( */ /* m_itsPOIHeader( */ /* -, */ /* 0, // To be updated at run time */ /* - */ /* ), */ /* m_itsEVCSNData( */ /* -, */ /* { c_PICS_ITS_CHARGING } */ /* ) */ /* )); */ /* // Update poi status */ /* } else { */ /* vc_evcsn := false; */ /* } */ // DENM, only if PX_ETSI_USE_CASE_ID is set to 1 if ((vc_denm == true) and (PX_ETSI_USE_CASE_ID == 1)) { // Build the list of the DENM events for the specified RSU (PX_RSU_ID) and the given zone (PX_ETSI_ZONE_ID) for (v_counter := 0; v_counter < lengthof(PICS_DENM_EVENTS_RSU[p_rsu_id][PX_ETSI_ZONE_ID - 1]); v_counter := v_counter + 1) { var DenmEventsParmsPerZone v_denmEventsParmsPerZone := PICS_DENM_EVENTS_RSU[p_rsu_id][PX_ETSI_ZONE_ID - 1]; v_denmParmContainers := m_denmParmContainers( PICS_RSU_PARAMS[p_rsu_id].stationID, f_incDenmSequenceNumber(), PICS_DENM_REPETITION_INTERVAL, v_denmEventsParmsPerZone[v_counter].eventPosition, v_denmEventsParmsPerZone[v_counter].causeCodeType, v_denmEventsParmsPerZone[v_counter].eventHistory, v_denmEventsParmsPerZone[v_counter].traces, PICS_DENM_VALIDITY_DURATION, PICS_DENM_RELEVANCE_DISTANCE, PICS_DENM_RELEVANCE_TRAFFIC_DIRECTION ); v_denms[v_counter] := valueof( m_denmPdu_rsu( PICS_RSU_PARAMS[p_rsu_id].stationID, m_denm( v_denmParmContainers.managementContainer, v_denmParmContainers.situationContainer, v_denmParmContainers.locationContainer ))); if (ispresent(v_denmEventsParmsPerZone[v_counter].roadWorksContainerExtended)) { v_denms[v_counter].denm.alacarte := m_alacarte(v_denmEventsParmsPerZone[v_counter].roadWorksContainerExtended); } } // End of 'for' statement // Update referenceDenms field, all except the current one for (v_counter := 0; v_counter < lengthof(PICS_DENM_EVENTS_RSU[p_rsu_id][PX_ETSI_ZONE_ID - 1]); v_counter := v_counter + 1) { if (ispresent(v_denms[v_counter].denm.alacarte.roadWorks)) { var integer v_referenceDenms := 0; for (var integer v_counter1 := 0; v_counter1 < lengthof(PICS_DENM_EVENTS_RSU[p_rsu_id][PX_ETSI_ZONE_ID - 1]); v_counter1 := v_counter1 + 1) { if (v_counter1 == v_counter) { continue; } v_denms[v_counter].denm.alacarte.roadWorks.referenceDenms[v_referenceDenms] := v_denms[v_counter1].denm.management.actionID; v_referenceDenms := v_referenceDenms + 1; } // End of 'for' statement } } // End of 'for' statement } else { vc_denm := false; } // CAM if (vc_cam == true) { // Build the list of the CAM events if (PX_ETSI_USE_CASE_ID == 7) { vc_longPosVectorRsu := PICS_UC7_LPV.longPosVector; v_cam := m_camParm( PICS_UC7_LPV.stationID, PICS_UC7_LPV.stationType, PICS_UC7_LPV.vehicleRole, m_rsuPosition( PICS_UC7_LPV.longPosVector.latitude, PICS_UC7_LPV.longPosVector.longitude ), PICS_UC7_LPV.pathHistory, { rsuContainerHighFrequency := { protectedCommunicationZonesRSU := omit } } ); } else if (PX_ETSI_USE_CASE_ID == 6) { // FIXME To be removed only for test v_cam := m_camMsg_vehicle( PICS_RSU_PARAMS[p_rsu_id].stationID, f_getCurrentTime() mod 65536, // Shall be updated in function f_prepare_vehicle_cam m_rsuPosition( vc_longPosVectorRsu.latitude, vc_longPosVectorRsu.longitude ) ); } else if (PX_ETSI_USE_CASE_ID == 9) { v_cam := m_camParm( PICS_RSU_PARAMS[p_rsu_id].stationID, -, -, m_rsuPosition( vc_longPosVectorRsu.latitude, vc_longPosVectorRsu.longitude ), PICS_RSU_PARAMS[p_rsu_id].pathHistory, m_highFrequencyContainer_rsuContainerHighFrequency( m_rSUContainerHighFrequency( PICS_UC9_PCZ ))); } else { v_cam := m_camParm( PICS_RSU_PARAMS[p_rsu_id].stationID, -, -, m_rsuPosition( vc_longPosVectorRsu.latitude, vc_longPosVectorRsu.longitude ), PICS_RSU_PARAMS[p_rsu_id].pathHistory, { rsuContainerHighFrequency := { protectedCommunicationZonesRSU := omit } } ); } } if (vc_beacon == true) { // Build the list of the BeACON events v_beacon := 'AAAAAAAA'O; // TODO Use a PICS } // Build the messages value list for this RSU vc_rsuMessagesValueList[p_rsu_id] := m_rsuProfile( v_beacon, v_cam, v_denms, v_mapem, v_spatems, v_ivim, // v_evcsn, v_ssem ); //log("vc_rsuMessagesValueList[p_rsu_id] = ", vc_rsuMessagesValueList[p_rsu_id]); if (PICS_RSU_PARAMS[p_rsu_id].geoShape == e_geoCircle) { vc_geoArea := { shape := e_geoCircle, area := { geoAreaPosLatitude := vc_longPosVectorRsu.latitude, geoAreaPosLongitude := vc_longPosVectorRsu.longitude, distanceA := PICS_RSU_PARAMS[p_rsu_id].geoParms.radius, distanceB := PICS_RSU_PARAMS[p_rsu_id].geoParms.radius, angle := 0 } } } else { log("*** " & testcasename() & ": INCONC: Wrong PICS_RSU_GEOAREA_FORM event initialisation ***"); setverdict(inconc); stop; } } // End of function f_setup_rsu function f_process_cf_event( in CfEvent p_cfEvent ) runs on ItsRSUsSimulator return boolean { var template (value) CfResult v_result := true; // Terminate simulation if (p_cfEvent == "stop") { if (ispresent(vc_rsuMessagesValueList[vc_rsu_id].beacon)) { tc_beacon.stop; } if (ispresent(vc_rsuMessagesValueList[vc_rsu_id].cam)) { tc_cam.stop; } if (ispresent(vc_rsuMessagesValueList[vc_rsu_id].denms)) { tc_denm.stop; } if (ispresent(vc_rsuMessagesValueList[vc_rsu_id].mapem)) { tc_mapem.stop; } if (ispresent(vc_rsuMessagesValueList[vc_rsu_id].spatems)) { tc_spatem.stop; } if (ispresent(vc_rsuMessagesValueList[vc_rsu_id].ivim)) { tc_ivim.stop; } } else { v_result := false; } cfPort.send(v_result); return true; } // End of function f_process_cf_event function f_prepare_beacon( out template (value) GnRawPayload p_payload ) runs on ItsRSUsSimulator { p_payload := valueof( f_adaptPayload( vc_rsuMessagesValueList[vc_rsu_id].beacon, 0, -, e_any ) ); log("f_prepare_beacon: ", p_payload); } // End of function f_prepare_beacon function f_prepare_cam( out template (value) GnRawPayload p_payload ) runs on ItsRSUsSimulator { vc_rsuMessagesValueList[vc_rsu_id].cam.cam.generationDeltaTime := f_getCurrentTime() mod 65536; // See ETSI EN 302 637-2 V1.3.0 - Clause B.3 generationDelatTime p_payload := valueof( f_adaptPayload( bit2oct( encvalue( valueof( vc_rsuMessagesValueList[vc_rsu_id].cam ))), PICS_CAM_BTP_DESTINATION_PORT, PICS_CAM_BTP_SOURCE_PORT ) ); } // End of function f_prepare_cam function f_prepare_denm( out template (value) GnRawPayload p_payload, in boolean p_cancellation := false ) runs on ItsRSUsSimulator { // Update dynamic parms vc_rsuMessagesValueList[vc_rsu_id].denms[vc_denmEventCounter].denm.management.referenceTime := f_getCurrentTime(); if (p_cancellation == true) { vc_rsuMessagesValueList[vc_rsu_id].denms[vc_denmEventCounter].denm.management.termination := isCancellation; } p_payload := valueof( f_adaptPayload( bit2oct( encvalue( valueof(vc_rsuMessagesValueList[vc_rsu_id].denms[vc_denmEventCounter] ))), PICS_DENM_BTP_DESTINATION_PORT, PICS_DENM_BTP_SOURCE_PORT ) ); vc_denmEventCounter := (vc_denmEventCounter + 1) mod lengthof(vc_rsuMessagesValueList[vc_rsu_id].denms); } // End of function f_prepare_denm function f_prepare_mapem( out template (value) GnRawPayload p_payload ) runs on ItsRSUsSimulator { p_payload := valueof( f_adaptPayload( bit2oct( encvalue( valueof( vc_rsuMessagesValueList[vc_rsu_id].mapem ))), PICS_MAPEM_BTP_DESTINATION_PORT, PICS_MAPEM_BTP_SOURCE_PORT ) ); } // End of function f_prepare_mapem function f_computeEndPhaseStartTime( in TimeMark p_timeMark, in UInt32 p_inc ) return TimeMark { var UInt32 v_endPhaseStartTime := p_timeMark + p_inc; return v_endPhaseStartTime mod 36000; } function f_prepare_spatem( in template (value) SPATEM p_spatem, out template (value) GnRawPayload p_payload ) runs on ItsRSUsSimulator { var template (omit) SPATEM v_spatem := p_spatem; // Make a copy var TimeMark v_currentTimeMark := f_getCurrentTimeMark(); if (vc_currentPhaseStartTime == 36001) { // First call vc_currentPhaseStartTime := v_currentTimeMark; select (vc_spatemStatesId) { case (0) { vc_endPhaseStartTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_30); } case (1) { vc_endPhaseStartTime := f_computeEndPhaseStartTime(v_currentTimeMark, PICS_SPATEM_REPITITION_DURATION_STATE_30); } case (2) { vc_endPhaseStartTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_30); } } // End of 'select' statement } if (v_currentTimeMark >= vc_endPhaseStartTime) { var float t := (int2float(v_currentTimeMark - vc_endPhaseStartTime) / int2float(v_currentTimeMark)); log("t = ", t); if (t < 1.0) { // Change state vc_spatemStatesId := (vc_spatemStatesId + 1) mod vc_spatemStatesNum; vc_currentPhaseStartTime := v_currentTimeMark; vc_endPhaseStartTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_30); } } log("vc_currentPhaseStartTime = ", vc_currentPhaseStartTime); log("v_currentTimeMark = ", v_currentTimeMark); log("vc_endPhaseStartTime = ", vc_endPhaseStartTime); log("vc_spatemStatesId = ", vc_spatemStatesId); // Rebuild SPATEM message for (var integer v_intersection := 0; v_intersection < lengthof(v_spatem.spat.intersections); v_intersection := v_intersection + 1) { var template (omit) MovementList v_states := vc_states[vc_signalGroupParmId][v_intersection]; v_spatem.spat.intersections[v_intersection].states := { v_states[vc_spatemStatesId] }; v_spatem.spat.intersections[v_intersection].moy := f_getMinuteOfTheYear(); v_spatem.spat.intersections[v_intersection].timeStamp := f_getDSecond(); v_spatem.spat.intersections[v_intersection].revision := (valueof(v_spatem.spat.intersections[v_intersection].revision) + 1) mod 128; select (vc_spatemStatesId) { case (0) { // permissive_Movement_Allowed v_spatem.spat.intersections[v_intersection].states[1] := v_states[1]; // permissive-clearance //v_spatem.spat.intersections[v_intersection].states[2] := v_states[2]; // Update startTime & minEndTime v_spatem.spat.intersections[v_intersection].states[0].state_time_speed[0].timing.minEndTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_30); v_spatem.spat.intersections[v_intersection].states[1].state_time_speed[0].timing.startTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_30); v_spatem.spat.intersections[v_intersection].states[1].state_time_speed[0].timing.minEndTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_40); } case (1) { // permissive-clearance v_spatem.spat.intersections[v_intersection].states[1] := v_states[2]; // stop-And-Remain //v_spatem.spat.intersections[v_intersection].states[2] := v_states[0]; // Update startTime & minEndTime v_spatem.spat.intersections[v_intersection].states[0].state_time_speed[0].timing.minEndTime := f_computeEndPhaseStartTime(v_currentTimeMark, PICS_SPATEM_REPITITION_DURATION_STATE_10); v_spatem.spat.intersections[v_intersection].states[1].state_time_speed[0].timing.startTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_10); v_spatem.spat.intersections[v_intersection].states[1].state_time_speed[0].timing.minEndTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_30); } case (2) { // stop-And-Remain v_spatem.spat.intersections[v_intersection].states[1] := v_states[0]; // permissive_Movement_Allowed //v_spatem.spat.intersections[v_intersection].states[2] := v_states[1]; // Update startTime & minEndTime v_spatem.spat.intersections[v_intersection].states[0].state_time_speed[0].timing.minEndTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_20); v_spatem.spat.intersections[v_intersection].states[1].state_time_speed[0].timing.startTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_20); v_spatem.spat.intersections[v_intersection].states[1].state_time_speed[0].timing.minEndTime := f_computeEndPhaseStartTime(vc_currentPhaseStartTime, PICS_SPATEM_REPITITION_DURATION_STATE_50); } case else { } } // End of 'select' statement } // End of 'for' statement log("v_spatem.spat.intersections = ", v_spatem.spat.intersections); p_payload := valueof( f_adaptPayload( bit2oct( encvalue( valueof( v_spatem ))), PICS_SPATEM_BTP_DESTINATION_PORT, PICS_SPATEM_BTP_SOURCE_PORT ) ); } // End of function f_prepare_spatem function f_prepare_ivim( out template (value) GnRawPayload p_payload ) runs on ItsRSUsSimulator { p_payload := valueof( f_adaptPayload( bit2oct( encvalue( valueof( vc_rsuMessagesValueList[vc_rsu_id].ivim ))), PICS_IVIM_BTP_DESTINATION_PORT, PICS_IVIM_BTP_SOURCE_PORT ) ); } // End of function f_prepare_ivim /* function f_prepare_evcsn( */ /* out template (value) GnRawPayload p_payload */ /* ) runs on ItsRSUsSimulator { */ /* vc_rsuMessagesValueList[vc_rsu_id].evcsn.evcsn.poiHeader.timeStamp := f_getCurrentTime(); // Check if it is ITS or UTC time */ /* log("vc_rsuMessagesValueList[vc_rsu_id].evcsn", valueof(vc_rsuMessagesValueList[vc_rsu_id].evcsn)); */ /* p_payload := valueof( */ /* f_adaptPayload( */ /* bit2oct( */ /* encvalue( */ /* valueof( */ /* vc_rsuMessagesValueList[vc_rsu_id].evcsn */ /* ))), */ /* PICS_EVCSN_BTP_DESTINATION_PORT, */ /* PICS_EVCSN_BTP_SOURCE_PORT */ /* ) */ /* ); */ /* } // End of function f_prepare_evcsn */ function f_adaptPayload( in template (value) octetstring p_finalPayload, in template (value) BtpPortId p_destPort, in template (value) BtpPortId p_srcPort := 0, in NextHeader p_nextHeader := PX_GN_UPPER_LAYER ) return template (value) GnRawPayload { var template (value) GnRawPayload v_payload := ''O; if(p_nextHeader == e_any) { v_payload := p_finalPayload; return v_payload; } if(p_nextHeader == e_ipv6) { log("*** " & testcasename() & ": INCONC: Layer IPv6 not supported ***"); setverdict(inconc); stop; } if(p_nextHeader == e_btpA) { v_payload := int2oct(valueof(p_destPort), 2) & int2oct(valueof(p_srcPort), 2) & valueof(p_finalPayload); return v_payload; } if(p_nextHeader == e_btpB) { v_payload := int2oct(valueof(p_destPort), 2) & int2oct(valueof(p_srcPort), 2) & valueof(p_finalPayload); return v_payload; } return v_payload; } // End of function f_adaptPayload function f_isInApproach( in ThreeDLocation p_detectionPoint, in ThreeDLocation p_location, in float p_dist := 150.0 ) return boolean { var float v_dist := fx_computeDistance(p_detectionPoint.latitude, p_detectionPoint.longitude, p_location.latitude, p_location.longitude); log("v_dist = ", v_dist); return v_dist <= p_dist; } function f_mirror_and_send_vehicle_cam( in template (value) CAM p_camSimu, in CAM p_camVehicle, in ThreeDLocation p_location ) runs on ItsRSUsSimulator { // Local variables var ReferencePosition v_newPosition := p_camVehicle.cam.camParameters.basicContainer.referencePosition; var template (value) GnRawPayload v_payload; // Apply 90° rotation if (PICS_USE_LPV == true) { fx_computePositionFromRotation( p_location.latitude, p_location.longitude, PICS_UC6_COLLISION_POINT_Z2.latitude, // Z1 PICS_UC6_COLLISION_POINT_Z2.longitude, // Z1 900, v_newPosition.latitude, v_newPosition.longitude ); log("Rotation: (", p_location.latitude, ", ", p_location.longitude, ") --> (", v_newPosition.latitude, ", ", v_newPosition.longitude, ")"); } else { fx_computePositionFromRotation( p_camVehicle.cam.camParameters.basicContainer.referencePosition.latitude, p_camVehicle.cam.camParameters.basicContainer.referencePosition.longitude, PICS_UC6_COLLISION_POINT_Z2.latitude, // Z1 PICS_UC6_COLLISION_POINT_Z2.longitude, // Z1 2450, v_newPosition.latitude, v_newPosition.longitude ); log("Rotation: (", p_camVehicle.cam.camParameters.basicContainer.referencePosition.latitude, ", ", p_camVehicle.cam.camParameters.basicContainer.referencePosition.longitude, ") --> (", v_newPosition.latitude, ", ", v_newPosition.longitude, ")"); } /*v_newPosition.latitude := ; v_newPosition.longitude := ;*/ // Update CAM p_camSimu.cam.generationDeltaTime := f_getCurrentTime() mod 65536; // See ETSI EN 302 637-2 V1.3.0 - Clause B.3 generationDelatTime p_camSimu.cam.camParameters.basicContainer.referencePosition := v_newPosition; p_camSimu.cam.camParameters.highFrequencyContainer := p_camVehicle.cam.camParameters.highFrequencyContainer; v_payload := valueof( f_adaptPayload( bit2oct( encvalue( valueof( p_camSimu ))), PICS_CAM_BTP_DESTINATION_PORT, PICS_CAM_BTP_SOURCE_PORT ) ); // Update GN vc_longPosVectorRsu := PICS_UC6_VEHICLE_TEMPLATE_POSITION; vc_longPosVectorRsu.latitude := valueof(p_camSimu.cam.camParameters.basicContainer.referencePosition.latitude); vc_longPosVectorRsu.longitude := valueof(p_camSimu.cam.camParameters.basicContainer.referencePosition.longitude); vc_geoArea := PICS_UC6_VEHICLE_TEMPLATE_GEOAREA; vc_geoArea.area.geoAreaPosLatitude := valueof(p_camSimu.cam.camParameters.basicContainer.referencePosition.latitude); vc_geoArea.area.geoAreaPosLongitude := valueof(p_camSimu.cam.camParameters.basicContainer.referencePosition.longitude); // And send it f_send(v_payload, PICS_CAM_ITS_AID); } // End of function f_mirror_and_send_vehicle_cam function f_send( in template (value) GnRawPayload p_payload, in UInt32 p_its_aid ) runs on ItsRSUsSimulator { var GeoNetworkingPdu v_geoNetworkingPdu; vc_longPosVectorRsu.timestamp_ := f_computeGnTimestamp(); if (p_its_aid == 36) { // CAM v_geoNetworkingPdu := valueof(m_geoNwPdu( // FIXME Use PIXIT parameter to get a fully configurable template m_geoNwShbPacket_payload( vc_longPosVectorRsu, valueof(p_payload) ), Lifetime:{ multiplier := c_defaultLifetime, ltBase := e_100s }, c_hopLimit1 )); } else if (p_its_aid == 37) { // DENM v_geoNetworkingPdu := valueof(m_geoNwPdu( // FIXME Use PIXIT parameter to get a fully configurable template m_geoNwTsbPacket_payload( f_incLocalSeqNumber(), vc_longPosVectorRsu, -, -, valueof(p_payload) ), Lifetime:{ multiplier := c_defaultLifetime, ltBase := e_100s }, c_hopLimit1 )); } else if ((p_its_aid == 137) or (p_its_aid == 138)) { // MAPEM/SPATEM v_geoNetworkingPdu := valueof(m_geoNwPdu( // FIXME Use PIXIT parameter to get a fully configurable template m_geoNwTsbPacket_payload( f_incLocalSeqNumber(), vc_longPosVectorRsu, -, -, valueof(p_payload) ), Lifetime:{ multiplier := c_defaultLifetime, ltBase := e_100s }, c_hopLimit1 )); } else { v_geoNetworkingPdu := valueof(m_geoNwPdu( // FIXME Use PIXIT parameter to get a fully configurable template m_geoNwBroadcastPacket_payload( // TODO modifes 'template (value) GnNonSecuredPacket m_geoNwBroadcastPacket' to set the field vc_longPosVectorRsu, f_incLocalSeqNumber(), f_geoArea2GeoBroadcastArea(vc_geoArea), -, -, valueof(p_payload) ), Lifetime:{ multiplier := c_defaultLifetime, ltBase := e_100s }, c_hopLimit1 )); v_geoNetworkingPdu.gnPacket.packet.commonHeader.nextHeader := e_any; } f_sendGeoNetMessage(valueof(m_geoNwReq_linkLayerBroadcast(v_geoNetworkingPdu, p_its_aid))); } // End of function f_send function f_processCam( in GeoNetworkingPdu p_geoNetworkingPdu ) runs on ItsRSUsSimulator { var bitstring v_enc_msg; log("CAM=", p_geoNetworkingPdu); if (PICS_SEND_CAM_INDICATION) { var UtCamEventInd v_utCamEventInd; var integer v_result; // Extract CAM message var octetstring v_payload := p_geoNetworkingPdu.gnPacket.packet.payload; // Remove BTP layer v_payload := substr(v_payload, 4, lengthof(v_payload) - 4); // Send UtEventCamIndication v_enc_msg := oct2bit(v_payload); if (decvalue(v_enc_msg, v_utCamEventInd.camMsg) == 0) { cfPort.send(v_utCamEventInd); } } } function f_processSrem( in GeoNetworkingPdu p_geoNetworkingPdu ) runs on ItsRSUsSimulator { log("SREM=", p_geoNetworkingPdu); if (ispresent(p_geoNetworkingPdu.gnPacket.packet.payload)) { /* TODO Decode and process GnPayload or use different ports if (ispresent(p_geoNetworkingPdu.gnPacket.packet.payload.decodedPayload.btpPacket.payload.decodedPayload)) { if (ischosen(p_geoNetworkingPdu.gnPacket.packet.payload.decodedPayload.btpPacket.payload.decodedPayload.sremPacket)) { var SignalRequestMessage v_signalRequestMessage := p_geoNetworkingPdu.gnPacket.packet.payload.decodedPayload.btpPacket.payload.decodedPayload.sremPacket.srm; var template (value) GnRawPayload v_payload; log(v_signalRequestMessage); // Build response // TODO v_ssem.ssm.status v_payload := valueof( f_adaptPayload( bit2oct( encvalue( valueof( m_ssem( v_signalRequestMessage )))), PICS_SSEM_BTP_DESTINATION_PORT, PICS_SSEM_BTP_SOURCE_PORT ) ); // Send SSEM f_send(v_payload, PICS_SSEM_ITS_AID); } // else, ignore message } // else, ignore message */ } // else, ignore message } // End of function f_processSrem function f_incLocalSeqNumber() runs on ItsRSUsSimulator return UInt16 { vc_localSeqNumber := (vc_localSeqNumber + 1) mod 65536; return vc_localSeqNumber; } function f_incMsgIssueRevision() runs on ItsRSUsSimulator return MsgCount { vc_msgIssueRevision := (vc_msgIssueRevision + 1) mod 128; // See MsgCount declaration return vc_msgIssueRevision; } function f_getMsgIssueRevision() runs on ItsRSUsSimulator return MsgCount { return vc_msgIssueRevision; } function f_incDenmSequenceNumber() runs on ItsRSUsSimulator return SequenceNumber { vc_sequenceNumber := (vc_sequenceNumber + 1) mod 65536; // See SequenceNumber declaration return vc_sequenceNumber; } function f_getDenmSequenceNumber() runs on ItsRSUsSimulator return SequenceNumber { return vc_sequenceNumber; } function f_payload_template( in integer p_dest_port, in integer p_src_port ) return template (present) octetstring { log(">>> f_payload_template: ", p_dest_port, " - ", p_src_port); var template (present) Oct2 v_t1 := int2oct(PICS_SREM_BTP_DESTINATION_PORT, 2); var template (present) Oct2 v_t2 := int2oct(PICS_SREM_BTP_SOURCE_PORT, 2); var template (present) octetstring v_t3 := ? length (5 .. 65535); var template (present) octetstring v_out := valueof(v_t1) & valueof(v_t2) & valueof(v_t3); return v_out } altstep a_process_cf_ut_command() runs on ItsRSUsSimulator { var UtGnInitialize v_utGnInitialize; var UtPkiInitialize v_utPkiInitialize; var UtGnTrigger v_utGnTrigger; var UtCamTrigger v_utCamTrigger; var UtPkiTrigger v_utPkiTrigger; [] cfPort.receive(UtGnInitialize:?) -> value v_utGnInitialize { log("v_utGnInitialize = ", v_utGnInitialize); cfPort.send(UtGnResults: { utGnInitializeResult := true } ); repeat; } [] cfPort.receive(UtGnTrigger:?) -> value v_utGnTrigger { cfPort.send(UtGnResults: { utGnTriggerResult := true } ); log("v_utGnTrigger = ", v_utGnTrigger); if (ischosen(v_utGnTrigger.geoUnicast)) { var GnNonSecuredPacket v_geoNwUnicastPacket := valueof( m_geoNwUnicastPacket_with_payload( vc_longPosVectorRsu, f_getIutShortPosVector(), f_incLocalSeqNumber(), c_defaultHopLimit, v_utGnTrigger.geoUnicast.trafficClass, v_utGnTrigger.geoUnicast.payload )); var GeoNetworkingPdu v_geoNwPdu := valueof( m_geoNwPdu( v_geoNwUnicastPacket, m_lifetimeBase1s(v_utGnTrigger.geoUnicast.lifetime), c_defaultHopLimit ) ); v_geoNwPdu.gnPacket.packet.commonHeader.nextHeader := e_any; v_geoNwPdu.gnPacket.packet.extendedHeader.geoUnicastHeader.dstPosVector.gnAddr := v_utGnTrigger.geoUnicast.gnAddress; geoNetworkingPort.send(m_geoNwReq_linkLayerBroadcast(v_geoNwPdu)); } else if (ischosen(v_utGnTrigger.geoBroadcast)) { var GeoBroadcastArea v_broadcastArea; var GnNonSecuredPacket v_geoNwBroadcastPacket; var GeoNetworkingPdu v_geoNwPdu; if (v_utGnTrigger.geoBroadcast.shape == e_geoCircle) { v_broadcastArea.geoBroadcastSubType := e_geoBroadcastCircle; } else if (v_utGnTrigger.geoBroadcast.shape == e_geoRect) { v_broadcastArea.geoBroadcastSubType := e_geoBroadcastRect; } else if (v_utGnTrigger.geoBroadcast.shape == e_geoElip) { v_broadcastArea.geoBroadcastSubType := e_geoBroadcastElip; } else { v_broadcastArea.geoBroadcastSubType := e_reserved; } v_broadcastArea.geoBroadcastArea := v_utGnTrigger.geoBroadcast.area; v_geoNwBroadcastPacket := valueof( m_geoNwBroadcastPacket_payload( vc_longPosVectorRsu, f_incLocalSeqNumber(), v_broadcastArea, c_defaultHopLimit, v_utGnTrigger.geoBroadcast.trafficClass, v_utGnTrigger.geoBroadcast.payload )); v_geoNwPdu := valueof( m_geoNwPdu( v_geoNwBroadcastPacket, m_lifetimeBase1s(v_utGnTrigger.geoBroadcast.lifetime), c_defaultHopLimit )); } repeat; } [vc_cam == true] cfPort.receive(UtCamInitialize:?) { cfPort.send(UtCamResults: { utCamInitializeResult := true } ); repeat; } [vc_cam == true] cfPort.receive(UtCamTrigger: { changeSpeed := ? }) { cfPort.send(UtCamResults: { utCamTriggerResult := true } ); vc_cam_timer_value := vc_cam_timer_value / 2.0; repeat; } [vc_cam == true] cfPort.receive(UtCamTrigger: { changeCurvature := ? }) -> value v_utCamTrigger { log("v_utCamTrigger = ", v_utCamTrigger); if (ispresent(vc_rsuMessagesValueList[vc_rsu_id].cam.cam.camParameters.highFrequencyContainer.basicVehicleContainerHighFrequency)) { cfPort.send(UtCamResults: { utCamTriggerResult := true } ); vc_rsuMessagesValueList[vc_rsu_id].cam.cam.camParameters.highFrequencyContainer.basicVehicleContainerHighFrequency.curvature.curvatureValue := v_utCamTrigger.changeCurvature; } else { cfPort.send(UtCamResults: { utCamTriggerResult := false } ); } repeat; } [vc_cam == true] cfPort.receive(UtCamTrigger: { changeHeading := ? }) -> value v_utCamTrigger { log("v_utCamTrigger = ", v_utCamTrigger); if (ispresent(vc_rsuMessagesValueList[vc_rsu_id].cam.cam.camParameters.highFrequencyContainer.basicVehicleContainerHighFrequency)) { cfPort.send(UtCamResults: { utCamTriggerResult := true } ); vc_rsuMessagesValueList[vc_rsu_id].cam.cam.camParameters.highFrequencyContainer.basicVehicleContainerHighFrequency.heading.headingValue := valueof(vc_rsuMessagesValueList[vc_rsu_id].cam.cam.camParameters.highFrequencyContainer.basicVehicleContainerHighFrequency.heading.headingValue) + v_utCamTrigger.changeHeading; } else { cfPort.send(UtCamResults: { utCamTriggerResult := false } ); } repeat; } /*[vc_cam == true] cfPort.receive(UtCamTrigger: { changePosition := ? }) { cfPort.send(UtCamResults: { utCamTriggerResult := true } ); //TODO vc_cam_timer_value := vc_cam_timer_value / 4.0; repeat; }*/ [vc_denm == true] cfPort.receive(UtDenmInitialize:?) { cfPort.send(UtDenmResults: { utDenmInitializeResult := true } ); repeat; } [vc_pki == true] cfPort.receive(UtPkiInitialize:?) -> value v_utPkiInitialize { log("v_utPkiInitialize = ", v_utPkiInitialize); cfPort.send(UtPkiResults: { utPkiInitializeResult := true } ); repeat; } [vc_pki == true] cfPort.receive(UtPkiTrigger:?) -> value v_utPkiTrigger { var ItsPkiHttp v_pki; cfPort.send(UtPkiResults: { utPkiTriggerResult := true } ); v_pki := ItsPkiHttp.create("TriggeredEc") alive; v_pki.start(f_trigger_enrolment_request_await_response( vc_reenrolment, vc_ec_certificates_counter, vc_ec_certificates )); //v_pki.done; repeat; } [] cfPort.receive { // Ignore it log("*** " & testcasename() & ": INFO: Unexpected CF message received ***"); repeat; } } // End of 'altstep' statement function f_trigger_enrolment_request_await_response( inout boolean p_reenrolment, inout integer p_ec_certificates_counter, inout SequenceOfCertificate p_ec_certificates ) runs on ItsPkiHttp { // Local variables var Oct32 v_private_key; var Oct32 v_compressed_public_key; var integer v_compressed_mode; var Oct32 v_request_hash; var Oct16 v_encrypted_sym_key; var Oct16 v_aes_sym_key; var Oct16 v_authentication_vector; var Oct12 v_nonce; var octetstring v_salt; var Ieee1609Dot2Data v_ieee1609dot2_signed_and_encrypted_data; var HeaderLines v_headers; var HttpMessage v_response; var EtsiTs102941Data v_etsi_ts_102941_data; timer v_t := 5.0; log(">>> f_trigger_enrolment_request_await_response"); f_cfHttpUp(PICS_TS_EA_CERTIFICATE_ID); f_http_build_inner_ec_request(v_private_key, v_compressed_public_key, v_compressed_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce, v_salt, v_ieee1609dot2_signed_and_encrypted_data, v_request_hash); f_init_default_headers_list(-, "inner_ec_request", v_headers); httpPort.send( m_http_request( m_http_request_post( PICS_HTTP_POST_URI, v_headers, m_http_message_body_binary( m_binary_body_ieee1609dot2_data( v_ieee1609dot2_signed_and_encrypted_data ))))); // Wait for the resposne v_t.start; alt { [] httpPort.receive( mw_http_response( mw_http_response_ok( mw_http_message_body_binary( mw_binary_body_ieee1609dot2_data( mw_enrolmentResponseMessage( mw_encryptedData( -, mw_SymmetricCiphertext_aes128ccm ))))))) -> value v_response { v_t.stop; log("f_trigger_enrolment_request_await_response: receive ", v_response); if (f_verify_pki_message(v_private_key, v_aes_sym_key, v_authentication_vector, vc_eaWholeHash, vc_eaCertificate, v_response.response.body.binary_body.ieee1609dot2_data, false, v_etsi_ts_102941_data) == false) { log("f_trigger_enrolment_request_await_response: Failed to verify PKI message ***"); } else { log("f_trigger_enrolment_request_await_response: Receive ", v_etsi_ts_102941_data, " ***"); // Verify the received EC certificate log("f_trigger_enrolment_request_await_response: match ", match(v_etsi_ts_102941_data.content, mw_enrolmentResponse(mw_innerEcResponse_ok(substr(v_request_hash, 0, 16), mw_etsiTs103097Certificate(-, mw_toBeSignedCertificate_ec, -)))), " ***"); // TODO In TITAN, this is the only way to get the unmatching in log if (match(v_etsi_ts_102941_data.content, mw_enrolmentResponse(mw_innerEcResponse_ok(substr(v_request_hash, 0, 16), mw_etsiTs103097Certificate(-, mw_toBeSignedCertificate_ec, -))))) { var InnerEcResponse v_inner_ec_response := v_etsi_ts_102941_data.content.enrolmentResponse; if (f_verify_ec_certificate(v_etsi_ts_102941_data.content.enrolmentResponse.certificate, vc_eaCertificate, v_compressed_public_key, v_compressed_mode)) { log("f_trigger_enrolment_request_await_response: Well-secured EA certificate received ***"); log("p_inner_ec_response= ", v_inner_ec_response); p_reenrolment := true; // Store the new certificate p_ec_certificates[p_ec_certificates_counter] := v_inner_ec_response.certificate; p_ec_certificates_counter := p_ec_certificates_counter + 1; } else { log("f_trigger_enrolment_request_await_response: Cannot verify EC certificate signature ***"); } } else { log("f_trigger_enrolment_request_await_response: Unexpected message received ***"); } } } [] v_t.timeout { log("*** " & testcasename() & ": INCONC: Expected message not received ***"); } } // End of 'alt' statement f_cfHttpDown(); log("<<< f_trigger_enrolment_request_await_response"); } } // End of module ItsRSUsSimulator_Functions