src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataUnitDecoderImpl.kt
@@ -1,12 +1,12 @@
package com.flightfeather.uav.socket.decoder.impl
import com.flightfeather.uav.socket.bean.*
import com.flightfeather.uav.socket.bean.AirData
import com.flightfeather.uav.socket.bean.AirDataPackage
import com.flightfeather.uav.socket.bean.AirTypeData
import com.flightfeather.uav.socket.decoder.DataUnitDecoder
import com.flightfeather.uav.socket.decoder.RealTimeDataDecoder
import com.flightfeather.uav.socket.eunm.ObdDataType
import com.flightfeather.uav.socket.eunm.FactorType
import org.slf4j.LoggerFactory
import java.lang.StringBuilder
import java.util.*
import java.text.SimpleDateFormat
/**
 * @author riku
@@ -15,113 +15,156 @@
class DataUnitDecoderImpl : DataUnitDecoder {
    private val logger = LoggerFactory.getLogger(javaClass.name)
    private var realTimeDataDecoder: RealTimeDataDecoder = RealTimeDataDecoderImpl()
    override fun getCarRegisterData(b: List<String>): List<CarRegisterData> {
        val time = decodeDataTime(b)
    private val types = mutableMapOf<String?, MutableList<AirTypeData>>()
        val serialNum = "${b[6]}${b[7]}".toInt(16)
        val simCode = StringBuilder()
        for (i in 10 until b.size) {
            simCode.append(b[i].toInt(16).toChar())
    override fun getAirConfirmData(b: List<String>, deviceCode: String?): List<AirTypeData> {
        val resultList = mutableListOf<AirTypeData>()
        b.forEach {
            FactorType.getByIndex(it.toInt(16))?.let { f->
                resultList.add(AirTypeData(f))
            }
        }
        if (!types.containsKey(deviceCode)) {
            types[deviceCode] = mutableListOf()
        }
        types[deviceCode]?.clear()
        types[deviceCode]?.addAll(resultList)
        return mutableListOf(CarRegisterData(time, serialNum, simCode.toString()))
        return resultList
    }
    override fun getRealTimeData(b: List<String>): List<RealTimeData> {
        val time = decodeDataTime(b)
    override fun getAirData(b: List<String>, deviceCode: String?): List<AirData> {
        val resultList = mutableListOf<AirData>()
        //国标法: 起始字节为7 开始的2个字节表示 流水号
//        val serialNum = "${b[7]}${b[8]}".toInt(16)
        //上海法: 起始字节为6 开始的2个字节表示 流水号
        val serialNum = "${b[6]}${b[7]}".toInt(16)
        val dataList = mutableListOf<String>().apply { addAll(b) }
        //删去前6位时间
        for (i in 0..5) {
            if (dataList.isNotEmpty()) dataList.removeAt(0)
        if (!types.containsKey(deviceCode)) {
            return resultList
        }
        //fixme 2019.9.15 目前两种规则有冲突,并且只从数据内容无法区分。暂时使用 国标法
        /*
        * 删去流水号,得到信息标志与信息体的组合
        * (国标法:去除前6位时间后,起始字节为1 开始的2个字节表示 流水号)
        */
