All Downloads are FREE. Search and download functionalities are using the official Maven repository.

p-sim-ecu.doip-sim-ecu-dsl.0.9.11.source-code.SimGateway.kt Maven / Gradle / Ivy

Go to download

This is a kotlin based domain specific language (dsl), to quickly and intuitively write custom DoIP ECU simulations.

There is a newer version: 0.15.1
Show newest version
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.slf4j.MDCContext
import library.*
import org.slf4j.MDC
import kotlin.properties.Delegates
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

@Suppress("unused")
open class GatewayData(name: String) : RequestsData(name) {
    /**
     * Network address this gateway should bind on (default: 0.0.0.0)
     */
    var localAddress: String = "0.0.0.0"

    /**
     * Network port this gateway should bind on (default: 13400)
     */
    var localPort: Int = 13400

    /**
     * Multicast address
     */
    var multicastAddress: String? = null

    /**
     * Whether VAM broadcasts shall be sent on startup (default: true)
     */
    var broadcastEnable: Boolean = true

    /**
     * Default broadcast address for VAM messages (default: 255.255.255.255)
     */
    var broadcastAddress: String = "255.255.255.255"

    /**
     * The logical address under which the gateway shall be reachable
     */
    var logicalAddress by Delegates.notNull()

    /**
     * The functional address under which the gateway (and other ecus) shall be reachable
     */
    var functionalAddress by Delegates.notNull()

    /**
     * Vehicle identifier, 17 chars, will be filled with '0`, or if left null, set to 0xFF
     */
    var vin: String? = null // 17 byte VIN

    /**
     * Group ID of the gateway
     */
    var gid: ByteArray = byteArrayOf(0, 0, 0, 0, 0, 0) // 6 byte group identification (used before mac is set)

    /**
     * Entity ID of the gateway
     */
    var eid: ByteArray = byteArrayOf(0, 0, 0, 0, 0, 0) // 6 byte entity identification (usually MAC)

    /**
     * Interval between sending pending NRC messages (0x78)
     */
    var pendingNrcSendInterval: Duration = 2.seconds

    /**
     * Maximum payload data size allowed for a DoIP message
     */
    var maxDataSize: Int = Int.MAX_VALUE

    var tlsMode: TlsMode = TlsMode.DISABLED
    var tlsPort: Int = 3496
    var tlsOptions: TlsOptions = TlsOptions()

    private val _ecus: MutableList = mutableListOf()
    private val _additionalVams: MutableList = mutableListOf()

    val ecus: List
        get() = this._ecus.toList()

    /**
     * Defines an ecu and its properties as behind this gateway
     */
    fun ecu(name: String, receiver: EcuData.() -> Unit) {
        val ecuData = EcuData(name)
        receiver.invoke(ecuData)
        _ecus.add(ecuData)
    }

    fun doipEntity(name: String, vam: DoipUdpVehicleAnnouncementMessage, receiver: EcuData.() -> Unit) {
        val ecuData = EcuData(name)
        receiver.invoke(ecuData)
        _ecus.add(ecuData)
        _additionalVams.add(vam)
    }
}

private fun GatewayData.toGatewayConfig(): DoipEntityConfig {
    val config = DoipEntityConfig(
        name = this.name,
        gid = this.gid,
        eid = this.eid,
        localAddress = this.localAddress,
        localPort = this.localPort,
        logicalAddress = this.logicalAddress,
        broadcastEnabled = this.broadcastEnable,
        broadcastAddress = this.broadcastAddress,
        pendingNrcSendInterval = this.pendingNrcSendInterval,
        tlsMode = this.tlsMode,
        tlsPort = this.tlsPort,
        tlsOptions = this.tlsOptions,
        // Fill up too short vin's with 'Z' - if no vin is given, use 0xFF, as defined in ISO 13400 for when no vin is set (yet)
        vin = this.vin?.padEnd(17, 'Z')?.toByteArray() ?: ByteArray(17).let { it.fill(0xFF.toByte()); it },
        maxDataSize = this.maxDataSize,
    )

    // Add the gateway itself as an ecu, so it too can receive requests
    val gatewayEcuConfig = EcuConfig(
        name = this.name,
        physicalAddress = this.logicalAddress,
        functionalAddress = this.functionalAddress,
        pendingNrcSendInterval = this.pendingNrcSendInterval,
    )
    config.ecuConfigList.add(gatewayEcuConfig)

    // Add all the ecus defined for the gateway to the ecuConfigList, so they can later be found and instantiated as SimDslEcu
    config.ecuConfigList.addAll(this.ecus.map { it.toEcuConfig() })
    return config
}

class SimGateway(private val data: GatewayData) : DoipEntity(data.toGatewayConfig()) {
    val requests: List
        get() = data.requests

    override fun createEcu(config: EcuConfig): SimulatedEcu {
        // To be able to handle requests for the gateway itself, insert a dummy ecu with the gateways logicalAddress
        if (config.name == data.name) {
            val ecu = EcuData(
                name = data.name,
                physicalAddress = data.logicalAddress,
                functionalAddress = data.functionalAddress,
                requests = data.requests,
                nrcOnNoMatch =  data.nrcOnNoMatch,
                resetHandler = data.resetHandler,
                requestRegexMatchBytes = data.requestRegexMatchBytes,
                ackBytesLengthMap = data.ackBytesLengthMap,
                pendingNrcSendInterval = data.pendingNrcSendInterval,
            )
            return SimEcu(ecu)
        }

        // Match the other ecus by name, and create an SimDslEcu for them, since StandardEcu can't handle our
        // requirements for handling requests
        val ecuData = data.ecus.first { it.name == config.name }
        return SimEcu(ecuData)
    }

    override fun findEcuByName(name: String): SimEcu? {
        return super.findEcuByName(name) as SimEcu?
    }

    fun reset(recursiveEcus: Boolean = true) {
        runBlocking {
            MDC.put("ecu", name)

            launch(MDCContext()) {
                logger.infoIf { "Resetting gateway" }
                requests.forEach { it.reset() }
                if (recursiveEcus) {
                    ecus.forEach { (it as SimEcu).reset() }
                }
            }
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy