#include "evm.h" #include "facilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static UTF8String_t *create_utf8_from_string(const char *string, size_t length) { UTF8String_t *utf8_string = calloc(1, sizeof(UTF8String_t)); utf8_string->buf = calloc(length, sizeof(uint8_t)); utf8_string->size = length; memcpy(utf8_string->buf, string, length); return utf8_string; } static UTF8String_t *create_empty_utf8_string() { UTF8String_t *utf8_string = calloc(1, sizeof(UTF8String_t)); utf8_string->size = 0; return utf8_string; } static int mk_evcsnm(uint8_t *evcsnm_oer, uint32_t *evcsnm_len) { int rv = 0; int shm_fd, shm_valid = 0; EI1_EvcsnPdu_t *evcsnm = calloc(1, sizeof(EI1_EvcsnPdu_t)); evcsnm->header.protocolVersion = 2; evcsnm->header.messageID = 1; pthread_mutex_lock(&facilities.id.lock); evcsnm->header.stationID = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); uint64_t now = itss_time_get(); asn_ulong2INTEGER(&evcsnm->evcsn.poiHeader.timeStamp, now); evcsnm->evcsn.poiHeader.poiType = 1; // set to "EV charging station POI ID = 1" evcsnm->evcsn.poiHeader.relayCapable = 1; evcsnm->evcsn.evcsnData.totalNumberOfStations = 1; evcsnm->evcsn.evcsnData.chargingStationsData.list.array = calloc(1, sizeof(void *)); evcsnm->evcsn.evcsnData.chargingStationsData.list.count = 1; evcsnm->evcsn.evcsnData.chargingStationsData.list.size = sizeof(void *) * 1; evcsnm->evcsn.evcsnData.chargingStationsData.list.array[0] = calloc(1, sizeof(struct EI1_ItsChargingStationData)); struct EI1_ItsChargingStationData *cs0 = evcsnm->evcsn.evcsnData.chargingStationsData.list.array[0]; cs0->chargingStationID = 0; itss_space_lock(); itss_space_get(); cs0->chargingStationLocation.latitude = 405970830; cs0->chargingStationLocation.longitude = -86628610; cs0->chargingStationLocation.altitude.altitudeValue = epv.space.altitude; cs0->chargingStationLocation.altitude.altitudeConfidence = epv.space.altitude_conf; cs0->chargingStationLocation.positionConfidenceEllipse.semiMajorConfidence = EI1_SemiAxisLength_unavailable; cs0->chargingStationLocation.positionConfidenceEllipse.semiMinorConfidence = EI1_SemiAxisLength_unavailable; cs0->chargingStationLocation.positionConfidenceEllipse.semiMajorOrientation = EI1_HeadingValue_unavailable; cs0->accessibility = *create_utf8_from_string("Free Access", strlen("Free Access")); cs0->pricing = *create_utf8_from_string(".15 €/kWh", strlen(".15 €/kWh")); cs0->openingDaysHours = *create_utf8_from_string("Always", strlen("Always")); const char *booking_url = "ccam.av.it.pt"; cs0->bookingContactInfo = create_utf8_from_string(booking_url, strlen(booking_url)); cs0->chargingSpotsAvailable.list.array = calloc(1, sizeof(void *)); cs0->chargingSpotsAvailable.list.count = 1; cs0->chargingSpotsAvailable.list.size = sizeof(void *) * 1; cs0->chargingSpotsAvailable.list.array[0] = calloc(1, sizeof(struct EI1_ItsChargingSpotDataElements)); struct EI1_ItsChargingSpotDataElements *cs_elem0 = cs0->chargingSpotsAvailable.list.array[0]; cs_elem0->energyAvailability = *create_utf8_from_string("Max: 30kW", strlen("Max: 30kW")); cs_elem0->type.buf = calloc(1, sizeof(uint8_t)); cs_elem0->type.size = 1; cs_elem0->type.bits_unused = 0; cs_elem0->type.buf[0] = 0x03; cs_elem0->typeOfReceptacle.buf = calloc(1, sizeof(uint8_t)); cs_elem0->typeOfReceptacle.size = 1; cs_elem0->typeOfReceptacle.bits_unused = 0; cs_elem0->typeOfReceptacle.buf[0] = 0x0D; cs_elem0->parkingPlacesData = calloc(1, sizeof(struct EI1_ParkingPlacesData)); cs_elem0->parkingPlacesData->list.array = calloc(2, sizeof(void *)); cs_elem0->parkingPlacesData->list.count = 2; cs_elem0->parkingPlacesData->list.size = sizeof(void *) * 2; // As requested onnly 2 parking places are available for (int parckingPlaceIndex = 0; parckingPlaceIndex < 2; parckingPlaceIndex++) { cs_elem0->parkingPlacesData->list.array[parckingPlaceIndex] = calloc(1, sizeof(struct EI1_SpotAvailability)); struct EI1_SpotAvailability *spot = cs_elem0->parkingPlacesData->list.array[parckingPlaceIndex]; spot->maxWaitingTimeMinutes = 0; spot->blocking = 1; } itss_space_unlock(epv); // if (facilities.station_type == StationType_roadSideUnit) //{ // } asn_enc_rval_t enc = uper_encode_to_buffer(&asn_DEF_EI1_EvcsnPdu, NULL, evcsnm, evcsnm_oer, 512); if (enc.encoded == -1) { log_error("[ev] failed encoding evcsnm (%s)", enc.failed_type->name); rv = 1; goto cleanup; } *evcsnm_len = (enc.encoded + 7) / 8; cleanup: ASN_STRUCT_FREE(asn_DEF_EI1_EvcsnPdu, evcsnm); return rv; } static uint64_t pre_reservation_id = 1; static uint64_t reservation_id = 1; int evrsrm_recv(EI1_EV_RSR_t *evrsr_request) { int rv = 0; EIS_NetworkingRequest_t* nr = calloc(1, sizeof(EIS_NetworkingRequest_t)); nr->present = EIS_NetworkingRequest_PR_packet; EIS_NetworkingPacketRequest_t* npr = &nr->choice.packet; npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn; npr->network.choice.gn.trafficClass = 2; npr->network.choice.gn.destinationAddress.buf = malloc(6); for (int i = 0; i < 6; ++i) { npr->network.choice.gn.destinationAddress.buf[i] = 0xff; } npr->network.choice.gn.destinationAddress.size = 6; npr->network.choice.gn.packetTransportType = EIS_PacketTransportType_shb; npr->network.choice.gn.securityProfile.sign = true; npr->transport.present = EIS_NetworkingPacketRequestTP_PR_btp; npr->transport.choice.btp.btpType = EIS_BTPType_btpB; npr->transport.choice.btp.destinationPort = EIS_Port_evrsr; npr->data.buf = malloc(512); // Fill header for FacilitiesIndication and FacilitiesMessageIndication structs EIS_FacilitiesIndication_t *fi = calloc(1, sizeof(EIS_FacilitiesIndication_t)); fi->present = EIS_FacilitiesIndication_PR_message; EIS_FacilitiesMessageIndication_t *fmi = &fi->choice.message; fmi->itsMessageType = EIS_ItsMessageType_evrsr; fmi->data.buf = malloc(512); uint8_t tr_oer[1024]; uint8_t fi_oer[1024]; tr_oer[0] = 4; // Facilities fi_oer[0] = 4; if (!(evrsr_request->messageBody.present == EI1_EV_RSR_MessageBody_PR_preReservationRequestMessage || evrsr_request->messageBody.present == EI1_EV_RSR_MessageBody_PR_reservationRequestMessage || evrsr_request->messageBody.present == EI1_EV_RSR_MessageBody_PR_cancellationRequestMessage || evrsr_request->messageBody.present == EI1_EV_RSR_MessageBody_PR_updateRequestMessage)) { rv = 1; goto cleanup; } int evrsr_response; if (evrsr_request->messageBody.present == EI1_EV_RSR_MessageBody_PR_preReservationRequestMessage) evrsr_response = evrsrm_pre_reservation_response(npr->data.buf, (uint32_t *)&npr->data.size); else if (evrsr_request->messageBody.present == EI1_EV_RSR_MessageBody_PR_reservationRequestMessage) evrsr_response = evrsrm_reservation_response(evrsr_request, npr->data.buf, (uint32_t *)&npr->data.size); else if (evrsr_request->messageBody.present == EI1_EV_RSR_MessageBody_PR_cancellationRequestMessage) evrsr_response = evrsrm_cancellation_response(evrsr_request, npr->data.buf, (uint32_t *)&npr->data.size); else if (evrsr_request->messageBody.present == EI1_EV_RSR_MessageBody_PR_updateRequestMessage) evrsr_response = evrsrm_update_response(evrsr_request, npr->data.buf, (uint32_t *)&npr->data.size); if (evrsr_response != 0) { rv = 1; goto cleanup; } memcpy(fmi->data.buf, npr->data.buf, npr->data.size); fmi->data.size = npr->data.size; uint32_t id = itss_id(npr->data.buf, npr->data.size); npr->id = id; fmi->id = id; asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, nr, tr_oer + 1, 1023); if (enc.encoded == -1) { log_error("[ev] failed encoding transport request (%s)", enc.failed_type->name); rv = 1; goto cleanup; } asn_enc_rval_t enc_fdi = oer_encode_to_buffer(&asn_DEF_EIS_FacilitiesIndication, NULL, fi, fi_oer + 1, 1023); if (enc_fdi.encoded == -1) { log_error("[ev] encoding FI for evrsrm failed"); rv = 1; goto cleanup; } itss_queue_send(facilities.tx_queue, tr_oer, enc.encoded + 1, ITSS_NETWORKING, id, "NR.packet.btp"); itss_queue_send(facilities.tx_queue, fi_oer, enc_fdi.encoded + 1, ITSS_APPLICATIONS, id, "FI.message"); cleanup: log_debug("[ev] evrsrm_recv done with rv %d", rv); return rv; } static int evrsrm_cancellation_response(EI1_EV_RSR_t *evrsrm_request, uint8_t *evrsrm_oer, uint32_t *evrsrm_len){ int rv = 0; EI1_EV_RSR_t *evrsr_response = calloc(1, sizeof(EI1_EV_RSR_t)); evrsr_response->header.protocolVersion = 1; evrsr_response->header.messageID = 7; pthread_mutex_lock(&facilities.id.lock); evrsr_response->header.stationID = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); evrsr_response->messageBody.present = EI1_EV_RSR_MessageBody_PR_cancellationResponseMessage; EI1_CancellationResponseMessage_t *evrsr_cancellation_response = &evrsr_response->messageBody.choice.cancellationResponseMessage; evrsr_cancellation_response->reservation_ID.buf = calloc(8, sizeof(uint8_t)); evrsr_cancellation_response->reservation_ID.size = 8; memccpy(evrsr_cancellation_response->reservation_ID.buf, evrsrm_request->messageBody.choice.cancellationRequestMessage.reservation_ID.buf, 0, 8); evrsr_cancellation_response->cancellationResponseCode = EI1_CancellationResponseCode_ok; asn_enc_rval_t enc = uper_encode_to_buffer(&asn_DEF_EI1_EV_RSR, NULL, evrsr_response, evrsrm_oer, 512); if (enc.encoded == -1) { log_error("[ev] failed encoding evrsrm cancellation response (%s)", enc.failed_type->name); rv = 1; goto cleanup; } *evrsrm_len = (enc.encoded + 7) / 8; cleanup: ASN_STRUCT_FREE(asn_DEF_EI1_EV_RSR, evrsr_response); return rv; } static int evrsrm_update_response(EI1_EV_RSR_t *evrsrm_request, uint8_t *evrsrm_oer, uint32_t *evrsrm_len){ int rv = 0; EI1_EV_RSR_t *evrsr_response = calloc(1, sizeof(EI1_EV_RSR_t)); evrsr_response->header.protocolVersion = 1; evrsr_response->header.messageID = 7; pthread_mutex_lock(&facilities.id.lock); evrsr_response->header.stationID = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); evrsr_response->messageBody.present = EI1_EV_RSR_MessageBody_PR_updateResponseMessage; EI1_UpdateResponseMessage_t *evrsr_update_response = &evrsr_response->messageBody.choice.updateResponseMessage; evrsr_update_response->reservation_ID.buf = calloc(8, sizeof(uint8_t)); evrsr_update_response->reservation_ID.size = 8; memccpy(evrsr_update_response->reservation_ID.buf, evrsrm_request->messageBody.choice.updateRequestMessage.reservation_ID.buf, 0, 8); evrsr_update_response->updateResponseCode = EI1_UpdateResponseCode_ok; asn_enc_rval_t enc = uper_encode_to_buffer(&asn_DEF_EI1_EV_RSR, NULL, evrsr_response, evrsrm_oer, 512); if (enc.encoded == -1) { log_error("[ev] failed encoding evrsrm update response (%s)", enc.failed_type->name); rv = 1; goto cleanup; } *evrsrm_len = (enc.encoded + 7) / 8; cleanup: ASN_STRUCT_FREE(asn_DEF_EI1_EV_RSR, evrsr_response); return rv; } static int evrsrm_reservation_response(EI1_EV_RSR_t *evrsrm_request, uint8_t *evrsrm_oer, uint32_t *evrsrm_len) { int rv = 0; EI1_EV_RSR_t *evrsr_response = calloc(1, sizeof(EI1_EV_RSR_t)); evrsr_response->header.protocolVersion = 1; evrsr_response->header.messageID = 7; pthread_mutex_lock(&facilities.id.lock); evrsr_response->header.stationID = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); evrsr_response->messageBody.present = EI1_EV_RSR_MessageBody_PR_reservationResponseMessage; EI1_ReservationResponseMessage_t *response = &evrsr_response->messageBody.choice.reservationResponseMessage; // Assumes the pre reservation was successful response->reservationResponseCode = EI1_ReservationResponseCode_ok; response->reservation_ID = calloc(1, sizeof(EI1_Reservation_ID_t)); response->reservation_ID->buf = calloc(8, sizeof(uint8_t)); response->reservation_ID->size = 8; response->reservation_ID->buf[0] = '0' + reservation_id / 10000000; response->reservation_ID->buf[1] = '0' + (reservation_id / 1000000) % 10; response->reservation_ID->buf[2] = '0' + (reservation_id / 100000) % 10; response->reservation_ID->buf[3] = '0' + (reservation_id / 10000) % 10; response->reservation_ID->buf[4] = '0' + (reservation_id / 1000) % 10; response->reservation_ID->buf[5] = '0' + (reservation_id / 100) % 10; response->reservation_ID->buf[6] = '0' + (reservation_id / 10) % 10; response->reservation_ID->buf[7] = '0' + reservation_id % 10; response->reservation_Password = calloc(1, sizeof(EI1_Reservation_Password_t)); response->reservation_Password->buf = calloc(8, sizeof(uint8_t)); response->reservation_Password->size = 8; response->reservation_Password->buf[0] = 'i'; response->reservation_Password->buf[1] = 't'; response->reservation_Password->buf[2] = '2'; response->reservation_Password->buf[3] = 's'; response->reservation_Password->buf[4] = 'i'; response->reservation_Password->buf[5] = 't'; response->reservation_Password->buf[6] = '2'; response->reservation_Password->buf[7] = 's'; // estimated arrival time + tolerance time response->expirationTime = evrsrm_request->messageBody.choice.reservationRequestMessage.arrivalTime; response->expirationTime += 15 * 60 * 1000; // 15 minutes asn_enc_rval_t enc = uper_encode_to_buffer(&asn_DEF_EI1_EV_RSR, NULL, evrsr_response, evrsrm_oer, 512); if (enc.encoded == -1) { log_error("[ev] failed encoding evrsrm reservation response (%s)", enc.failed_type->name); rv = 1; goto cleanup; } *evrsrm_len = (enc.encoded + 7) / 8; reservation_id++; cleanup: ASN_STRUCT_FREE(asn_DEF_EI1_EV_RSR, evrsr_response); return rv; } static int evrsrm_pre_reservation_response(uint8_t *evrsrm_oer, uint32_t *evrsrm_len) { int rv = 0; EI1_EV_RSR_t *evrsr_response = calloc(1, sizeof(EI1_EV_RSR_t)); evrsr_response->header.protocolVersion = 1; evrsr_response->header.messageID = 7; pthread_mutex_lock(&facilities.id.lock); evrsr_response->header.stationID = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); evrsr_response->messageBody.present = EI1_EV_RSR_MessageBody_PR_preReservationResponseMessage; EI1_PreReservationResponseMessage_t *response = &evrsr_response->messageBody.choice.preReservationResponseMessage; response->preReservation_ID.buf = calloc(8, sizeof(uint8_t)); response->preReservation_ID.size = 8; response->preReservation_ID.buf[0] = '0' + (pre_reservation_id / 10000000); response->preReservation_ID.buf[1] = '0' + (pre_reservation_id / 1000000) % 10; response->preReservation_ID.buf[2] = '0' + (pre_reservation_id / 100000) % 10; response->preReservation_ID.buf[3] = '0' + (pre_reservation_id / 10000) % 10; response->preReservation_ID.buf[4] = '0' + (pre_reservation_id / 1000) % 10; response->preReservation_ID.buf[5] = '0' + (pre_reservation_id / 100) % 10; response->preReservation_ID.buf[6] = '0' + (pre_reservation_id / 10) % 10; response->preReservation_ID.buf[7] = '0' + pre_reservation_id % 10; response->availabilityStatus = 0; response->supportedPaymentTypes.buf = calloc(1, sizeof(uint8_t)); response->supportedPaymentTypes.bits_unused = 0; response->supportedPaymentTypes.size = 1; response->supportedPaymentTypes.buf[0] = 0x00; response->preReservationExpirationTime = 0; asn_enc_rval_t enc = uper_encode_to_buffer(&asn_DEF_EI1_EV_RSR, NULL, evrsr_response, evrsrm_oer, 512); if (enc.encoded == -1) { log_error("[ev] failed encoding evrsrm pre reservation response (%s)", enc.failed_type->name); rv = 1; goto cleanup; } *evrsrm_len = (enc.encoded + 7) / 8; pre_reservation_id++; cleanup: ASN_STRUCT_FREE(asn_DEF_EI1_EV_RSR, evrsr_response); return rv; } int evcsnm_check(EI1_EvcsnPdu_t *evcsnm) { return 0; } int evrsrm_check(EI1_EV_RSR_t *evrsrm) { return 0; } enum EVM_CHECK_R check_evcsnm(EIS_BTPPacketIndication_t *bpi, EI1_EvcsnPdu_t *evcsnm, uint8_t *ssp, uint32_t ssp_len) { return 0; } enum EVM_CHECK_R check_evrsrm(EIS_BTPPacketIndication_t *bpi, EI1_EV_RSR_t *evrsrm, uint8_t *ssp, uint32_t ssp_len) { return 0; } void *evcsn_service() { int rv = 0; EIS_NetworkingRequest_t* nr = calloc(1, sizeof(EIS_NetworkingRequest_t)); nr->present = EIS_NetworkingRequest_PR_packet; EIS_NetworkingPacketRequest_t* npr = &nr->choice.packet; npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn; npr->network.choice.gn.trafficClass = 2; npr->network.choice.gn.destinationAddress.buf = malloc(6); for (int i = 0; i < 6; ++i) { npr->network.choice.gn.destinationAddress.buf[i] = 0xff; } npr->network.choice.gn.destinationAddress.size = 6; npr->network.choice.gn.packetTransportType = EIS_PacketTransportType_shb; npr->network.choice.gn.securityProfile.sign = true; npr->transport.present = EIS_NetworkingPacketRequestTP_PR_btp; npr->transport.choice.btp.btpType = EIS_BTPType_btpB; npr->transport.choice.btp.destinationPort = EIS_Port_poi; npr->data.buf = malloc(512); // Fill header for FacilitiesIndication and FacilitiesMessageIndication structs EIS_FacilitiesIndication_t *fi = calloc(1, sizeof(EIS_FacilitiesIndication_t)); fi->present = EIS_FacilitiesIndication_PR_message; EIS_FacilitiesMessageIndication_t *fmi = &fi->choice.message; fmi->itsMessageType = EIS_ItsMessageType_poi; fmi->data.buf = malloc(512); uint8_t tr_oer[1024]; uint8_t fi_oer[1024]; tr_oer[0] = 4; // Facilities fi_oer[0] = 4; while (!facilities.exit) { usleep(1000 * 1000); if (facilities.evm_args.activate) { rv = mk_evcsnm(npr->data.buf, (uint32_t *)&npr->data.size); if (rv) { continue; } memcpy(fmi->data.buf, npr->data.buf, npr->data.size); fmi->data.size = npr->data.size; uint32_t id = itss_id(npr->data.buf, npr->data.size); npr->id = id; fmi->id = id; asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, nr, tr_oer + 1, 1023); if (enc.encoded == -1) { log_error("encoding TR for evcsnm failed"); continue; } asn_enc_rval_t enc_fdi = oer_encode_to_buffer(&asn_DEF_EIS_FacilitiesIndication, NULL, fi, fi_oer + 1, 1023); if (enc_fdi.encoded == -1) { log_error("encoding FI for evcsnm failed"); continue; } itss_queue_send(facilities.tx_queue, tr_oer, enc.encoded + 1, ITSS_NETWORKING, id, "NR.packet.btp"); itss_queue_send(facilities.tx_queue, fi_oer, enc_fdi.encoded + 1, ITSS_APPLICATIONS, id, "FI.message"); // Logging if (facilities.logging.dbms) { pthread_mutex_lock(&facilities.id.lock); uint32_t station_id = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); itss_db_add(facilities.logging.dbms, station_id, npr->id, true, EI1_messageID_evcsn, NULL, npr->data.buf, npr->data.size); } if (facilities.logging.recorder) { uint16_t buffer_len = 2048; uint8_t buffer[buffer_len]; int e = itss_management_record_packet_sdu( buffer, buffer_len, npr->data.buf, npr->data.size, id, itss_time_get(), ITSS_FACILITIES, true); if (e != -1) { itss_queue_send(facilities.tx_queue, buffer, e, ITSS_MANAGEMENT, id, "MReq.packet.set"); } } } } ASN_STRUCT_FREE(asn_DEF_EIS_NetworkingRequest, nr); return NULL; }