riku
2021-01-13 4db9806cc644bd58124aa9d8f1dbf9aee60d408f
1. 根据新协议做协议解析调整
已修改12个文件
已删除4个文件
已添加7个文件
502 ■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/common/config/CorsConfig.kt 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/FileUtil.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/GsonUtils.kt 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/bean/BaseJson.kt 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/bean/BaseResponse.kt 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/bean/DataVo.kt 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/bean/VehicleInfoVo.kt 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/RealTimeDataService.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/RealTimeDataServiceImpl.kt 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/web/RealTimeDataController.kt 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/repository/VehicleRepository.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/MessageManager.kt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/bean/AirDataPackage.kt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/bean/DataUnit.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataPackageDecoderImpl.kt 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataUnitDecoderImpl.kt 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/eunm/FactorType.kt 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/eunm/ObdDataType.kt 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/Test.kt 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/config/CorsConfig.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package com.flightfeather.uav.common.config
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
import org.springframework.web.filter.CorsFilter
@Configuration
class CorsConfig {
    private fun buildConfig(): CorsConfiguration {
        return CorsConfiguration().apply {
            addAllowedOrigin("*")
            addAllowedHeader("*")
            addAllowedMethod("*")
            allowCredentials = true
        }
    }
    @Bean
    fun corsFilter(): CorsFilter {
        val source = UrlBasedCorsConfigurationSource().apply {
            registerCorsConfiguration("/**", buildConfig())
        }
        return CorsFilter(source)
    }
}
src/main/kotlin/com/flightfeather/uav/common/utils/FileUtil.kt
@@ -13,7 +13,7 @@
class FileUtil {
    private var file: File
    private var basePath:String = "${File.separator}ObdData${File.separator}"
    private var basePath:String = "${File.separator}UAVData${File.separator}"
    private var closeThread: Thread? = null
    private var fw: FileWriter? = null
    private var bw: BufferedWriter? = null
src/main/kotlin/com/flightfeather/uav/common/utils/GsonUtils.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
package com.flightfeather.uav.common.utils
import com.google.gson.Gson
import com.google.gson.JsonParser
import java.util.ArrayList
/**
 * @author riku
 * Date: 2019/4/28
 * GSON序列化工具类
 */
object GsonUtils {
    fun getNoteJsonString(jsonString: String, note: String): String {
        if (jsonString.isEmpty()) {
            throw RuntimeException("getNoteJsonString jsonString empty")
        }
        if (note.isEmpty()) {
            throw RuntimeException("getNoteJsonString note empty")
        }
        val element = JsonParser().parse(jsonString)
        if (element.isJsonNull) {
            throw RuntimeException("getNoteJsonString element empty")
        }
        return element.asJsonObject.get(note).toString()
    }
    fun <T> parserJsonToArrayBeans(jsonString: String, note: String, beanClazz: Class<T>): List<T> {
        val noteJsonString = getNoteJsonString(jsonString, note)
        return parserJsonToArrayBeans(noteJsonString, beanClazz)
    }
    fun <T> parserJsonToArrayBeans(jsonString: String, beanClazz: Class<T>): List<T> {
        if (jsonString.isEmpty()) {
            throw RuntimeException("parserJsonToArrayBeans jsonString empty")
        }
        val jsonElement = JsonParser().parse(jsonString)
        if (jsonElement.isJsonNull) {
            throw RuntimeException("parserJsonToArrayBeans jsonElement empty")
        }
        if (!jsonElement.isJsonArray) {
            throw RuntimeException("parserJsonToArrayBeans jsonElement is not JsonArray")
        }
        val jsonArray = jsonElement.asJsonArray
        val beans = ArrayList<T>()
        for (jsonElement2 in jsonArray) {
            val bean = Gson().fromJson(jsonElement2, beanClazz)
            beans.add(bean)
        }
        return beans
    }
    fun <T> parserJsonToBean(jsonString: String, clazzBean: Class<T>): T {
        if (jsonString.isEmpty()) {
            throw RuntimeException("parserJsonToBean jsonString empty")
        }
        val jsonElement = JsonParser().parse(jsonString)
        if (jsonElement.isJsonNull) {
            throw RuntimeException("parserJsonToBean jsonElement empty")
        }
        if (!jsonElement.isJsonObject) {
            throw RuntimeException("parserJsonToBean is not object")
        }
        return Gson().fromJson(jsonElement, clazzBean)
    }
    fun <T> parserJsonToBean(jsonString: String, note: String, clazzBean: Class<T>): T {
        val noteJsonString = getNoteJsonString(jsonString, note)
        return parserJsonToBean(noteJsonString, clazzBean)
    }
    fun toJsonString(obj: Any?): String {
        return if (obj != null) {
            Gson().toJson(obj)
        } else {
            throw RuntimeException("obj could not be empty")
        }
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/bean/BaseJson.kt
ÎļþÒÑɾ³ý
src/main/kotlin/com/flightfeather/uav/lightshare/bean/BaseResponse.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package com.flightfeather.uav.lightshare.bean
import com.fasterxml.jackson.annotation.JsonInclude
/**
 * @author riku
 * Date: 2020/10/9
 * ç½‘络请求返回数据基类
 */
//"请求返回基本结构"
@JsonInclude(JsonInclude.Include.NON_NULL)
data class BaseResponse<T>(
        var success: Boolean,
        var message: String = "",
        val head: DataHead? = null,
        val data: T? = null
){
    init {
        if (message.isBlank()) {
            message = if (success) {
                "请求成功"
            } else {
                "请求失败"
            }
        }
    }
}
//"分页信息"
data class DataHead(
        var page: Int = 1,
        var totalPage: Int = 1
)
src/main/kotlin/com/flightfeather/uav/lightshare/bean/DataVo.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.flightfeather.uav.lightshare.bean
import com.fasterxml.jackson.annotation.JsonInclude
import com.flightfeather.uav.socket.bean.AirData
/**
 * @author riku
 * Date: 2020/9/10
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
data class DataVo(
        //时间,  yyyy-MM-dd HH:mm:ss
        var time: String? = null,
        //站点编号
        var deviceCode: String? = null,
        //数据值
        var values: List<AirData>? = null,
        //经度
        var lng: Double? = null,
        //纬度
        var lat: Double? = null
)
src/main/kotlin/com/flightfeather/uav/lightshare/bean/VehicleInfoVo.kt
ÎļþÒÑɾ³ý
src/main/kotlin/com/flightfeather/uav/lightshare/service/RealTimeDataService.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.flightfeather.uav.lightshare.service
import com.flightfeather.uav.lightshare.bean.BaseResponse
import com.flightfeather.uav.lightshare.bean.DataVo
interface RealTimeDataService {
    fun getSecondData(deviceCode: String?, page: Int?, perPage: Int?): BaseResponse<List<DataVo>>
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/RealTimeDataServiceImpl.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.common.utils.GsonUtils
import com.flightfeather.uav.domain.entity.RealTimeData
import com.flightfeather.uav.domain.mapper.RealTimeDataMapper
import com.flightfeather.uav.lightshare.bean.BaseResponse
import com.flightfeather.uav.lightshare.bean.DataHead
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.lightshare.service.RealTimeDataService
import com.flightfeather.uav.socket.bean.AirData
import com.github.pagehelper.PageHelper
import org.springframework.stereotype.Service
import tk.mybatis.mapper.entity.Example
import java.text.SimpleDateFormat
@Service
class RealTimeDataServiceImpl(val realTimeDataMapper: RealTimeDataMapper) : RealTimeDataService {
    override fun getSecondData(deviceCode: String?, page: Int?, perPage: Int?): BaseResponse<List<DataVo>> {
        val _perPage = perPage ?: 60
        val _page = page ?: 1
        val pageInfo = PageHelper.startPage<RealTimeData>(_page, _perPage)
        val result = mutableListOf<DataVo>()
        realTimeDataMapper.selectByExample(Example(RealTimeData::class.java).apply {
            createCriteria().apply {
                deviceCode?.let { andEqualTo("deviceCode", it) }
            }
            orderBy("dataTime").desc()
        }).forEach {
            result.add(DataVo(
                    SimpleDateFormat.getDateTimeInstance().format(it.dataTime),
                    it.deviceCode,
                    GsonUtils.parserJsonToArrayBeans(it.factors, AirData::class.java),
                    it.longitude.toDouble(), it.latitude.toDouble()
            ))
        }
        result.reverse()
        return BaseResponse(true, head = DataHead(pageInfo.pageNum, pageInfo.pages), data = result)
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/web/RealTimeDataController.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package com.flightfeather.uav.lightshare.web
import com.flightfeather.uav.lightshare.service.RealTimeDataService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("air/realtime")
class RealTimeDataController(val realTimeDataService: RealTimeDataService) {
    @GetMapping("/sec")
    fun getSecondData(
            @RequestParam(value = "deviceCode", required = false) deviceCode: String?,
            @RequestParam(value = "page", required = false) page: Int?,
            @RequestParam(value = "perPage", required = false) perPage: Int?
    ) = realTimeDataService.getSecondData(deviceCode,page, perPage)
}
src/main/kotlin/com/flightfeather/uav/repository/VehicleRepository.kt
ÎļþÒÑɾ³ý
src/main/kotlin/com/flightfeather/uav/socket/MessageManager.kt
@@ -24,6 +24,8 @@
    companion object{
        private lateinit var instance: MessageManager
        private const val TAG = "UAV"
    }
    @Autowired
@@ -46,10 +48,10 @@
        if (bccCheck(msg)) {
            //保存
            DeviceSession.saveDevice(packageData.deviceCode, ctx)
//            saveToTxt(msg)
            saveToTxt(msg)
            saveToDataBase(packageData)
        } else {
            println("------数据BCC校验失败,舍弃 [${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]")
            println("------${TAG}数据BCC校验失败,舍弃 [${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]")
        }
    }
src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt
@@ -10,16 +10,23 @@
class ServerHandler : ChannelInboundHandlerAdapter() {
    companion object {
        private const val TAG = "UAV"
    }
    val attributeKey = AttributeKey.valueOf<String>("deviceCode")
    val messageManager = MessageManager()
    override fun channelRegistered(ctx: ChannelHandlerContext?) {
        super.channelRegistered(ctx)
        println("------端口有IP连接:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        println()
        println("------${TAG}端口有IP连接:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
//        ctx?.fireChannelActive()
    }
    override fun channelActive(ctx: ChannelHandlerContext?) {
        println("------端口有IP激活:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        println()
        println("------${TAG}端口有IP激活:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        super.channelActive(ctx)
    }
@@ -29,7 +36,8 @@
        val sb = StringBuilder()
        if (msg is ByteArray) {
            println("------收到的原始数据:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
            println()
            println("------${TAG}收到的原始数据:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
            msg.forEach {
                val a: Int = if (it < 0) {
                    it + 256
@@ -48,7 +56,7 @@
        }
        val str = sb.toString()
        if (str.isNotEmpty()) {
            MessageManager().dealStringMsg(str, ctx)
            messageManager.dealStringMsg(str, ctx)
        }
    }
@@ -58,7 +66,7 @@
    }
    override fun channelInactive(ctx: ChannelHandlerContext?) {
        println("------端口有IP不活动:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        println("------${TAG}端口有IP不活动:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        super.channelInactive(ctx)
    }
src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt
@@ -1,5 +1,6 @@
package com.flightfeather.uav.socket
import com.flightfeather.uav.socket.decoder.impl.DataPackageDecoderImpl
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.ByteToMessageDecoder
@@ -13,11 +14,11 @@
class UAVByteDataDecoder : ByteToMessageDecoder() {
    companion object {
        private const val HEAD_BYTES = 2//数据头所占长度
        private const val LENGTH_BYTES = 1//数据位数所占长度
        private const val BCC_BYTES = 2//校验码长度
        const val BASE_LENGTH = HEAD_BYTES + LENGTH_BYTES + BCC_BYTES
        const val BASE_LENGTH = DataPackageDecoderImpl.HEAD_BYTES + DataPackageDecoderImpl.COMMAND_UNIT_BYTES +
                DataPackageDecoderImpl.DEVICE_CODE_BYTES + DataPackageDecoderImpl.DATA_LENGTH + DataPackageDecoderImpl.BCC_BYTES
        const val HEAD1 = 0x01.toByte()
        const val HEAD_LENGTH = DataPackageDecoderImpl.HEAD_BYTES + DataPackageDecoderImpl.COMMAND_UNIT_BYTES +
                DataPackageDecoderImpl.DEVICE_CODE_BYTES
    }
    override fun decode(p0: ChannelHandlerContext?, p1: ByteBuf?, p2: MutableList<Any>?) {
@@ -41,11 +42,12 @@
                    // æ ‡è®°åŒ…头开始的index
                    it.markReaderIndex()
                    // è¯»åˆ°äº†åè®®çš„开始标志,结束while循环
                    val b = ByteArray(2)
                    val b = ByteArray(HEAD_LENGTH)
                    it.readBytes(b)
                    if (b[0] == HEAD1) {
                        dataList.add(b[0])
                        dataList.add(b[1])
                        b.forEach {b ->
                            dataList.add(b)
                        }
                        break
                    }
@@ -69,14 +71,14 @@
                //数据单元的长度
                val length = getDataUnitLength(it, dataList)
                // åˆ¤æ–­è¯·æ±‚数据单元数据及[LENGTH_BYTES]个字节的校验码是否到齐
                if (it.readableBytes() < length + BCC_BYTES) {
                if (it.readableBytes() < length + DataPackageDecoderImpl.BCC_BYTES) {
                    // è¿˜åŽŸè¯»æŒ‡é’ˆ
                    it.readerIndex(beginReader)
                    return
                }
                //读取数据单元和校验码数据
                ByteArray(length + BCC_BYTES).apply {
                ByteArray(length + DataPackageDecoderImpl.BCC_BYTES).apply {
                    it.readBytes(this)
                }.forEach {b ->
                    dataList.add(b)
src/main/kotlin/com/flightfeather/uav/socket/bean/AirDataPackage.kt
@@ -33,10 +33,12 @@
        //数据中的保留字节数
        const val RESERVED_DATA_COUNT = 12
        //一个动态监测因子的属性所占字节数
        const val FACTOR_BIT_LENGTH_1 = 6
        //一个保留监测因子的属性所占字节数
        const val FACTOR_BIT_LENGTH_2 = 3
        //一个动态监测因子的属性所占字节数
        const val FACTOR_BIT_LENGTH_1 = 6
        const val FACTOR_BIT_LENGTH_3 = 2
    }
}
src/main/kotlin/com/flightfeather/uav/socket/bean/DataUnit.kt
@@ -11,5 +11,5 @@
 * æ ¹æ®å‘½ä»¤å•å…ƒ @see [AirCommandUnit] çš„分类,不同类型的结构不同,见各子类
 */
open class DataUnit {
    var time: Date? = null
}
src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt
@@ -21,8 +21,8 @@
 */
interface DataUnitDecoder {
    fun getAirConfirmData(b: List<String>): List<AirTypeData>
    fun getAirConfirmData(b: List<String>, deviceCode: String?): List<AirTypeData>
    fun getAirData(b: List<String>): List<AirData>
    fun getAirData(b: List<String>, deviceCode: String?): List<AirData>
}
src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataPackageDecoderImpl.kt
@@ -5,6 +5,7 @@
import com.flightfeather.uav.socket.decoder.DataUnitDecoder
import com.flightfeather.uav.socket.eunm.AirCommandUnit
import java.util.*
import kotlin.text.StringBuilder
/**
 * @author riku
@@ -12,54 +13,78 @@
 */
class DataPackageDecoderImpl : DataPackageDecoder {
    companion object {
        const val HEAD_BYTES = 1
        const val COMMAND_UNIT_BYTES = 1
        const val DEVICE_CODE_BYTES = 1
        const val DATA_LENGTH = 1
        const val BCC_BYTES = 2
    }
    private val dataUnitDecoder: DataUnitDecoder = DataUnitDecoderImpl()
    override fun getHead(b: List<String>): String? {
        return if (b.isNotEmpty()) {
            b[0]
            val s = StringBuilder()
            repeat(HEAD_BYTES) {
                s.append(b[it])
            }
            s.toString()
        } else {
            null
        }
    }
    override fun getCommandUnit(b: List<String>): Int? = if (b.size >= 2) {
        b[1].toIntOrNull(16)
    override fun getCommandUnit(b: List<String>): Int? = if (b.size >= (HEAD_BYTES + COMMAND_UNIT_BYTES)) {
        val s = StringBuilder()
        repeat(COMMAND_UNIT_BYTES) {
            s.append(b[HEAD_BYTES + it])
        }
        s.toString().toIntOrNull(16)
    } else {
        null
    }
    override fun getDeviceCode(b: List<String>): String? {
        return null
    override fun getDeviceCode(b: List<String>): String? = if (b.size >= (HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES)) {
        //2021/1/7 '0A'代表车载设备,'0B'代表无人机设备
        val s = StringBuilder()
        repeat(DEVICE_CODE_BYTES) {
            s.append(b[HEAD_BYTES + COMMAND_UNIT_BYTES + it])
        }
        s.toString()
    } else {
        null
    }
    override fun getDataTime(b: List<String>): Date {
        //fixme 2020/06/11  ç›®å‰æ•°æ®æµä¸­ä¸åŒ…含采样时间,所以采用服务器接收时间作为采样时间
        // FIXME: 2021/1/7 é‡‡æ ·æ—¶é—´å’Œç›‘测因子一同放在了数据部分,此处不再做解析
        return Date()
    }
    override fun getDataLength(b: List<String>): Int {
        if (b.size < 5) return 0
        if (b.size <= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH) return 0
        val hexNum = b[2]
        val hexNum = b[HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES]
        return hexNum.toIntOrNull(16) ?: 0
    }
    override fun getDataUnit(b: List<String>): List<DataUnit> {
        if (getDataLength(b) == 0 || b.size < 5) {
        if (getDataLength(b) == 0 || b.size <= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH) {
            return emptyList()
        }
        val unit = mutableListOf<String>()
        for (i in 3..b.size - 3) {
        val start = HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH
        for (i in start..b.size - 1 - BCC_BYTES) {
            unit.add(b[i])
        }
        dataUnitDecoder.run {
            return when (getCommandUnit(b)) {
                AirCommandUnit.Confirm.value -> getAirConfirmData(unit)
                AirCommandUnit.AirData.value -> getAirData(unit)
                AirCommandUnit.Confirm.value -> getAirConfirmData(unit, getDeviceCode(b))
                AirCommandUnit.AirData.value -> getAirData(unit, getDeviceCode(b))
                else -> emptyList()
            }
        }
src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataUnitDecoderImpl.kt
@@ -16,26 +16,33 @@
    private val logger = LoggerFactory.getLogger(javaClass.name)
    private val types = mutableListOf<AirTypeData>()
    private val types = mutableMapOf<String?, MutableList<AirTypeData>>()
    override fun getAirConfirmData(b: List<String>): List<AirTypeData> {
    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))
            }
        }
        types.clear()
        types.addAll(resultList)
        if (!types.containsKey(deviceCode)) {
            types[deviceCode] = mutableListOf()
        }
        types[deviceCode]?.clear()
        types[deviceCode]?.addAll(resultList)
        return resultList
    }
    override fun getAirData(b: List<String>): List<AirData> {
    override fun getAirData(b: List<String>, deviceCode: String?): List<AirData> {
        val resultList = mutableListOf<AirData>()
        if (!types.containsKey(deviceCode)) {
            return resultList
        }
        var i = 0
        types.forEach {
        types[deviceCode]?.forEach {
            if (i > b.size - it.factorType.byteLength) {
                return@forEach
            }
@@ -43,13 +50,17 @@
            when (it.factorType) {
                FactorType.LNG -> {
                    val valid = b[i].toInt(16).toChar()//经纬度是否有效(有效: A; æ— æ•ˆ: V)
                    val a1 = b[i + 1].toInt(16)
                    val b1 = b[i + 2].toInt(16)
                    var b2 = "${b[i + 3]}${b[i + 4]}".toInt(16).toDouble()
                    while (b2 >= 1) {
                        b2 /= 10
                    }
                    val lng = a1 + (b1 + b2) / 60
                    //经纬度原始值,例: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 {
@@ -62,11 +73,12 @@
                FactorType.LAT -> {
                    val a1 = b[i].toInt(16)
                    val b1 = b[i + 1].toInt(16)
                    var b2 = "${b[i + 2]}${b[i + 3]}".toInt(16).toDouble()
                    while (b2 >= 1) {
                        b2 /= 10
                    }
                    val lat = a1 + (b1 + b2) / 60
                    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()
@@ -131,6 +143,14 @@
                                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()
                            })
                        }
                    }
                }
            }
src/main/kotlin/com/flightfeather/uav/socket/eunm/FactorType.kt
@@ -19,7 +19,9 @@
    LNG(12,"LNG",6),//经度
    LAT(13,"LAT",5),//纬度
    VELOCITY(14, "VELOCITY", 3),//速度
    TIME(15, "TIME", 6);//时间
    TIME(15, "TIME", 6),//时间
    WIND_SPEED(16, "WIND_SPEED", 3),
    WIND_DIRECTION(17, "WIND_DIRECTION", 2);
    companion object {
@@ -39,6 +41,8 @@
            LAT.value -> LAT
            VELOCITY.value -> VELOCITY
            TIME.value -> TIME
            WIND_SPEED.value -> WIND_SPEED
            WIND_DIRECTION.value -> WIND_DIRECTION
            else -> null
        }
    }
src/main/kotlin/com/flightfeather/uav/socket/eunm/ObdDataType.kt
ÎļþÒÑɾ³ý
src/main/resources/application.yml
@@ -8,6 +8,11 @@
    url: jdbc:mysql://114.215.109.124:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
    username: root
    password: 123456
    hikari:
      maximum-pool-size: 500
      minimum-idle: 20
      idle-timeout: 60000
      connection-timeout: 60000
  jmx:
    enabled: false
src/test/kotlin/com/flightfeather/uav/Test.kt
@@ -1,10 +1,44 @@
package com.flightfeather.uav
import com.flightfeather.uav.socket.bean.DataUnit
import com.flightfeather.uav.socket.decoder.AirDataDecoder
import com.flightfeather.uav.socket.eunm.AirCommandUnit
import com.google.gson.Gson
import org.junit.Test
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStreamWriter
import java.text.SimpleDateFormat
import java.util.*
/**
 * @author riku
 * Date: 2019/9/12
 */
class Test {
    @Test
    fun foo1() {
        val s = SimpleDateFormat.getDateTimeInstance().format(Date())
        println(s)
    }
    @Test
    fun foo2() {
        val file = File("E:\\VSprojects\\uav-monitor\\asset\\data\\data-2020-12-24-01-34-24.txt")
        val outFile = File("E:\\VSprojects\\uav-monitor\\asset\\data\\data.json")
        val out = OutputStreamWriter(FileOutputStream(outFile))
        val list = mutableListOf<List<DataUnit>>()
        file.readLines().forEach {
            val p = AirDataDecoder.instance.decode(it)
//            val str = Gson().toJson(p.dataUnit)
            if (p.commandUnit == AirCommandUnit.AirData.value) {
                list.add(p.dataUnit)
            }
        }
        val str = Gson().toJson(list)
        out.append(str)
        out.flush()
        out.close()
    }
}