//        if (dataList.size >= 2) dataList.removeAt(1)
//        if (dataList.size >= 2) dataList.removeAt(1)
        /*
        * 删去流水号,得到信息标志与信息体的组合
        * (上海法:去除前6位时间后,起始字节为0 开始的2个字节表示 流水号)
        */
        if (dataList.isNotEmpty()) dataList.removeAt(0)
        if (dataList.isNotEmpty()) dataList.removeAt(0)
        val resultList = mutableListOf<RealTimeData>()
        /*
         * 最终得到的数据结构为 [ 信息类型标志, 信息体, ...... , 信息类型标志, 信息体 ]
         */
        while (dataList.isNotEmpty()) {
            //得到最前面的一组信息类型+信息体列表
            val data = realTimeDataDecoder.getDataListByDataType(dataList)
            if (data.isNotEmpty()) {
                val r = when (data[0].toInt(16)) {
                    ObdDataType.ObdData.value -> realTimeDataDecoder.getObdData(time, serialNum, data)
                    ObdDataType.EngineDataFlow.value -> realTimeDataDecoder.getEngineDataStream(time, serialNum, data)
                    ObdDataType.SupplementDataFlow.value -> realTimeDataDecoder.getSupplementDataStream(time, serialNum, data)
                    else -> null
                }
                if (r != null) {
                    resultList.add(r)
                }
                for (i in 0 until data.size) {
                    if (dataList.isNotEmpty()) dataList.removeAt(0)
                }
            }else if (dataList.isNotEmpty()) {
                //按照规则没有取到信息体,并且原数据不为空,表示原数据格式错误,退出循环
                logger.error("-------数据信息流或补充数据流格式错误")
                break
        var i = 0
        types[deviceCode]?.forEach {
            if (i > b.size - it.factorType.byteLength) {
                return@forEach
            }
            when (it.factorType) {
                FactorType.LNG -> {
                    val valid = b[i].toInt(16).toChar()//经纬度是否有效(有效: A; 无效: V)
                    //经纬度原始值,例:121°30.0411′,其中 121 对应a1,30对应b1,04对应b2,11对应b3
                    val a1 = b[i + 1].toInt(16)//度
                    val b1 = b[i + 2].toInt(16)//分(整数)
                    var b2 = b[i + 3].toInt(16).toDouble()//分(小数部分前两位)
                    var b3 = b[i + 4].toInt(16).toDouble()//分(小数部分后两位)
//                    var b2 = "${b[i + 3]}${b[i + 4]}".toInt(16).toDouble()
                    b2 /= 100
                    b3 /= 10000
                    val lng = a1 + (b1 + b2 + b3) / 60
                    val s = b[i + 5].toInt(16).toChar()
                    resultList.add(AirData().apply {
                        factorId = it.factorType.value?.toString()
                        factorName = it.factorType.des
                        factorData = lng
                        statusList = listOf(valid.toString(), s.toString())
                    })
                }
                FactorType.LAT -> {
                    val a1 = b[i].toInt(16)
                    val b1 = b[i + 1].toInt(16)
                    var b2 = b[i + 2].toInt(16).toDouble()//分(小数部分前两位)
                    var b3 = b[i + 3].toInt(16).toDouble()//分(小数部分后两位)
                    b2 /= 100
                    b3 /= 10000
                    val lat = a1 + (b1 + b2 + b3) / 60
                    val s = b[i + 4].toInt(16).toChar()
                    resultList.add(AirData().apply {
                        factorId = it.factorType.value.toString()
                        factorName = it.factorType.des
                        factorData = lat
                        statusList = listOf(s.toString())
                    })
                }
                FactorType.TIME -> {
                    val year = b[i].toInt(16).toString().run { numberFormat(this) }
                    val month = b[i + 1].toInt(16).toString().run { numberFormat(this) }
                    val day = b[i + 2].toInt(16).toString().run { numberFormat(this) }
                    val hour = b[i + 3].toInt(16).toString().run { numberFormat(this) }
                    val minute = b[i + 4].toInt(16).toString().run { numberFormat(this) }
                    val second = b[i + 5].toInt(16).toString().run { numberFormat(this) }
                    val date = "20$year-$month-$day $hour:$minute:$second"
                    val time = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date).time
                    resultList.add(AirData().apply {
                        factorId = it.factorType.value.toString()
                        factorName = it.factorType.des
                        factorData = time.toDouble()
                        statusList = listOf(date)
                    })
                }
                else -> {
                    when (it.factorType.byteLength) {
                        AirDataPackage.FACTOR_BIT_LENGTH_2 -> {
                            val a1 = "${b[i]}${b[i + 1]}".toInt(16)
                            var b1 = b[i + 2].toInt(16).toDouble()
                            while (b1 >= 1) {
                                b1 /= 10
                            }
                            val data1 = a1 + b1
                            resultList.add(AirData().apply {
                                factorId = it.factorType.value?.toString()
                                factorName = it.factorType.des
                                factorData = data1
                            })
                        }
                        AirDataPackage.FACTOR_BIT_LENGTH_1 -> {
                            //数据实际值(3位字节表示)
                            val a1 = "${b[i]}${b[i + 1]}".toInt(16)
                            var b1 = b[i + 2].toInt(16).toDouble()
                            while (b1 >= 1) {
                                b1 /= 10
                            }
                            val data1 = a1 + b1
                            //数据物理量(3位字节表示)
                            val a2 = "${b[i+3]}${b[i + 4]}".toInt(16)
                            var b2 = b[i + 5].toInt(16).toDouble()
                            while (b2 >= 1) {
                                b2 /= 10
                            }
                            val data2 = a2 + b2
                            resultList.add(AirData().apply {
                                factorId = it.factorType.value?.toString()
                                factorName = it.factorType.des
                                factorData = data1
                                physicalQuantity = data2
                            })
                        }
                        AirDataPackage.FACTOR_BIT_LENGTH_3 -> {
                            val data = "${b[i]}${b[i + 1]}".toInt(16)
                            resultList.add(AirData().apply {
                                factorId = it.factorType.value.toString()
                                factorName = it.factorType.des
                                factorData = data.toDouble()
                            })
                        }
                    }
                }
            }
            i += it.factorType.byteLength
        }
        return resultList
    }
    override fun getReplacementData(b: List<String>): List<ReplacementData> = getRealTimeData(b)
    override fun getCarLogOutData(b: List<String>): List<CarLogOutData> {
        val time = decodeDataTime(b)
        val serialNum = "${b[6]}${b[7]}".toInt(16)
        return mutableListOf(CarLogOutData(time, serialNum))
    }
    override fun getTimeCalibrationData(b: List<String>): List<TimeCalibrationData> = emptyList()
    override fun decodeDataTime(b: List<String>): Date? {
        if (b.size < 6) {
            return null
        }
        val year = b[0].toInt(16) + 2000
        if (year < 2000 || year > 2099) return null
        val month = b[1].toInt(16)
        val day = b[2].toInt(16)
        val hour = b[3].toInt(16)
        val min = b[4].toInt(16)
        val sec = b[5].toInt(16)
        val cal  = Calendar.getInstance().apply {
            set(year, month - 1, day, hour, min, sec)
            set(Calendar.MILLISECOND, 0)
        }
        return cal.time
    }
    private fun numberFormat(num: String) =
            if (num.length < 2) {
                "0$num"
            } else {
                num
            }
}